From 7c46f49513b7838a927dacd4a554f95b5de4b174 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 5 Jan 2024 12:18:26 -0500 Subject: [PATCH 001/188] Split Aircraft.Design.RESERVES to two variables --- .../getting_started/input_csv_phase_info.md | 23 +++++++ aviary/interface/methods_for_level2.py | 68 +++++++++++-------- aviary/interface/test/test_reserve_support.py | 8 +-- .../large_single_aisle_1_GwGm.csv | 4 +- .../large_single_aisle_1_GwGm.dat | 2 + .../small_single_aisle_GwGm.csv | 4 +- .../small_single_aisle_GwGm.dat | 4 +- .../test_aircraft/aircraft_for_bench_FwFm.csv | 3 +- .../test_aircraft/aircraft_for_bench_FwGm.csv | 3 +- .../test_aircraft/aircraft_for_bench_GwFm.csv | 3 +- .../test_aircraft/aircraft_for_bench_GwGm.csv | 3 +- ...converter_configuration_test_data_GwGm.csv | 4 +- ...converter_configuration_test_data_GwGm.dat | 4 +- .../legacy_code_data/gasp_default_values.dat | 4 +- aviary/utils/process_input_decks.py | 57 ++++++++++++++-- aviary/variable_info/variable_meta_data.py | 30 +++++++- aviary/variable_info/variables.py | 2 + 17 files changed, 175 insertions(+), 51 deletions(-) diff --git a/aviary/docs/getting_started/input_csv_phase_info.md b/aviary/docs/getting_started/input_csv_phase_info.md index 08fc04076..447c43733 100644 --- a/aviary/docs/getting_started/input_csv_phase_info.md +++ b/aviary/docs/getting_started/input_csv_phase_info.md @@ -6,6 +6,29 @@ This section is under development. ``` +`initial_guesses` is a dictionary that contains values used to initialize the trajectory. It contains the following keys along with default values: + +- actual_takeoff_mass: 0, +- rotation_mass: .99, +- operating_empty_mass: 0, +- fuel_burn_per_passenger_mile: 0.1, +- cruise_mass_final: 0, +- flight_duration: 0, +- time_to_climb: 0, +- climb_range: 0, +- reserves: 0 + +The initial guess of `reserves` is used to define the reserve fuel. Initially, its value can be anything larger than 10 or anything between -1 and 0. There are three variables to control the reserve fuel in the model file (`.csv`): +- Aircraft.Design.RESERVES: the required fuel reserves: directly in lbm, +- Aircraft.Design.RESERVES_FRACTION: the required fuel reserves: given as a proportion of mission fuel, +- Aircraft.Design.RESERVES_OPTION: if 1, use Aircraft.Design.RESERVES; if 2, use Aircraft.Design.RESERVES_FRACTION + +If the value of parameter `reserves` is not 0 and is within the allowed range, the initial guess of reserve fuel is determined by the parameter `reserves`: +- if `reserves > 10.0`, we set `Aircraft.Design.RESERVES = reserves` and `Aircraft.Design.RESERVES_OPTION = 1`, +- if `-1.0 <= reserves <= 0`, we set `Aircraft.Design.RESERVES_FRACTION = reserves` and `Aircraft.Design.RESERVES_OPTION = 2`. + +The initial guess of `reserves` is always converted to the actual design reserves (instead of reserve factor) and is used to update the initial guesses of `fuel_burn_per_passenger_mile` and `cruise_mass_final`. + ## Phase Info Dictionary `phase_info` is a nested dictionary that Aviary uses for users to define their mission phases - how they are built, the design variables, constraints, connections, etc. diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 06f038472..26d89e116 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -2436,31 +2436,45 @@ def _add_gasp_landing_systems(self): ) def _add_fuel_reserve_component(self, reserves_name=Mission.Design.RESERVE_FUEL): - reserves_val = self.aviary_inputs.get_val(Aircraft.Design.RESERVES) - if reserves_val <= 0: - reserves_val = -reserves_val - self.model.add_subsystem( - "reserves_calc", - om.ExecComp( - f"reserve_fuel = {reserves_val}*(takeoff_mass - final_mass)", - takeoff_mass={"units": "lbm"}, - final_mass={"units": "lbm"}, - reserve_fuel={"units": "lbm"} - ), - promotes_inputs=[ - ("takeoff_mass", Mission.Summary.GROSS_MASS), - ("final_mass", Mission.Landing.TOUCHDOWN_MASS), - ], - promotes_outputs=[("reserve_fuel", reserves_name)], - ) - elif reserves_val > 10: - self.model.add_subsystem( - "reserves_calc", - om.ExecComp( - f"reserve_fuel = {reserves_val}", - reserve_fuel={"val": reserves_val, "units": "lbm"} - ), - promotes_outputs=[("reserve_fuel", reserves_name)], - ) + reserves_val = self.aviary_inputs.get_val(Aircraft.Design.RESERVES, units='lbm') + reserves_fac = self.aviary_inputs.get_val( + Aircraft.Design.RESERVES_FRACTION, units='unitless') + reserves_opt = self.aviary_inputs.get_val( + Aircraft.Design.RESERVES_OPTION, units='unitless') + if reserves_opt == 1: + if reserves_val > 10: + self.model.add_subsystem( + "reserves_calc", + om.ExecComp( + f"reserve_fuel = {reserves_val}", + reserve_fuel={"val": reserves_val, "units": "lbm"} + ), + promotes_outputs=[("reserve_fuel", reserves_name)], + ) + else: + raise ValueError('"aircraft:design:reserves" is not valid below 10.') + elif reserves_opt == 2: + if reserves_fac <= 0 and reserves_fac >= -1: + reserves_fac = -reserves_fac + self.model.add_subsystem( + "reserves_calc", + om.ExecComp( + f"reserve_fuel = {reserves_fac}*(takeoff_mass - final_mass)", + takeoff_mass={"units": "lbm"}, + final_mass={"units": "lbm"}, + reserve_fuel={"units": "lbm"} + ), + promotes_inputs=[ + ("takeoff_mass", Mission.Summary.GROSS_MASS), + ("final_mass", Mission.Landing.TOUCHDOWN_MASS), + ], + promotes_outputs=[("reserve_fuel", reserves_name)], + ) + elif reserves_fac > 0 and reserves_fac <= 1: + raise ValueError( + '"aircraft:design:reserves_fraction" between 0 and 1 is not implemented.') + else: + raise ValueError( + '"aircraft:design:reserves_fraction" is not valid if less than -1 or larger than 1.') else: - raise ValueError('"aircraft:design:reserves" is not valid between 0 and 10.') + raise ValueError('"aircraft:design:reserves_option" must be 1 or 2.') diff --git a/aviary/interface/test/test_reserve_support.py b/aviary/interface/test/test_reserve_support.py index b0b3982d8..7fed83a67 100644 --- a/aviary/interface/test/test_reserve_support.py +++ b/aviary/interface/test/test_reserve_support.py @@ -25,10 +25,7 @@ def test_post_mission_promotion(self): prob.load_inputs(csv_path) prob.check_inputs() - # TODO: This needs to be converted into a reserve and a scaler so that it can - # be given proper units. - # The units here are lbm. - prob.aviary_inputs.set_val(Aircraft.Design.RESERVES, 10000.0, units='unitless') + prob.aviary_inputs.set_val(Aircraft.Design.RESERVES, 10000.0, units='lbm') prob.add_pre_mission_systems() prob.add_phases() @@ -75,7 +72,8 @@ def test_gasp_relative_reserve(self): prob.run_model() - res_frac = prob.aviary_inputs.get_val(Aircraft.Design.RESERVES, units='unitless') + res_frac = prob.aviary_inputs.get_val( + Aircraft.Design.RESERVES_FRACTION, units='unitless') td_mass = prob.model.get_val(Mission.Landing.TOUCHDOWN_MASS, units='lbm') reserve = prob.model.get_val(Mission.Design.RESERVE_FUEL, units='lbm') assert_near_equal(reserve, -res_frac * (140000.0 - td_mass), 1e-3) diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv index 7a69a9942..2092a85fb 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv @@ -14,7 +14,9 @@ aircraft:design:drag_increment,0.00175,unitless aircraft:design:equipment_mass_coefficients,928,0.0736,0.112,0.14,1959,1.65,551,11192,5,3,50,7.6,12,unitless aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves,4998,unitless +aircraft:design:reserves,4998,lbm +aircraft:design:reserves_fraction,0,unitless +aircraft:design:reserves_option,1,unitless aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat index f23fff285..b8a4d51f3 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat @@ -195,6 +195,8 @@ aircraft:engine:data_file=models/engines/turbofan_23k_1.deck ROSCAB=9999., ! cabin rate of sink during descent (500.) fpm RSMX=900., ! maximum allowable rate of sink during landing approach ft per min (1000) FRESF=4998, ! Reserve Fuel fraction of mission fuel (minus sign for code trigger) + FRESF2=0, ! Reserve fuel fraction of mission fuel (negative sign trigger) + FRESF3=1, ! Use Reserve Fuel RF(1)=.05, ! Reserve Fuel Input: Time for Missed Approach RF(2)=125., ! Reserve Fuel Input: Range to alternate RF(3)=20000., ! Reserve Fuel Input: Cruise altitude to alternate diff --git a/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv b/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv index e395cf439..c444f9a8e 100644 --- a/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv +++ b/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv @@ -14,7 +14,9 @@ aircraft:design:drag_increment,0.0018,unitless aircraft:design:equipment_mass_coefficients,778,0.06,0.112,0.14,1349,1.65,397,9071,7.6,3,50,6,12,unitless aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves,-0.125,unitless +aircraft:design:reserves,0,lbm +aircraft:design:reserves_fraction,-0.125,unitless +aircraft:design:reserves_option,2,unitless aircraft:design:static_margin,0.05,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.025,unitless diff --git a/aviary/models/small_single_aisle/small_single_aisle_GwGm.dat b/aviary/models/small_single_aisle/small_single_aisle_GwGm.dat index 143b405d4..d6736b834 100644 --- a/aviary/models/small_single_aisle/small_single_aisle_GwGm.dat +++ b/aviary/models/small_single_aisle/small_single_aisle_GwGm.dat @@ -205,7 +205,9 @@ OFEM=.78, ! off design specified mission Mach number ROSCAB=9999., ! cabin rate of sink during descent (500.) fpm RSMX=900., ! maximum allowable rate of sink during landing approach ft per min (1000) - FRESF=-.125, ! Reserve Fuel fraction of mission fuel (minus sign for code trigger) + FRESF=0, ! Reserve Fuel + FRESF2=-.125, ! Reserve Fuel fraction of mission fuel (minus sign for code trigger) + FRESF3=2, ! Use Reserve Fuel RF(1)=2.0, ! Reserve Fuel Input: Time for Missed Approach (min) RF(2)=100., ! Reserve Fuel Input: Range to alternate RF(3)=25000., ! Reserve Fuel Input: Cruise altitude to alternate diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv index 0c2985b9e..a3b66e387 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv @@ -25,7 +25,8 @@ aircraft:design:base_area,0.0,ft**2 aircraft:design:empty_mass_margin_scaler,0.0,unitless aircraft:design:lift_dependent_drag_coeff_factor,0.909839381134961,unitless aircraft:design:touchdown_mass,152800.0,lbm -aircraft:design:reserves,3000.,unitless +aircraft:design:reserves,3000.,lbm +aircraft:design:reserves_option,1,unitless aircraft:design:subsonic_drag_coeff_factor,1.0,unitless aircraft:design:supersonic_drag_coeff_factor,1.0,unitless aircraft:design:use_alt_mass,False,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv index d8128ce1e..316c73a5c 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv @@ -12,7 +12,8 @@ aircraft:design:drag_increment,0.00175,unitless aircraft:design:equipment_mass_coefficients,928,0.0736,0.112,0.14,1959,1.65,551,11192,5,3,50,7.6,12,unitless aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves,3000.,unitless +aircraft:design:reserves,3000.,lbm +aircraft:design:reserves_option,1,unitless aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.025,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv index 58caba631..4881c183b 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv @@ -39,7 +39,8 @@ aircraft:design:lift_dependent_drag_coeff_factor,0.909839381134961,unitless aircraft:design:touchdown_mass,152800.0,lbm aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves,5000.,unitless +aircraft:design:reserves,5000.,lbm +aircraft:design:reserves_option,1,unitless aircraft:design:smooth_mass_discontinuities,False,unitless aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv index 70c78f420..17f76a7c0 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv @@ -13,7 +13,8 @@ aircraft:design:drag_increment,0.00175,unitless aircraft:design:equipment_mass_coefficients,928,0.0736,0.112,0.14,1959,1.65,551,11192,5,3,50,7.6,12,unitless aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves,4998,unitless +aircraft:design:reserves,4998,lbm +aircraft:design:reserves_option,1,unitless aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless diff --git a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv index a52b15fb7..4367304b9 100644 --- a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv +++ b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv @@ -14,7 +14,9 @@ aircraft:design:drag_increment,0.0014,unitless aircraft:design:equipment_mass_coefficients,1014,0.0736,0.085,0.105,1504,1.65,126,9114,5,3,0,10,12,unitless aircraft:design:max_structural_speed,440,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves,-0.15,unitless +aircraft:design:reserves,0,lbm +aircraft:design:reserves_fraction,-0.15,unitless +aircraft:design:reserves_option,2,unitless aircraft:design:static_margin,0.05,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless diff --git a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.dat b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.dat index 1ee358869..e6ed8dbee 100644 --- a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.dat +++ b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.dat @@ -209,7 +209,9 @@ aircraft:engine:data_file=models/engines/turbofan_23k_1.deck OFEM=.78, ! off design specified mission Mach number ROSCAB=9999., ! cabin rate of sink during descent (500.) fpm RSMX=900., ! maximum allowable rate of sink during landing approach ft per min (1000) - FRESF=-0.15, ! Reserve fuel fraction of mission fuel (negative sign trigger) + FRESF=0, ! Reserve Fuel + FRESF2=-0.15, ! Reserve fuel fraction of mission fuel (negative sign trigger) + FRESF3=2, ! Use Reserve Fuel fraction RF(1)=.05, ! Reserve Fuel Input: Time for Missed Approach RF(2)=125., ! Reserve Fuel Input: Range to alternate RF(3)=20000., ! Reserve Fuel Input: Cruise altitude to alternate diff --git a/aviary/utils/legacy_code_data/gasp_default_values.dat b/aviary/utils/legacy_code_data/gasp_default_values.dat index 57a3de66c..9121140fb 100644 --- a/aviary/utils/legacy_code_data/gasp_default_values.dat +++ b/aviary/utils/legacy_code_data/gasp_default_values.dat @@ -83,7 +83,9 @@ EYEW=1.5,deg FLAPN=1,unitless FN_REF=28690,lbf FPYL=0.7,unitless -FRESF=4998,unitless +FRESF=4998,lbm +FRESF2=-0.1,unitless +FRESF3=1,unitless FUELD=6.687,lbm/galUS FVOL_MRG=0,unitless HAPP=50,ft diff --git a/aviary/utils/process_input_decks.py b/aviary/utils/process_input_decks.py index 46c9256a5..22bc6ae05 100644 --- a/aviary/utils/process_input_decks.py +++ b/aviary/utils/process_input_decks.py @@ -45,7 +45,9 @@ def create_vehicle(vehicle_deck=''): aircraft_values.set_val('mass_defect', val=10000, units='lbm') aircraft_values.set_val('problem_type', val=ProblemType.SIZING) aircraft_values.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False) - aircraft_values.set_val(Aircraft.Design.RESERVES, val=4998) + aircraft_values.set_val(Aircraft.Design.RESERVES, val=4998, units='lbm') + aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, val=0, units='unitless') + aircraft_values.set_val(Aircraft.Design.RESERVES_OPTION, val=0, units='unitless') vehicle_deck = get_path(vehicle_deck) @@ -164,10 +166,56 @@ def update_dependent_options(aircraft_values: AviaryValues(), dependent_options) def initial_guessing(aircraft_values: AviaryValues()): problem_type = aircraft_values.get_val('problem_type') + reserves_option = aircraft_values.get_val(Aircraft.Design.RESERVES_OPTION) reserves = aircraft_values.get_val( - Aircraft.Design.RESERVES) if initial_guesses['reserves'] == 0 else initial_guesses['reserves'] + Aircraft.Design.RESERVES, units='lbm') if initial_guesses['reserves'] == 0 else initial_guesses['reserves'] + if reserves_option == 1: + aircraft_values.set_val(Aircraft.Design.RESERVES, reserves, units='lbm') + if reserves < 10: + raise ValueError('"aircraft:design:reserves" must be greater than 10 lbm.') + elif reserves_option == 2: + if initial_guesses['reserves'] == 0: + reserves = aircraft_values.get_val( + Aircraft.Design.RESERVES_FRACTION, units='unitless') + else: + reserves = initial_guesses['reserves'] + aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, + reserves, units='unitless') + if reserves < -1 or reserves > 0: + raise ValueError('"aircraft:design:reserves_fraction" must be in [-1, 0].') + else: + # if aircraft:design:reserves_option is not set, + # then determine reserves based on initial_guesses['reserves'] + if initial_guesses['reserves'] > 10: + reserves = initial_guesses['reserves'] + reserves_option = 1 + aircraft_values.set_val(Aircraft.Design.RESERVES, reserves, units='lbm') + elif initial_guesses['reserves'] < 0: + reserves = initial_guesses['reserves'] + reserves_option = 2 + aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, + reserves, units='unitless') + elif initial_guesses['reserves'] == 0 and reserves > 10: + reserves_option = 1 + aircraft_values.set_val(Aircraft.Design.RESERVES, reserves, units='lbm') + elif initial_guesses['reserves'] == 0 and reserves < 0: + reserves_option = 2 + aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, + reserves, units='unitless') + aircraft_values.set_val(Aircraft.Design.RESERVES_OPTION, + reserves_option, units='unitless') + num_pax = aircraft_values.get_val(Aircraft.CrewPayload.NUM_PASSENGERS) + if reserves_option == 2: + if reserves <= 0: + reserves *= -(num_pax * initial_guesses['fuel_burn_per_passenger_mile'] * + aircraft_values.get_val(Mission.Design.RANGE, units='NM')) + else: + raise ValueError( + 'The case that "aircraft:design:reserves_fraction" is between 0 and 1 is not implemented.') + initial_guesses['reserves'] = reserves + if Mission.Summary.GROSS_MASS in aircraft_values: mission_mass = aircraft_values.get_val(Mission.Summary.GROSS_MASS, units='lbm') else: @@ -179,11 +227,6 @@ def initial_guessing(aircraft_values: AviaryValues()): else: cruise_mass_final = initial_guesses['cruise_mass_final'] - if reserves < 0: - reserves *= -(num_pax * - initial_guesses['fuel_burn_per_passenger_mile'] * aircraft_values.get_val(Mission.Design.RANGE, units='NM')) - initial_guesses['reserves'] = reserves - # takeoff mass not given if mission_mass <= 0: if problem_type == ProblemType.ALTERNATE: diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index bd44af54c..f8aeb4c27 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -1204,9 +1204,35 @@ "LEAPS1": None }, option=True, + units="lbm", + desc='required fuel reserves: directly in lbm', + default_value=0, +) + +add_meta_data( + Aircraft.Design.RESERVES_FRACTION, + meta_data=_MetaData, + historical_name={"GASP": 'INGASP.FRESF2', # the real name is INGASP.FRESF + "FLOPS": None, + "LEAPS1": None + }, + option=True, + units="unitless", + desc='required fuel reserves: given as a proportion of mission fuel', + default_value=0, +) + +add_meta_data( + Aircraft.Design.RESERVES_OPTION, + meta_data=_MetaData, + historical_name={"GASP": 'INGASP.FRESF3', # the real name is INGASP.FRESF + "FLOPS": None, + "LEAPS1": None + }, + option=True, + types=int, units="unitless", - desc='required fuel reserves: given either as a proportion of mission fuel' - '(<0) or directly in lbf (>10)', + desc='if 1, use Aircraft.Design.RESERVES; if 2, use Aircraft.Design.RESERVES_FRACTION', default_value=0, ) diff --git a/aviary/variable_info/variables.py b/aviary/variable_info/variables.py index 51d5df4c6..df40a30ad 100644 --- a/aviary/variable_info/variables.py +++ b/aviary/variable_info/variables.py @@ -149,6 +149,8 @@ class Design: OPERATING_MASS = 'aircraft:design:operating_mass' PART25_STRUCTURAL_CATEGORY = 'aircraft:design:part25_structural_category' RESERVES = 'aircraft:design:reserves' + RESERVES_FRACTION = 'aircraft:design:reserves_fraction' + RESERVES_OPTION = 'aircraft:design:reserves_option' SMOOTH_MASS_DISCONTINUITIES = 'aircraft:design:smooth_mass_discontinuities' STATIC_MARGIN = 'aircraft:design:static_margin' STRUCTURAL_MASS_INCREMENT = 'aircraft:design:structural_mass_increment' From cda06b0f1bff9df52e053d76d6c4d37bd4004452 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 5 Jan 2024 13:40:45 -0500 Subject: [PATCH 002/188] minor change to doc file --- aviary/docs/getting_started/input_csv_phase_info.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aviary/docs/getting_started/input_csv_phase_info.md b/aviary/docs/getting_started/input_csv_phase_info.md index 447c43733..b3a8358d9 100644 --- a/aviary/docs/getting_started/input_csv_phase_info.md +++ b/aviary/docs/getting_started/input_csv_phase_info.md @@ -19,9 +19,9 @@ This section is under development. - reserves: 0 The initial guess of `reserves` is used to define the reserve fuel. Initially, its value can be anything larger than 10 or anything between -1 and 0. There are three variables to control the reserve fuel in the model file (`.csv`): -- Aircraft.Design.RESERVES: the required fuel reserves: directly in lbm, -- Aircraft.Design.RESERVES_FRACTION: the required fuel reserves: given as a proportion of mission fuel, -- Aircraft.Design.RESERVES_OPTION: if 1, use Aircraft.Design.RESERVES; if 2, use Aircraft.Design.RESERVES_FRACTION +- `Aircraft.Design.RESERVES`: the required fuel reserves: directly in lbm, +- `Aircraft.Design.RESERVES_FRACTION`: the required fuel reserves: given as a proportion of mission fuel, +- `Aircraft.Design.RESERVES_OPTION`: if 1, use `Aircraft.Design.RESERVES`; if 2, use `Aircraft.Design.RESERVES_FRACTION` If the value of parameter `reserves` is not 0 and is within the allowed range, the initial guess of reserve fuel is determined by the parameter `reserves`: - if `reserves > 10.0`, we set `Aircraft.Design.RESERVES = reserves` and `Aircraft.Design.RESERVES_OPTION = 1`, From 73b528c1c6b1a7ed756a7165926b4e0c31083c5c Mon Sep 17 00:00:00 2001 From: "Kenneth T. Moore" Date: Fri, 5 Jan 2024 15:53:21 -0500 Subject: [PATCH 003/188] Switch some interps to more efficient versions; cleaned up a couple failing benches --- .../phases/detailed_takeoff_phases.py | 20 +++++++------- .../gasp_based/flaps_model/meta_model.py | 26 +++++++++---------- .../aerodynamics/gasp_based/gaspaero.py | 2 +- .../benchmark_tests/test_bench_FwGm.py | 8 +++--- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/aviary/mission/flops_based/phases/detailed_takeoff_phases.py b/aviary/mission/flops_based/phases/detailed_takeoff_phases.py index 742c774f8..c044fd9b8 100644 --- a/aviary/mission/flops_based/phases/detailed_takeoff_phases.py +++ b/aviary/mission/flops_based/phases/detailed_takeoff_phases.py @@ -198,7 +198,7 @@ def build_phase(self, aviary_options=None): phase.add_state( Dynamic.MASS, fix_initial=True, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', + lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, targets=Dynamic.MASS, ) @@ -368,7 +368,7 @@ def build_phase(self, aviary_options=None): phase.add_state( Dynamic.MASS, fix_initial=False, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', + lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, targets=Dynamic.MASS, ) @@ -651,7 +651,7 @@ def build_phase(self, aviary_options=None): phase.add_state( Dynamic.MASS, fix_initial=False, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', + lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, targets=Dynamic.MASS, ) @@ -852,7 +852,7 @@ def build_phase(self, aviary_options: AviaryValues = None): phase.add_state( Dynamic.MASS, fix_initial=False, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', + lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, targets=Dynamic.MASS, ) @@ -1088,7 +1088,7 @@ def build_phase(self, aviary_options: AviaryValues = None): phase.add_state( Dynamic.MASS, fix_initial=False, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', + lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, targets=Dynamic.MASS, ) @@ -1320,7 +1320,7 @@ def build_phase(self, aviary_options: AviaryValues = None): phase.add_state( Dynamic.MASS, fix_initial=False, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', + lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, targets=Dynamic.MASS, ) @@ -1548,7 +1548,7 @@ def build_phase(self, aviary_options: AviaryValues = None): phase.add_state( Dynamic.MASS, fix_initial=False, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', + lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, targets=Dynamic.MASS, ) @@ -1764,7 +1764,7 @@ def build_phase(self, aviary_options: AviaryValues = None): phase.add_state( Dynamic.MASS, fix_initial=False, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', + lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, targets=Dynamic.MASS, ) @@ -1993,7 +1993,7 @@ def build_phase(self, aviary_options: AviaryValues = None): phase.add_state( Dynamic.MASS, fix_initial=False, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', + lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, targets=Dynamic.MASS, ) @@ -2199,7 +2199,7 @@ def build_phase(self, aviary_options=None): phase.add_state( Dynamic.MASS, fix_initial=False, fix_final=False, - lower=0.0, ref=5e4, defect_ref=5e4, units='kg', + lower=0.0, upper=1e9, ref=5e4, defect_ref=5e4, units='kg', rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, targets=Dynamic.MASS, ) diff --git a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/meta_model.py b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/meta_model.py index fc711963d..a1736cdcd 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/meta_model.py +++ b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/meta_model.py @@ -21,7 +21,7 @@ def setup(self): # VDEL1 VDEL1_interp = self.add_subsystem( "VDEL1_interp", - om.MetaModelStructuredComp(method="scipy_slinear", extrapolate=True), + om.MetaModelStructuredComp(method="1D-slinear", extrapolate=True), promotes_inputs=[ "aircraft:*", ], @@ -61,7 +61,7 @@ def setup(self): # VDEL2 VDEL2_interp = self.add_subsystem( "VDEL2_interp", - om.MetaModelStructuredComp(method="scipy_slinear", extrapolate=True), + om.MetaModelStructuredComp(method="1D-slinear", extrapolate=True), promotes_inputs=[ "flap_defl_ratio", ], @@ -149,7 +149,7 @@ def setup(self): # VLAM1 VLAM1_interp = self.add_subsystem( "VLAM1_interp", - om.MetaModelStructuredComp(method="scipy_slinear", extrapolate=True), + om.MetaModelStructuredComp(method="1D-slinear", extrapolate=True), promotes_inputs=[ "aircraft:*", ], @@ -215,7 +215,7 @@ def setup(self): # VLAM2 VLAM2_interp = self.add_subsystem( "VLAM2_interp", - om.MetaModelStructuredComp(method="scipy_slinear", extrapolate=True), + om.MetaModelStructuredComp(method="1D-slinear", extrapolate=True), promotes_inputs=[ Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED, ], @@ -275,7 +275,7 @@ def setup(self): # VLAM3 VLAM3_interp = self.add_subsystem( "VLAM3_interp", - om.MetaModelStructuredComp(method="scipy_slinear", extrapolate=True), + om.MetaModelStructuredComp(method="1D-slinear", extrapolate=True), promotes_inputs=[ "aircraft:*", ], @@ -339,7 +339,7 @@ def setup(self): # VLAM4 VLAM4_interp = self.add_subsystem( "VLAM4_interp", - om.MetaModelStructuredComp(method="scipy_slinear", extrapolate=True), + om.MetaModelStructuredComp(method="1D-slinear", extrapolate=True), promotes_inputs=[ Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED, ], @@ -430,7 +430,7 @@ def setup(self): # VLAM5 VLAM5_interp = self.add_subsystem( "VLAM5_intep", - om.MetaModelStructuredComp(method="scipy_slinear", extrapolate=True), + om.MetaModelStructuredComp(method="1D-slinear", extrapolate=True), promotes_inputs=[ "aircraft:*", ], @@ -482,7 +482,7 @@ def setup(self): # VLAM6 VLAM6_interp = self.add_subsystem( "VLAM6_interp", - om.MetaModelStructuredComp(method="scipy_slinear", extrapolate=True), + om.MetaModelStructuredComp(method="1D-slinear", extrapolate=True), promotes_inputs=[ "flap_defl", ], @@ -603,7 +603,7 @@ def setup(self): # VLAM7 VLAM7_interp = self.add_subsystem( "VLAM7_interp", - om.MetaModelStructuredComp(method="scipy_slinear", extrapolate=True), + om.MetaModelStructuredComp(method="1D-slinear", extrapolate=True), promotes_inputs=[ Aircraft.Wing.FLAP_SPAN_RATIO, ], @@ -631,7 +631,7 @@ def setup(self): # VLAM10 VLAM10_interp = self.add_subsystem( "VLAM10_interp", - om.MetaModelStructuredComp(method="scipy_slinear", extrapolate=True), + om.MetaModelStructuredComp(method="1D-slinear", extrapolate=True), promotes_inputs=[ "slat_defl_ratio", ], @@ -689,7 +689,7 @@ def setup(self): # VLAM11 VLAM11_interp = self.add_subsystem( "VLAM11_interp", - om.MetaModelStructuredComp(method="scipy_slinear", extrapolate=True), + om.MetaModelStructuredComp(method="1D-slinear", extrapolate=True), promotes_inputs=[ Aircraft.Wing.SLAT_SPAN_RATIO, ], @@ -717,7 +717,7 @@ def setup(self): # VLAM13 VLAM13_interp = self.add_subsystem( "VLAM13_interp", - om.MetaModelStructuredComp(method="scipy_slinear", extrapolate=True), + om.MetaModelStructuredComp(method="1D-slinear", extrapolate=True), promotes_inputs=[ "reynolds", ], @@ -775,7 +775,7 @@ def setup(self): # VLAM14 VLAM14_interp = self.add_subsystem( "VLAM14_interp", - om.MetaModelStructuredComp(method="scipy_slinear", extrapolate=True), + om.MetaModelStructuredComp(method="1D-slinear", extrapolate=True), promotes_inputs=[ Dynamic.Mission.MACH, ], diff --git a/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py b/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py index a5ca197fe..a0fb90a81 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py +++ b/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py @@ -789,7 +789,7 @@ def setup(self): self.add_subsystem("xlifts", Xlifts(num_nodes=nn), promotes=["*"]) # implements EAERO - interp = om.MetaModelStructuredComp(method="slinear") + interp = om.MetaModelStructuredComp(method="2D-slinear") interp.add_input("bbar", 0.0, units="unitless", training_data=xbbar) interp.add_input("hbar", 0.0, units="unitless", training_data=xhbar) interp.add_output("sigma", 0.0, units="unitless", training_data=sig1) diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py index c73db751c..057f480f4 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py @@ -21,16 +21,16 @@ def bench_test_swap_3_FwGm(self): # There are no truth values for these. assert_near_equal(prob.get_val(Mission.Design.GROSS_MASS), - 184426., tolerance=rtol) + 186418., tolerance=rtol) assert_near_equal(prob.get_val(Aircraft.Design.OPERATING_MASS), - 104215., tolerance=rtol) + 104530., tolerance=rtol) assert_near_equal(prob.get_val(Mission.Summary.TOTAL_FUEL_MASS), - 42355., tolerance=rtol) + 44032., tolerance=rtol) assert_near_equal(prob.get_val('landing.' + Mission.Landing.GROUND_DISTANCE), - 2544.3, tolerance=rtol) + 2528., tolerance=rtol) assert_near_equal(prob.get_val("traj.desc2.timeseries.states:distance")[-1], 3675.0, tolerance=rtol) From 4dd8f285e2c21ef9135bdd852ace74eb1f2c3319 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 5 Jan 2024 15:39:00 -0600 Subject: [PATCH 004/188] Added changes needed for simple mission <-> FLOPS mission benches --- .../flops_based/phases/simple_energy_phase.py | 68 +++++++++++++---- .../test_aircraft/aircraft_for_bench_GwFm.csv | 4 +- .../benchmark_tests/test_bench_FwFm.py | 69 +++++++++++++++-- .../benchmark_tests/test_bench_GwFm.py | 76 +++++++++++++++++-- aviary/validation_cases/benchmark_utils.py | 20 +++-- 5 files changed, 202 insertions(+), 35 deletions(-) diff --git a/aviary/mission/flops_based/phases/simple_energy_phase.py b/aviary/mission/flops_based/phases/simple_energy_phase.py index e5ffd1928..9f6c9296a 100644 --- a/aviary/mission/flops_based/phases/simple_energy_phase.py +++ b/aviary/mission/flops_based/phases/simple_energy_phase.py @@ -1,5 +1,3 @@ -from math import isclose - import dymos as dm from aviary.mission.flops_based.phases.phase_builder_base import ( @@ -162,6 +160,8 @@ def build_phase(self, aviary_options: AviaryValues = None): initial_altitude = user_options.get_item('initial_altitude')[0] final_altitude = user_options.get_item('final_altitude')[0] solve_for_range = user_options.get_val('solve_for_range') + no_descent = user_options.get_val('no_descent') + no_climb = user_options.get_val('no_climb') ############## # Add States # @@ -205,13 +205,23 @@ def build_phase(self, aviary_options: AviaryValues = None): ################ # Add Controls # ################ - phase.add_polynomial_control( - Dynamic.Mission.MACH, - targets=Dynamic.Mission.MACH, units=mach_bounds[1], - opt=optimize_mach, lower=mach_bounds[0][0], upper=mach_bounds[0][1], - rate_targets=[Dynamic.Mission.MACH_RATE], - order=polynomial_control_order, ref=0.5, - ) + use_polynomial_control = polynomial_control_order is not None + if use_polynomial_control: + phase.add_polynomial_control( + Dynamic.Mission.MACH, + targets=Dynamic.Mission.MACH, units=mach_bounds[1], + opt=optimize_mach, lower=mach_bounds[0][0], upper=mach_bounds[0][1], + rate_targets=[Dynamic.Mission.MACH_RATE], + order=polynomial_control_order, ref=0.5, + ) + else: + phase.add_control( + Dynamic.Mission.MACH, + targets=Dynamic.Mission.MACH, units=mach_bounds[1], + opt=optimize_mach, lower=mach_bounds[0][0], upper=mach_bounds[0][1], + rate_targets=[Dynamic.Mission.MACH_RATE], + ref=0.5, + ) if optimize_mach and fix_initial: phase.add_boundary_constraint( @@ -224,13 +234,22 @@ def build_phase(self, aviary_options: AviaryValues = None): ) # Add altitude rate as a control - phase.add_polynomial_control( - Dynamic.Mission.ALTITUDE, - targets=Dynamic.Mission.ALTITUDE, units=altitude_bounds[1], - opt=optimize_altitude, lower=altitude_bounds[0][0], upper=altitude_bounds[0][1], - rate_targets=[Dynamic.Mission.ALTITUDE_RATE], - order=polynomial_control_order, ref=altitude_bounds[0][1], - ) + if use_polynomial_control: + phase.add_polynomial_control( + Dynamic.Mission.ALTITUDE, + targets=Dynamic.Mission.ALTITUDE, units=altitude_bounds[1], + opt=optimize_altitude, lower=altitude_bounds[0][0], upper=altitude_bounds[0][1], + rate_targets=[Dynamic.Mission.ALTITUDE_RATE], + order=polynomial_control_order, ref=altitude_bounds[0][1], + ) + else: + phase.add_control( + Dynamic.Mission.ALTITUDE, + targets=Dynamic.Mission.ALTITUDE, units=altitude_bounds[1], + opt=optimize_altitude, lower=altitude_bounds[0][0], upper=altitude_bounds[0][1], + rate_targets=[Dynamic.Mission.ALTITUDE_RATE], + ref=altitude_bounds[0][1], + ) if optimize_altitude and fix_initial: phase.add_boundary_constraint( @@ -278,9 +297,20 @@ def build_phase(self, aviary_options: AviaryValues = None): output_name=Dynamic.Mission.THROTTLE, units='unitless' ) + phase.add_timeseries_output( + Dynamic.Mission.VELOCITY, + output_name=Dynamic.Mission.VELOCITY, units='m/s' + ) + ################### # Add Constraints # ################### + if no_descent: + phase.add_path_constraint(Dynamic.Mission.ALTITUDE_RATE, lower=0.0) + + if no_climb: + phase.add_path_constraint(Dynamic.Mission.ALTITUDE_RATE, upper=0.0) + required_available_climb_rate, units = user_options.get_item( 'required_available_climb_rate') @@ -360,6 +390,12 @@ def _extra_ode_init_kwargs(self): 'required_available_climb_rate', val=None, units='m/s', desc='minimum avaliable climb rate') +EnergyPhase._add_meta_data( + 'no_climb', val=False, desc='aircraft is not allowed to climb during phase') + +EnergyPhase._add_meta_data( + 'no_descent', val=False, desc='aircraft is not allowed to descend during phase') + EnergyPhase._add_meta_data('constrain_final', val=False) EnergyPhase._add_meta_data('input_initial', val=False) diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv index 58caba631..30c295959 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv @@ -251,7 +251,7 @@ aircraft:wing:wetted_area,2396.56,ft**2 aircraft:wing:zero_lift_angle,-1.2,deg mission:constraints:max_mach,0.785,unitless mission:design:cruise_altitude,25000,ft -mission:design:gross_mass,175400.0,lbm +mission:design:gross_mass,150935.0,lbm mission:design:lift_coefficient_max_flaps_up,1.2596,unitless mission:design:range,3500,NM mission:design:thrust_takeoff_per_eng,28928.1,lbf @@ -261,7 +261,7 @@ mission:landing:lift_coefficient_flap_increment,1.0293,unitless mission:landing:lift_coefficient_max,2.8155,unitless mission:summary:cruise_mach,0.785,unitless mission:summary:fuel_flow_scaler,1.0,unitless -mission:summary:gross_mass,175400,lbm +mission:summary:gross_mass,150935,lbm mission:takeoff:airport_altitude,0,ft mission:takeoff:drag_coefficient_flap_increment,0.0085,unitless mission:takeoff:fuel_simple,577,lbm diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index 7a302d4dd..5fbbf6181 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -1,21 +1,19 @@ -import os import unittest import numpy as np from openmdao.utils.testing_utils import use_tempdirs from aviary.interface.default_phase_info.flops import phase_info +from aviary.interface.default_phase_info.simple import phase_info as simple_phase_info from aviary.interface.methods_for_level1 import run_aviary from aviary.validation_cases.benchmark_utils import \ compare_against_expected_values +import copy @use_tempdirs class ProblemPhaseTestCase(unittest.TestCase): - def bench_test_swap_4_FwFm(self): - prob = run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info, - mission_method="FLOPS", mass_method="FLOPS") - + def setUp(self): expected_dict = {} expected_dict['times'] = np.array([[120.], @@ -263,7 +261,66 @@ def bench_test_swap_4_FwFm(self): [116.22447082], [102.07377559]]) - compare_against_expected_values(prob, expected_dict) + self.expected_dict = expected_dict + + def bench_test_swap_4_FwFm(self): + prob = run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info, + mission_method="FLOPS", mass_method="FLOPS") + + compare_against_expected_values(prob, self.expected_dict) + + def bench_test_swap_4_FwFm_simple(self): + ph_in = copy.deepcopy(simple_phase_info) + + ph_in['pre_mission']['include_takeoff'] = True + + ph_in['climb']['user_options']['optimize_mach'] = True + ph_in['climb']['user_options']['optimize_altitude'] = True + ph_in['climb']['user_options']['mach_bounds'] = ((0.1, 0.8), "unitless") + ph_in['climb']['user_options']['duration_bounds'] = ((5.0, 50.0), "min") + ph_in['climb']['user_options']['initial_mach'] = (0.2, "unitless") + ph_in['climb']['user_options']['final_mach'] = (0.79, "unitless") + ph_in['climb']['user_options']['final_altitude'] = (35000., "ft") + ph_in['climb']['user_options']['altitude_bounds'] = ((0., 36000.), "ft") + ph_in['climb']['user_options']['polynomial_control_order'] = None + ph_in['climb']['user_options']['num_segments'] = 6 + ph_in['climb']['user_options']['order'] = 3 + ph_in['climb']['user_options']['no_descent'] = True + ph_in['climb']['initial_guesses']['times'] = ([0, 40.], "min") + + ph_in['cruise']['user_options']['optimize_mach'] = True + ph_in['cruise']['user_options']['optimize_altitude'] = True + ph_in['cruise']['user_options']['polynomial_control_order'] = 1 + ph_in['cruise']['user_options']['initial_mach'] = (0.79, "unitless") + ph_in['cruise']['user_options']['final_mach'] = (0.79, "unitless") + ph_in['cruise']['user_options']['initial_altitude'] = (35000., "ft") + ph_in['cruise']['user_options']['altitude_bounds'] = ((35000., 35000.), "ft") + ph_in['cruise']['user_options']['final_altitude'] = (35000., "ft") + ph_in['cruise']['user_options']['mach_bounds'] = ((0.78, 0.8), "unitless") + ph_in['cruise']['user_options']['duration_bounds'] = ((60., 7200.), "min") + ph_in['cruise']['user_options']['num_segments'] = 1 + ph_in['cruise']['user_options']['order'] = 3 + + ph_in['descent']['user_options']['optimize_mach'] = True + ph_in['descent']['user_options']['optimize_altitude'] = True + ph_in['descent']['user_options']['mach_bounds'] = ((0.2, 0.8), "unitless") + ph_in['descent']['user_options']['initial_mach'] = (0.79, "unitless") + ph_in['descent']['user_options']['final_mach'] = (0.3, "unitless") + ph_in['descent']['user_options']['polynomial_control_order'] = None + ph_in['descent']['user_options']['initial_altitude'] = (35000., "ft") + ph_in['descent']['user_options']['altitude_bounds'] = ((0., 35000.), "ft") + ph_in['descent']['user_options']['duration_bounds'] = ((5., 60.), "min") + ph_in['descent']['user_options']['num_segments'] = 5 + ph_in['descent']['user_options']['order'] = 3 + ph_in['descent']['user_options']['no_climb'] = False + + ph_in['post_mission']['include_landing'] = True + ph_in['post_mission']['target_range'] = (3360., 'nmi') + + prob = run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv', ph_in, + mission_method="simple", mass_method="FLOPS") + + compare_against_expected_values(prob, self.expected_dict, simple_flag=True) if __name__ == '__main__': diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py index 05b9a0590..a1aa96e33 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py @@ -5,13 +5,14 @@ Computed Aero Large Single Aisle 1 data ''' -import os +import copy import unittest import numpy as np from openmdao.utils.testing_utils import use_tempdirs from aviary.interface.default_phase_info.flops import phase_info +from aviary.interface.default_phase_info.simple import phase_info as simple_phase_info from aviary.interface.methods_for_level1 import run_aviary from aviary.validation_cases.benchmark_utils import \ compare_against_expected_values @@ -19,10 +20,7 @@ @use_tempdirs class ProblemPhaseTestCase(unittest.TestCase): - def bench_test_swap_1_GwFm(self): - prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwFm.csv', phase_info, - mission_method="FLOPS", mass_method="GASP") - + def setUp(self): expected_dict = {} expected_dict['times'] = np.array([[120.], [163.76271231], @@ -269,7 +267,73 @@ def bench_test_swap_1_GwFm(self): [116.34759903], [102.07377559]]) - compare_against_expected_values(prob, expected_dict) + self.expected_dict = expected_dict + + def bench_test_swap_1_GwFm(self): + prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwFm.csv', phase_info, + mission_method="FLOPS", mass_method="GASP") + + compare_against_expected_values(prob, self.expected_dict) + + def bench_test_swap_1_GwFm_simple(self): + ph_in = copy.deepcopy(simple_phase_info) + + ph_in['pre_mission']['include_takeoff'] = True + + ph_in['climb']['user_options']['optimize_mach'] = True + ph_in['climb']['user_options']['optimize_altitude'] = True + ph_in['climb']['user_options']['mach_bounds'] = ((0.2, 0.8), "unitless") + ph_in['climb']['user_options']['duration_bounds'] = ((5.0, 50.0), "min") + ph_in['climb']['user_options']['initial_mach'] = (0.2, "unitless") + ph_in['climb']['user_options']['final_mach'] = (0.79, "unitless") + ph_in['climb']['user_options']['initial_altitude'] = (35., "ft") + ph_in['climb']['user_options']['final_altitude'] = (35000., "ft") + ph_in['climb']['user_options']['altitude_bounds'] = ((0., 35000.), "ft") + ph_in['climb']['user_options']['polynomial_control_order'] = None + ph_in['climb']['user_options']['num_segments'] = 6 + ph_in['climb']['user_options']['order'] = 3 + ph_in['climb']['user_options']['no_descent'] = True + ph_in['climb']['user_options']['solve_for_range'] = False + ph_in['climb']['initial_guesses']['times'] = ([0, 40.], "min") + + ph_in['cruise']['user_options']['optimize_mach'] = True + ph_in['cruise']['user_options']['optimize_altitude'] = True + ph_in['cruise']['user_options']['polynomial_control_order'] = 1 + ph_in['cruise']['user_options']['initial_mach'] = (0.79, "unitless") + ph_in['cruise']['user_options']['final_mach'] = (0.79, "unitless") + ph_in['cruise']['user_options']['initial_altitude'] = (35000., "ft") + ph_in['cruise']['user_options']['altitude_bounds'] = ((35.e3, 35.e3), "ft") + ph_in['cruise']['user_options']['final_altitude'] = (35000., "ft") + ph_in['cruise']['user_options']['mach_bounds'] = ((0.78, 0.8), "unitless") + ph_in['cruise']['user_options']['duration_bounds'] = ((120., 900.), "min") + ph_in['cruise']['user_options']['num_segments'] = 1 + ph_in['cruise']['user_options']['order'] = 3 + ph_in['cruise']['user_options']['solve_for_range'] = False + ph_in['cruise']['user_options']['required_available_climb_rate'] = (1.524, 'm/s') + ph_in['cruise']['initial_guesses']['times'] = ([40, 500.], "min") + + ph_in['descent']['user_options']['optimize_mach'] = True + ph_in['descent']['user_options']['optimize_altitude'] = True + ph_in['descent']['user_options']['mach_bounds'] = ((0.3, 0.8), "unitless") + ph_in['descent']['user_options']['initial_mach'] = (0.79, "unitless") + ph_in['descent']['user_options']['final_mach'] = (0.3, "unitless") + ph_in['descent']['user_options']['polynomial_control_order'] = None + ph_in['descent']['user_options']['initial_altitude'] = (35000., "ft") + ph_in['descent']['user_options']['altitude_bounds'] = ((0., 35000.), "ft") + ph_in['descent']['user_options']['duration_bounds'] = ((5., 60.), "min") + ph_in['descent']['user_options']['num_segments'] = 5 + ph_in['descent']['user_options']['order'] = 3 + ph_in['descent']['user_options']['no_climb'] = True + ph_in['descent']['user_options']['solve_for_range'] = False + ph_in['descent']['initial_guesses']['times'] = ([360, 40.], "min") + + ph_in['post_mission']['include_landing'] = True + ph_in['post_mission']['target_range'] = (3360., 'nmi') + + prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwFm.csv', ph_in, + mission_method="simple", mass_method="GASP") + + compare_against_expected_values(prob, self.expected_dict, simple_flag=True) if __name__ == '__main__': diff --git a/aviary/validation_cases/benchmark_utils.py b/aviary/validation_cases/benchmark_utils.py index 8540817a2..22b1b97dd 100644 --- a/aviary/validation_cases/benchmark_utils.py +++ b/aviary/validation_cases/benchmark_utils.py @@ -5,7 +5,7 @@ from aviary.utils.test_utils.assert_utils import warn_timeseries_near_equal -def compare_against_expected_values(prob, expected_dict): +def compare_against_expected_values(prob, expected_dict, simple_flag=False): expected_times = expected_dict['times'] expected_altitudes = expected_dict['altitudes'] @@ -22,14 +22,24 @@ def compare_against_expected_values(prob, expected_dict): for idx, phase in enumerate(['climb', 'cruise', 'descent']): times.extend(prob.get_val(f'traj.{phase}.timeseries.time', units='s')) - altitudes.extend(prob.get_val( - f'traj.{phase}.timeseries.states:altitude', units='m')) + if simple_flag: + try: + altitudes.extend(prob.get_val( + f'traj.{phase}.timeseries.polynomial_controls:altitude', units='m')) + except KeyError: + altitudes.extend(prob.get_val( + f'traj.{phase}.timeseries.controls:altitude', units='m')) + velocities.extend(prob.get_val( + f'traj.{phase}.timeseries.velocity', units='m/s')) + else: + altitudes.extend(prob.get_val( + f'traj.{phase}.timeseries.states:altitude', units='m')) + velocities.extend(prob.get_val( + f'traj.{phase}.timeseries.states:velocity', units='m/s')) masses.extend( prob.get_val(f'traj.{phase}.timeseries.states:mass', units='kg')) ranges.extend( prob.get_val(f'traj.{phase}.timeseries.states:range', units='m')) - velocities.extend(prob.get_val( - f'traj.{phase}.timeseries.states:velocity', units='m/s')) times = np.array(times) altitudes = np.array(altitudes) From 89b932fbff50097c4b0e90ee4411df8d0f05579b Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 5 Jan 2024 16:12:47 -0600 Subject: [PATCH 005/188] Connected mass for simple mission correctly --- aviary/interface/default_phase_info/simple.py | 1 + aviary/interface/methods_for_level2.py | 28 +++- .../test_aircraft/aircraft_for_bench_GwFm.csv | 4 +- .../benchmark_tests/test_bench_FwFm.py | 138 ++++++++++------ .../benchmark_tests/test_bench_GwFm.py | 147 +++++++++++------- 5 files changed, 201 insertions(+), 117 deletions(-) diff --git a/aviary/interface/default_phase_info/simple.py b/aviary/interface/default_phase_info/simple.py index f62af4ad5..a82daaa06 100644 --- a/aviary/interface/default_phase_info/simple.py +++ b/aviary/interface/default_phase_info/simple.py @@ -36,6 +36,7 @@ "fix_duration": False, "initial_bounds": ((0.0, 0.0), "min"), "duration_bounds": ((64.0, 192.0), "min"), + "add_initial_mass_constraint": False, }, "initial_guesses": {"times": ([0, 128], "min")}, }, diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 06f038472..3801359aa 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -1131,7 +1131,7 @@ def add_post_mission_systems(self, include_landing=True): """ if include_landing and self.post_mission_info['include_landing']: - if self.mission_method == "FLOPS": + if self.mission_method == "FLOPS" or self.mission_method == "simple": self._add_flops_landing_systems() elif self.mission_method == "GASP": self._add_gasp_landing_systems() @@ -2347,16 +2347,30 @@ def _add_flops_landing_systems(self): 'traj.climb.initial_states:mass') self.model.connect(Mission.Takeoff.GROUND_DISTANCE, 'traj.climb.initial_states:range') - self.model.connect(Mission.Takeoff.FINAL_VELOCITY, - 'traj.climb.initial_states:velocity') - self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, - 'traj.climb.initial_states:altitude') + if self.mission_method == "FLOPS": + self.model.connect(Mission.Takeoff.FINAL_VELOCITY, + 'traj.climb.initial_states:velocity') + self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, + 'traj.climb.initial_states:altitude') + else: + pass + # TODO: connect this correctly + # mass is the most important to connect but these others should + # be connected as well + # self.model.connect(Mission.Takeoff.FINAL_VELOCITY, + # 'traj.climb.initial_states:mach') + # self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, + # 'traj.climb.controls:altitude') self.model.connect('traj.descent.states:mass', Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1]) # TODO: approach velocity should likely be connected - self.model.connect('traj.descent.states:altitude', Mission.Landing.INITIAL_ALTITUDE, - src_indices=[-1]) + if self.mission_method == "FLOPS": + self.model.connect('traj.descent.states:altitude', Mission.Landing.INITIAL_ALTITUDE, + src_indices=[-1]) + else: + self.model.connect('traj.descent.control_values:altitude', Mission.Landing.INITIAL_ALTITUDE, + src_indices=[0]) def _add_gasp_landing_systems(self): self.model.add_subsystem( diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv index 30c295959..58caba631 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv @@ -251,7 +251,7 @@ aircraft:wing:wetted_area,2396.56,ft**2 aircraft:wing:zero_lift_angle,-1.2,deg mission:constraints:max_mach,0.785,unitless mission:design:cruise_altitude,25000,ft -mission:design:gross_mass,150935.0,lbm +mission:design:gross_mass,175400.0,lbm mission:design:lift_coefficient_max_flaps_up,1.2596,unitless mission:design:range,3500,NM mission:design:thrust_takeoff_per_eng,28928.1,lbf @@ -261,7 +261,7 @@ mission:landing:lift_coefficient_flap_increment,1.0293,unitless mission:landing:lift_coefficient_max,2.8155,unitless mission:summary:cruise_mach,0.785,unitless mission:summary:fuel_flow_scaler,1.0,unitless -mission:summary:gross_mass,150935,lbm +mission:summary:gross_mass,175400,lbm mission:takeoff:airport_altitude,0,ft mission:takeoff:drag_coefficient_flap_increment,0.0085,unitless mission:takeoff:fuel_simple,577,lbm diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index 5fbbf6181..6027d9b4a 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -4,11 +4,10 @@ from openmdao.utils.testing_utils import use_tempdirs from aviary.interface.default_phase_info.flops import phase_info -from aviary.interface.default_phase_info.simple import phase_info as simple_phase_info from aviary.interface.methods_for_level1 import run_aviary from aviary.validation_cases.benchmark_utils import \ compare_against_expected_values -import copy +from aviary.variable_info.variables import Dynamic @use_tempdirs @@ -270,54 +269,92 @@ def bench_test_swap_4_FwFm(self): compare_against_expected_values(prob, self.expected_dict) def bench_test_swap_4_FwFm_simple(self): - ph_in = copy.deepcopy(simple_phase_info) + phase_info = { + "pre_mission": {"include_takeoff": True, "optimize_mass": True}, + "climb": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + 'fix_initial': {Dynamic.Mission.MASS: False, Dynamic.Mission.RANGE: False}, + 'input_initial': True, + "optimize_mach": True, + "optimize_altitude": True, + "polynomial_control_order": None, + "num_segments": 6, + "order": 3, + "solve_for_range": False, + "initial_mach": (0.2, "unitless"), + "final_mach": (0.79, "unitless"), + "mach_bounds": ((0.1, 0.8), "unitless"), + "initial_altitude": (0.0, "ft"), + "final_altitude": (35000.0, "ft"), + "altitude_bounds": ((0.0, 36000.0), "ft"), + "throttle_enforcement": "path_constraint", + "constrain_final": False, + "fix_duration": False, + "initial_bounds": ((0.0, 0.0), "min"), + "duration_bounds": ((5.0, 50.0), "min"), + "no_descent": True, + "add_initial_mass_constraint": False, + }, + "initial_guesses": {"times": ([0, 40.0], "min")}, + }, + "cruise": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + "optimize_mach": True, + "optimize_altitude": True, + "polynomial_control_order": 1, + "num_segments": 1, + "order": 3, + "solve_for_range": False, + "initial_mach": (0.79, "unitless"), + "final_mach": (0.79, "unitless"), + "mach_bounds": ((0.78, 0.8), "unitless"), + "initial_altitude": (35000.0, "ft"), + "final_altitude": (35000.0, "ft"), + "altitude_bounds": ((35000.0, 35000.0), "ft"), + "throttle_enforcement": "boundary_constraint", + "fix_initial": False, + "constrain_final": False, + "fix_duration": False, + "initial_bounds": ((64.0, 192.0), "min"), + "duration_bounds": ((60.0, 7200.0), "min"), + }, + "initial_guesses": {"times": ([128, 113], "min")}, + }, + "descent": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + "optimize_mach": True, + "optimize_altitude": True, + "polynomial_control_order": None, + "num_segments": 5, + "order": 3, + "solve_for_range": False, + "initial_mach": (0.79, "unitless"), + "final_mach": (0.3, "unitless"), + "mach_bounds": ((0.2, 0.8), "unitless"), + "initial_altitude": (35000.0, "ft"), + "final_altitude": (500.0, "ft"), + "altitude_bounds": ((0.0, 35000.0), "ft"), + "throttle_enforcement": "path_constraint", + "fix_initial": False, + "constrain_final": True, + "fix_duration": False, + "initial_bounds": ((120.5, 361.5), "min"), + "duration_bounds": ((5.0, 60.0), "min"), + "no_climb": False + }, + "initial_guesses": {"times": ([241, 58], "min")}, + }, + "post_mission": { + "include_landing": True, + "constrain_range": True, + "target_range": (3360.0, "nmi"), + }, + } - ph_in['pre_mission']['include_takeoff'] = True - - ph_in['climb']['user_options']['optimize_mach'] = True - ph_in['climb']['user_options']['optimize_altitude'] = True - ph_in['climb']['user_options']['mach_bounds'] = ((0.1, 0.8), "unitless") - ph_in['climb']['user_options']['duration_bounds'] = ((5.0, 50.0), "min") - ph_in['climb']['user_options']['initial_mach'] = (0.2, "unitless") - ph_in['climb']['user_options']['final_mach'] = (0.79, "unitless") - ph_in['climb']['user_options']['final_altitude'] = (35000., "ft") - ph_in['climb']['user_options']['altitude_bounds'] = ((0., 36000.), "ft") - ph_in['climb']['user_options']['polynomial_control_order'] = None - ph_in['climb']['user_options']['num_segments'] = 6 - ph_in['climb']['user_options']['order'] = 3 - ph_in['climb']['user_options']['no_descent'] = True - ph_in['climb']['initial_guesses']['times'] = ([0, 40.], "min") - - ph_in['cruise']['user_options']['optimize_mach'] = True - ph_in['cruise']['user_options']['optimize_altitude'] = True - ph_in['cruise']['user_options']['polynomial_control_order'] = 1 - ph_in['cruise']['user_options']['initial_mach'] = (0.79, "unitless") - ph_in['cruise']['user_options']['final_mach'] = (0.79, "unitless") - ph_in['cruise']['user_options']['initial_altitude'] = (35000., "ft") - ph_in['cruise']['user_options']['altitude_bounds'] = ((35000., 35000.), "ft") - ph_in['cruise']['user_options']['final_altitude'] = (35000., "ft") - ph_in['cruise']['user_options']['mach_bounds'] = ((0.78, 0.8), "unitless") - ph_in['cruise']['user_options']['duration_bounds'] = ((60., 7200.), "min") - ph_in['cruise']['user_options']['num_segments'] = 1 - ph_in['cruise']['user_options']['order'] = 3 - - ph_in['descent']['user_options']['optimize_mach'] = True - ph_in['descent']['user_options']['optimize_altitude'] = True - ph_in['descent']['user_options']['mach_bounds'] = ((0.2, 0.8), "unitless") - ph_in['descent']['user_options']['initial_mach'] = (0.79, "unitless") - ph_in['descent']['user_options']['final_mach'] = (0.3, "unitless") - ph_in['descent']['user_options']['polynomial_control_order'] = None - ph_in['descent']['user_options']['initial_altitude'] = (35000., "ft") - ph_in['descent']['user_options']['altitude_bounds'] = ((0., 35000.), "ft") - ph_in['descent']['user_options']['duration_bounds'] = ((5., 60.), "min") - ph_in['descent']['user_options']['num_segments'] = 5 - ph_in['descent']['user_options']['order'] = 3 - ph_in['descent']['user_options']['no_climb'] = False - - ph_in['post_mission']['include_landing'] = True - ph_in['post_mission']['target_range'] = (3360., 'nmi') - - prob = run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv', ph_in, + prob = run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info, mission_method="simple", mass_method="FLOPS") compare_against_expected_values(prob, self.expected_dict, simple_flag=True) @@ -325,4 +362,5 @@ def bench_test_swap_4_FwFm_simple(self): if __name__ == '__main__': test = ProblemPhaseTestCase() - test.bench_test_swap_4_FwFm() + test.setUp() + test.bench_test_swap_4_FwFm_simple() diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py index a1aa96e33..aa7193866 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py @@ -5,17 +5,16 @@ Computed Aero Large Single Aisle 1 data ''' -import copy import unittest import numpy as np from openmdao.utils.testing_utils import use_tempdirs from aviary.interface.default_phase_info.flops import phase_info -from aviary.interface.default_phase_info.simple import phase_info as simple_phase_info from aviary.interface.methods_for_level1 import run_aviary from aviary.validation_cases.benchmark_utils import \ compare_against_expected_values +from aviary.variable_info.variables import Dynamic @use_tempdirs @@ -276,66 +275,98 @@ def bench_test_swap_1_GwFm(self): compare_against_expected_values(prob, self.expected_dict) def bench_test_swap_1_GwFm_simple(self): - ph_in = copy.deepcopy(simple_phase_info) + phase_info = { + "pre_mission": {"include_takeoff": True, "optimize_mass": True}, + "climb": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + 'fix_initial': {Dynamic.Mission.MASS: False, Dynamic.Mission.RANGE: False}, + 'input_initial': True, + "optimize_mach": True, + "optimize_altitude": True, + "polynomial_control_order": None, + "num_segments": 6, + "order": 3, + "solve_for_range": False, + "initial_mach": (0.2, "unitless"), + "final_mach": (0.79, "unitless"), + "mach_bounds": ((0.1, 0.8), "unitless"), + "initial_altitude": (0.0, "ft"), + "final_altitude": (35000.0, "ft"), + "altitude_bounds": ((0.0, 36000.0), "ft"), + "throttle_enforcement": "path_constraint", + "constrain_final": False, + "fix_duration": False, + "initial_bounds": ((0.0, 0.0), "min"), + "duration_bounds": ((5.0, 50.0), "min"), + "no_descent": True, + "add_initial_mass_constraint": False, + }, + "initial_guesses": {"times": ([0, 40.0], "min")}, + }, + "cruise": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + "optimize_mach": True, + "optimize_altitude": True, + "polynomial_control_order": 1, + "num_segments": 1, + "order": 3, + "solve_for_range": False, + "initial_mach": (0.79, "unitless"), + "final_mach": (0.79, "unitless"), + "mach_bounds": ((0.78, 0.8), "unitless"), + "initial_altitude": (35000.0, "ft"), + "final_altitude": (35000.0, "ft"), + "altitude_bounds": ((35000.0, 35000.0), "ft"), + "throttle_enforcement": "boundary_constraint", + "fix_initial": False, + "constrain_final": False, + "fix_duration": False, + "initial_bounds": ((64.0, 192.0), "min"), + "duration_bounds": ((60.0, 7200.0), "min"), + }, + "initial_guesses": {"times": ([128, 113], "min")}, + }, + "descent": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + "optimize_mach": True, + "optimize_altitude": True, + "polynomial_control_order": None, + "num_segments": 5, + "order": 3, + "solve_for_range": False, + "initial_mach": (0.79, "unitless"), + "final_mach": (0.3, "unitless"), + "mach_bounds": ((0.2, 0.8), "unitless"), + "initial_altitude": (35000.0, "ft"), + "final_altitude": (500.0, "ft"), + "altitude_bounds": ((0.0, 35000.0), "ft"), + "throttle_enforcement": "path_constraint", + "fix_initial": False, + "constrain_final": True, + "fix_duration": False, + "initial_bounds": ((120.5, 361.5), "min"), + "duration_bounds": ((5.0, 60.0), "min"), + "no_climb": False + }, + "initial_guesses": {"times": ([241, 58], "min")}, + }, + "post_mission": { + "include_landing": True, + "constrain_range": True, + "target_range": (3360.0, "nmi"), + }, + } - ph_in['pre_mission']['include_takeoff'] = True - - ph_in['climb']['user_options']['optimize_mach'] = True - ph_in['climb']['user_options']['optimize_altitude'] = True - ph_in['climb']['user_options']['mach_bounds'] = ((0.2, 0.8), "unitless") - ph_in['climb']['user_options']['duration_bounds'] = ((5.0, 50.0), "min") - ph_in['climb']['user_options']['initial_mach'] = (0.2, "unitless") - ph_in['climb']['user_options']['final_mach'] = (0.79, "unitless") - ph_in['climb']['user_options']['initial_altitude'] = (35., "ft") - ph_in['climb']['user_options']['final_altitude'] = (35000., "ft") - ph_in['climb']['user_options']['altitude_bounds'] = ((0., 35000.), "ft") - ph_in['climb']['user_options']['polynomial_control_order'] = None - ph_in['climb']['user_options']['num_segments'] = 6 - ph_in['climb']['user_options']['order'] = 3 - ph_in['climb']['user_options']['no_descent'] = True - ph_in['climb']['user_options']['solve_for_range'] = False - ph_in['climb']['initial_guesses']['times'] = ([0, 40.], "min") - - ph_in['cruise']['user_options']['optimize_mach'] = True - ph_in['cruise']['user_options']['optimize_altitude'] = True - ph_in['cruise']['user_options']['polynomial_control_order'] = 1 - ph_in['cruise']['user_options']['initial_mach'] = (0.79, "unitless") - ph_in['cruise']['user_options']['final_mach'] = (0.79, "unitless") - ph_in['cruise']['user_options']['initial_altitude'] = (35000., "ft") - ph_in['cruise']['user_options']['altitude_bounds'] = ((35.e3, 35.e3), "ft") - ph_in['cruise']['user_options']['final_altitude'] = (35000., "ft") - ph_in['cruise']['user_options']['mach_bounds'] = ((0.78, 0.8), "unitless") - ph_in['cruise']['user_options']['duration_bounds'] = ((120., 900.), "min") - ph_in['cruise']['user_options']['num_segments'] = 1 - ph_in['cruise']['user_options']['order'] = 3 - ph_in['cruise']['user_options']['solve_for_range'] = False - ph_in['cruise']['user_options']['required_available_climb_rate'] = (1.524, 'm/s') - ph_in['cruise']['initial_guesses']['times'] = ([40, 500.], "min") - - ph_in['descent']['user_options']['optimize_mach'] = True - ph_in['descent']['user_options']['optimize_altitude'] = True - ph_in['descent']['user_options']['mach_bounds'] = ((0.3, 0.8), "unitless") - ph_in['descent']['user_options']['initial_mach'] = (0.79, "unitless") - ph_in['descent']['user_options']['final_mach'] = (0.3, "unitless") - ph_in['descent']['user_options']['polynomial_control_order'] = None - ph_in['descent']['user_options']['initial_altitude'] = (35000., "ft") - ph_in['descent']['user_options']['altitude_bounds'] = ((0., 35000.), "ft") - ph_in['descent']['user_options']['duration_bounds'] = ((5., 60.), "min") - ph_in['descent']['user_options']['num_segments'] = 5 - ph_in['descent']['user_options']['order'] = 3 - ph_in['descent']['user_options']['no_climb'] = True - ph_in['descent']['user_options']['solve_for_range'] = False - ph_in['descent']['initial_guesses']['times'] = ([360, 40.], "min") - - ph_in['post_mission']['include_landing'] = True - ph_in['post_mission']['target_range'] = (3360., 'nmi') - - prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwFm.csv', ph_in, - mission_method="simple", mass_method="GASP") + prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwFm.csv', phase_info, + mission_method="simple", mass_method="GASP", max_iter=15) compare_against_expected_values(prob, self.expected_dict, simple_flag=True) if __name__ == '__main__': z = ProblemPhaseTestCase() - z.bench_test_swap_1_GwFm() + z.setUp() + z.bench_test_swap_1_GwFm_simple() From 1798c04bae99caebebc83c7789d8e6820dd17529 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 5 Jan 2024 17:17:43 -0500 Subject: [PATCH 006/188] updates based on review comments --- .../getting_started/input_csv_phase_info.md | 2 +- aviary/interface/methods_for_level2.py | 15 ++++++----- aviary/utils/process_input_decks.py | 26 +++++++++---------- aviary/variable_info/enums.py | 23 ++++++++++++++++ aviary/variable_info/variable_meta_data.py | 9 ++++--- 5 files changed, 50 insertions(+), 25 deletions(-) diff --git a/aviary/docs/getting_started/input_csv_phase_info.md b/aviary/docs/getting_started/input_csv_phase_info.md index b3a8358d9..c60fad220 100644 --- a/aviary/docs/getting_started/input_csv_phase_info.md +++ b/aviary/docs/getting_started/input_csv_phase_info.md @@ -21,7 +21,7 @@ This section is under development. The initial guess of `reserves` is used to define the reserve fuel. Initially, its value can be anything larger than 10 or anything between -1 and 0. There are three variables to control the reserve fuel in the model file (`.csv`): - `Aircraft.Design.RESERVES`: the required fuel reserves: directly in lbm, - `Aircraft.Design.RESERVES_FRACTION`: the required fuel reserves: given as a proportion of mission fuel, -- `Aircraft.Design.RESERVES_OPTION`: if 1, use `Aircraft.Design.RESERVES`; if 2, use `Aircraft.Design.RESERVES_FRACTION` +- `Aircraft.Design.RESERVES_OPTION`: if `Set_Direct` (1), use `Aircraft.Design.RESERVES`; if `Set_Fraction` (2), use `Aircraft.Design.RESERVES_FRACTION`. If the value of parameter `reserves` is not 0 and is within the allowed range, the initial guess of reserve fuel is determined by the parameter `reserves`: - if `reserves > 10.0`, we set `Aircraft.Design.RESERVES = reserves` and `Aircraft.Design.RESERVES_OPTION = 1`, diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 26d89e116..4847119b0 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -48,7 +48,7 @@ from aviary.variable_info.functions import setup_trajectory_params, override_aviary_vars from aviary.variable_info.variables import Aircraft, Mission, Dynamic -from aviary.variable_info.enums import AnalysisScheme, ProblemType, SpeedType, AlphaModes +from aviary.variable_info.enums import AnalysisScheme, ProblemType, SpeedType, AlphaModes, Reserves_Type from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData from aviary.variable_info.variables_in import VariablesIn @@ -2441,7 +2441,7 @@ def _add_fuel_reserve_component(self, reserves_name=Mission.Design.RESERVE_FUEL) Aircraft.Design.RESERVES_FRACTION, units='unitless') reserves_opt = self.aviary_inputs.get_val( Aircraft.Design.RESERVES_OPTION, units='unitless') - if reserves_opt == 1: + if reserves_opt == Reserves_Type.Set_Direct: if reserves_val > 10: self.model.add_subsystem( "reserves_calc", @@ -2452,8 +2452,8 @@ def _add_fuel_reserve_component(self, reserves_name=Mission.Design.RESERVE_FUEL) promotes_outputs=[("reserve_fuel", reserves_name)], ) else: - raise ValueError('"aircraft:design:reserves" is not valid below 10.') - elif reserves_opt == 2: + raise ValueError(f'"{Aircraft.Design.RESERVES}" is not valid below 10.') + elif reserves_opt == Reserves_Type.Set_Fraction: if reserves_fac <= 0 and reserves_fac >= -1: reserves_fac = -reserves_fac self.model.add_subsystem( @@ -2472,9 +2472,10 @@ def _add_fuel_reserve_component(self, reserves_name=Mission.Design.RESERVE_FUEL) ) elif reserves_fac > 0 and reserves_fac <= 1: raise ValueError( - '"aircraft:design:reserves_fraction" between 0 and 1 is not implemented.') + f'"{Aircraft.Design.RESERVES_FRACTION}" between 0 and 1 is not implemented.') else: raise ValueError( - '"aircraft:design:reserves_fraction" is not valid if less than -1 or larger than 1.') + f'"{Aircraft.Design.RESERVES_FRACTION}" is not valid if less than -1 or larger than 1.') else: - raise ValueError('"aircraft:design:reserves_option" must be 1 or 2.') + raise ValueError(f'"{Aircraft.Design.RESERVES_OPTION}" must be \ + {Reserves_Type.Set_Directn} or {Reserves_Type.Set_Fraction}.') diff --git a/aviary/utils/process_input_decks.py b/aviary/utils/process_input_decks.py index 22bc6ae05..4baf00f29 100644 --- a/aviary/utils/process_input_decks.py +++ b/aviary/utils/process_input_decks.py @@ -22,7 +22,7 @@ from aviary.utils.aviary_values import AviaryValues, get_keys from aviary.utils.functions import convert_strings_to_data, set_value from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.enums import ProblemType +from aviary.variable_info.enums import ProblemType, Reserves_Type from aviary.variable_info.variable_meta_data import _MetaData from aviary.variable_info.variables import Aircraft, Mission from aviary.utils.functions import get_path @@ -47,7 +47,7 @@ def create_vehicle(vehicle_deck=''): aircraft_values.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False) aircraft_values.set_val(Aircraft.Design.RESERVES, val=4998, units='lbm') aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, val=0, units='unitless') - aircraft_values.set_val(Aircraft.Design.RESERVES_OPTION, val=0, units='unitless') + aircraft_values.set_val(Aircraft.Design.RESERVES_OPTION, val=Reserves_Type.Set_None, units='unitless') vehicle_deck = get_path(vehicle_deck) @@ -169,11 +169,11 @@ def initial_guessing(aircraft_values: AviaryValues()): reserves_option = aircraft_values.get_val(Aircraft.Design.RESERVES_OPTION) reserves = aircraft_values.get_val( Aircraft.Design.RESERVES, units='lbm') if initial_guesses['reserves'] == 0 else initial_guesses['reserves'] - if reserves_option == 1: + if reserves_option == Reserves_Type.Set_Direct: aircraft_values.set_val(Aircraft.Design.RESERVES, reserves, units='lbm') if reserves < 10: - raise ValueError('"aircraft:design:reserves" must be greater than 10 lbm.') - elif reserves_option == 2: + raise ValueError(f'"{Aircraft.Design.RESERVES}" must be greater than 10 lbm.') + elif reserves_option == Reserves_Type.Set_Fraction: if initial_guesses['reserves'] == 0: reserves = aircraft_values.get_val( Aircraft.Design.RESERVES_FRACTION, units='unitless') @@ -182,24 +182,24 @@ def initial_guessing(aircraft_values: AviaryValues()): aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, reserves, units='unitless') if reserves < -1 or reserves > 0: - raise ValueError('"aircraft:design:reserves_fraction" must be in [-1, 0].') + raise ValueError(f'"{Aircraft.Design.RESERVES_FRACTION}" must be in [-1, 0].') else: - # if aircraft:design:reserves_option is not set, + # if Aircraft.Design.RESERVES_FRACTION is not set, # then determine reserves based on initial_guesses['reserves'] if initial_guesses['reserves'] > 10: reserves = initial_guesses['reserves'] - reserves_option = 1 + reserves_option = Reserves_Type.Set_Direct aircraft_values.set_val(Aircraft.Design.RESERVES, reserves, units='lbm') elif initial_guesses['reserves'] < 0: reserves = initial_guesses['reserves'] - reserves_option = 2 + reserves_option = Reserves_Type.Set_Fraction aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, reserves, units='unitless') elif initial_guesses['reserves'] == 0 and reserves > 10: - reserves_option = 1 + reserves_option = Reserves_Type.Set_Direct aircraft_values.set_val(Aircraft.Design.RESERVES, reserves, units='lbm') elif initial_guesses['reserves'] == 0 and reserves < 0: - reserves_option = 2 + reserves_option = Reserves_Type.Set_Fraction aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, reserves, units='unitless') aircraft_values.set_val(Aircraft.Design.RESERVES_OPTION, @@ -207,13 +207,13 @@ def initial_guessing(aircraft_values: AviaryValues()): num_pax = aircraft_values.get_val(Aircraft.CrewPayload.NUM_PASSENGERS) - if reserves_option == 2: + if reserves_option == Reserves_Type.Set_Fraction: if reserves <= 0: reserves *= -(num_pax * initial_guesses['fuel_burn_per_passenger_mile'] * aircraft_values.get_val(Mission.Design.RANGE, units='NM')) else: raise ValueError( - 'The case that "aircraft:design:reserves_fraction" is between 0 and 1 is not implemented.') + f'The case that "{Aircraft.Design.RESERVES_FRACTION}" is between 0 and 1 is not implemented.') initial_guesses['reserves'] = reserves if Mission.Summary.GROSS_MASS in aircraft_values: diff --git a/aviary/variable_info/enums.py b/aviary/variable_info/enums.py index 912283e50..3c9cafc78 100644 --- a/aviary/variable_info/enums.py +++ b/aviary/variable_info/enums.py @@ -181,3 +181,26 @@ class Flap_Type(Enum): """ Double-slotted Fowler flaps """ + +@unique +class Reserves_Type(Enum): + """ + Defines the type of reserves used. Currently, Set_by_Time is not implemented. + """ + + Set_None = 0 + """ + Do not set it and let initial_guess['reserves'] decide. + """ + Set_Direct = 1 + """ + Set required fuel reserves directly in lbm (must be larger than 10). + """ + Set_Fraction = 2 + """ + Set required fuel reserves as a proportion of mission fuel (must be btween -1 and 0). + """ + Set_by_Time = 3 + """ + Set required fuel reserves as a proportion of time (must be btween 0 and 1 which correspond to 0 and 45 minutes). + """ \ No newline at end of file diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index f8aeb4c27..cb3e9f42f 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -7,7 +7,7 @@ import numpy as np from aviary.utils.develop_metadata import add_meta_data -from aviary.variable_info.enums import Flap_Type, GASP_Engine_Type +from aviary.variable_info.enums import Flap_Type, GASP_Engine_Type, Reserves_Type from aviary.variable_info.variables import Aircraft, Dynamic, Mission # --------------------------- @@ -1230,10 +1230,11 @@ "LEAPS1": None }, option=True, - types=int, + types=Reserves_Type, units="unitless", - desc='if 1, use Aircraft.Design.RESERVES; if 2, use Aircraft.Design.RESERVES_FRACTION', - default_value=0, + desc=f'if {Reserves_Type.Set_Direct}, use Aircraft.Design.RESERVES; \ + if {Reserves_Type.Set_Fraction}, use Aircraft.Design.RESERVES_FRACTION', + default_value=Reserves_Type.Set_None, ) add_meta_data( From eb56dccd2b79e12a2c7149c506c4e4e20e73ef70 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 5 Jan 2024 17:41:48 -0500 Subject: [PATCH 007/188] update due to autopep8 requirements --- aviary/utils/process_input_decks.py | 9 ++++++--- aviary/variable_info/enums.py | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/aviary/utils/process_input_decks.py b/aviary/utils/process_input_decks.py index 4baf00f29..c7fa8c26b 100644 --- a/aviary/utils/process_input_decks.py +++ b/aviary/utils/process_input_decks.py @@ -47,7 +47,8 @@ def create_vehicle(vehicle_deck=''): aircraft_values.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False) aircraft_values.set_val(Aircraft.Design.RESERVES, val=4998, units='lbm') aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, val=0, units='unitless') - aircraft_values.set_val(Aircraft.Design.RESERVES_OPTION, val=Reserves_Type.Set_None, units='unitless') + aircraft_values.set_val(Aircraft.Design.RESERVES_OPTION, + val=Reserves_Type.Set_None, units='unitless') vehicle_deck = get_path(vehicle_deck) @@ -172,7 +173,8 @@ def initial_guessing(aircraft_values: AviaryValues()): if reserves_option == Reserves_Type.Set_Direct: aircraft_values.set_val(Aircraft.Design.RESERVES, reserves, units='lbm') if reserves < 10: - raise ValueError(f'"{Aircraft.Design.RESERVES}" must be greater than 10 lbm.') + raise ValueError( + f'"{Aircraft.Design.RESERVES}" must be greater than 10 lbm.') elif reserves_option == Reserves_Type.Set_Fraction: if initial_guesses['reserves'] == 0: reserves = aircraft_values.get_val( @@ -182,7 +184,8 @@ def initial_guessing(aircraft_values: AviaryValues()): aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, reserves, units='unitless') if reserves < -1 or reserves > 0: - raise ValueError(f'"{Aircraft.Design.RESERVES_FRACTION}" must be in [-1, 0].') + raise ValueError( + f'"{Aircraft.Design.RESERVES_FRACTION}" must be in [-1, 0].') else: # if Aircraft.Design.RESERVES_FRACTION is not set, # then determine reserves based on initial_guesses['reserves'] diff --git a/aviary/variable_info/enums.py b/aviary/variable_info/enums.py index 3c9cafc78..aabe458d1 100644 --- a/aviary/variable_info/enums.py +++ b/aviary/variable_info/enums.py @@ -182,6 +182,7 @@ class Flap_Type(Enum): Double-slotted Fowler flaps """ + @unique class Reserves_Type(Enum): """ @@ -203,4 +204,4 @@ class Reserves_Type(Enum): Set_by_Time = 3 """ Set required fuel reserves as a proportion of time (must be btween 0 and 1 which correspond to 0 and 45 minutes). - """ \ No newline at end of file + """ From b345ac3ee00822a1f8849cdd055007c5c419188d Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Mon, 8 Jan 2024 11:46:10 -0500 Subject: [PATCH 008/188] Added check to see if the reports directory exists before creating the dashboard --- aviary/visualization/dashboard.py | 320 ++++++++++++++++++------------ 1 file changed, 197 insertions(+), 123 deletions(-) diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index 342efc704..f31110571 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -17,13 +17,15 @@ import openmdao.api as om from openmdao.utils.general_utils import env_truthy -pn.extension(sizing_mode='stretch_width') +pn.extension(sizing_mode="stretch_width") # Constants # Can't get using CSS to work with frames and the raw_css for the template so going with # this for now -iframe_css = "width=100% height=4000vh overflow=hidden margin=0px padding=0px border=none" -aviary_variables_json_file_name = 'aviary_vars.json' +iframe_css = ( + "width=100% height=4000vh overflow=hidden margin=0px padding=0px border=none" +) +aviary_variables_json_file_name = "aviary_vars.json" def _dashboard_setup_parser(parser): @@ -36,21 +38,41 @@ def _dashboard_setup_parser(parser): The parser we're adding options to. """ parser.add_argument( - 'script_name', + "script_name", type=str, - help='Name of aviary script that was run (not including .py).' + help="Name of aviary script that was run (not including .py).", ) - parser.add_argument('--problem_recorder', type=str, help="Problem case recorder file name", - dest='problem_recorder', default='aviary_history.db') - parser.add_argument('--driver_recorder', type=str, help="Driver case recorder file name", - dest='driver_recorder', default=None) - parser.add_argument('--port', dest='port', type=int, - default=5000, help="dashboard server port ID (default is 5000)") + parser.add_argument( + "--problem_recorder", + type=str, + help="Problem case recorder file name", + dest="problem_recorder", + default="aviary_history.db", + ) + parser.add_argument( + "--driver_recorder", + type=str, + help="Driver case recorder file name", + dest="driver_recorder", + default=None, + ) + parser.add_argument( + "--port", + dest="port", + type=int, + default=5000, + help="dashboard server port ID (default is 5000)", + ) # For future use - parser.add_argument('-d', '--debug', action='store_true', dest='debug_output', - help="show debugging output") + parser.add_argument( + "-d", + "--debug", + action="store_true", + dest="debug_output", + help="show debugging output", + ) def _dashboard_cmd(options, user_args): @@ -64,8 +86,12 @@ def _dashboard_cmd(options, user_args): user_args : list of str Args to be passed to the user script. """ - dashboard(options.script_name, options.problem_recorder, - options.driver_recorder, options.port) + dashboard( + options.script_name, + options.problem_recorder, + options.driver_recorder, + options.port, + ) def create_report_frame(format, text_filepath): @@ -82,21 +108,22 @@ def create_report_frame(format, text_filepath): Returns ------- pane : Panel.Pane or None - A Panel Pane object to be displayed in the dashboard. Or None if the file + A Panel Pane object to be displayed in the dashboard. Or None if the file does not exist. """ if os.path.exists(text_filepath): - if format == 'html': + if format == "html": report_pane = pn.pane.HTML( - f'') - elif format in ['markdown', 'text']: + f"" + ) + elif format in ["markdown", "text"]: with open(text_filepath, "rb") as f: file_text = f.read() # need to deal with some encoding errors - file_text = file_text.decode('latin-1') - if format == 'markdown': + file_text = file_text.decode("latin-1") + if format == "markdown": report_pane = pn.pane.Markdown(file_text) - elif format == 'text': + elif format == "text": report_pane = pn.pane.Markdown(f"```\n{file_text}\n```\n") else: raise RuntimeError(f"Report format of {format} is not supported.") @@ -110,8 +137,8 @@ def create_aviary_variables_table_data_nested(script_name, recorder_file): Create a JSON file with information about Aviary variables. The JSON file has one level of hierarchy of the variables. The file - is written to aviary_vars.json. That file is then read in by the - aviary/visualization/assets/aviary_vars/script.js script. That is inside the + is written to aviary_vars.json. That file is then read in by the + aviary/visualization/assets/aviary_vars/script.js script. That is inside the aviary/visualization/assets/aviary_vars/index.html file that is embedded in the dashboard. @@ -129,18 +156,29 @@ def create_aviary_variables_table_data_nested(script_name, recorder_file): """ cr = om.CaseReader(recorder_file) - case = cr.get_case('final') - outputs = case.list_outputs(explicit=True, implicit=True, val=True, - residuals=True, residuals_tol=None, - units=True, shape=True, bounds=True, desc=True, - scaling=False, hierarchical=True, print_arrays=True, - out_stream=None, return_format='dict') + case = cr.get_case("final") + outputs = case.list_outputs( + explicit=True, + implicit=True, + val=True, + residuals=True, + residuals_tol=None, + units=True, + shape=True, + bounds=True, + desc=True, + scaling=False, + hierarchical=True, + print_arrays=True, + out_stream=None, + return_format="dict", + ) sorted_abs_names = sorted(outputs.keys()) grouped = {} for s in sorted_abs_names: - prefix = s.split(':')[0] + prefix = s.split(":")[0] if prefix not in grouped: grouped[prefix] = [] grouped[prefix].append(s) @@ -154,8 +192,8 @@ def create_aviary_variables_table_data_nested(script_name, recorder_file): table_data_nested.append( { "abs_name": group_name, - "prom_name": outputs[var_info]['prom_name'], - "value": str(outputs[var_info]['val']), + "prom_name": outputs[var_info]["prom_name"], + "value": str(outputs[var_info]["val"]), } ) else: @@ -166,8 +204,8 @@ def create_aviary_variables_table_data_nested(script_name, recorder_file): children_list.append( { "abs_name": children_name, - "prom_name": outputs[children_name]['prom_name'], - "value": str(outputs[children_name]['val']), + "prom_name": outputs[children_name]["prom_name"], + "value": str(outputs[children_name]["val"]), } ) table_data_nested.append( # not a real var, just a group of vars so no values @@ -179,8 +217,10 @@ def create_aviary_variables_table_data_nested(script_name, recorder_file): } ) - aviary_variables_file_path = f'reports/{script_name}/aviary_vars/{aviary_variables_json_file_name}' - with open(aviary_variables_file_path, 'w') as fp: + aviary_variables_file_path = ( + f"reports/{script_name}/aviary_vars/{aviary_variables_json_file_name}" + ) + with open(aviary_variables_file_path, "w") as fp: json.dump(table_data_nested, fp) return table_data_nested @@ -196,7 +236,7 @@ def convert_case_recorder_file_to_df(recorder_file_name): Name of the case recorder file. """ cr = om.CaseReader(recorder_file_name) - driver_cases = cr.list_cases('driver', out_stream=None) + driver_cases = cr.list_cases("driver", out_stream=None) df = None for i, case in enumerate(driver_cases): @@ -231,7 +271,9 @@ def convert_case_recorder_file_to_df(recorder_file_name): df = pd.DataFrame(columns=header) # Now fill up a row - row = [i,] + row = [ + i, + ] # important to do in this order since that is the order added to the header for varname in objectives_names: value = objectives[varname] @@ -268,7 +310,13 @@ def dashboard(script_name, problem_recorder, driver_recorder, port): driver_recorder : str Name of the recorder file containing the Driver cases. """ - reports_dir = f'reports/{script_name}/' + reports_dir = f"reports/{script_name}/" + + if not Path(reports_dir).is_dir(): + raise ValueError( + f"The script name, '{script_name}', does not have a reports folder associated with it. " + f"The directory '{reports_dir}' does not exist." + ) # TODO - use lists and functions to do this with a lot less code @@ -276,125 +324,140 @@ def dashboard(script_name, problem_recorder, driver_recorder, port): design_tabs_list = [] # Inputs - inputs_pane = create_report_frame('html', f'{reports_dir}/inputs.html') + inputs_pane = create_report_frame("html", f"{reports_dir}/inputs.html") if inputs_pane: - design_tabs_list.append(('Inputs', inputs_pane)) + design_tabs_list.append(("Inputs", inputs_pane)) # Debug Input List - input_list_pane = create_report_frame('text', 'input_list.txt') + input_list_pane = create_report_frame("text", "input_list.txt") if input_list_pane: - design_tabs_list.append(('Debug Input List', input_list_pane)) + design_tabs_list.append(("Debug Input List", input_list_pane)) # Debug Output List - output_list_pane = create_report_frame('text', 'output_list.txt') + output_list_pane = create_report_frame("text", "output_list.txt") if output_list_pane: - design_tabs_list.append(('Debug Output List', output_list_pane)) + design_tabs_list.append(("Debug Output List", output_list_pane)) # N2 - n2_pane = create_report_frame('html', f'{reports_dir}/n2.html') + n2_pane = create_report_frame("html", f"{reports_dir}/n2.html") if n2_pane: - design_tabs_list.append(('N2', n2_pane)) + design_tabs_list.append(("N2", n2_pane)) # Trajectory Linkage - traj_linkage_report_pane = create_report_frame('html', - f'{reports_dir}/traj_linkage_report.html') + traj_linkage_report_pane = create_report_frame( + "html", f"{reports_dir}/traj_linkage_report.html" + ) if traj_linkage_report_pane: - design_tabs_list.append(('Trajectory Linkage Report', - traj_linkage_report_pane)) + design_tabs_list.append(("Trajectory Linkage Report", traj_linkage_report_pane)) ####### Optimization Tab ####### optimization_tabs_list = [] # Driver scaling - driver_scaling_report_pane = create_report_frame('html', - f'{reports_dir}/driver_scaling_report.html') + driver_scaling_report_pane = create_report_frame( + "html", f"{reports_dir}/driver_scaling_report.html" + ) if driver_scaling_report_pane: - optimization_tabs_list.append(('Driver Scaling Report', - driver_scaling_report_pane)) + optimization_tabs_list.append( + ("Driver Scaling Report", driver_scaling_report_pane) + ) # Coloring report - coloring_report_pane = create_report_frame('html', - f'{reports_dir}/total_coloring.html') + coloring_report_pane = create_report_frame( + "html", f"{reports_dir}/total_coloring.html" + ) if coloring_report_pane: - optimization_tabs_list.append(('Total Coloring Report', - coloring_report_pane)) + optimization_tabs_list.append(("Total Coloring Report", coloring_report_pane)) # Optimization report - opt_report_pane = create_report_frame('html', - f'{reports_dir}/opt_report.html') + opt_report_pane = create_report_frame("html", f"{reports_dir}/opt_report.html") if opt_report_pane: - optimization_tabs_list.append(('Optimization Report', - opt_report_pane)) + optimization_tabs_list.append(("Optimization Report", opt_report_pane)) # IPOPT report - ipopt_pane = create_report_frame('text', - f'{reports_dir}/IPOPT.out') + ipopt_pane = create_report_frame("text", f"{reports_dir}/IPOPT.out") if ipopt_pane: - optimization_tabs_list.append(('IPOPT Output', ipopt_pane)) + optimization_tabs_list.append(("IPOPT Output", ipopt_pane)) # SNOPT report - snopt_pane = create_report_frame('text', - f'{reports_dir}/SNOPT_print.out') + snopt_pane = create_report_frame("text", f"{reports_dir}/SNOPT_print.out") if snopt_pane: - optimization_tabs_list.append(('SNOPT Output', snopt_pane)) + optimization_tabs_list.append(("SNOPT Output", snopt_pane)) # SNOPT summary - snopt_summary_pane = create_report_frame('text', - f'{reports_dir}/SNOPT_summary.out') + snopt_summary_pane = create_report_frame("text", f"{reports_dir}/SNOPT_summary.out") if snopt_summary_pane: - optimization_tabs_list.append(('SNOPT Summary', snopt_summary_pane)) + optimization_tabs_list.append(("SNOPT Summary", snopt_summary_pane)) # PyOpt report - pyopt_solution_pane = create_report_frame('text', - f'{reports_dir}/pyopt_solution.txt') + pyopt_solution_pane = create_report_frame( + "text", f"{reports_dir}/pyopt_solution.txt" + ) if pyopt_solution_pane: - optimization_tabs_list.append(('PyOpt Solution', pyopt_solution_pane)) + optimization_tabs_list.append(("PyOpt Solution", pyopt_solution_pane)) # Desvars, cons, opt interactive plot if driver_recorder: if os.path.exists(driver_recorder): - df = convert_case_recorder_file_to_df(f'{driver_recorder}') + df = convert_case_recorder_file_to_df(f"{driver_recorder}") if df is not None: variables = pn.widgets.CheckBoxGroup( name="Variables", options=list(df.columns), # just so all of them aren't plotted from the beginning. Skip the iter count - value=list(df.columns)[1:2] + value=list(df.columns)[1:2], ) ipipeline = df.interactive() - ihvplot = ipipeline.hvplot(y=variables, responsive=True, min_height=400, - color=list(Category10[10]), - yformatter="%.0f", - title="Model Optimization using OpenMDAO") + ihvplot = ipipeline.hvplot( + y=variables, + responsive=True, + min_height=400, + color=list(Category10[10]), + yformatter="%.0f", + title="Model Optimization using OpenMDAO", + ) optimization_plot_pane = pn.Column( pn.Row( pn.Column( variables, pn.VSpacer(height=30), pn.VSpacer(height=30), - width=300 + width=300, ), ihvplot.panel(), ) ) optimization_tabs_list.append( - ('Desvars, cons, opt', optimization_plot_pane)) + ("Desvars, cons, opt", optimization_plot_pane) + ) else: - optimization_tabs_list.append(('Desvars, cons, opt', pn.pane.Markdown( - f"# Recorder file '{driver_recorder}' does not have Driver case recordings"))) + optimization_tabs_list.append( + ( + "Desvars, cons, opt", + pn.pane.Markdown( + f"# Recorder file '{driver_recorder}' does not have Driver case recordings" + ), + ) + ) else: - optimization_tabs_list.append(('Desvars, cons, opt', pn.pane.Markdown( - f"# Recorder file '{driver_recorder}' not found"))) + optimization_tabs_list.append( + ( + "Desvars, cons, opt", + pn.pane.Markdown(f"# Recorder file '{driver_recorder}' not found"), + ) + ) ####### Results Tab ####### results_tabs_list = [] # Trajectory results - traj_results_report_pane = create_report_frame('html', - f'{reports_dir}/traj_results_report.html') + traj_results_report_pane = create_report_frame( + "html", f"{reports_dir}/traj_results_report.html" + ) if traj_results_report_pane: - results_tabs_list.append(('Trajectory Results Report', - traj_results_report_pane)) + results_tabs_list.append( + ("Trajectory Results Report", traj_results_report_pane) + ) # Make the Aviary variables table pane if problem_recorder: @@ -406,26 +469,32 @@ def dashboard(script_name, problem_recorder, driver_recorder, port): # copy index.html file to reports/script_name/aviary_vars/index.html aviary_dir = pathlib.Path(importlib.util.find_spec("aviary").origin).parent - shutil.copy(aviary_dir.joinpath( - 'visualization/assets/aviary_vars/index.html'), aviary_vars_dir.joinpath('index.html')) - shutil.copy(aviary_dir.joinpath( - 'visualization/assets/aviary_vars/script.js'), aviary_vars_dir.joinpath('script.js')) + shutil.copy( + aviary_dir.joinpath("visualization/assets/aviary_vars/index.html"), + aviary_vars_dir.joinpath("index.html"), + ) + shutil.copy( + aviary_dir.joinpath("visualization/assets/aviary_vars/script.js"), + aviary_vars_dir.joinpath("script.js"), + ) # copy script.js file to reports/script_name/aviary_vars/index.html. # mod the script.js file to point at the json file # create the json file and put it in reports/script_name/aviary_vars/aviary_vars.json create_aviary_variables_table_data_nested( - script_name, problem_recorder) # create the json file - aviary_vars_pane = create_report_frame('html', - f'{reports_dir}/aviary_vars/index.html') + script_name, problem_recorder + ) # create the json file + aviary_vars_pane = create_report_frame( + "html", f"{reports_dir}/aviary_vars/index.html" + ) - results_tabs_list.append(('Aviary Variables', aviary_vars_pane)) + results_tabs_list.append(("Aviary Variables", aviary_vars_pane)) ####### Subsystems Tab ####### subsystem_tabs_list = [] # Look through subsystems directory for markdown files - for md_file in Path(f'{reports_dir}subsystems').glob('*.md'): - example_subsystems_pane = create_report_frame('markdown', str(md_file)) + for md_file in Path(f"{reports_dir}subsystems").glob("*.md"): + example_subsystems_pane = create_report_frame("markdown", str(md_file)) subsystem_tabs_list.append((md_file.stem, example_subsystems_pane)) design_tabs = pn.Tabs(*design_tabs_list) @@ -458,48 +527,53 @@ def dashboard(script_name, problem_recorder, driver_recorder, port): # Add subtabs to tabs high_level_tabs = [] - high_level_tabs.append(('Model', design_tabs)) - high_level_tabs.append(('Optimization', optimization_tabs)) - high_level_tabs.append(('Results', results_tabs)) + high_level_tabs.append(("Model", design_tabs)) + high_level_tabs.append(("Optimization", optimization_tabs)) + high_level_tabs.append(("Results", results_tabs)) if subsystem_tabs_list: - high_level_tabs.append(('Subsystems', subsystem_tabs)) - tabs = pn.Tabs(*high_level_tabs, styles={'background': 'white'}) + high_level_tabs.append(("Subsystems", subsystem_tabs)) + tabs = pn.Tabs(*high_level_tabs, styles={"background": "white"}) template = pn.template.FastListTemplate( - title=f'Aviary Dashboard for {script_name}', + title=f"Aviary Dashboard for {script_name}", logo="assets/aviary_logo.png", favicon="assets/aviary_logo.png", main=[tabs], accent_base_color="black", header_background="rgb(0, 212, 169)", - background_color='white', + background_color="white", theme=DefaultTheme, theme_toggle=False, ) - if env_truthy('TESTFLO_RUNNING'): + if env_truthy("TESTFLO_RUNNING"): show = False threaded = True else: show = True threaded = False - assets_dir = pathlib.Path(importlib.util.find_spec( - "aviary").origin).parent.joinpath('visualization/assets/') - home_dir = '.' - server = pn.serve(template, port=port, address='localhost', - websocket_origin=f'localhost:{port}', - show=show, - threaded=threaded, - static_dirs={ - 'reports': reports_dir, - 'home': home_dir, - 'assets': assets_dir, - }) + assets_dir = pathlib.Path( + importlib.util.find_spec("aviary").origin + ).parent.joinpath("visualization/assets/") + home_dir = "." + server = pn.serve( + template, + port=port, + address="localhost", + websocket_origin=f"localhost:{port}", + show=show, + threaded=threaded, + static_dirs={ + "reports": reports_dir, + "home": home_dir, + "assets": assets_dir, + }, + ) server.stop() -if __name__ == '__main__': +if __name__ == "__main__": # so we can get the files written to the repo top directory # os.chdir('/Users/hschilli/Documents/OpenMDAO/dev/I365-create-launcher/') parser = argparse.ArgumentParser() From 0584139bd0bc13b3a5c4becb2f11654e4df32b35 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 8 Jan 2024 10:52:32 -0600 Subject: [PATCH 009/188] Moved OAS example to a notebook --- aviary/docs/examples/OAS_subsystem.ipynb | 407 ++++++++++++++++++ aviary/docs/examples/OAS_subsystem.md | 120 ------ .../OAS_weight/OAS_wing_weight_analysis.py | 6 +- .../OAS_weight/run_simple_OAS_mission.py | 13 +- 4 files changed, 412 insertions(+), 134 deletions(-) create mode 100644 aviary/docs/examples/OAS_subsystem.ipynb delete mode 100644 aviary/docs/examples/OAS_subsystem.md diff --git a/aviary/docs/examples/OAS_subsystem.ipynb b/aviary/docs/examples/OAS_subsystem.ipynb new file mode 100644 index 000000000..d0c2fe73e --- /dev/null +++ b/aviary/docs/examples/OAS_subsystem.ipynb @@ -0,0 +1,407 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Using Aviary and OpenAeroStruct Together\n", + "\n", + "This is an example of an external subsystem using the [OpenAeroStruct (OAS)](https://github.com/mdolab/OpenAeroStruct) structural analysis system to perform aerostructural optimization of a typical large single aisle transport aircraft wing.\n", + "The subsystem is based on the [OpenAeroStruct aerostructural optimization with wingbox](https://mdolab-openaerostruct.readthedocs-hosted.com/en/latest/aerostructural_wingbox_walkthrough.html) example problem.\n", + "\n", + "This example performs a sub-optimization for minimum wing weight that is then used by Aviary.\n", + "Another use case would be to perform a structural analysis only.\n", + "Structural design variables would be passed to the subsystem from Aviary and wing weight and a constraint or constraints representing the structural analysis would be passed back to Aviary for use by the top level optimization.\n", + "\n", + "## Motivation\n", + "\n", + "There may be a need for a higher fidelity tool to compute wing weight instead of relying on the empirical methods in core Aviary.\n", + "A structural analysis external tool is usually used because of an unusual aircraft configuration that may not be predicted my Aviary empirical weight estimation methods, but in this example case it is simply a demonstration of an external capability to compute wing weight.\n", + "\n", + "## External Dependencies\n", + "\n", + "The user must install [OpenAeroStruct](https://github.com/mdolab/OpenAeroStruct) into their Python environment using the command 'pip install openaerostruct'.\n", + "The user must also install the [ambiance](https://ambiance.readthedocs.io/en/latest/) package using the command 'pip install ambiance'.\n", + "\n", + "## Subsystem Details\n", + "\n", + "There are two parts to building an external subsystem -- the analysis tool and the Aviary external subsystem builder for that tool.\n", + "The analysis tool takes inputs and parameters from Aviary and return outputs that Aviary can use to override existing variables.\n", + "The subsystem builder uses the Aviary external subsystem builder template to connect the analysis tool to Aviary as either a pre-mission, mission or post-mission subsystem.\n", + "\n", + "For this case, the analysis tool will compute a wing weight in the pre-mission portion of the Aviary analysis and return its value to Aviary to override the empirical wing weight value.\n", + "Fuel weight is passed in from Aviary as the only input currently, but other inputs may also be passed in through the subsystem builder, [OAS_wing_weight_builder](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_builder.py), by the `promotes_inputs` parameter.\n", + "Other Aviary variables can also be added as additional inputs based on user needs.\n", + "\n", + "```{note}\n", + "Some modifications of the [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) code may be necessary to add new inputs not already defined.\n", + "```\n", + "\n", + "Here is the builder object for the OAS wing weight analysis example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %load ../../examples/external_subsystems/OAS_weight/OAS_wing_weight_builder.py\n", + "\"\"\"\n", + "Builder for an OpenAeroStruct component that computes a new wing mass.\n", + "\n", + "\"\"\"\n", + "import openmdao.api as om\n", + "import aviary.api as av\n", + "from aviary.examples.external_subsystems.OAS_weight.OAS_wing_weight_analysis import OAStructures\n", + "\n", + "\n", + "class OASWingWeightBuilder(av.SubsystemBuilderBase):\n", + " def __init__(self, name='wing_weight'):\n", + " super().__init__(name)\n", + "\n", + " def build_pre_mission(self, aviary_inputs):\n", + " '''\n", + " Build an OpenMDAO system for the pre-mission computations of the subsystem.\n", + "\n", + " Returns\n", + " -------\n", + " pre_mission_sys : openmdao.core.System\n", + " An OpenMDAO system containing all computations that need to happen in\n", + " the pre-mission (formerly statics) part of the Aviary problem. This\n", + " includes sizing, design, and other non-mission parameters.\n", + " '''\n", + "\n", + " wing_group = om.Group()\n", + " wing_group.add_subsystem(\"aerostructures\",\n", + " OAStructures(\n", + " symmetry=True,\n", + " wing_weight_ratio=1.0,\n", + " S_ref_type='projected',\n", + " n_point_masses=1,\n", + " num_twist_cp=4,\n", + " num_box_cp=51),\n", + " promotes_inputs=[\n", + " ('fuel', av.Mission.Design.FUEL_MASS),\n", + " ],\n", + " promotes_outputs=[('wing_weight', av.Aircraft.Wing.MASS)])\n", + "\n", + " return wing_group\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Analysis Model Details\n", + "\n", + "This analysis is based on the Aviary benchmark [aircraft_for_bench_FwFm](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv) input data representing a typical large single aisle class transport aircraft.\n", + "The analysis code [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) contains the `OAStructures` class which performs a structural analysis of the wing.\n", + "\n", + "We'll now discuss this code in more detail.\n", + "\n", + "First, we create a mesh that defines the shape of the wing based on the span, the location of the wing break typical of a transport aircraft, the dihedral and the wing root, wing break, and wing tip chord lengths.\n", + "The twist of the wing is defined along the span at a set of control points and must be present as it is used in the optimization problem.\n", + "\n", + "We then use this mesh to define a simplified finite element model of the wing structural box.\n", + "We also define the airfoil shapes as an input to OpenAeroStruct for a given wing thickness to chord ratio (t/c) to represent the wing box thickness.\n", + "We then set initial values for the wing skin thickness and spar thickness are set, along with material properties and stress allowables for a metal material, typically aluminum.\n", + "OpenAeroStruct will then calculate aeroelastic loads for a 2.5g maneuver condition and apply those loads to the finite element model of the wing structure.\n", + "\n", + "Results of the structural optimization determine the optimum wing skin thickness, spar cap thickness, wing twist, wing t/c and maneuver angle of attack that satisfies strength constraints while minimizing wing weight.\n", + "The 'OAStructures' class returns the optimized wing mass and the fuel mass burned but currently only the wing mass is used to override the Aviary variable 'Aircraft.Wing.MASS'.\n", + "\n", + "The [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) code may be executed in Python to test the OpenAeroStruct analysis outside of the Aviary subsystem interface.\n", + "Default values for each of the inputs and options are included at the bottom of the analysis code file.\n", + "This can be a useful test to demonstrate that the OpenAeroStruct analysis model has been properly defined and the model returns reasonable results.\n", + "\n", + "Once the user is satisfied that the results are acceptable, the analysis tool can then be added as an external subsystem and tested in a mission.\n", + "\n", + "## Subsystem variables\n", + "\n", + "A variety of parameters may be defined for an OpenAeroStruct model.\n", + "These allow the user to control how the aerodynamic and finite element meshes are subdivided, give details about the aerodynamic solution and provide structural material properties and structural scaling factors.\n", + "The input variables passed in from Aviary may include the fuel mass, reserve fuel mass, airfoil description, engine mass and its location, lift and drag coefficients and the cruise conditions of Mach, altitude, SFC and range.\n", + "\n", + "This is a list of the available options defined for the structural analysis:\n", + "\n", + "- symmetry\n", + "- chord_cos_spacing\n", + "- span_cos_spacing\n", + "- num_box_cp\n", + "- num_twist_cp\n", + "- S_ref_type\n", + "- fem_model_type\n", + "- with_viscous\n", + "- with_wave\n", + "- k_lam\n", + "- c_max_t\n", + "- E\n", + "- G\n", + "- yield\n", + "- mrho\n", + "- strength_factor_for_upper_skin\n", + "- wing_weight_ratio\n", + "- exact_failure_constraint\n", + "- struct_weight_relief\n", + "- distributed_fuel_weight\n", + "- n_point_masses\n", + "- fuel_density\n", + "\n", + "This is a list of the inputs defined for the structural analysis:\n", + "\n", + "- box_upper_x\n", + "- box_lower_x\n", + "- box_upper_y\n", + "- box_lower_y\n", + "- twist_cp\n", + "- spar_thickness_cp\n", + "- skin_thickness_cp\n", + "- t_over_c_cp\n", + "- airfoil_t_over_c\n", + "- fuel\n", + "- fuel_reserve\n", + "- CL0\n", + "- CD0\n", + "- cruise_Mach\n", + "- cruise_altitude\n", + "- cruise_range\n", + "- cruise_SFC\n", + "- engine_mass\n", + "- engine_location\n", + "\n", + "The 2 outputs from the analysis tool are:\n", + "\n", + "- wing_weight\n", + "- fuel_burn\n", + "\n", + "See [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) and the [OpenAeroStruct aerostructural optimization with wingbox](https://mdolab-openaerostruct.readthedocs-hosted.com/en/latest/aerostructural_wingbox_walkthrough.html) documentation for descriptions of these variables.\n", + "\n", + "## Test Case\n", + "\n", + "A simple Aviary mission is defined to test the inclusion of the OpenAeroStruct wing weight subsystem during the pre-mission phase.\n", + "The test mission is defined in [run_simple_OAS_mission](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS/run_simple_OAS_mission.py) and is a mission based on input data read from the benchmark data file [aircraft_for_bench_FwFm](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv).\n", + "\n", + "The OpenAeroStruct subsystem is used to compute an optimum wing mass which will override the Aviary computed wing mass value.\n", + "The value of the Aviary variable `Aircraft.Wing.MASS` is printed at the conclusion of the mission to verify that the wing weight from the subsystem is overriding the Aviary computed wing weight.\n", + "\n", + "A variable in the [run_simple_OAS_mission](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS/run_simple_OAS_mission.py) file named `use_OAS` may be set by the user to `True` or `False` to run the simple mission with or without the OpenAeroStruct subsystem included.\n", + "This will allow the mission to be flown either using the Aviary empirical wing weight estimation (`use_OAS=False`) or with the OpenAeroStruct subsystem (`use_OAS=True`).\n", + "\n", + "Wing weight optimization of this type usually does not have knowledge of non-optimum wing mass values such as leading and training edge structure, actuators, stiffeners, etc.\n", + "The optimum wing mass computed by the `OAStructures` class can be scaled using the option `wing_weight_ratio` to better match either the Aviary empirical wing weight value or a known fly-away weight estimate for your wing model.\n", + "One method to determine the wing_weight_ratio would be to run the mission to calculate the Aviary empirical wing weight and then run [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) by itself using its default input values and compare wing weights. The `wing_weight_ratio` value may then be set to calibrate the OpenAeroStruct wing weight to the expected fly-away weight.\n", + "\n", + "This calibration step has already been performed for this model, so the user may run the simple mission with or without the OpenAeroStruct subsystem active and compare the results.\n", + "\n", + "## Example Run Script\n", + "\n", + "Here is the full run script used to run the simple mission with the OpenAeroStruct subsystem active.\n", + "This run script is also available in the [run_simple_OAS_mission file.](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS/run_simple_OAS_mission.py)\n", + "\n", + "\n", + "```{note}\n", + "We do not actually perform the optimization below.\n", + "Instead, we define and set up the model and the call to run the optimization is commented you.\n", + "You can uncomment this and run the code block to perform a full optimization.\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %load ../../examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py\n", + "'''\n", + "This is a simple test mission to demonstrate the inclusion of a\n", + "pre-mission user defined external subsystem. The simple mission\n", + "is based on input data read from the benchmark data file bench_4.csv,\n", + "which represents a single-aisle commercial transport aircraft. The\n", + "OpenAeroStruct (OAS) subsystem is used to compute an optimum wing\n", + "mass which will override the Aviary computed wing mass value.\n", + "\n", + "The flag 'use_OAS' is set to 'True' to include the OAS subsystem in\n", + "the mission, or set to 'False' to run the mission without the\n", + "subsystem so that wing mass values between the 2 methods may be\n", + "compared.\n", + "\n", + "'''\n", + "\n", + "import numpy as np\n", + "import openmdao.api as om\n", + "import aviary.api as av\n", + "from aviary.examples.external_subsystems.OAS_weight.OAS_wing_weight_builder import OASWingWeightBuilder\n", + "\n", + "# flag to turn on/off OpenAeroStruct subsystem for comparison testing\n", + "use_OAS = True\n", + "\n", + "wing_weight_builder = OASWingWeightBuilder()\n", + "\n", + "# Load the phase_info and other common setup tasks\n", + "phase_info = {\n", + " 'climb_1': {\n", + " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", + " 'user_options': {\n", + " 'optimize_mach': False,\n", + " 'optimize_altitude': False,\n", + " 'polynomial_control_order': 1,\n", + " 'num_segments': 5,\n", + " 'order': 3,\n", + " 'solve_for_range': False,\n", + " 'initial_mach': (0.2, 'unitless'),\n", + " 'final_mach': (0.72, 'unitless'),\n", + " 'mach_bounds': ((0.18, 0.74), 'unitless'),\n", + " 'initial_altitude': (0.0, 'ft'),\n", + " 'final_altitude': (32000.0, 'ft'),\n", + " 'altitude_bounds': ((0.0, 34000.0), 'ft'),\n", + " 'throttle_enforcement': 'path_constraint',\n", + " 'fix_initial': True,\n", + " 'constrain_final': False,\n", + " 'fix_duration': False,\n", + " 'initial_bounds': ((0.0, 0.0), 'min'),\n", + " 'duration_bounds': ((64.0, 192.0), 'min'),\n", + " },\n", + " 'initial_guesses': {'times': ([0, 128], 'min')},\n", + " },\n", + " 'climb_2': {\n", + " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", + " 'user_options': {\n", + " 'optimize_mach': False,\n", + " 'optimize_altitude': False,\n", + " 'polynomial_control_order': 1,\n", + " 'num_segments': 5,\n", + " 'order': 3,\n", + " 'solve_for_range': False,\n", + " 'initial_mach': (0.72, 'unitless'),\n", + " 'final_mach': (0.72, 'unitless'),\n", + " 'mach_bounds': ((0.7, 0.74), 'unitless'),\n", + " 'initial_altitude': (32000.0, 'ft'),\n", + " 'final_altitude': (34000.0, 'ft'),\n", + " 'altitude_bounds': ((23000.0, 38000.0), 'ft'),\n", + " 'throttle_enforcement': 'boundary_constraint',\n", + " 'fix_initial': False,\n", + " 'constrain_final': False,\n", + " 'fix_duration': False,\n", + " 'initial_bounds': ((64.0, 192.0), 'min'),\n", + " 'duration_bounds': ((56.5, 169.5), 'min'),\n", + " },\n", + " 'initial_guesses': {'times': ([128, 113], 'min')},\n", + " },\n", + " 'descent_1': {\n", + " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", + " 'user_options': {\n", + " 'optimize_mach': False,\n", + " 'optimize_altitude': False,\n", + " 'polynomial_control_order': 1,\n", + " 'num_segments': 5,\n", + " 'order': 3,\n", + " 'solve_for_range': False,\n", + " 'initial_mach': (0.72, 'unitless'),\n", + " 'final_mach': (0.36, 'unitless'),\n", + " 'mach_bounds': ((0.34, 0.74), 'unitless'),\n", + " 'initial_altitude': (34000.0, 'ft'),\n", + " 'final_altitude': (500.0, 'ft'),\n", + " 'altitude_bounds': ((0.0, 38000.0), 'ft'),\n", + " 'throttle_enforcement': 'path_constraint',\n", + " 'fix_initial': False,\n", + " 'constrain_final': True,\n", + " 'fix_duration': False,\n", + " 'initial_bounds': ((120.5, 361.5), 'min'),\n", + " 'duration_bounds': ((29.0, 87.0), 'min'),\n", + " },\n", + " 'initial_guesses': {'times': ([241, 58], 'min')},\n", + " },\n", + " 'post_mission': {\n", + " 'include_landing': False,\n", + " 'constrain_range': True,\n", + " 'target_range': (1800., 'nmi'),\n", + " },\n", + "}\n", + "\n", + "phase_info['pre_mission'] = {'include_takeoff': False, 'optimize_mass': True}\n", + "if use_OAS:\n", + " phase_info['pre_mission']['external_subsystems'] = [wing_weight_builder]\n", + "\n", + "aircraft_definition_file = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'\n", + "mission_method = 'simple'\n", + "mass_method = 'FLOPS'\n", + "make_plots = False\n", + "max_iter = 100\n", + "optimizer = 'IPOPT'\n", + "\n", + "prob = av.AviaryProblem(phase_info, mission_method=mission_method, mass_method='FLOPS')\n", + "\n", + "prob.load_inputs(aircraft_definition_file)\n", + "prob.check_inputs()\n", + "prob.add_pre_mission_systems()\n", + "prob.add_phases()\n", + "prob.add_post_mission_systems()\n", + "prob.link_phases()\n", + "prob.add_driver(optimizer=optimizer, max_iter=max_iter)\n", + "prob.add_design_variables()\n", + "prob.add_objective()\n", + "prob.setup()\n", + "\n", + "if use_OAS:\n", + " OAS_sys = 'pre_mission.wing_weight.aerostructures.'\n", + " prob.set_val(OAS_sys + 'box_upper_x', np.array([0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32,\n", + " 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6]), units='unitless')\n", + " prob.set_val(OAS_sys + 'box_lower_x', np.array([0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32,\n", + " 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6]), units='unitless')\n", + " prob.set_val(OAS_sys + 'box_upper_y', np.array([0.0447, 0.046, 0.0472, 0.0484, 0.0495, 0.0505, 0.0514, 0.0523, 0.0531, 0.0538, 0.0545, 0.0551, 0.0557, 0.0563, 0.0568, 0.0573, 0.0577, 0.0581, 0.0585, 0.0588, 0.0591, 0.0593, 0.0595, 0.0597,\n", + " 0.0599, 0.06, 0.0601, 0.0602, 0.0602, 0.0602, 0.0602, 0.0602, 0.0601, 0.06, 0.0599, 0.0598, 0.0596, 0.0594, 0.0592, 0.0589, 0.0586, 0.0583, 0.058, 0.0576, 0.0572, 0.0568, 0.0563, 0.0558, 0.0553, 0.0547, 0.0541]), units='unitless')\n", + " prob.set_val(OAS_sys + 'box_lower_y', np.array([-0.0447, -0.046, -0.0473, -0.0485, -0.0496, -0.0506, -0.0515, -0.0524, -0.0532, -0.054, -0.0547, -0.0554, -0.056, -0.0565, -0.057, -0.0575, -0.0579, -0.0583, -0.0586, -0.0589, -0.0592, -0.0594, -0.0595, -0.0596, -\n", + " 0.0597, -0.0598, -0.0598, -0.0598, -0.0598, -0.0597, -0.0596, -0.0594, -0.0592, -0.0589, -0.0586, -0.0582, -0.0578, -0.0573, -0.0567, -0.0561, -0.0554, -0.0546, -0.0538, -0.0529, -0.0519, -0.0509, -0.0497, -0.0485, -0.0472, -0.0458, -0.0444]), units='unitless')\n", + " prob.set_val(OAS_sys + 'twist_cp', np.array([-6., -6., -4., 0.]), units='deg')\n", + " prob.set_val(OAS_sys + 'spar_thickness_cp',\n", + " np.array([0.004, 0.005, 0.008, 0.01]), units='m')\n", + " prob.set_val(OAS_sys + 'skin_thickness_cp',\n", + " np.array([0.005, 0.01, 0.015, 0.025]), units='m')\n", + " prob.set_val(OAS_sys + 't_over_c_cp',\n", + " np.array([0.08, 0.08, 0.10, 0.08]), units='unitless')\n", + " prob.set_val(OAS_sys + 'airfoil_t_over_c', 0.12, units='unitless')\n", + " prob.set_val(OAS_sys + 'fuel', 40044.0, units='lbm')\n", + " prob.set_val(OAS_sys + 'fuel_reserve', 3000.0, units='lbm')\n", + " prob.set_val(OAS_sys + 'CD0', 0.0078, units='unitless')\n", + " prob.set_val(OAS_sys + 'cruise_Mach', 0.785, units='unitless')\n", + " prob.set_val(OAS_sys + 'cruise_altitude', 11303.682962301647, units='m')\n", + " prob.set_val(OAS_sys + 'cruise_range', 3500, units='nmi')\n", + " prob.set_val(OAS_sys + 'cruise_SFC', 0.53 / 3600, units='1/s')\n", + " prob.set_val(OAS_sys + 'engine_mass', 7400, units='lbm')\n", + " prob.set_val(OAS_sys + 'engine_location', np.array([25, -10.0, 0.0]), units='m')\n", + "\n", + "prob.set_initial_guesses()\n", + "# prob.run_aviary_problem('dymos_solution.db', make_plots=False)\n", + "# print('wing mass = ', prob.model.get_val(av.Aircraft.Wing.MASS, units='lbm'))\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.17" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/aviary/docs/examples/OAS_subsystem.md b/aviary/docs/examples/OAS_subsystem.md deleted file mode 100644 index 10958f502..000000000 --- a/aviary/docs/examples/OAS_subsystem.md +++ /dev/null @@ -1,120 +0,0 @@ -# Using Aviary and OpenAeroStruct Together - -This is an example of an external subsystem using the [OpenAeroStruct](https://github.com/mdolab/OpenAeroStruct) structural analysis system to perform aerostructural optimization of a typical large single aisle transport aircraft wing. -The subsystem is based on the [OpenAeroStruct aerostructural optimization with wingbox](https://mdolab-openaerostruct.readthedocs-hosted.com/en/latest/aerostructural_wingbox_walkthrough.html) example problem. - -While this example performs a sub-optimization for minimum wing weight that is then used by Aviary, a more typical case would be to perform a structural analysis only. -Structural design variables would be passed to the subsystem from Aviary and wing weight and a constraint or constraints representing the structural analysis would be passed back to Aviary for use by the top level optimization. - -## Motivation - -There may be a need for a higher fidelity tool to compute wing weight instead of relying on the empirical methods in core Aviary. -A structural analysis external tool is usually used because of an unusual aircraft configuration that may not be predicted my Aviary empirical weight estimation methods, but in this example case it is simply a demonstration of an external capability to compute wing weight. - -## External Dependencies - -The user must install [OpenAeroStruct](https://github.com/mdolab/OpenAeroStruct) into their Python environment using the command 'pip install openaerostruct'. -The user must also install the [ambiance](https://ambiance.readthedocs.io/en/latest/) 1993 standard atmosphere code using the command 'pip install ambiance'. - -## Subsystem Details - -There are two parts to building an external subsystem -- the analysis tool and the Aviary external subsystem builder for that tool. -The analysis tool takes inputs and parameters from Aviary and return outputs that Aviary can use to override existing variables. -The subsystem builder uses the Aviary external subsystem builder template to connect the analysis tool to Aviary as either a pre-mission, mission or post-mission subsystem. - -For this case, the analysis tool will compute a wing weight in the pre-mission portion of the Aviary analysis and return its value to Aviary to override the empirical wing weight value. -Fuel weight is passed in from Aviary as the only input currently, but other inputs may also be passed in through the subsystem builder, [OAS_wing_weight_builder](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_builder.py), by the 'promotes_inputs' parameter. -Other Aviary variables can also be added in the future as additional inputs. Some modifications of the [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) code may be necessary to add new inputs not already defined. - -## Analysis Model Details - -This analysis is based on the Aviary benchmark [aircraft_for_bench_FwFm](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv) input data representing a typical large single aisle class transport aircraft. -The analysis code [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) contains the `OAStructures` class which performs a structural analysis of the wing. -A mesh is created that defines the shape of the wing based on the span, the location of the wing break typical of a transport aircraft, the dihedral and the wing root, wing break and wing tip chord lengths. -The twist of the wing is defined along the span at a set of control points, and must be present as it is used in the optimization problem. -This mesh will also be used to define a simplified finite element model of the wing structural box. -An airfoil shape is defined as an input to OpenAeroStruct for a given wing thickness to chord ratio (t/c) to represent the wing box thickness. -Initial values for wing skin thickness and spar thickness are set, along with material properties and stress allowables for a metal material, typically aluminum. -OpenAeroStruct will then calculate aeroelastic loads for a 2.5g maneuver condition and apply those loads to the finite element model of the wing structure. -Results of the structural optimization determine the optimum wing skin thickness, spar cap thickness, wing twist, wing t/c and maneuver angle of attack that satisfies strength constraints while minimizing wing weight. -The 'OAStructures' class returns the optimized wing mass and the fuel mass burned but currently only the wing mass is used to override the Aviary variable 'Aircraft.Wing.MASS'. -The [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) code may be executed in Python to test the OpenAeroStruct analysis outside of the Aviary subsystem interface. -Default values for each of the inputs and options are included at the bottom of the analysis code file. -This can be a useful test to demonstrate that the OpenAeroStruct analysis model has been properly defined and the model returns reasonable results. -Once the user is satisfied that the results are acceptable, the analysis tool can then be added as an external subsystem and tested in a mission. - -## Subsystem variables - -A variety of parameters may be defined for an OpenAeroStruct model. -These allow the user to control how the aerodynamic and finite element meshes are subdivided, give details about the aerodynamic solution and provide structural material properties and structural scaling factors. -The input variables passed in from Aviary may include the fuel mass, reserve fuel mass, airfoil description, engine mass and its location, lift and drag coefficients and the cruise conditions of Mach, altitude, SFC and range. - -This is a list of the available options defined for the structural analysis: - -- symmetry -- chord_cos_spacing -- span_cos_spacing -- num_box_cp -- num_twist_cp -- S_ref_type -- fem_model_type -- with_viscous -- with_wave -- k_lam -- c_max_t -- E -- G -- yield -- mrho -- strength_factor_for_upper_skin -- wing_weight_ratio -- exact_failure_constraint -- struct_weight_relief -- distributed_fuel_weight -- n_point_masses -- fuel_density - -This is a list of the inputs defined for the structural analysis: - -- box_upper_x -- box_lower_x -- box_upper_y -- box_lower_y -- twist_cp -- spar_thickness_cp -- skin_thickness_cp -- t_over_c_cp -- airfoil_t_over_c -- fuel -- fuel_reserve -- CL0 -- CD0 -- cruise_Mach -- cruise_altitude -- cruise_range -- cruise_SFC -- engine_mass -- engine_location - -The 2 outputs from the analysis tool are: - -- wing_weight -- fuel_burn - -See [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) and the [OpenAeroStruct aerostructural optimization with wingbox](https://mdolab-openaerostruct.readthedocs-hosted.com/en/latest/aerostructural_wingbox_walkthrough.html) documentation for descriptions of these variables. - -## Test Case - -A simple Aviary mission is defined to test the inclusion of the OpenAeroStruct wing weight subsystem during the pre-mission phase. -The test mission is defined in [run_simple_OAS_mission](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS/run_simple_OAS_mission.py) and is a mission based on input data read from the benchmark data file [aircraft_for_bench_FwFm](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv). -The OpenAeroStruct (OAS) subsystem is used to compute an optimum wing mass which will override the Aviary computed wing mass value. -The value of the Aviary variable `Aircraft.Wing.MASS` is printed at the conclusion of the mission to verify that the wing weight from the subsystem is overriding the Aviary computed wing weight. - -A variable in the [run_simple_OAS_mission](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS/run_simple_OAS_mission.py) file named `use_OAS` may be set by the user to `True` or `False` to run the simple mission with or without the OpenAeroStruct subsystem included. -This will allow the mission to be flown either using the Aviary empirical wing weight estimation (use_OAS='False') or with the OpenAero Struct subsystem (use_OAS='True'). - -Wing weight optimization of this type usually does not have knowledge of non-optimum wing mass values such as leading and training edge structure, actuators, stiffeners, etc. -The optimum wing mass computed by the `OAStructures` class can be scaled using the option 'wing_weight_ratio' to better match either the Aviary empirical wing weight value or a known fly-away weight estimate for your wing model. -One method to determine the wing_weight_ratio would be to run the mission to calculate the Aviary empirical wing weight and then run [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) by itself using its default input values and compare wing weights. The 'wing_weight_ratio' value may then be set to calibrate the OpenAeroStruct wing weight to the expected fly-away weight. - -This calibration step has already been performed for this model, so the user may run the simple mission with or without the OpenAeroStruct subsystem active and compare the results. diff --git a/aviary/examples/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py b/aviary/examples/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py index 3e71d3f58..ca7785a0e 100644 --- a/aviary/examples/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py +++ b/aviary/examples/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py @@ -1,9 +1,9 @@ ''' OpenMDAO component for aerostructural analysis using OpenAeroStruct. -This analysis is based on the bench_4.csv input data representing a +This analysis is based on the aircraft_for_bench_FwFm.csv input data representing a single-aisle commercial transport aircraft. The user_mesh method is currently -hard-coded with values taken from the bench_4 data, but should be coded +hard-coded with values taken from the aircraft_for_bench_FwFm data, but should be coded to use the Aircraft.Wing.* variables for a more general capability. The OAStructures class performs a structural analysis of the given wing @@ -551,7 +551,7 @@ def compute(self, inputs, outputs): prob.setup() # test data taken from the OpenAeroStruct example aeroelastic wingbox example - # and the bench_4.csv benchmark data file. All length units are in meters + # and the aircraft_for_bench_FwFm.csv benchmark data file. All length units are in meters # and all mass units are in kilograms for this test data. prob['OAS.box_upper_x'] = np.array([0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6]) diff --git a/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py b/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py index 656ca18ed..3617fc343 100644 --- a/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py +++ b/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py @@ -113,8 +113,7 @@ mass_method = 'FLOPS' make_plots = False max_iter = 100 -optimizer = 'SNOPT' - +optimizer = 'IPOPT' prob = av.AviaryProblem(phase_info, mission_method=mission_method, mass_method='FLOPS') @@ -124,15 +123,7 @@ prob.add_phases() prob.add_post_mission_systems() prob.link_phases() - -driver = prob.driver = om.pyOptSparseDriver() -driver.options["optimizer"] = optimizer -driver.declare_coloring() -driver.opt_settings["Major iterations limit"] = max_iter -driver.opt_settings["Major optimality tolerance"] = 1e-4 -driver.opt_settings["Major feasibility tolerance"] = 1e-5 -driver.opt_settings["iSumm"] = 6 - +prob.add_driver(optimizer=optimizer, max_iter=max_iter) prob.add_design_variables() prob.add_objective() prob.setup() From a23dc8e0fa8db2cba99103792e50303fe57c4025 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 8 Jan 2024 11:29:47 -0600 Subject: [PATCH 010/188] Updated logic for using poly controls on simple mission --- README.md | 11 +++++------ aviary/docs/getting_started/installation.md | 9 +++++++-- aviary/interface/graphical_input.py | 1 + .../mission/flops_based/phases/simple_energy_phase.py | 4 +++- .../benchmark_tests/test_bench_FwFm.py | 3 +++ .../benchmark_tests/test_bench_GwFm.py | 5 +++-- 6 files changed, 22 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index be877c920..0a2d83541 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,10 @@ The user can select which type of mission analysis to use, as well as whether to ## Installation -The simplest installation method for development is an "editable mode" install with ``pip`` in your terminal: +The simplest installation method for users is to install via pip. +From within the base folder of Aviary, perform this command in your terminal: - pip install -e . - -This installs the package in the current environment such that changes to the Python code don't require re-installation.This command should be performed while in the folder containing ``setup.py``. + pip install . ## Documentation @@ -31,7 +30,7 @@ Otherwise you can build the docs locally: ## Visualization -To visualize XDSMs and successfully pass spec tests, all the XDSM files must be run. This can be done using the `run_all.py` utility script within the `aviary/xdsm` directory. This is a necessary step before unit testing, otherwise unit tests will fail. +To create XDSM visualizations of some of the Aviary code, run the `run_all.py` utility script within the `aviary/xdsm` directory. ## Validation @@ -62,4 +61,4 @@ This will run all of the longer tests in parallel using all of your available CP ## Package Versions Information on the versions of the packages required for Aviary can be found in the most recent [GitHub Actions runs](https://github.com/OpenMDAO/Aviary/actions). -We have also provided a static version of the `environment.yml` at the top level of the Aviary repo. \ No newline at end of file +We have also provided a static version of the `environment.yml` at the top level of the Aviary repo. diff --git a/aviary/docs/getting_started/installation.md b/aviary/docs/getting_started/installation.md index e0a53a553..4f484a085 100644 --- a/aviary/docs/getting_started/installation.md +++ b/aviary/docs/getting_started/installation.md @@ -2,12 +2,17 @@ ## Quick start installation -The simplest installation method for development is an "editable mode" install with ``pip``. +The simplest installation method for users is to install via pip. From within the base folder of Aviary, perform this command in your terminal: + pip install . + +If you are a developer and plan to modify parts of the Aviary code, install in an "editable mode" with ``pip``: + pip install -e . -This installs the package in the current environment such that changes to the Python code don't require re-installation.This command should be performed while in the folder containing ``setup.py``. +This installs the package in the current environment such that changes to the Python code don't require re-installation. +This command should be performed while in the folder containing ``setup.py``. ## Installation on Linux for Developers diff --git a/aviary/interface/graphical_input.py b/aviary/interface/graphical_input.py index babc6e72d..1fb3c7c18 100644 --- a/aviary/interface/graphical_input.py +++ b/aviary/interface/graphical_input.py @@ -145,6 +145,7 @@ def create_bounds(center): 'optimize_mach': optimize_mach_phase_vars[i].get(), 'optimize_altitude': optimize_altitude_phase_vars[i].get(), 'polynomial_control_order': polynomial_order, + 'use_polynomial_control': True, 'num_segments': num_segments, 'order': 3, 'solve_for_range': False, diff --git a/aviary/mission/flops_based/phases/simple_energy_phase.py b/aviary/mission/flops_based/phases/simple_energy_phase.py index 9f6c9296a..3514be333 100644 --- a/aviary/mission/flops_based/phases/simple_energy_phase.py +++ b/aviary/mission/flops_based/phases/simple_energy_phase.py @@ -152,6 +152,7 @@ def build_phase(self, aviary_options: AviaryValues = None): optimize_altitude = user_options.get_val('optimize_altitude') input_initial = user_options.get_val('input_initial') polynomial_control_order = user_options.get_item('polynomial_control_order')[0] + use_polynomial_control = user_options.get_val('use_polynomial_control') throttle_enforcement = user_options.get_val('throttle_enforcement') mach_bounds = user_options.get_item('mach_bounds') altitude_bounds = user_options.get_item('altitude_bounds') @@ -205,7 +206,6 @@ def build_phase(self, aviary_options: AviaryValues = None): ################ # Add Controls # ################ - use_polynomial_control = polynomial_control_order is not None if use_polynomial_control: phase.add_polynomial_control( Dynamic.Mission.MACH, @@ -374,6 +374,8 @@ def _extra_ode_init_kwargs(self): EnergyPhase._add_meta_data('polynomial_control_order', val=None) +EnergyPhase._add_meta_data('use_polynomial_control', val=True) + EnergyPhase._add_meta_data('add_initial_mass_constraint', val=False) EnergyPhase._add_meta_data('fix_initial', val=True) diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index 6027d9b4a..c86c541df 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -279,6 +279,7 @@ def bench_test_swap_4_FwFm_simple(self): "optimize_mach": True, "optimize_altitude": True, "polynomial_control_order": None, + "use_polynomial_control": False, "num_segments": 6, "order": 3, "solve_for_range": False, @@ -304,6 +305,7 @@ def bench_test_swap_4_FwFm_simple(self): "optimize_mach": True, "optimize_altitude": True, "polynomial_control_order": 1, + "use_polynomial_control": True, "num_segments": 1, "order": 3, "solve_for_range": False, @@ -328,6 +330,7 @@ def bench_test_swap_4_FwFm_simple(self): "optimize_mach": True, "optimize_altitude": True, "polynomial_control_order": None, + "use_polynomial_control": False, "num_segments": 5, "order": 3, "solve_for_range": False, diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py index aa7193866..2dd22d79b 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py @@ -284,7 +284,7 @@ def bench_test_swap_1_GwFm_simple(self): 'input_initial': True, "optimize_mach": True, "optimize_altitude": True, - "polynomial_control_order": None, + "use_polynomial_control": False, "num_segments": 6, "order": 3, "solve_for_range": False, @@ -310,6 +310,7 @@ def bench_test_swap_1_GwFm_simple(self): "optimize_mach": True, "optimize_altitude": True, "polynomial_control_order": 1, + "use_polynomial_control": True, "num_segments": 1, "order": 3, "solve_for_range": False, @@ -333,7 +334,7 @@ def bench_test_swap_1_GwFm_simple(self): "user_options": { "optimize_mach": True, "optimize_altitude": True, - "polynomial_control_order": None, + "use_polynomial_control": False, "num_segments": 5, "order": 3, "solve_for_range": False, From 95459c2e60c3c7278ac1b7a2dbb43eae0fd6a1e5 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Mon, 8 Jan 2024 13:36:04 -0500 Subject: [PATCH 011/188] Fixed bug in test that tested dashboard. It assumed the reports would be in a tmp directory but they are actually in the name of the script, test_simple_mission. The new test to make sure reports directory exist caused this to fail --- aviary/interface/test/test_simple_mission.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aviary/interface/test/test_simple_mission.py b/aviary/interface/test/test_simple_mission.py index 1b5762dcb..327843fcd 100644 --- a/aviary/interface/test/test_simple_mission.py +++ b/aviary/interface/test/test_simple_mission.py @@ -4,7 +4,6 @@ from openmdao.utils.testing_utils import require_pyoptsparse, use_tempdirs import subprocess - @use_tempdirs class AircraftMissionTestSuite(unittest.TestCase): @@ -119,7 +118,7 @@ def test_mission_basic_and_dashboard(self): self.assertIsNotNone(prob) self.assertFalse(prob.failed) - cmd = f'aviary dashboard --problem_recorder dymos_solution.db --driver_recorder driver_test.db tmp' + cmd = f'aviary dashboard --problem_recorder dymos_solution.db --driver_recorder driver_test.db test_simple_mission' # this only tests that a given command line tool returns a 0 return code. It doesn't # check the expected output at all. The underlying functions that implement the # commands should be tested seperately. From 474bc6c3d101673edeec176d794274aafebad3e6 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 8 Jan 2024 17:37:25 -0500 Subject: [PATCH 012/188] removed RESERVES_OPTION and set RESERVES_FRACTION to positive --- .../getting_started/input_csv_phase_info.md | 9 ++- aviary/interface/methods_for_level2.py | 64 +++++++------------ aviary/interface/test/test_reserve_support.py | 2 +- .../large_single_aisle_1_GwGm.csv | 1 - .../large_single_aisle_1_GwGm.dat | 2 - .../small_single_aisle_GwGm.dat | 4 +- .../test_aircraft/aircraft_for_bench_FwFm.csv | 1 - .../test_aircraft/aircraft_for_bench_FwGm.csv | 1 - .../test_aircraft/aircraft_for_bench_GwFm.csv | 1 - .../test_aircraft/aircraft_for_bench_GwGm.csv | 1 - ...converter_configuration_test_data_GwGm.csv | 1 - ...converter_configuration_test_data_GwGm.dat | 4 +- aviary/utils/Fortran_to_Aviary.py | 7 ++ .../legacy_code_data/gasp_default_values.dat | 2 - aviary/utils/process_input_decks.py | 63 +++++------------- aviary/variable_info/variable_meta_data.py | 19 +----- aviary/variable_info/variables.py | 1 - 17 files changed, 57 insertions(+), 126 deletions(-) diff --git a/aviary/docs/getting_started/input_csv_phase_info.md b/aviary/docs/getting_started/input_csv_phase_info.md index c60fad220..a1b309d8a 100644 --- a/aviary/docs/getting_started/input_csv_phase_info.md +++ b/aviary/docs/getting_started/input_csv_phase_info.md @@ -18,14 +18,13 @@ This section is under development. - climb_range: 0, - reserves: 0 -The initial guess of `reserves` is used to define the reserve fuel. Initially, its value can be anything larger than 10 or anything between -1 and 0. There are three variables to control the reserve fuel in the model file (`.csv`): +The initial guess of `reserves` is used to define the reserve fuel. Initially, its value can be anything larger than or equal to 0. There are two variables to control the reserve fuel in the model file (`.csv`): - `Aircraft.Design.RESERVES`: the required fuel reserves: directly in lbm, - `Aircraft.Design.RESERVES_FRACTION`: the required fuel reserves: given as a proportion of mission fuel, -- `Aircraft.Design.RESERVES_OPTION`: if `Set_Direct` (1), use `Aircraft.Design.RESERVES`; if `Set_Fraction` (2), use `Aircraft.Design.RESERVES_FRACTION`. -If the value of parameter `reserves` is not 0 and is within the allowed range, the initial guess of reserve fuel is determined by the parameter `reserves`: -- if `reserves > 10.0`, we set `Aircraft.Design.RESERVES = reserves` and `Aircraft.Design.RESERVES_OPTION = 1`, -- if `-1.0 <= reserves <= 0`, we set `Aircraft.Design.RESERVES_FRACTION = reserves` and `Aircraft.Design.RESERVES_OPTION = 2`. +If the value of initial guess of `reserves` is not 0 and is within the allowed range, the initial guess of reserve fuel is determined by the parameter `reserves`: +- if `reserves > 1.0`, we set `Aircraft.Design.RESERVES = reserves`, +- if `0.0 <= reserves <= 1.0`, we set `Aircraft.Design.RESERVES_FRACTION = reserves`. The initial guess of `reserves` is always converted to the actual design reserves (instead of reserve factor) and is used to update the initial guesses of `fuel_burn_per_passenger_mile` and `cruise_mass_final`. diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 4847119b0..68e5ff51c 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -48,7 +48,7 @@ from aviary.variable_info.functions import setup_trajectory_params, override_aviary_vars from aviary.variable_info.variables import Aircraft, Mission, Dynamic -from aviary.variable_info.enums import AnalysisScheme, ProblemType, SpeedType, AlphaModes, Reserves_Type +from aviary.variable_info.enums import AnalysisScheme, ProblemType, SpeedType, AlphaModes from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData from aviary.variable_info.variables_in import VariablesIn @@ -2439,43 +2439,27 @@ def _add_fuel_reserve_component(self, reserves_name=Mission.Design.RESERVE_FUEL) reserves_val = self.aviary_inputs.get_val(Aircraft.Design.RESERVES, units='lbm') reserves_fac = self.aviary_inputs.get_val( Aircraft.Design.RESERVES_FRACTION, units='unitless') - reserves_opt = self.aviary_inputs.get_val( - Aircraft.Design.RESERVES_OPTION, units='unitless') - if reserves_opt == Reserves_Type.Set_Direct: - if reserves_val > 10: - self.model.add_subsystem( - "reserves_calc", - om.ExecComp( - f"reserve_fuel = {reserves_val}", - reserve_fuel={"val": reserves_val, "units": "lbm"} - ), - promotes_outputs=[("reserve_fuel", reserves_name)], - ) - else: - raise ValueError(f'"{Aircraft.Design.RESERVES}" is not valid below 10.') - elif reserves_opt == Reserves_Type.Set_Fraction: - if reserves_fac <= 0 and reserves_fac >= -1: - reserves_fac = -reserves_fac - self.model.add_subsystem( - "reserves_calc", - om.ExecComp( - f"reserve_fuel = {reserves_fac}*(takeoff_mass - final_mass)", - takeoff_mass={"units": "lbm"}, - final_mass={"units": "lbm"}, - reserve_fuel={"units": "lbm"} - ), - promotes_inputs=[ - ("takeoff_mass", Mission.Summary.GROSS_MASS), - ("final_mass", Mission.Landing.TOUCHDOWN_MASS), - ], - promotes_outputs=[("reserve_fuel", reserves_name)], - ) - elif reserves_fac > 0 and reserves_fac <= 1: - raise ValueError( - f'"{Aircraft.Design.RESERVES_FRACTION}" between 0 and 1 is not implemented.') - else: - raise ValueError( - f'"{Aircraft.Design.RESERVES_FRACTION}" is not valid if less than -1 or larger than 1.') + if reserves_val > 0.0: + self.model.add_subsystem( + "reserves_calc", + om.ExecComp( + f"reserve_fuel = {reserves_val}", + reserve_fuel={"val": reserves_val, "units": "lbm"} + ), + promotes_outputs=[("reserve_fuel", reserves_name)], + ) else: - raise ValueError(f'"{Aircraft.Design.RESERVES_OPTION}" must be \ - {Reserves_Type.Set_Directn} or {Reserves_Type.Set_Fraction}.') + self.model.add_subsystem( + "reserves_calc", + om.ExecComp( + f"reserve_fuel = {reserves_fac}*(takeoff_mass - final_mass)", + takeoff_mass={"units": "lbm"}, + final_mass={"units": "lbm"}, + reserve_fuel={"units": "lbm"} + ), + promotes_inputs=[ + ("takeoff_mass", Mission.Summary.GROSS_MASS), + ("final_mass", Mission.Landing.TOUCHDOWN_MASS), + ], + promotes_outputs=[("reserve_fuel", reserves_name)], + ) diff --git a/aviary/interface/test/test_reserve_support.py b/aviary/interface/test/test_reserve_support.py index 7fed83a67..8109be9e5 100644 --- a/aviary/interface/test/test_reserve_support.py +++ b/aviary/interface/test/test_reserve_support.py @@ -76,7 +76,7 @@ def test_gasp_relative_reserve(self): Aircraft.Design.RESERVES_FRACTION, units='unitless') td_mass = prob.model.get_val(Mission.Landing.TOUCHDOWN_MASS, units='lbm') reserve = prob.model.get_val(Mission.Design.RESERVE_FUEL, units='lbm') - assert_near_equal(reserve, -res_frac * (140000.0 - td_mass), 1e-3) + assert_near_equal(reserve, res_frac * (140000.0 - td_mass), 1e-3) if __name__ == '__main__': diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv index 2092a85fb..0bf88a607 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv @@ -16,7 +16,6 @@ aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless aircraft:design:reserves,4998,lbm aircraft:design:reserves_fraction,0,unitless -aircraft:design:reserves_option,1,unitless aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat index b8a4d51f3..f23fff285 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat @@ -195,8 +195,6 @@ aircraft:engine:data_file=models/engines/turbofan_23k_1.deck ROSCAB=9999., ! cabin rate of sink during descent (500.) fpm RSMX=900., ! maximum allowable rate of sink during landing approach ft per min (1000) FRESF=4998, ! Reserve Fuel fraction of mission fuel (minus sign for code trigger) - FRESF2=0, ! Reserve fuel fraction of mission fuel (negative sign trigger) - FRESF3=1, ! Use Reserve Fuel RF(1)=.05, ! Reserve Fuel Input: Time for Missed Approach RF(2)=125., ! Reserve Fuel Input: Range to alternate RF(3)=20000., ! Reserve Fuel Input: Cruise altitude to alternate diff --git a/aviary/models/small_single_aisle/small_single_aisle_GwGm.dat b/aviary/models/small_single_aisle/small_single_aisle_GwGm.dat index d6736b834..9ad297777 100644 --- a/aviary/models/small_single_aisle/small_single_aisle_GwGm.dat +++ b/aviary/models/small_single_aisle/small_single_aisle_GwGm.dat @@ -205,9 +205,7 @@ OFEM=.78, ! off design specified mission Mach number ROSCAB=9999., ! cabin rate of sink during descent (500.) fpm RSMX=900., ! maximum allowable rate of sink during landing approach ft per min (1000) - FRESF=0, ! Reserve Fuel - FRESF2=-.125, ! Reserve Fuel fraction of mission fuel (minus sign for code trigger) - FRESF3=2, ! Use Reserve Fuel + FRESF=0.125, ! Reserve Fuel fraction of mission fuel (minus sign for code trigger) RF(1)=2.0, ! Reserve Fuel Input: Time for Missed Approach (min) RF(2)=100., ! Reserve Fuel Input: Range to alternate RF(3)=25000., ! Reserve Fuel Input: Cruise altitude to alternate diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv index a3b66e387..c415c912b 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv @@ -26,7 +26,6 @@ aircraft:design:empty_mass_margin_scaler,0.0,unitless aircraft:design:lift_dependent_drag_coeff_factor,0.909839381134961,unitless aircraft:design:touchdown_mass,152800.0,lbm aircraft:design:reserves,3000.,lbm -aircraft:design:reserves_option,1,unitless aircraft:design:subsonic_drag_coeff_factor,1.0,unitless aircraft:design:supersonic_drag_coeff_factor,1.0,unitless aircraft:design:use_alt_mass,False,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv index 316c73a5c..2224b8ba5 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv @@ -13,7 +13,6 @@ aircraft:design:equipment_mass_coefficients,928,0.0736,0.112,0.14,1959,1.65,551, aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless aircraft:design:reserves,3000.,lbm -aircraft:design:reserves_option,1,unitless aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.025,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv index 4881c183b..9688bdf8d 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv @@ -40,7 +40,6 @@ aircraft:design:touchdown_mass,152800.0,lbm aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless aircraft:design:reserves,5000.,lbm -aircraft:design:reserves_option,1,unitless aircraft:design:smooth_mass_discontinuities,False,unitless aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv index 17f76a7c0..de310d32c 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv @@ -14,7 +14,6 @@ aircraft:design:equipment_mass_coefficients,928,0.0736,0.112,0.14,1959,1.65,551, aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless aircraft:design:reserves,4998,lbm -aircraft:design:reserves_option,1,unitless aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless diff --git a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv index 4367304b9..a9e6e1ce0 100644 --- a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv +++ b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv @@ -16,7 +16,6 @@ aircraft:design:max_structural_speed,440,mi/h aircraft:design:part25_structural_category,3,unitless aircraft:design:reserves,0,lbm aircraft:design:reserves_fraction,-0.15,unitless -aircraft:design:reserves_option,2,unitless aircraft:design:static_margin,0.05,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless diff --git a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.dat b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.dat index e6ed8dbee..ce493357c 100644 --- a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.dat +++ b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.dat @@ -209,9 +209,7 @@ aircraft:engine:data_file=models/engines/turbofan_23k_1.deck OFEM=.78, ! off design specified mission Mach number ROSCAB=9999., ! cabin rate of sink during descent (500.) fpm RSMX=900., ! maximum allowable rate of sink during landing approach ft per min (1000) - FRESF=0, ! Reserve Fuel - FRESF2=-0.15, ! Reserve fuel fraction of mission fuel (negative sign trigger) - FRESF3=2, ! Use Reserve Fuel fraction + FRESF=0.15, ! Reserve fuel fraction of mission fuel (negative sign trigger) RF(1)=.05, ! Reserve Fuel Input: Time for Missed Approach RF(2)=125., ! Reserve Fuel Input: Range to alternate RF(3)=20000., ! Reserve Fuel Input: Cruise altitude to alternate diff --git a/aviary/utils/Fortran_to_Aviary.py b/aviary/utils/Fortran_to_Aviary.py index 63a035830..e46b1f27d 100644 --- a/aviary/utils/Fortran_to_Aviary.py +++ b/aviary/utils/Fortran_to_Aviary.py @@ -434,6 +434,13 @@ def update_gasp_options(vehicle_data): input_values.set_val(Aircraft.Wing.FLAP_DRAG_INCREMENT_OPTIMUM, [[.12, .23, .13, .23, .23, .1, .15][flap_ind]]) + res = input_values.get_val(Aircraft.Design.RESERVES, units='lbm')[0] + if res <= 1.0: + input_values.set_val(Aircraft.Design.RESERVES, [0], units='lbm') + input_values.set_val(Aircraft.Design.RESERVES_FRACTION, [-res], units='unitless') + else: + input_values.set_val(Aircraft.Design.RESERVES_FRACTION, [0], units='unitless') + vehicle_data['input_values'] = input_values return vehicle_data diff --git a/aviary/utils/legacy_code_data/gasp_default_values.dat b/aviary/utils/legacy_code_data/gasp_default_values.dat index 9121140fb..686f5f1d7 100644 --- a/aviary/utils/legacy_code_data/gasp_default_values.dat +++ b/aviary/utils/legacy_code_data/gasp_default_values.dat @@ -84,8 +84,6 @@ FLAPN=1,unitless FN_REF=28690,lbf FPYL=0.7,unitless FRESF=4998,lbm -FRESF2=-0.1,unitless -FRESF3=1,unitless FUELD=6.687,lbm/galUS FVOL_MRG=0,unitless HAPP=50,ft diff --git a/aviary/utils/process_input_decks.py b/aviary/utils/process_input_decks.py index c7fa8c26b..49ea338a5 100644 --- a/aviary/utils/process_input_decks.py +++ b/aviary/utils/process_input_decks.py @@ -22,7 +22,7 @@ from aviary.utils.aviary_values import AviaryValues, get_keys from aviary.utils.functions import convert_strings_to_data, set_value from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.enums import ProblemType, Reserves_Type +from aviary.variable_info.enums import ProblemType from aviary.variable_info.variable_meta_data import _MetaData from aviary.variable_info.variables import Aircraft, Mission from aviary.utils.functions import get_path @@ -47,8 +47,6 @@ def create_vehicle(vehicle_deck=''): aircraft_values.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False) aircraft_values.set_val(Aircraft.Design.RESERVES, val=4998, units='lbm') aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, val=0, units='unitless') - aircraft_values.set_val(Aircraft.Design.RESERVES_OPTION, - val=Reserves_Type.Set_None, units='unitless') vehicle_deck = get_path(vehicle_deck) @@ -167,56 +165,29 @@ def update_dependent_options(aircraft_values: AviaryValues(), dependent_options) def initial_guessing(aircraft_values: AviaryValues()): problem_type = aircraft_values.get_val('problem_type') - reserves_option = aircraft_values.get_val(Aircraft.Design.RESERVES_OPTION) - reserves = aircraft_values.get_val( - Aircraft.Design.RESERVES, units='lbm') if initial_guesses['reserves'] == 0 else initial_guesses['reserves'] - if reserves_option == Reserves_Type.Set_Direct: - aircraft_values.set_val(Aircraft.Design.RESERVES, reserves, units='lbm') - if reserves < 10: - raise ValueError( - f'"{Aircraft.Design.RESERVES}" must be greater than 10 lbm.') - elif reserves_option == Reserves_Type.Set_Fraction: - if initial_guesses['reserves'] == 0: + if initial_guesses['reserves'] == 0: + reserves = aircraft_values.get_val(Aircraft.Design.RESERVES, units='lbm') + if reserves == 0: reserves = aircraft_values.get_val( Aircraft.Design.RESERVES_FRACTION, units='unitless') - else: - reserves = initial_guesses['reserves'] - aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, - reserves, units='unitless') - if reserves < -1 or reserves > 0: - raise ValueError( - f'"{Aircraft.Design.RESERVES_FRACTION}" must be in [-1, 0].') else: - # if Aircraft.Design.RESERVES_FRACTION is not set, - # then determine reserves based on initial_guesses['reserves'] - if initial_guesses['reserves'] > 10: - reserves = initial_guesses['reserves'] - reserves_option = Reserves_Type.Set_Direct - aircraft_values.set_val(Aircraft.Design.RESERVES, reserves, units='lbm') - elif initial_guesses['reserves'] < 0: - reserves = initial_guesses['reserves'] - reserves_option = Reserves_Type.Set_Fraction - aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, - reserves, units='unitless') - elif initial_guesses['reserves'] == 0 and reserves > 10: - reserves_option = Reserves_Type.Set_Direct + reserves = initial_guesses['reserves'] + if reserves < 0.0: + raise ValueError('initial_guesses["reserves"] must be greater than 0.') + elif reserves <= 1.0: + aircraft_values.set_val(Aircraft.Design.RESERVES, 0.0, units='lbm') + aircraft_values.set_val( + Aircraft.Design.RESERVES_FRACTION, reserves, units='unitless') + else: aircraft_values.set_val(Aircraft.Design.RESERVES, reserves, units='lbm') - elif initial_guesses['reserves'] == 0 and reserves < 0: - reserves_option = Reserves_Type.Set_Fraction - aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, - reserves, units='unitless') - aircraft_values.set_val(Aircraft.Design.RESERVES_OPTION, - reserves_option, units='unitless') + aircraft_values.set_val( + Aircraft.Design.RESERVES_FRACTION, 0.0, units='unitless') num_pax = aircraft_values.get_val(Aircraft.CrewPayload.NUM_PASSENGERS) - if reserves_option == Reserves_Type.Set_Fraction: - if reserves <= 0: - reserves *= -(num_pax * initial_guesses['fuel_burn_per_passenger_mile'] * - aircraft_values.get_val(Mission.Design.RANGE, units='NM')) - else: - raise ValueError( - f'The case that "{Aircraft.Design.RESERVES_FRACTION}" is between 0 and 1 is not implemented.') + if reserves <= 0: + reserves *= -(num_pax * initial_guesses['fuel_burn_per_passenger_mile'] * + aircraft_values.get_val(Mission.Design.RANGE, units='NM')) initial_guesses['reserves'] = reserves if Mission.Summary.GROSS_MASS in aircraft_values: diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index cb3e9f42f..ac3334802 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -7,7 +7,7 @@ import numpy as np from aviary.utils.develop_metadata import add_meta_data -from aviary.variable_info.enums import Flap_Type, GASP_Engine_Type, Reserves_Type +from aviary.variable_info.enums import Flap_Type, GASP_Engine_Type from aviary.variable_info.variables import Aircraft, Dynamic, Mission # --------------------------- @@ -1212,7 +1212,7 @@ add_meta_data( Aircraft.Design.RESERVES_FRACTION, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.FRESF2', # the real name is INGASP.FRESF + historical_name={"GASP": None, "FLOPS": None, "LEAPS1": None }, @@ -1222,21 +1222,6 @@ default_value=0, ) -add_meta_data( - Aircraft.Design.RESERVES_OPTION, - meta_data=_MetaData, - historical_name={"GASP": 'INGASP.FRESF3', # the real name is INGASP.FRESF - "FLOPS": None, - "LEAPS1": None - }, - option=True, - types=Reserves_Type, - units="unitless", - desc=f'if {Reserves_Type.Set_Direct}, use Aircraft.Design.RESERVES; \ - if {Reserves_Type.Set_Fraction}, use Aircraft.Design.RESERVES_FRACTION', - default_value=Reserves_Type.Set_None, -) - add_meta_data( Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES, meta_data=_MetaData, diff --git a/aviary/variable_info/variables.py b/aviary/variable_info/variables.py index df40a30ad..a8cdad7cb 100644 --- a/aviary/variable_info/variables.py +++ b/aviary/variable_info/variables.py @@ -150,7 +150,6 @@ class Design: PART25_STRUCTURAL_CATEGORY = 'aircraft:design:part25_structural_category' RESERVES = 'aircraft:design:reserves' RESERVES_FRACTION = 'aircraft:design:reserves_fraction' - RESERVES_OPTION = 'aircraft:design:reserves_option' SMOOTH_MASS_DISCONTINUITIES = 'aircraft:design:smooth_mass_discontinuities' STATIC_MARGIN = 'aircraft:design:static_margin' STRUCTURAL_MASS_INCREMENT = 'aircraft:design:structural_mass_increment' From 54cdb4ee537ffa8c50bfa9f0a2a616a78475fb83 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 8 Jan 2024 17:38:14 -0500 Subject: [PATCH 013/188] removed RESERVES_OPTION and set RESERVES_FRACTION to positive --- aviary/models/small_single_aisle/small_single_aisle_GwGm.csv | 1 - 1 file changed, 1 deletion(-) diff --git a/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv b/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv index c444f9a8e..8b6bae066 100644 --- a/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv +++ b/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv @@ -16,7 +16,6 @@ aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless aircraft:design:reserves,0,lbm aircraft:design:reserves_fraction,-0.125,unitless -aircraft:design:reserves_option,2,unitless aircraft:design:static_margin,0.05,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.025,unitless From 24713b66d1f4beb5f154a6ce796f4e743f2e8dd7 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 8 Jan 2024 17:31:11 -0600 Subject: [PATCH 014/188] Converting over tests to not use FLOPS mission method --- aviary/interface/methods_for_level2.py | 82 +++++----------- aviary/interface/test/test_interface_bugs.py | 2 +- aviary/interface/test/test_reserve_support.py | 16 +-- .../test/test_custom_engine_model.py | 97 +++++-------------- .../test/test_external_subsystem_bus.py | 16 ++- 5 files changed, 58 insertions(+), 155 deletions(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 3801359aa..3d867983c 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -18,9 +18,6 @@ from aviary.constants import GRAV_ENGLISH_LBM, RHO_SEA_LEVEL_ENGLISH from aviary.mission.flops_based.phases.build_landing import Landing from aviary.mission.flops_based.phases.build_takeoff import Takeoff -from aviary.mission.flops_based.phases.climb_phase import Climb -from aviary.mission.flops_based.phases.cruise_phase import Cruise -from aviary.mission.flops_based.phases.descent_phase import Descent from aviary.mission.flops_based.phases.simple_energy_phase import EnergyPhase from aviary.mission.gasp_based.ode.groundroll_ode import GroundrollODE from aviary.mission.gasp_based.ode.params import ParamPort @@ -146,6 +143,10 @@ def __init__(self, phase_info, mission_method, mass_method, analysis_scheme=Anal self.phase_info = phase_info self.traj = None + if mission_method == "FLOPS": + raise NotImplementedError( + "The FLOPS mission method is no longer supported in Aviary. Please use the `simple` mission method. This might require updating your `phase_info` object defintion.") + self.mission_method = mission_method self.mass_method = mass_method self.analysis_scheme = analysis_scheme @@ -361,7 +362,7 @@ def add_pre_mission_systems(self): self._add_gasp_takeoff_systems() # Check for 'FLOPS' mission method - elif self.mission_method == "FLOPS" or self.mission_method == "simple": + elif self.mission_method == "simple": self._add_flops_takeoff_systems() def _add_flops_takeoff_systems(self): @@ -651,30 +652,9 @@ def _get_flops_phase(self, phase_name, phase_idx): default_mission_subsystems = [ subsystems['aerodynamics'], subsystems['propulsion']] - if self.mission_method == "FLOPS" or self.mission_method == "simple": - if self.mission_method == "simple": - climb_builder = EnergyPhase - cruise_builder = EnergyPhase - descent_builder = EnergyPhase - else: - climb_builder = Climb - cruise_builder = Cruise - descent_builder = Descent - - if phase_name == 'climb': - phase_object = climb_builder.from_phase_info( - phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data) - - elif phase_name == 'cruise': - phase_object = cruise_builder.from_phase_info( - phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data) - - elif phase_name == 'descent': - phase_object = descent_builder.from_phase_info( - phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data) - else: - phase_object = EnergyPhase.from_phase_info( - phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data) + if self.mission_method == "simple": + phase_object = EnergyPhase.from_phase_info( + phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data) phase = phase_object.build_phase(aviary_options=self.aviary_inputs) @@ -1009,7 +989,7 @@ def add_subsystem_timeseries_outputs(phase, phase_name): if phase_name == 'ascent': self._add_groundroll_eq_constraint(phase) - elif self.mission_method == "FLOPS" or self.mission_method == "simple": + elif self.mission_method == "simple": for phase_idx, phase_name in enumerate(phases): phase = traj.add_phase( phase_name, self._get_flops_phase(phase_name, phase_idx)) @@ -1131,7 +1111,7 @@ def add_post_mission_systems(self, include_landing=True): """ if include_landing and self.post_mission_info['include_landing']: - if self.mission_method == "FLOPS" or self.mission_method == "simple": + if self.mission_method == "simple": self._add_flops_landing_systems() elif self.mission_method == "GASP": self._add_gasp_landing_systems() @@ -1150,7 +1130,7 @@ def add_post_mission_systems(self, include_landing=True): self.post_mission.add_subsystem(external_subsystem.name, subsystem_postmission) - if self.mission_method == "FLOPS" or self.mission_method == "simple": + if self.mission_method == "simple": phases = list(self.phase_info.keys()) ecomp = om.ExecComp('fuel_burned = initial_mass - mass_final', initial_mass={'units': 'lbm'}, @@ -1325,13 +1305,6 @@ def add_linkage_constraint(self, phase_a, phase_b, var_b): self._link_phases_helper_with_options( phases, 'optimize_mach', Dynamic.Mission.MACH) - elif self.mission_method == "FLOPS": - self.traj.link_phases( - phases, ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=False, ref=1.e4) - self.traj.link_phases( - phases, [Dynamic.Mission.VELOCITY], connected=False, ref=250.) - elif self.mission_method == "GASP": if self.analysis_scheme is AnalysisScheme.COLLOCATION: self.traj.link_phases(["groundroll", "rotation", "ascent"], [ @@ -1584,7 +1557,7 @@ def add_design_variables(self): for dv_name, dv_dict in dv_dict.items(): self.model.add_design_var(dv_name, **dv_dict) - if self.mission_method == "FLOPS" or self.mission_method == "simple": + if self.mission_method == "simple": optimize_mass = self.pre_mission_info.get('optimize_mass') if optimize_mass: self.model.add_design_var(Mission.Design.GROSS_MASS, units='lbm', @@ -1707,7 +1680,7 @@ def add_objective(self, objective_type=None, ref=None): self.model.add_objective(Mission.Objectives.FUEL, ref=ref) # If 'mission_method' is 'FLOPS', add a 'fuel_burned' objective - elif self.mission_method == "FLOPS" or self.mission_method == "simple": + elif self.mission_method == "simple": ref = ref if ref is not None else default_ref_values.get("fuel_burned", 1) self.model.add_objective("fuel_burned", ref=ref) @@ -2347,30 +2320,19 @@ def _add_flops_landing_systems(self): 'traj.climb.initial_states:mass') self.model.connect(Mission.Takeoff.GROUND_DISTANCE, 'traj.climb.initial_states:range') - if self.mission_method == "FLOPS": - self.model.connect(Mission.Takeoff.FINAL_VELOCITY, - 'traj.climb.initial_states:velocity') - self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, - 'traj.climb.initial_states:altitude') - else: - pass - # TODO: connect this correctly - # mass is the most important to connect but these others should - # be connected as well - # self.model.connect(Mission.Takeoff.FINAL_VELOCITY, - # 'traj.climb.initial_states:mach') - # self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, - # 'traj.climb.controls:altitude') + # TODO: connect this correctly + # mass is the most important to connect but these others should + # be connected as well + # self.model.connect(Mission.Takeoff.FINAL_VELOCITY, + # 'traj.climb.initial_states:mach') + # self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, + # 'traj.climb.controls:altitude') self.model.connect('traj.descent.states:mass', Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1]) # TODO: approach velocity should likely be connected - if self.mission_method == "FLOPS": - self.model.connect('traj.descent.states:altitude', Mission.Landing.INITIAL_ALTITUDE, - src_indices=[-1]) - else: - self.model.connect('traj.descent.control_values:altitude', Mission.Landing.INITIAL_ALTITUDE, - src_indices=[0]) + self.model.connect('traj.descent.control_values:altitude', Mission.Landing.INITIAL_ALTITUDE, + src_indices=[0]) def _add_gasp_landing_systems(self): self.model.add_subsystem( diff --git a/aviary/interface/test/test_interface_bugs.py b/aviary/interface/test/test_interface_bugs.py index cf60b67f8..44089da8b 100644 --- a/aviary/interface/test/test_interface_bugs.py +++ b/aviary/interface/test/test_interface_bugs.py @@ -67,7 +67,7 @@ def test_post_mission_promotion(self): WingWeightBuilder(name="wing_external") ] - prob = AviaryProblem(phase_info, mission_method="FLOPS", mass_method="FLOPS") + prob = AviaryProblem(phase_info, mission_method="simple", mass_method="FLOPS") csv_path = pkg_resources.resource_filename( "aviary", "models/test_aircraft/aircraft_for_bench_GwFm.csv") diff --git a/aviary/interface/test/test_reserve_support.py b/aviary/interface/test/test_reserve_support.py index b0b3982d8..5419efd15 100644 --- a/aviary/interface/test/test_reserve_support.py +++ b/aviary/interface/test/test_reserve_support.py @@ -1,12 +1,11 @@ from copy import deepcopy -import pkg_resources import unittest from openmdao.utils.assert_utils import assert_near_equal from openmdao.utils.testing_utils import use_tempdirs from aviary.interface.methods_for_level2 import AviaryProblem -from aviary.interface.default_phase_info.flops import phase_info as ph_in_flops +from aviary.interface.default_phase_info.simple import phase_info as ph_in_flops from aviary.interface.default_phase_info.gasp import phase_info as ph_in_gasp from aviary.variable_info.variables import Aircraft, Mission @@ -17,12 +16,9 @@ class StaticGroupTest(unittest.TestCase): def test_post_mission_promotion(self): phase_info = deepcopy(ph_in_flops) - prob = AviaryProblem(phase_info, mission_method="FLOPS", mass_method="FLOPS") + prob = AviaryProblem(phase_info, mission_method="simple", mass_method="FLOPS") - csv_path = pkg_resources.resource_filename( - "aviary", "models/test_aircraft/aircraft_for_bench_GwFm.csv") - - prob.load_inputs(csv_path) + prob.load_inputs("models/test_aircraft/aircraft_for_bench_FwFm.csv") prob.check_inputs() # TODO: This needs to be converted into a reserve and a scaler so that it can @@ -40,6 +36,7 @@ def test_post_mission_promotion(self): prob.add_objective(objective_type="mass", ref=-1e5) prob.setup() + prob.set_initial_guesses() prob.run_model() @@ -53,10 +50,7 @@ def test_gasp_relative_reserve(self): prob = AviaryProblem(phase_info, mission_method="GASP", mass_method="GASP") - csv_path = pkg_resources.resource_filename( - "aviary", "models/small_single_aisle/small_single_aisle_GwGm.csv") - - prob.load_inputs(csv_path) + prob.load_inputs("models/small_single_aisle/small_single_aisle_GwGm.csv") prob.check_inputs() prob.aviary_inputs.set_val(Mission.Summary.GROSS_MASS, 140000.0, units='lbm') diff --git a/aviary/subsystems/propulsion/test/test_custom_engine_model.py b/aviary/subsystems/propulsion/test/test_custom_engine_model.py index 0619d5ff3..40fee525e 100644 --- a/aviary/subsystems/propulsion/test/test_custom_engine_model.py +++ b/aviary/subsystems/propulsion/test/test_custom_engine_model.py @@ -1,16 +1,12 @@ import unittest -import openmdao import dymos as dm import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal -from packaging import version from aviary.subsystems.propulsion.engine_model import EngineModel from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic -import dymos as dm -import unittest from openmdao.utils.assert_utils import assert_near_equal from openmdao.utils.testing_utils import use_tempdirs @@ -126,13 +122,8 @@ def get_initial_guesses(self): @use_tempdirs class CustomEngineTest(unittest.TestCase): def test_custom_engine(self): - - import pkg_resources - from aviary.interface.methods_for_level2 import AviaryProblem - aero_data = "subsystems/aerodynamics/gasp_based/data/large_single_aisle_1_aero_free.txt" - phase_info = { 'pre_mission': { 'include_takeoff': False, @@ -140,38 +131,28 @@ def test_custom_engine(self): 'optimize_mass': True, }, 'cruise': { - 'subsystem_options': { - 'core_aerodynamics': {'method': 'solved_alpha', 'aero_data': aero_data, 'training_data': False} + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + "optimize_mach": False, + "optimize_altitude": False, + "polynomial_control_order": 1, + "num_segments": 2, + "order": 3, + "solve_for_range": False, + "initial_mach": (0.72, "unitless"), + "final_mach": (0.72, "unitless"), + "mach_bounds": ((0.7, 0.74), "unitless"), + "initial_altitude": (35000.0, "ft"), + "final_altitude": (35000.0, "ft"), + "altitude_bounds": ((23000.0, 38000.0), "ft"), + "throttle_enforcement": "boundary_constraint", + "fix_initial": False, + "constrain_final": False, + "fix_duration": False, + "initial_bounds": ((0.0, 0.0), "min"), + "duration_bounds": ((10., 30.), "min"), }, - 'external_subsystems': [], - 'user_options': { - 'fix_initial': False, - 'fix_final': False, - 'fix_duration': False, - 'num_segments': 2, - 'order': 3, - 'initial_ref': (1., 's'), - 'initial_bounds': ((0., 0.), 's'), - 'duration_ref': (21.e3, 's'), - 'duration_bounds': ((1.e3, 10.e3), 's'), - 'min_altitude': (10.668e3, 'm'), - 'max_altitude': (10.668e3, 'm'), - 'min_mach': 0.8, - 'max_mach': 0.8, - 'required_available_climb_rate': (1.524, 'm/s'), - 'input_initial': False, - 'mass_f_cruise': (1.e4, 'lbm'), - 'range_f_cruise': (1.e6, 'm'), - }, - 'initial_guesses': { - 'times': ([0., 30.], 'min'), - 'altitude': ([35.e3, 35.e3], 'ft'), - 'velocity': ([455.49, 455.49], 'kn'), - 'mass': ([130.e3, 128.e3], 'lbm'), - 'range': ([0., 300.], 'nmi'), - 'velocity_rate': ([0., 0.], 'm/s**2'), - 'throttle': ([0.6, 0.6], 'unitless'), - } + "initial_guesses": {"times": ([0, 30], "min")}, }, 'post_mission': { 'include_landing': False, @@ -179,15 +160,13 @@ def test_custom_engine(self): } } - csv_path = pkg_resources.resource_filename( - "aviary", "models/test_aircraft/aircraft_for_bench_GwFm.csv") - - prob = AviaryProblem(phase_info, mission_method="FLOPS", + prob = AviaryProblem(phase_info, mission_method="simple", mass_method="FLOPS", reports=False) # Load aircraft and options data from user # Allow for user overrides here - prob.load_inputs(csv_path, engine_builder=SimpleTestEngine()) + prob.load_inputs("models/test_aircraft/aircraft_for_bench_GwFm.csv", + engine_builder=SimpleTestEngine()) # Have checks for clashing user inputs # Raise warnings or errors depending on how clashing the issues are @@ -226,34 +205,6 @@ def test_custom_engine(self): assert_near_equal(float(prob.get_val('traj.cruise.rhs_all.y')), 4., tol) - prob_vars = prob.list_problem_vars( - print_arrays=True, driver_scaling=False, out_stream=None) - - design_vars_dict = dict(prob_vars['design_vars']) - - # List of all expected variable names in design_vars - expected_var_names = [ - 'traj.phases.cruise.indep_states.states:altitude', - 'traj.phases.cruise.indep_states.states:velocity', - 'traj.phases.cruise.indep_states.states:mass', - 'traj.phases.cruise.indep_states.states:range', - ] - - # Check that all expected variable names are present in design_vars - for var_name in expected_var_names: - self.assertIn(var_name, design_vars_dict) - - # Check values - assert_near_equal(design_vars_dict['traj.phases.cruise.indep_states.states:altitude']['val'], [ - 10668.] * 7, tolerance=tol) - assert_near_equal(design_vars_dict['traj.phases.cruise.indep_states.states:velocity']['val'], [ - 234.3243] * 7, tolerance=tol) - # print the mass and range - assert_near_equal(design_vars_dict['traj.phases.cruise.indep_states.states:mass']['val'], [ - 58967.0081, 58805.95966377, 58583.74569223, 58513.41573, 58352.36729377, 58130.15332223, 58059.82336], tolerance=tol) - assert_near_equal(design_vars_dict['traj.phases.cruise.indep_states.states:range']['val'], [ - 0., 98633.17494548, 234726.82505452, 277800., 376433.17494548, 512526.82505452, 555600.], tolerance=tol) - if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/test/test_external_subsystem_bus.py b/aviary/subsystems/test/test_external_subsystem_bus.py index f8257a1b5..a88f1067b 100644 --- a/aviary/subsystems/test/test_external_subsystem_bus.py +++ b/aviary/subsystems/test/test_external_subsystem_bus.py @@ -1,8 +1,7 @@ """ - Test external subsystem bus API. +Test external subsystem bus API. """ from copy import deepcopy -import pkg_resources import unittest import numpy as np @@ -10,8 +9,7 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal -import aviary.api as av -from aviary.interface.default_phase_info.flops import phase_info as ph_in +from aviary.interface.default_phase_info.simple import phase_info as ph_in from aviary.interface.methods_for_level2 import AviaryProblem from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase @@ -23,7 +21,7 @@ def setup(self): self.add_output('for_cruise', np.ones((2, 1)), units='ft') self.add_output('for_descent', np.ones((2, 1)), units='ft') - def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): + def compute(self, inputs, outputs): outputs['for_climb'] = np.array([[3.1], [1.7]]) outputs['for_cruise'] = np.array([[1.2], [4.1]]) outputs['for_descent'] = np.array([[3.], [8.]]) @@ -39,7 +37,7 @@ def setup(self): self.add_input('xx', shape=shape, units='ft') self.add_output('yy', shape=shape, units='ft') - def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): + def compute(self, inputs, outputs): outputs['yy'] = 2.0 * inputs['xx'] @@ -90,11 +88,9 @@ def test_external_subsystem_bus(self): phase_info['cruise']['external_subsystems'] = [CustomBuilder(name='test')] phase_info['descent']['external_subsystems'] = [CustomBuilder(name='test')] - prob = AviaryProblem(phase_info, mission_method="FLOPS", mass_method="FLOPS") + prob = AviaryProblem(phase_info, mission_method="simple", mass_method="FLOPS") - csv_path = pkg_resources.resource_filename( - "aviary", "models/test_aircraft/aircraft_for_bench_FwFm.csv") - prob.load_inputs(csv_path) + prob.load_inputs("models/test_aircraft/aircraft_for_bench_FwFm.csv") prob.check_inputs() prob.add_pre_mission_systems() From c91210b2ff133c12280e6fde285310363bf22e1c Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 8 Jan 2024 17:39:19 -0600 Subject: [PATCH 015/188] updating more tests --- .../test/test_solved_aero_group.py | 10 +- .../test_subsystems_within_a_mission.py | 92 ++++++++----------- 2 files changed, 40 insertions(+), 62 deletions(-) diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py index 59c5dc0b7..117d5854e 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py @@ -14,7 +14,7 @@ from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase from aviary.utils.csv_data_file import read_data_file from aviary.utils.named_values import NamedValues -from aviary.interface.default_phase_info.flops import phase_info +from aviary.interface.default_phase_info.simple import phase_info from aviary.variable_info.variables import Aircraft from copy import deepcopy @@ -47,7 +47,7 @@ class TestSolvedAero(unittest.TestCase): def test_solved_aero_pass_polar(self): # Test that passing training data provides the same results prob = AviaryProblem( - phase_info, mission_method="FLOPS", mass_method="FLOPS") + phase_info, mission_method="simple", mass_method="FLOPS") csv_path = pkg_resources.resource_filename( "aviary", "subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv") @@ -88,7 +88,7 @@ def test_solved_aero_pass_polar(self): ph_in['cruise']['subsystem_options'] = {'core_aerodynamics': subsystem_options} - prob = AviaryProblem(ph_in, mission_method="FLOPS", mass_method="FLOPS") + prob = AviaryProblem(ph_in, mission_method="simple", mass_method="FLOPS") prob.load_inputs(csv_path) @@ -203,6 +203,4 @@ def build_pre_mission(self, aviary_inputs): if __name__ == "__main__": - # unittest.main() - test = TestSolvedAero() - test.test_solved_aero_pass_polar() + unittest.main() diff --git a/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py b/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py index 795424041..1535269e4 100644 --- a/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py +++ b/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py @@ -1,7 +1,6 @@ import numpy as np import unittest -import pkg_resources from numpy.testing import assert_almost_equal from openmdao.utils.testing_utils import use_tempdirs @@ -15,48 +14,36 @@ @use_tempdirs class TestSubsystemsMission(unittest.TestCase): def setUp(self): - polar_file = "subsystems/aerodynamics/gasp_based/data/large_single_aisle_1_aero_free.txt" - aero_data = pkg_resources.resource_filename("aviary", polar_file) - self.phase_info = { 'pre_mission': { 'include_takeoff': False, 'external_subsystems': [ArrayGuessSubsystemBuilder(), AdditionalArrayGuessSubsystemBuilder()], - 'optimize_mass': False, + 'optimize_mass': True, }, 'cruise': { - 'subsystem_options': { - 'core_aerodynamics': {'method': 'solved_alpha', 'aero_data': aero_data, 'training_data': False} - }, + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, 'external_subsystems': [ArrayGuessSubsystemBuilder(), AdditionalArrayGuessSubsystemBuilder()], - 'user_options': { - 'fix_initial': True, - 'fix_final': False, - 'fix_duration': False, - 'num_segments': 1, - 'order': 5, - 'initial_ref': (1., 's'), - 'initial_bounds': ((0., 0.), 's'), - 'duration_ref': (21.e3, 's'), - 'duration_bounds': ((10.e3, 20.e3), 's'), - 'min_altitude': (10.668e3, 'm'), - 'max_altitude': (10.668e3, 'm'), - 'min_mach': 0.8, - 'max_mach': 0.8, - 'required_available_climb_rate': (1.524, 'm/s'), - 'input_initial': False, - 'mass_f_cruise': (1.e4, 'lbm'), - 'range_f_cruise': (1.e6, 'm'), + "user_options": { + "optimize_mach": False, + "optimize_altitude": False, + "polynomial_control_order": 1, + "num_segments": 2, + "order": 3, + "solve_for_range": False, + "initial_mach": (0.72, "unitless"), + "final_mach": (0.72, "unitless"), + "mach_bounds": ((0.7, 0.74), "unitless"), + "initial_altitude": (35000.0, "ft"), + "final_altitude": (35000.0, "ft"), + "altitude_bounds": ((23000.0, 38000.0), "ft"), + "throttle_enforcement": "boundary_constraint", + "fix_initial": True, + "constrain_final": False, + "fix_duration": False, + "initial_bounds": ((0.0, 0.0), "min"), + "duration_bounds": ((10., 30.), "min"), }, - 'initial_guesses': { - 'times': ([0., 15000.], 's'), - 'altitude': ([35.e3, 35.e3], 'ft'), - 'velocity': ([455.49, 455.49], 'kn'), - 'mass': ([130.e3, 120.e3], 'lbm'), - 'range': ([0., 3000.], 'NM'), - 'velocity_rate': ([0., 0.], 'm/s**2'), - 'throttle': ([0.6, 0.6], 'unitless'), - } + "initial_guesses": {"times": ([0, 30], "min")}, }, 'post_mission': { 'include_landing': False, @@ -68,12 +55,9 @@ def test_subsystems_in_a_mission(self): phase_info = self.phase_info.copy() prob = AviaryProblem( - phase_info, mission_method="FLOPS", mass_method="FLOPS") + phase_info, mission_method="simple", mass_method="FLOPS") - csv_path = pkg_resources.resource_filename( - "aviary", "models/test_aircraft/aircraft_for_bench_GwFm.csv") - - prob.load_inputs(csv_path) + prob.load_inputs("models/test_aircraft/aircraft_for_bench_FwFm.csv") # Have checks for clashing user inputs # Raise warnings or errors depending on how clashing the issues are @@ -102,29 +86,27 @@ def test_subsystems_in_a_mission(self): # add an assert to see if the initial guesses are correct for Mission.Dummy.VARIABLE assert_almost_equal(prob[f'traj.phases.cruise.states:{Mission.Dummy.VARIABLE}'], [[10.], - [22.57838779], - [47.47686109], - [75.08412877], - [94.86062235], - [100.],]) + [25.97729616], + [48.02270384], + [55.], + [70.97729616], + [93.02270384], + [100.]]) prob.run_aviary_problem() # add an assert to see if MoreMission.Dummy.TIMESERIES_VAR was correctly added to the dymos problem assert_almost_equal(prob[f'traj.phases.cruise.timeseries.{MoreMission.Dummy.TIMESERIES_VAR}'], np.array( - [[0.5, 0.5, 0.5, 0.5, 0.5, 0.5]]).T) + [[0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]]).T) def test_bad_initial_guess_key(self): phase_info = self.phase_info.copy() phase_info['cruise']['initial_guesses']['bad_guess_name'] = ([10., 100.], 'm') - prob = AviaryProblem(phase_info, mission_method="FLOPS", + prob = AviaryProblem(phase_info, mission_method="simple", mass_method="FLOPS", reports=False) - csv_path = pkg_resources.resource_filename( - "aviary", "models/test_aircraft/aircraft_for_bench_GwFm.csv") - - prob.load_inputs(csv_path) + prob.load_inputs("models/test_aircraft/aircraft_for_bench_FwFm.csv") # Have checks for clashing user inputs # Raise warnings or errors depending on how clashing the issues are @@ -134,12 +116,10 @@ def test_bad_initial_guess_key(self): with self.assertRaises(TypeError) as context: prob.add_phases() + print(str(context.exception)) self.assertTrue( - 'Cruise: cruise: unsupported initial guess: bad_guess_name' in str(context.exception)) + 'EnergyPhase: cruise: unsupported initial guess: bad_guess_name' in str(context.exception)) if __name__ == "__main__": - # unittest.main() - test = TestSubsystemsMission() - test.setUp() - test.test_subsystems_in_a_mission() + unittest.main() From 0005f91cbfd35fb8dfafc1d07ada9d908f9810f1 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 8 Jan 2024 17:41:13 -0600 Subject: [PATCH 016/188] All tests pass, benchmarks next --- .../benchmark_tests/test_0_iters.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index 4656a3be2..a016efa4c 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -1,17 +1,12 @@ -import os import unittest -import pkg_resources import dymos from openmdao.utils.testing_utils import require_pyoptsparse, use_tempdirs from packaging import version -from aviary.api import Mission, Dynamic from aviary.interface.methods_for_level2 import AviaryProblem from aviary.interface.default_phase_info.gasp import phase_info as gasp_phase_info -from aviary.interface.default_phase_info.flops import phase_info as flops_phase_info -from aviary.interface.default_phase_info.flops import phase_info as ph_in +from aviary.interface.default_phase_info.simple import phase_info as flops_phase_info from aviary.interface.default_phase_info.solved import phase_info as solved_phase_info -from copy import deepcopy class BaseProblemPhaseTestCase(unittest.TestCase): @@ -50,7 +45,7 @@ class FLOPSZeroItersTestCase(BaseProblemPhaseTestCase): @require_pyoptsparse(optimizer="IPOPT") def test_flops_zero_iters(self): - self.build_and_run_problem(flops_phase_info, "FLOPS", + self.build_and_run_problem(flops_phase_info, "simple", "FLOPS", 'models/test_aircraft/aircraft_for_bench_FwFm.csv') @@ -67,6 +62,6 @@ def test_zero_iters_solved(self): if __name__ == "__main__": - # unittest.main() - test = FLOPSZeroItersTestCase() - test.test_flops_zero_iters() + unittest.main() + # test = FLOPSZeroItersTestCase() + # test.test_flops_zero_iters() From ac6087d25a80d93242ed5e85a951907ebc3c8ec4 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 8 Jan 2024 19:23:47 -0500 Subject: [PATCH 017/188] rename Aircraft.Design.RESERVES to Aircraft.Design.FIXED_RESERVES_FUEL and remove Aircraft.Design.IJEFF --- .../getting_started/input_csv_phase_info.md | 4 +-- aviary/interface/methods_for_level2.py | 5 +-- aviary/interface/test/test_reserve_support.py | 3 +- .../large_single_aisle_1_GwGm.csv | 2 +- .../small_single_aisle_GwGm.csv | 4 +-- .../test_aircraft/aircraft_for_bench_FwFm.csv | 2 +- .../test_aircraft/aircraft_for_bench_FwGm.csv | 2 +- .../test_aircraft/aircraft_for_bench_GwFm.csv | 2 +- .../test_aircraft/aircraft_for_bench_GwGm.csv | 2 +- ...converter_configuration_test_data_GwGm.csv | 4 +-- aviary/utils/Fortran_to_Aviary.py | 6 ++-- aviary/utils/process_input_decks.py | 11 ++++--- aviary/variable_info/variable_meta_data.py | 32 ++++++------------- aviary/variable_info/variables.py | 3 +- 14 files changed, 37 insertions(+), 45 deletions(-) diff --git a/aviary/docs/getting_started/input_csv_phase_info.md b/aviary/docs/getting_started/input_csv_phase_info.md index a1b309d8a..6f3781fd3 100644 --- a/aviary/docs/getting_started/input_csv_phase_info.md +++ b/aviary/docs/getting_started/input_csv_phase_info.md @@ -19,11 +19,11 @@ This section is under development. - reserves: 0 The initial guess of `reserves` is used to define the reserve fuel. Initially, its value can be anything larger than or equal to 0. There are two variables to control the reserve fuel in the model file (`.csv`): -- `Aircraft.Design.RESERVES`: the required fuel reserves: directly in lbm, +- `Aircraft.Design.FIXED_RESERVES_FUEL`: the required fuel reserves: directly in lbm, - `Aircraft.Design.RESERVES_FRACTION`: the required fuel reserves: given as a proportion of mission fuel, If the value of initial guess of `reserves` is not 0 and is within the allowed range, the initial guess of reserve fuel is determined by the parameter `reserves`: -- if `reserves > 1.0`, we set `Aircraft.Design.RESERVES = reserves`, +- if `reserves > 1.0`, we set `Aircraft.Design.FIXED_RESERVES_FUEL = reserves`, - if `0.0 <= reserves <= 1.0`, we set `Aircraft.Design.RESERVES_FRACTION = reserves`. The initial guess of `reserves` is always converted to the actual design reserves (instead of reserve factor) and is used to update the initial guesses of `fuel_burn_per_passenger_mile` and `cruise_mass_final`. diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 68e5ff51c..3667ae4e9 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -2436,7 +2436,8 @@ def _add_gasp_landing_systems(self): ) def _add_fuel_reserve_component(self, reserves_name=Mission.Design.RESERVE_FUEL): - reserves_val = self.aviary_inputs.get_val(Aircraft.Design.RESERVES, units='lbm') + reserves_val = self.aviary_inputs.get_val( + Aircraft.Design.FIXED_RESERVES_FUEL, units='lbm') reserves_fac = self.aviary_inputs.get_val( Aircraft.Design.RESERVES_FRACTION, units='unitless') if reserves_val > 0.0: @@ -2448,7 +2449,7 @@ def _add_fuel_reserve_component(self, reserves_name=Mission.Design.RESERVE_FUEL) ), promotes_outputs=[("reserve_fuel", reserves_name)], ) - else: + elif reserves_fac >= 0 and reserves_fac <= 1: self.model.add_subsystem( "reserves_calc", om.ExecComp( diff --git a/aviary/interface/test/test_reserve_support.py b/aviary/interface/test/test_reserve_support.py index 8109be9e5..860ac397e 100644 --- a/aviary/interface/test/test_reserve_support.py +++ b/aviary/interface/test/test_reserve_support.py @@ -25,7 +25,8 @@ def test_post_mission_promotion(self): prob.load_inputs(csv_path) prob.check_inputs() - prob.aviary_inputs.set_val(Aircraft.Design.RESERVES, 10000.0, units='lbm') + prob.aviary_inputs.set_val( + Aircraft.Design.FIXED_RESERVES_FUEL, 10000.0, units='lbm') prob.add_pre_mission_systems() prob.add_phases() diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv index 0bf88a607..b9b9912fe 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv @@ -12,9 +12,9 @@ aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,16.5,unitless aircraft:design:drag_increment,0.00175,unitless aircraft:design:equipment_mass_coefficients,928,0.0736,0.112,0.14,1959,1.65,551,11192,5,3,50,7.6,12,unitless +aircraft:design:fixed_reserves_fuel,4998,lbm aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves,4998,lbm aircraft:design:reserves_fraction,0,unitless aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm diff --git a/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv b/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv index 8b6bae066..f47ed1bfb 100644 --- a/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv +++ b/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv @@ -12,10 +12,10 @@ aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,16.5,unitless aircraft:design:drag_increment,0.0018,unitless aircraft:design:equipment_mass_coefficients,778,0.06,0.112,0.14,1349,1.65,397,9071,7.6,3,50,6,12,unitless +aircraft:design:fixed_reserves_fuel,0,lbm aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves,0,lbm -aircraft:design:reserves_fraction,-0.125,unitless +aircraft:design:reserves_fraction,0.125,unitless aircraft:design:static_margin,0.05,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.025,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv index c415c912b..01633dc49 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv @@ -25,7 +25,7 @@ aircraft:design:base_area,0.0,ft**2 aircraft:design:empty_mass_margin_scaler,0.0,unitless aircraft:design:lift_dependent_drag_coeff_factor,0.909839381134961,unitless aircraft:design:touchdown_mass,152800.0,lbm -aircraft:design:reserves,3000.,lbm +aircraft:design:fixed_reserves_fuel,3000.,lbm aircraft:design:subsonic_drag_coeff_factor,1.0,unitless aircraft:design:supersonic_drag_coeff_factor,1.0,unitless aircraft:design:use_alt_mass,False,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv index 2224b8ba5..3a4f5348e 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv @@ -12,7 +12,7 @@ aircraft:design:drag_increment,0.00175,unitless aircraft:design:equipment_mass_coefficients,928,0.0736,0.112,0.14,1959,1.65,551,11192,5,3,50,7.6,12,unitless aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves,3000.,lbm +aircraft:design:fixed_reserves_fuel,3000.,lbm aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.025,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv index 9688bdf8d..01f9be0cc 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv @@ -39,7 +39,7 @@ aircraft:design:lift_dependent_drag_coeff_factor,0.909839381134961,unitless aircraft:design:touchdown_mass,152800.0,lbm aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves,5000.,lbm +aircraft:design:fixed_reserves_fuel,5000.,lbm aircraft:design:smooth_mass_discontinuities,False,unitless aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv index de310d32c..c6c89e6f3 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv @@ -13,7 +13,7 @@ aircraft:design:drag_increment,0.00175,unitless aircraft:design:equipment_mass_coefficients,928,0.0736,0.112,0.14,1959,1.65,551,11192,5,3,50,7.6,12,unitless aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves,4998,lbm +aircraft:design:fixed_reserves_fuel,4998,lbm aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless diff --git a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv index a9e6e1ce0..ee9f695ca 100644 --- a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv +++ b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv @@ -12,10 +12,10 @@ aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,30,unitless aircraft:design:drag_increment,0.0014,unitless aircraft:design:equipment_mass_coefficients,1014,0.0736,0.085,0.105,1504,1.65,126,9114,5,3,0,10,12,unitless +aircraft:design:fixed_reserves_fuel,0,lbm aircraft:design:max_structural_speed,440,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves,0,lbm -aircraft:design:reserves_fraction,-0.15,unitless +aircraft:design:reserves_fraction,0.15,unitless aircraft:design:static_margin,0.05,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless diff --git a/aviary/utils/Fortran_to_Aviary.py b/aviary/utils/Fortran_to_Aviary.py index e46b1f27d..ce0f09aae 100644 --- a/aviary/utils/Fortran_to_Aviary.py +++ b/aviary/utils/Fortran_to_Aviary.py @@ -434,10 +434,10 @@ def update_gasp_options(vehicle_data): input_values.set_val(Aircraft.Wing.FLAP_DRAG_INCREMENT_OPTIMUM, [[.12, .23, .13, .23, .23, .1, .15][flap_ind]]) - res = input_values.get_val(Aircraft.Design.RESERVES, units='lbm')[0] + res = input_values.get_val(Aircraft.Design.FIXED_RESERVES_FUEL, units='lbm')[0] if res <= 1.0: - input_values.set_val(Aircraft.Design.RESERVES, [0], units='lbm') - input_values.set_val(Aircraft.Design.RESERVES_FRACTION, [-res], units='unitless') + input_values.set_val(Aircraft.Design.FIXED_RESERVES_FUEL, [0], units='lbm') + input_values.set_val(Aircraft.Design.RESERVES_FRACTION, [res], units='unitless') else: input_values.set_val(Aircraft.Design.RESERVES_FRACTION, [0], units='unitless') diff --git a/aviary/utils/process_input_decks.py b/aviary/utils/process_input_decks.py index 49ea338a5..7f2698895 100644 --- a/aviary/utils/process_input_decks.py +++ b/aviary/utils/process_input_decks.py @@ -45,7 +45,7 @@ def create_vehicle(vehicle_deck=''): aircraft_values.set_val('mass_defect', val=10000, units='lbm') aircraft_values.set_val('problem_type', val=ProblemType.SIZING) aircraft_values.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False) - aircraft_values.set_val(Aircraft.Design.RESERVES, val=4998, units='lbm') + aircraft_values.set_val(Aircraft.Design.FIXED_RESERVES_FUEL, val=4998, units='lbm') aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, val=0, units='unitless') vehicle_deck = get_path(vehicle_deck) @@ -166,7 +166,8 @@ def update_dependent_options(aircraft_values: AviaryValues(), dependent_options) def initial_guessing(aircraft_values: AviaryValues()): problem_type = aircraft_values.get_val('problem_type') if initial_guesses['reserves'] == 0: - reserves = aircraft_values.get_val(Aircraft.Design.RESERVES, units='lbm') + reserves = aircraft_values.get_val( + Aircraft.Design.FIXED_RESERVES_FUEL, units='lbm') if reserves == 0: reserves = aircraft_values.get_val( Aircraft.Design.RESERVES_FRACTION, units='unitless') @@ -175,11 +176,13 @@ def initial_guessing(aircraft_values: AviaryValues()): if reserves < 0.0: raise ValueError('initial_guesses["reserves"] must be greater than 0.') elif reserves <= 1.0: - aircraft_values.set_val(Aircraft.Design.RESERVES, 0.0, units='lbm') + aircraft_values.set_val( + Aircraft.Design.FIXED_RESERVES_FUEL, 0.0, units='lbm') aircraft_values.set_val( Aircraft.Design.RESERVES_FRACTION, reserves, units='unitless') else: - aircraft_values.set_val(Aircraft.Design.RESERVES, reserves, units='lbm') + aircraft_values.set_val( + Aircraft.Design.FIXED_RESERVES_FUEL, reserves, units='lbm') aircraft_values.set_val( Aircraft.Design.RESERVES_FRACTION, 0.0, units='unitless') diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index ac3334802..0c949e1c2 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -1049,26 +1049,27 @@ ) add_meta_data( - Aircraft.Design.FIXED_USEFUL_LOAD, + Aircraft.Design.FIXED_RESERVES_FUEL, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WFUL', + historical_name={"GASP": 'INGASP.FRESF', "FLOPS": None, "LEAPS1": None }, - units='lbm', - desc='total mass of fixed useful load: crew, service items, trapped oil, etc', + option=True, + units="lbm", + desc='required fuel reserves: directly in lbm', + default_value=0, ) add_meta_data( - Aircraft.Design.IJEFF, + Aircraft.Design.FIXED_USEFUL_LOAD, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.ijeff', + historical_name={"GASP": 'INGASP.WFUL', "FLOPS": None, "LEAPS1": None }, - desc="A flag used by Jeff V. Bowles to debug GASP code during his 53 years supporting the development of GASP. \ - This flag is planted here to thank him for his hard work and dedication, Aviary wouldn't be what it is today \ - without his help.", + units='lbm', + desc='total mass of fixed useful load: crew, service items, trapped oil, etc', ) add_meta_data( @@ -1196,19 +1197,6 @@ desc='part 25 structural category', ) -add_meta_data( - Aircraft.Design.RESERVES, - meta_data=_MetaData, - historical_name={"GASP": 'INGASP.FRESF', - "FLOPS": None, - "LEAPS1": None - }, - option=True, - units="lbm", - desc='required fuel reserves: directly in lbm', - default_value=0, -) - add_meta_data( Aircraft.Design.RESERVES_FRACTION, meta_data=_MetaData, diff --git a/aviary/variable_info/variables.py b/aviary/variable_info/variables.py index a8cdad7cb..84deaf290 100644 --- a/aviary/variable_info/variables.py +++ b/aviary/variable_info/variables.py @@ -131,8 +131,8 @@ class Design: EXTERNAL_SUBSYSTEMS_MASS = 'aircraft:design:external_subsystems_mass' FINENESS = 'aircraft:design:fineness' FIXED_EQUIPMENT_MASS = 'aircraft:design:fixed_equipment_mass' + FIXED_RESERVES_FUEL = 'aircraft:design:fixed_reserves_fuel' FIXED_USEFUL_LOAD = 'aircraft:design:fixed_useful_load' - IJEFF = 'aircraft:design:ijeff' LAMINAR_FLOW_LOWER = 'aircraft:design:laminar_flow_lower' LAMINAR_FLOW_UPPER = 'aircraft:design:laminar_flow_upper' @@ -148,7 +148,6 @@ class Design: MAX_STRUCTURAL_SPEED = 'aircraft:design:max_structural_speed' OPERATING_MASS = 'aircraft:design:operating_mass' PART25_STRUCTURAL_CATEGORY = 'aircraft:design:part25_structural_category' - RESERVES = 'aircraft:design:reserves' RESERVES_FRACTION = 'aircraft:design:reserves_fraction' SMOOTH_MASS_DISCONTINUITIES = 'aircraft:design:smooth_mass_discontinuities' STATIC_MARGIN = 'aircraft:design:static_margin' From f3ad946f15ddd30cdfba7f17b6045be226b00f24 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 8 Jan 2024 19:13:37 -0600 Subject: [PATCH 018/188] All benchmarks pass with simple mission --- .../benchmark_tests/test_bench_FwFm.py | 13 +++-------- .../benchmark_tests/test_bench_GwFm.py | 11 ++-------- aviary/validation_cases/benchmark_utils.py | 22 +++++++------------ 3 files changed, 13 insertions(+), 33 deletions(-) diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index c86c541df..fc7087aa0 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -3,7 +3,6 @@ import numpy as np from openmdao.utils.testing_utils import use_tempdirs -from aviary.interface.default_phase_info.flops import phase_info from aviary.interface.methods_for_level1 import run_aviary from aviary.validation_cases.benchmark_utils import \ compare_against_expected_values @@ -263,12 +262,6 @@ def setUp(self): self.expected_dict = expected_dict def bench_test_swap_4_FwFm(self): - prob = run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info, - mission_method="FLOPS", mass_method="FLOPS") - - compare_against_expected_values(prob, self.expected_dict) - - def bench_test_swap_4_FwFm_simple(self): phase_info = { "pre_mission": {"include_takeoff": True, "optimize_mass": True}, "climb": { @@ -353,17 +346,17 @@ def bench_test_swap_4_FwFm_simple(self): "post_mission": { "include_landing": True, "constrain_range": True, - "target_range": (3360.0, "nmi"), + "target_range": (3350.0, "nmi"), }, } prob = run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info, mission_method="simple", mass_method="FLOPS") - compare_against_expected_values(prob, self.expected_dict, simple_flag=True) + compare_against_expected_values(prob, self.expected_dict) if __name__ == '__main__': test = ProblemPhaseTestCase() test.setUp() - test.bench_test_swap_4_FwFm_simple() + test.bench_test_swap_4_FwFm() diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py index 2dd22d79b..37ba996e4 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py @@ -10,7 +10,6 @@ import numpy as np from openmdao.utils.testing_utils import use_tempdirs -from aviary.interface.default_phase_info.flops import phase_info from aviary.interface.methods_for_level1 import run_aviary from aviary.validation_cases.benchmark_utils import \ compare_against_expected_values @@ -269,12 +268,6 @@ def setUp(self): self.expected_dict = expected_dict def bench_test_swap_1_GwFm(self): - prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwFm.csv', phase_info, - mission_method="FLOPS", mass_method="GASP") - - compare_against_expected_values(prob, self.expected_dict) - - def bench_test_swap_1_GwFm_simple(self): phase_info = { "pre_mission": {"include_takeoff": True, "optimize_mass": True}, "climb": { @@ -364,10 +357,10 @@ def bench_test_swap_1_GwFm_simple(self): prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwFm.csv', phase_info, mission_method="simple", mass_method="GASP", max_iter=15) - compare_against_expected_values(prob, self.expected_dict, simple_flag=True) + compare_against_expected_values(prob, self.expected_dict) if __name__ == '__main__': z = ProblemPhaseTestCase() z.setUp() - z.bench_test_swap_1_GwFm_simple() + z.bench_test_swap_1_GwFm() diff --git a/aviary/validation_cases/benchmark_utils.py b/aviary/validation_cases/benchmark_utils.py index 22b1b97dd..f7d011fd4 100644 --- a/aviary/validation_cases/benchmark_utils.py +++ b/aviary/validation_cases/benchmark_utils.py @@ -5,7 +5,7 @@ from aviary.utils.test_utils.assert_utils import warn_timeseries_near_equal -def compare_against_expected_values(prob, expected_dict, simple_flag=False): +def compare_against_expected_values(prob, expected_dict): expected_times = expected_dict['times'] expected_altitudes = expected_dict['altitudes'] @@ -22,20 +22,14 @@ def compare_against_expected_values(prob, expected_dict, simple_flag=False): for idx, phase in enumerate(['climb', 'cruise', 'descent']): times.extend(prob.get_val(f'traj.{phase}.timeseries.time', units='s')) - if simple_flag: - try: - altitudes.extend(prob.get_val( - f'traj.{phase}.timeseries.polynomial_controls:altitude', units='m')) - except KeyError: - altitudes.extend(prob.get_val( - f'traj.{phase}.timeseries.controls:altitude', units='m')) - velocities.extend(prob.get_val( - f'traj.{phase}.timeseries.velocity', units='m/s')) - else: + try: altitudes.extend(prob.get_val( - f'traj.{phase}.timeseries.states:altitude', units='m')) - velocities.extend(prob.get_val( - f'traj.{phase}.timeseries.states:velocity', units='m/s')) + f'traj.{phase}.timeseries.polynomial_controls:altitude', units='m')) + except KeyError: + altitudes.extend(prob.get_val( + f'traj.{phase}.timeseries.controls:altitude', units='m')) + velocities.extend(prob.get_val( + f'traj.{phase}.timeseries.velocity', units='m/s')) masses.extend( prob.get_val(f'traj.{phase}.timeseries.states:mass', units='kg')) ranges.extend( From a7b0e50f6e6b860cfc2db61d349379b52c3332f6 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 8 Jan 2024 19:56:29 -0600 Subject: [PATCH 019/188] All tests pass; benchmarks next --- aviary/api.py | 4 - aviary/interface/test/test_interface_bugs.py | 2 +- aviary/interface/test/test_phase_info.py | 53 +- aviary/mission/flops_based/ode/mission_EOM.py | 48 -- aviary/mission/flops_based/ode/mission_ODE.py | 154 ----- .../flops_based/ode/test/test_mission_EOM.py | 55 -- .../phases/benchmark_tests/__init__.py | 0 .../test_bench_climb_large_single_aisle_1.py | 260 --------- .../test_bench_climb_large_single_aisle_2.py | 366 ------------ ...bench_cruise_climb_large_single_aisle_1.py | 316 ---------- .../test_bench_cruise_large_single_aisle_1.py | 253 -------- .../test_bench_cruise_large_single_aisle_2.py | 247 -------- ...test_bench_descent_large_single_aisle_1.py | 255 --------- ...test_bench_descent_large_single_aisle_2.py | 256 --------- .../mission/flops_based/phases/climb_phase.py | 102 ---- .../flops_based/phases/cruise_phase.py | 437 -------------- .../flops_based/phases/descent_phase.py | 103 ---- .../flops_based/phases/energy_phase.py | 541 ------------------ .../flops_based/phases/phase_builder_base.py | 2 +- .../flops_based/phases/simple_energy_phase.py | 3 +- .../test_FLOPS_based_full_mission_N3CC.py | 4 - ...based_full_mission_large_single_aisle_1.py | 6 - ...based_full_mission_large_single_aisle_2.py | 5 - .../test_FLOPS_based_sizing_N3CC.py | 3 - 24 files changed, 9 insertions(+), 3466 deletions(-) delete mode 100644 aviary/mission/flops_based/ode/mission_EOM.py delete mode 100644 aviary/mission/flops_based/ode/mission_ODE.py delete mode 100644 aviary/mission/flops_based/ode/test/test_mission_EOM.py delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/__init__.py delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py delete mode 100644 aviary/mission/flops_based/phases/climb_phase.py delete mode 100644 aviary/mission/flops_based/phases/cruise_phase.py delete mode 100644 aviary/mission/flops_based/phases/descent_phase.py delete mode 100644 aviary/mission/flops_based/phases/energy_phase.py diff --git a/aviary/api.py b/aviary/api.py index 3e969c3f6..a7e55c7a5 100644 --- a/aviary/api.py +++ b/aviary/api.py @@ -68,7 +68,6 @@ from aviary.mission.gasp_based.ode.base_ode import BaseODE from aviary.mission.flops_based.ode.landing_ode import LandingODE as DetailedLandingODE from aviary.mission.flops_based.ode.landing_ode import FlareODE as DetailedFlareODE -from aviary.mission.flops_based.ode.mission_ODE import MissionODE as HeightEnergyMissionODE from aviary.mission.flops_based.ode.takeoff_ode import TakeoffODE as DetailedTakeoffODE from aviary.mission.gasp_based.ode.accel_ode import AccelODE as TwoDOFAccelerationODE from aviary.mission.gasp_based.ode.ascent_ode import AscentODE as TwoDOFAscentODE @@ -90,9 +89,6 @@ from aviary.mission.flops_based.phases.build_landing import Landing as HeightEnergyLandingPhaseBuilder # note that this is only for simplified right now from aviary.mission.flops_based.phases.build_takeoff import Takeoff as HeightEnergyTakeoffPhaseBuilder -from aviary.mission.flops_based.phases.climb_phase import Climb as HeightEnergyClimbPhaseBuilder -from aviary.mission.flops_based.phases.cruise_phase import Cruise as HeightEnergyCruisePhaseBuilder -from aviary.mission.flops_based.phases.descent_phase import Descent as HeightEnergyDescentPhaseBuilder from aviary.mission.flops_based.phases.detailed_landing_phases import LandingApproachToMicP3 as DetailedLandingApproachToMicP3PhaseBuilder from aviary.mission.flops_based.phases.detailed_landing_phases import LandingMicP3ToObstacle as DetailedLandingMicP3ToObstaclePhaseBuilder from aviary.mission.flops_based.phases.detailed_landing_phases import LandingObstacleToFlare as DetailedLandingObstacleToFlarePhaseBuilder diff --git a/aviary/interface/test/test_interface_bugs.py b/aviary/interface/test/test_interface_bugs.py index 44089da8b..7fd0f93d3 100644 --- a/aviary/interface/test/test_interface_bugs.py +++ b/aviary/interface/test/test_interface_bugs.py @@ -6,7 +6,7 @@ from aviary.interface.methods_for_level2 import AviaryProblem from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase -from aviary.interface.default_phase_info.flops import phase_info as ph_in +from aviary.interface.default_phase_info.simple import phase_info as ph_in from aviary.variable_info.variables import Aircraft from openmdao.utils.testing_utils import use_tempdirs diff --git a/aviary/interface/test/test_phase_info.py b/aviary/interface/test/test_phase_info.py index d1691db82..3facf1c45 100644 --- a/aviary/interface/test/test_phase_info.py +++ b/aviary/interface/test/test_phase_info.py @@ -8,8 +8,6 @@ from openmdao.utils.assert_utils import assert_near_equal -from aviary.interface.default_phase_info.flops import phase_info as ph_in_flops -from aviary.interface.default_phase_info.flops import phase_info_parameterization as phase_info_parameterization_flops from aviary.interface.default_phase_info.gasp import phase_info as ph_in_gasp from aviary.interface.default_phase_info.gasp import phase_info_parameterization as phase_info_parameterization_gasp from aviary.interface.methods_for_level2 import AviaryProblem @@ -17,7 +15,7 @@ from aviary.mission.flops_based.phases.phase_builder_base import \ PhaseBuilderBase as PhaseBuilder, phase_info_to_builder # must keep this import to register the phase -from aviary.mission.flops_based.phases.climb_phase import Climb +from aviary.mission.flops_based.phases.simple_energy_phase import EnergyPhase from aviary.variable_info.variables import Aircraft, Mission @@ -80,11 +78,11 @@ def _test_phase_info_dict(self, phase_info_dict, name): raise RuntimeError( f'value mismatch ({key}): {lhs_value} != {rhs_value}') - def test_default_phase_flops(self): - """Tests the roundtrip conversion for default_phase_info.flops""" - from aviary.interface.default_phase_info.flops import phase_info + def test_default_phase_simple(self): + """Tests the roundtrip conversion for default_phase_info.simple""" + from aviary.interface.default_phase_info.simple import phase_info local_phase_info = deepcopy(phase_info) - self._test_phase_info_dict(local_phase_info, 'climb') + self._test_phase_info_dict(local_phase_info, 'cruise') class TestParameterizePhaseInfo(unittest.TestCase): @@ -126,47 +124,6 @@ def test_phase_info_parameterization_gasp(self): assert_near_equal(prob.get_val("traj.cruise.rhs.mach")[0], 0.6) - def test_phase_info_parameterization_flops(self): - phase_info = deepcopy(ph_in_flops) - - prob = AviaryProblem(phase_info, mission_method="FLOPS", mass_method="FLOPS") - - csv_path = pkg_resources.resource_filename( - "aviary", "models/test_aircraft/aircraft_for_bench_FwFm.csv") - - prob.load_inputs(csv_path) - prob.check_inputs() - - # We can set some crazy vals, since we aren't going to optimize. - prob.aviary_inputs.set_val(Mission.Design.RANGE, 5000, 'km') - prob.aviary_inputs.set_val(Mission.Design.CRUISE_ALTITUDE, 31000, units='ft') - prob.aviary_inputs.set_val(Mission.Design.GROSS_MASS, 195000, 'lbm') - prob.aviary_inputs.set_val(Mission.Summary.CRUISE_MACH, 0.6, 'unitless') - - prob.add_pre_mission_systems() - prob.add_phases(phase_info_parameterization=phase_info_parameterization_flops) - prob.add_post_mission_systems() - - prob.link_phases() - - prob.setup() - prob.set_initial_guesses() - - prob.run_model() - - assert_near_equal(prob.get_val("traj.descent.timeseries.input_values:states:range", units='km')[-1], - 5000.0 * 3378.7 / 3500) - assert_near_equal(prob.get_val("traj.cruise.timeseries.input_values:states:altitude", units='ft')[0], - 31000.0) - assert_near_equal(prob.get_val("traj.climb.timeseries.input_values:states:mass", units='lbm')[-1], - 195000.0 * 165000 / 175400) - - # Mach enters as a constraint, so it won't impact openmdao outputs until successful optimization. - # So, to verify we are setting it, reach into internal constraint dicts. - # Order may change if more path constraints are added. - assert_near_equal(prob.model.traj.phases.cruise._path_constraints[1]['equals'], - 0.6) - # To run the tests if __name__ == '__main__': diff --git a/aviary/mission/flops_based/ode/mission_EOM.py b/aviary/mission/flops_based/ode/mission_EOM.py deleted file mode 100644 index 946a85468..000000000 --- a/aviary/mission/flops_based/ode/mission_EOM.py +++ /dev/null @@ -1,48 +0,0 @@ -import openmdao.api as om - -from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate -from aviary.mission.flops_based.ode.range_rate import RangeRate -from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate -from aviary.variable_info.variables import Dynamic - - -class MissionEOM(om.Group): - def initialize(self): - self.options.declare('num_nodes', types=int, - desc='Number of nodes to be evaluated in the RHS') - - def setup(self): - nn = self.options['num_nodes'] - - self.add_subsystem(name='specific_power', - subsys=SpecificEnergyRate(num_nodes=nn), - promotes_inputs=[Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, - Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.DRAG], - promotes_outputs=[Dynamic.Mission.SPECIFIC_ENERGY_RATE]) - self.add_subsystem(name=Dynamic.Mission.ALTITUDE_RATE, - subsys=AltitudeRate(num_nodes=nn), - promotes_inputs=[Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.VELOCITY], - promotes_outputs=[Dynamic.Mission.ALTITUDE_RATE]) - self.add_subsystem(name='groundspeed', - subsys=RangeRate(num_nodes=nn), - promotes_inputs=[ - Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY], - promotes_outputs=[Dynamic.Mission.RANGE_RATE]) - self.add_subsystem(name='excess_specific_power', - subsys=SpecificEnergyRate(num_nodes=nn), - promotes_inputs=[(Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.THRUST_MAX_TOTAL), - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DRAG], - promotes_outputs=[(Dynamic.Mission.SPECIFIC_ENERGY_RATE, Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS)]) - self.add_subsystem( - name=Dynamic.Mission.ALTITUDE_RATE_MAX, - subsys=AltitudeRate( - num_nodes=nn), - promotes_inputs=[ - (Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS), - Dynamic.Mission.VELOCITY_RATE, - Dynamic.Mission.VELOCITY], - promotes_outputs=[ - (Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.ALTITUDE_RATE_MAX)]) diff --git a/aviary/mission/flops_based/ode/mission_ODE.py b/aviary/mission/flops_based/ode/mission_ODE.py deleted file mode 100644 index 0ce3b3541..000000000 --- a/aviary/mission/flops_based/ode/mission_ODE.py +++ /dev/null @@ -1,154 +0,0 @@ -import numpy as np -import openmdao.api as om -from dymos.models.atmosphere import USatm1976Comp - -from aviary.mission.flops_based.ode.mission_EOM import MissionEOM -from aviary.subsystems.aerodynamics.flops_based.mach_number import MachNumber - -from aviary.mission.flops_based.ode.mission_EOM import MissionEOM -from aviary.utils.aviary_values import AviaryValues -from aviary.utils.functions import promote_aircraft_and_mission_vars -from aviary.variable_info.variable_meta_data import _MetaData -from aviary.variable_info.variables import Dynamic, Mission -from aviary.variable_info.variables_in import VariablesIn - - -class ExternalSubsystemGroup(om.Group): - def configure(self): - promote_aircraft_and_mission_vars(self) - - -class MissionODE(om.Group): - def initialize(self): - self.options.declare( - 'num_nodes', types=int, - desc='Number of nodes to be evaluated in the RHS') - self.options.declare( - 'subsystem_options', types=dict, default={}, - desc='dictionary of parameters to be passed to the subsystem builders') - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - self.options.declare( - 'core_subsystems', - desc='list of core subsystem builder instances to be added to the ODE' - ) - self.options.declare( - 'external_subsystems', default=[], - desc='list of external subsystem builder instances to be added to the ODE') - self.options.declare( - 'meta_data', default=_MetaData, - desc='metadata associated with the variables to be passed into the ODE') - self.options.declare( - 'use_actual_takeoff_mass', default=False, - desc='flag to use actual takeoff mass in the climb phase, otherwise assume 100 kg fuel burn') - - def setup(self): - options = self.options - nn = options['num_nodes'] - aviary_options = options['aviary_options'] - core_subsystems = options['core_subsystems'] - subsystem_options = options['subsystem_options'] - engine_count = len(aviary_options.get_val('engine_models')) - - self.add_subsystem( - 'input_port', - VariablesIn(aviary_options=aviary_options, - meta_data=self.options['meta_data'], - context='mission'), - promotes_inputs=['*'], - promotes_outputs=['*']) - self.add_subsystem( - name='atmosphere', - subsys=USatm1976Comp(num_nodes=nn), - promotes_inputs=[('h', Dynamic.Mission.ALTITUDE)], - promotes_outputs=[ - ('sos', Dynamic.Mission.SPEED_OF_SOUND), ('rho', Dynamic.Mission.DENSITY), - ('temp', Dynamic.Mission.TEMPERATURE), ('pres', Dynamic.Mission.STATIC_PRESSURE)]) - self.add_subsystem( - name=Dynamic.Mission.MACH, - subsys=MachNumber(num_nodes=nn), - promotes_inputs=[Dynamic.Mission.VELOCITY, Dynamic.Mission.SPEED_OF_SOUND], - promotes_outputs=[Dynamic.Mission.MACH]) - - base_options = {'num_nodes': nn, 'aviary_inputs': aviary_options} - - for subsystem in core_subsystems: - # check if subsystem_options has entry for a subsystem of this name - if subsystem.name in subsystem_options: - kwargs = subsystem_options[subsystem.name] - else: - kwargs = {} - - kwargs.update(base_options) - system = subsystem.build_mission(**kwargs) - - if system is not None: - self.add_subsystem(subsystem.name, - system, - promotes_inputs=subsystem.mission_inputs(**kwargs), - promotes_outputs=subsystem.mission_outputs(**kwargs)) - - # Create a lightly modified version of an OM group to add external subsystems - # to the ODE with a special configure() method that promotes - # all aircraft:* and mission:* variables to the ODE. - external_subsystem_group = ExternalSubsystemGroup() - add_subsystem_group = False - - for subsystem in self.options['external_subsystems']: - subsystem_mission = subsystem.build_mission( - num_nodes=nn, aviary_inputs=aviary_options) - if subsystem_mission is not None: - add_subsystem_group = True - external_subsystem_group.add_subsystem(subsystem.name, subsystem_mission) - - # Only add the external subsystem group if it has at least one subsystem. - # Without this logic there'd be an empty OM group added to the ODE. - if add_subsystem_group: - self.add_subsystem( - name='external_subsystems', - subsys=external_subsystem_group, - promotes_inputs=['*'], - promotes_outputs=['*']) - - self.add_subsystem( - name='mission_EOM', - subsys=MissionEOM(num_nodes=nn), - promotes_inputs=[ - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, - Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.THRUST_MAX_TOTAL, - Dynamic.Mission.DRAG, Dynamic.Mission.VELOCITY_RATE], - promotes_outputs=[ - Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, - Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.ALTITUDE_RATE_MAX, - Dynamic.Mission.RANGE_RATE]) - - self.set_input_defaults(Dynamic.Mission.MASS, val=np.ones(nn), units='kg') - self.set_input_defaults(Dynamic.Mission.VELOCITY, val=np.ones(nn), units='m/s') - self.set_input_defaults(Dynamic.Mission.ALTITUDE, val=np.ones(nn), units='m') - self.set_input_defaults( - Dynamic.Mission.THROTTLE, val=np.ones((nn, engine_count)), - units='unitless') - - if options['use_actual_takeoff_mass']: - exec_comp_string = 'initial_mass_residual = initial_mass - mass[0]' - initial_mass_string = Mission.Takeoff.FINAL_MASS - else: - exec_comp_string = 'initial_mass_residual = initial_mass - mass[0] - 100.' - initial_mass_string = Mission.Design.GROSS_MASS - - # Experimental: Add a component to constrain the initial mass to be equal to design gross weight. - initial_mass_residual_constraint = om.ExecComp( - exec_comp_string, - initial_mass={'units': 'kg'}, - mass={'units': 'kg', 'shape': (nn,)}, - initial_mass_residual={'units': 'kg'}, - ) - - self.add_subsystem('initial_mass_residual_constraint', initial_mass_residual_constraint, - promotes_inputs=[ - ('initial_mass', initial_mass_string), - ('mass', Dynamic.Mission.MASS) - ], - promotes_outputs=['initial_mass_residual']) diff --git a/aviary/mission/flops_based/ode/test/test_mission_EOM.py b/aviary/mission/flops_based/ode/test/test_mission_EOM.py deleted file mode 100644 index c2210d1f1..000000000 --- a/aviary/mission/flops_based/ode/test/test_mission_EOM.py +++ /dev/null @@ -1,55 +0,0 @@ -import unittest - -import openmdao.api as om - -from aviary.mission.flops_based.ode.mission_EOM import MissionEOM -from aviary.utils.test_utils.variable_test import assert_match_varnames -from aviary.validation_cases.validation_data.flops_data.full_mission_test_data import \ - data -from aviary.validation_cases.validation_tests import do_validation_test -from aviary.variable_info.variables import Dynamic - - -class MissionEOMTest(unittest.TestCase): - def setUp(self): - prob = self.prob = om.Problem() - - time, _ = data.get_item('time') - - prob.model.add_subsystem( - "mission_EOM", - MissionEOM(num_nodes=len(time)), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) - - prob.setup(check=False, force_alloc_complex=True) - - def test_case1(self): - - do_validation_test(self.prob, - 'full_mission_test_data', - input_validation_data=data, - output_validation_data=data, - input_keys=[Dynamic.Mission.DRAG, - Dynamic.Mission.MASS, - Dynamic.Mission.THRUST_TOTAL, - Dynamic.Mission.THRUST_MAX_TOTAL, - Dynamic.Mission.VELOCITY, - Dynamic.Mission.VELOCITY_RATE], - output_keys=[Dynamic.Mission.ALTITUDE_RATE, - # TODO: why does altitude_rate_max fail for cruise? - # - actual: 760.55416759 - # - desired: 3.86361517135375 - # Dynamic.Mission.ALTITUDE_RATE_MAX, - Dynamic.Mission.RANGE_RATE, - Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS], - tol=1e-12) - - def test_IO(self): - assert_match_varnames(self.prob.model) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/flops_based/phases/benchmark_tests/__init__.py b/aviary/mission/flops_based/phases/benchmark_tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py deleted file mode 100644 index 80ba4fb2e..000000000 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py +++ /dev/null @@ -1,260 +0,0 @@ -''' -NOTES: -Includes: -Climb -Computed Aero -Large Single Aisle 1 data -CURRENTLY REMOVED FROM BENCHMARK TEST SUITE -''' - -import unittest - -import dymos as dm -# Suppress the annoying warnings from matplotlib when running dymos. -import matplotlib as mpl -import numpy as np -import openmdao.api as om -import scipy.constants as _units -from dymos.utils.testing_utils import assert_timeseries_near_equal -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.flops_based.ode.mission_ODE import MissionODE -from aviary.mission.flops_based.phases.climb_phase import Climb -from aviary.interface.default_phase_info.flops import prop, aero, geom -from aviary.subsystems.premission import CorePreMission -from aviary.utils.functions import set_aviary_initial_values -from aviary.validation_cases.validation_tests import get_flops_inputs -from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Dynamic - -mpl.rc('figure', max_open_warning=0) - -try: - import pyoptsparse -except ImportError: - pyoptsparse = None - - -''' -NOTE benchmark currently hits iteration limit - problem only converges when velocity ref & ref0 in energyphase is changed to 1e3. - Changing velocity ref breaks some full-mission benchmarks, so is currently not - implemented -''' -# benchmark based on Large Single Aisle 1 (fixed cruise alt) FLOPS model - - -def run_trajectory(): - prob = om.Problem(model=om.Group()) - - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 50 - driver.opt_settings["Major optimality tolerance"] = 1e-5 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-3 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - # TODO enable coloring once issue has been resolved: - # https://github.com/OpenMDAO/OpenMDAO/issues/2507 - # driver.declare_coloring() - - ########################## - # Problem Settings # - ########################## - alt_i_climb = 0*_units.foot # m - alt_f_climb = 35000.0*_units.foot # m - mass_i_climb = 180623*_units.lb # kg - mass_f_climb = 176765*_units.lb # kg - v_i_climb = 198.44*_units.knot # m/s - v_f_climb = 455.49*_units.knot # m/s - mach_i_climb = 0.3 - mach_f_climb = 0.79 - range_i_climb = 0*_units.nautical_mile # m - range_f_climb = 160.3*_units.nautical_mile # m - t_i_climb = 2 * _units.minute # sec - t_f_climb = 26.20*_units.minute # sec - t_duration_climb = t_f_climb - t_i_climb - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle1FLOPS') - - climb_options = Climb( - 'test_climb', - initial_altitude=alt_i_climb, - final_altitude=alt_f_climb, - no_descent=False, - # note, Mach = 0.0 causes an error in aero, perhaps in other code - initial_mach=mach_i_climb, - final_mach=mach_f_climb, - fix_initial=True, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - aviary_options=aviary_inputs, - ) - - # replace debug_no_mass flag with list of subsystem builders without mass - core_subsystems = [prop, geom, aero] - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'core_premission', - CorePreMission(aviary_options=aviary_inputs, subsystems=core_subsystems), - promotes_inputs=['aircraft:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - transcription = dm.Radau(num_segments=6, order=3, compressed=False) - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - climb = climb_options.build_phase(MissionODE, transcription) - - traj.add_phase('climb', climb) - - climb.add_objective('time', loc='final', ref=1e3) - # climb.add_objective(Dynamic.Mission.MASS, loc='final', ref=-1e4) - - climb.set_time_options( - fix_initial=True, fix_duration=False, units='s', - duration_bounds=(1, t_duration_climb*2), duration_ref=t_duration_climb) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - - prob.setup() - - prob.set_val('traj.climb.t_initial', t_i_climb, units='s') - prob.set_val('traj.climb.t_duration', t_duration_climb, units='s') - - prob.set_val('traj.climb.states:altitude', climb.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m') - prob.set_val('traj.climb.states:velocity', climb.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s') - prob.set_val('traj.climb.states:mass', climb.interp( - Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') - prob.set_val('traj.climb.states:range', climb.interp( - Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') - - prob.set_val('traj.climb.controls:velocity_rate', - climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.05]), - units='m/s**2') - prob.set_val('traj.climb.controls:throttle', - climb.interp(Dynamic.Mission.THROTTLE, ys=[0.5, 0.5]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=False, make_plots=False, - solution_record_file='climb_max.db') - prob.record("final") - prob.cleanup() - - return prob - - -@unittest.skip('benchmark_climb_large_single_aisle_1 currently broken') -class ClimbPhaseTestCase(unittest.TestCase): - def bench_test_climb_large_single_aisle_1(self): - - prob = run_trajectory() - - times = prob.get_val('traj.climb.timeseries.time', units='s') - altitudes = prob.get_val('traj.climb.timeseries.states:altitude', units='m') - masses = prob.get_val('traj.climb.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.climb.timeseries.states:range', units='m') - velocities = prob.get_val('traj.climb.timeseries.states:velocity', units='m/s') - thrusts = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N') - - expected_times_s = [ - [120.], [194.07139282], [296.27479672], [328.62182461], - [328.62182461], [402.69321743], [504.89662133], [537.24364922], - [537.24364922], [611.31504204], [713.51844594], [745.86547383], - [745.86547383], [819.93686665], [922.14027055], [954.48729844], - [954.48729844], [1028.55869126], [1130.76209516], [1163.10912305], - [1163.10912305], [1237.18051587], [1339.38391977], [1371.73094766]] - expected_altitudes_m = [ - [0.], [682.4957554], [2476.9915886], [3148.23528025], - [3148.23528025], [4477.82410739], [5953.00480303], [6351.40548265], - [6351.40548265], [7144.57711953], [8022.01978103], [8258.96785373], - [8258.96785373], [8740.86702454], [9286.23944667], [9434.70712276], - [9434.70712276], [9740.61479402], [10091.17192047], [10187.1054111], - [10187.1054111], [10383.06677812], [10606.85289388], [10668.]] - expected_masses_kg = [ - [81929.21464651], [81734.3159625], [81482.28032417], [81409.67409534], - [81409.67409534], [81261.52268984], [81089.79910736], [81041.35712905], - [81041.35712905], [80939.57475401], [80815.51316484], [80779.24867668], - [80779.24867668], [80700.64682801], [80600.66210256], [80570.67210015], - [80570.67210015], [80504.18318007], [80416.95604372], [80390.28585848], - [80390.28585848], [80330.69704984], [80251.40682218], [80226.91650584]] - expected_ranges_m = [ - [0.], [11134.82482615], [33305.36225275], [40552.08037408], - [40552.08037408], [57694.75967874], [81567.92031544], [89129.68416299], - [89129.68416299], [106463.26453256], [130389.14274257], [137962.93786], - [137962.93786], [155308.03326502], [179243.7729914], [186819.85564691], - [186819.85564691], [204168.96379317], [228108.3526042], [235685.29047396], - [235685.29047396], [253035.99320713], [276976.90557005], [284554.20584747]] - expected_velocities_ms = [ - [102.08605905], [190.58935413], [228.38194188], [230.69562115], - [230.69562115], [233.30227629], [234.24467254], [234.25795132], - [234.25795132], [234.25795132], [234.25795132], [234.25795132], - [234.25795132], [234.25795132], [234.25795132], [234.25795132], - [234.25795132], [234.25795132], [234.25795132], [234.25795132], - [234.25795132], [234.25795132], [234.25795132], [234.25795132]] - expected_thrusts_N = [ - [218457.50162414], [171332.33326933], [141120.77188326], [131766.72736631], - [131766.72736631], [112828.24508393], [94178.64187388], [89529.25529378], - [89529.25529378], [80383.22196309], [71047.86501907], [68765.74648505], - [68765.74648505], [64112.90745184], [59068.27795964], [57877.0412593], - [57877.0412593], [55418.69760271], [52595.0053262], [51821.03735429], - [51821.03735429], [50238.39534494], [48428.26539664], [47933.1465328]] - expected_times_s = np.array(expected_times_s) - expected_altitudes_m = np.array(expected_altitudes_m) - expected_masses_kg = np.array(expected_masses_kg) - expected_ranges_m = np.array(expected_ranges_m) - expected_velocities_ms = np.array(expected_velocities_ms) - expected_thrusts_N = np.array(expected_thrusts_N) - - # NOTE rtol = 0.01 = 1% different from truth (first timeseries) - # atol = 1 = no more than +/-1 meter difference between values - atol = 1e-2 - rtol = 1e-3 - - # Objective - assert_near_equal(times[-1], expected_times_s[-1], tolerance=rtol) - - # Flight path - - assert_timeseries_near_equal( - expected_times_s, expected_masses_kg, times, masses, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_ranges_m, times, ranges, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_velocities_ms, times, velocities, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_thrusts_N, times, thrusts, - abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py deleted file mode 100644 index b924184b9..000000000 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py +++ /dev/null @@ -1,366 +0,0 @@ -''' -NOTES: -Includes: -Climb -Computed Aero -Large Single Aisle 2 data -''' - -import unittest - -import dymos as dm -# Suppress the annoying warnings from matplotlib when running dymos. -import matplotlib as mpl -import numpy as np -import openmdao.api as om -import scipy.constants as _units - -from dymos.utils.testing_utils import assert_timeseries_near_equal -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import use_tempdirs -from packaging import version -from aviary.variable_info.variables_in import VariablesIn - -from aviary.utils.aviary_values import AviaryValues -from aviary.mission.flops_based.phases.climb_phase import Climb -from aviary.interface.default_phase_info.flops import prop, aero, geom -from aviary.subsystems.premission import CorePreMission -from aviary.utils.functions import set_aviary_initial_values -from aviary.validation_cases.validation_tests import get_flops_inputs -from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Dynamic - -mpl.rc('figure', max_open_warning=0) - -try: - import pyoptsparse -except ImportError: - pyoptsparse = None - - -def run_trajectory(): - prob = om.Problem(model=om.Group()) - - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 40 - driver.opt_settings["Major optimality tolerance"] = 1e-5 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-3 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - # TODO enable coloring once issue has been resolved: - # https://github.com/OpenMDAO/OpenMDAO/issues/2507 - # driver.declare_coloring() - - ########################## - # Problem Settings # - ########################## - alt_i_climb = 35 * _units.foot # m - alt_f_climb = 35000.0 * _units.foot # m - mass_i_climb = 169172 * _units.lb # kg - mass_f_climb = 164160 * _units.lb # kg - v_i_climb = 198.44 * _units.knot # m/s - v_f_climb = 452.61 * _units.knot # m/s - mach_i_climb = 0.3 - mach_f_climb = 0.775 - range_i_climb = 0 * _units.nautical_mile # m - range_f_climb = 124 * _units.nautical_mile # m - t_i_climb = 0 - t_f_climb = 20.14 * _units.minute # sec - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle2FLOPS') - transcription = dm.Radau(num_segments=6, order=3, compressed=False) - climb_options = Climb( - 'test_climb', - user_options=AviaryValues({ - 'initial_altitude': (alt_i_climb, 'm'), - 'final_altitude': (alt_f_climb, 'm'), - 'initial_mach': (mach_i_climb, 'unitless'), - 'final_mach': (mach_f_climb, 'unitless'), - 'fix_initial': (True, 'unitless'), - 'fix_range': (False, 'unitless'), - 'input_initial': (False, 'unitless'), - }), - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - core_subsystems=[aero, prop], - transcription=transcription, - ) - - # replace debug_no_mass flag with list of subsystem builders without mass - core_subsystems = [prop, geom, aero] - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'core_premission', - CorePreMission(aviary_options=aviary_inputs, subsystems=core_subsystems), - promotes_inputs=['aircraft:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - climb = climb_options.build_phase(aviary_options=aviary_inputs) - - traj.add_phase('climb', climb) - - climb.timeseries_options['use_prefix'] = True - - climb.add_objective('time', loc='final', ref=t_f_climb) - - climb.set_time_options( - fix_initial=True, fix_duration=False, units='s', - duration_bounds=(t_f_climb * 0.5, t_f_climb * 2), duration_ref=t_f_climb) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs, phases=['climb']) - - prob.model.add_subsystem( - 'input_sink', - VariablesIn(aviary_options=aviary_inputs), - promotes_inputs=['*'], - promotes_outputs=['*'] - ) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - - prob.setup() - - prob.set_val('traj.climb.t_initial', t_i_climb, units='s') - prob.set_val('traj.climb.t_duration', t_f_climb, units='s') - - prob.set_val('traj.climb.states:altitude', climb.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m') - prob.set_val('traj.climb.states:velocity', climb.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s') - prob.set_val('traj.climb.states:mass', climb.interp( - Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') - prob.set_val('traj.climb.states:range', climb.interp( - Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') # nmi - - prob.set_val('traj.climb.controls:velocity_rate', - climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.05]), - units='m/s**2') - prob.set_val('traj.climb.controls:throttle', - climb.interp(Dynamic.Mission.THROTTLE, ys=[0.5, 0.5]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=False, make_plots=False, - solution_record_file='climb_large_single_aisle_2.db') - prob.record("final") - prob.cleanup() - - return prob - - -@use_tempdirs -class ClimbPhaseTestCase(unittest.TestCase): - def bench_test_climb_large_single_aisle_2(self): - - prob = run_trajectory() - - times = prob.get_val('traj.climb.timeseries.time', units='s') - altitudes = prob.get_val('traj.climb.timeseries.states:altitude', units='m') - masses = prob.get_val('traj.climb.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.climb.timeseries.states:range', units='m') - velocities = prob.get_val('traj.climb.timeseries.states:velocity', units='m/s') - thrusts = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N') - - expected_times_s = [[0.], - [47.24020828], - [112.42205385], - [133.05188512], - [133.05188512], - [180.2920934], - [245.47393897], - [266.10377023], - [266.10377023], - [313.34397852], - [378.52582409], - [399.15565535], - [399.15565535], - [446.39586363], - [511.5777092], - [532.20754047], - [532.20754047], - [579.44774875], - [644.62959432], - [665.25942558], - [665.25942558], - [712.49963387], - [777.68147944], - [798.3113107]] - expected_altitudes_m = [[1.06680000e+01], - [1.64717443e+02], - [1.21077165e+03], - [1.65467452e+03], - [1.65467452e+03], - [2.63158548e+03], - [3.89195114e+03], - [4.26784031e+03], - [4.26784031e+03], - [5.08501440e+03], - [6.12319963e+03], - [6.43302565e+03], - [6.43302565e+03], - [7.11281142e+03], - [7.98114971e+03], - [8.23811059e+03], - [8.23811059e+03], - [8.78587957e+03], - [9.45185516e+03], - [9.64164118e+03], - [9.64164118e+03], - [1.00442465e+04], - [1.05301137e+04], - [1.06680000e+04]] - expected_masses_kg = [[76735.12841764], - [76606.6291851], - [76423.55875817], - [76369.21098493], - [76369.21098493], - [76249.27821197], - [76096.52180626], - [76051.03001076], - [76051.03001076], - [75951.61028918], - [75824.47689696], - [75786.47518169], - [75786.47518169], - [75703.26334226], - [75596.63038983], - [75564.65308165], - [75564.65308165], - [75493.66861479], - [75400.85356264], - [75372.67886333], - [75372.67886333], - [75310.24572772], - [75228.35359487], - [75203.34794937]] - expected_ranges_m = [[0.], - [6656.35106052], - [19411.34037117], - [23606.44276229], - [23606.44276229], - [33597.9222712], - [47757.51502804], - [52308.8364503], - [52308.8364503], - [62843.02681099], - [77579.88662088], - [82280.86896803], - [82280.86896803], - [93082.94529627], - [108032.30577631], - [112765.20449737], - [112765.20449737], - [123607.6358803], - [138572.23956024], - [143309.37828794], - [143309.37828794], - [154158.17439593], - [169129.72020176], - [173868.65393385]] - expected_velocities_ms = [[102.08635556], - [173.4078533], - [206.56979636], - [209.71234319], - [209.71234319], - [215.12096513], - [220.69657248], - [222.14669648], - [222.14669648], - [225.06833215], - [228.02045426], - [228.64470582], - [228.64470582], - [229.49739505], - [229.80567178], - [229.81001554], - [229.81001554], - [229.81001554], - [229.81001554], - [229.81001554], - [229.81001554], - [229.81001554], - [229.81001554], - [229.81001554]] - expected_thrusts_N = [[183100.97258682], - [163996.9938714], - [144753.36497874], - [140427.87965941], - [140427.87965941], - [131136.19372391], - [119398.47487166], - [115939.50935006], - [115939.50935006], - [108449.59352749], - [99269.67371293], - [96533.89180294], - [96533.89180294], - [90902.4892038], - [84031.52375462], - [81889.41102505], - [81889.41102505], - [77138.3352612], - [71330.53467419], - [69720.96587699], - [69720.96587699], - [66405.48655242], - [62587.8225939], - [61541.80174696]] - - expected_times_s = np.array(expected_times_s) - expected_altitudes_m = np.array(expected_altitudes_m) - expected_masses_kg = np.array(expected_masses_kg) - expected_ranges_m = np.array(expected_ranges_m) - expected_velocities_ms = np.array(expected_velocities_ms) - expected_thrusts_N = np.array(expected_thrusts_N) - - # NOTE rtol = 0.01 = 1% different from truth (first timeseries) - # atol = 1 = no more than +/-1 meter difference between values - atol = 1e-2 - rtol = 1e-3 - - # Objective - assert_near_equal(times[-1], expected_times_s[-1], tolerance=rtol) - - # Flight path - assert_timeseries_near_equal( - expected_times_s, expected_masses_kg, times, masses, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_ranges_m, times, ranges, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_velocities_ms, times, velocities, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_thrusts_N, times, thrusts, - abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == "__main__": - test = ClimbPhaseTestCase() - test.bench_test_climb_large_single_aisle_2() diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py deleted file mode 100644 index b5b42004c..000000000 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py +++ /dev/null @@ -1,316 +0,0 @@ -############################################################### -# NOTES: -# Includes: -# Cruise -# Computed Aero -# Large Single Aisle 1 data -############################################################### -import unittest - -import dymos as dm -# Suppress the annoying warnings from matplotlib when running dymos. -import matplotlib as mpl -import numpy as np -import openmdao.api as om -import scipy.constants as _units - -from dymos.utils.testing_utils import assert_timeseries_near_equal -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.flops_based.ode.mission_ODE import MissionODE -from aviary.mission.flops_based.phases.cruise_phase import Cruise -from aviary.interface.default_phase_info.flops import prop, aero, geom -from aviary.subsystems.premission import CorePreMission -from aviary.utils.functions import set_aviary_initial_values -from aviary.utils.functions import get_path -from aviary.validation_cases.validation_tests import get_flops_inputs -from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Dynamic - -mpl.rc('figure', max_open_warning=0) - - -try: - import pyoptsparse -except ImportError: - pyoptsparse = None - - -# benchmark based on Large Single Aisle 1 (fixed cruise alt) FLOPS model - -def run_trajectory(): - prob = om.Problem(model=om.Group()) - - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 30 - driver.opt_settings["Major optimality tolerance"] = 1e-5 - driver.opt_settings["Major feasibility tolerance"] = 1e-5 - driver.opt_settings["iSumm"] = 6 - driver.opt_settings["Verify level"] = 3 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-6 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - # TODO enable coloring once issue has been resolved: - # https://github.com/OpenMDAO/OpenMDAO/issues/2507 - # driver.declare_coloring() - - ########################## - # Problem Settings # - ########################## - alt_min_cruise = 30000*_units.foot # m - alt_max_cruise = 36000*_units.foot # m - alt_i_cruise = alt_min_cruise - alt_f_cruise = 36000*_units.foot # m - mass_i_cruise = 176765*_units.lb # kg - mass_f_cruise = 143521*_units.lb # kg - velocity_i_cruise = 465.55*_units.knot # m/s - velocity_f_cruise = 465.55*_units.knot # m/s - mach_i_cruise = 0.79 - mach_f_cruise = 0.79 - mach_min_cruise = 0.78999 - mach_max_cruise = 0.79001 - range_i_cruise = 160.3*_units.nautical_mile # m - range_f_cruise = 3243.9*_units.nautical_mile # m - t_i_cruise = 26.20*_units.minute # sec - t_f_cruise = 432.38*_units.minute # sec - t_duration_cruise = t_f_cruise - t_i_cruise - - prob.set_solver_print(level=0) - - transcription = dm.Radau(num_segments=8, order=3, compressed=True) - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle1FLOPS') - # engine_models = aviary_inputs['engine_models'] - - cruise_options = Cruise( - 'test_cruise', - min_altitude=alt_min_cruise, # m - max_altitude=alt_max_cruise, # m - # note, Mach = 0.0 causes an error in aero, perhaps in other code - min_mach=mach_min_cruise, - max_mach=mach_max_cruise, - required_available_climb_rate=300*_units.foot/_units.minute, # ft/min to m/s - fix_initial=True, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - aviary_options=aviary_inputs, - # engine_models=engine_models, - no_descent=True, - velocity_f_cruise=velocity_f_cruise, - mass_f_cruise=mass_f_cruise, - range_f_cruise=range_f_cruise, - - ) - - # replace debug_no_mass flag with list of subsystem builders without mass - core_subsystems = [prop, geom, aero] - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'core_premission', - CorePreMission(aviary_options=aviary_inputs, subsystems=core_subsystems), - promotes_inputs=['aircraft:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - cruise = cruise_options.build_phase(MissionODE, transcription) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - traj.add_phase('cruise', cruise) - - cruise.set_time_options( - fix_initial=True, fix_duration=False, units='s', - duration_bounds=(1, t_duration_cruise*2), duration_ref=t_duration_cruise) - - cruise.add_objective(Dynamic.Mission.MASS, loc='final', ref=-mass_f_cruise) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - - # IVC = prob.model.add_subsystem('IVC', om.IndepVarComp(), promotes_outputs=['*']) - # IVC.add_output('alt_i', val=32000, units='ft') - prob.model.add_constraint( - 'traj.cruise.states:altitude', - indices=[0], equals=alt_min_cruise, units='m', ref=alt_max_cruise) - - # Alternative implmentation of above - # holds the first node in altitude constant - # cruise.set_state_options(Dynamic.Mission.ALTITUDE, fix_initial=True) - - prob.setup() - - prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s') - prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s') - - prob.set_val( - 'traj.cruise.states:altitude', cruise.interp( - Dynamic.Mission.ALTITUDE, ys=[ - alt_i_cruise, (alt_f_cruise + alt_i_cruise) / 2]), units='m') - prob.set_val( - 'traj.cruise.states:velocity', cruise.interp( - Dynamic.Mission.VELOCITY, ys=[ - velocity_i_cruise, velocity_f_cruise]), units='m/s') - prob.set_val('traj.cruise.states:mass', cruise.interp( - Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi - - prob.set_val('traj.cruise.controls:velocity_rate', - cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), - units='m/s**2') - prob.set_val('traj.cruise.controls:throttle', - cruise.interp(Dynamic.Mission.THROTTLE, ys=[0.5, 0.5]), - units='unitless') - - dm.run_problem(prob, simulate=False, make_plots=False, - solution_record_file='cruise_climb_max.db') - # TODO Simulate=True is crashing here so turned it off - - prob.cleanup() - prob.record("final") - - return prob - - -@unittest.skip('benchmark cruise climb currently broken') -class CruisePhaseTestCase(unittest.TestCase): - def bench_test_cruise_climb_large_single_aisle_1(self): - - prob = run_trajectory() - - times = prob.get_val('traj.cruise.timeseries.time', units='s') - altitudes = prob.get_val('traj.cruise.timeseries.states:altitude', units='m') - masses = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.cruise.timeseries.states:range', units='m') - velocities = prob.get_val('traj.cruise.timeseries.states:velocity', units='m/s') - thrusts = prob.get_val('traj.cruise.timeseries.thrust_net_total', units='N') - - expected_times_s = [ - [1572.0], [2654.1067424751645], [4147.193185981006], - [4619.749940380141], [4619.749940380141], [5701.856682855307], - [7194.943126361148], [7667.499880760283], [7667.499880760283], - [8749.606623235448], [10242.693066741289], [10715.249821140425], - [10715.249821140425], [11797.356563615589], [13290.44300712143], - [13762.999761520567], [13762.999761520567], [14845.106503995732], - [16338.192947501573], [16810.749701900706], [16810.749701900706], - [17892.856444375873], [19385.942887881713], [19858.49964228085], - [19858.49964228085], [20940.606384756014], [22433.692828261857], - [22906.249582660992], [22906.249582660992], [23988.356325136156], - [25481.442768642], [25953.999523041133]] - expected_altitudes_m = [ - [9143.999999999998], [9708.208298692567], [10127.822388940609], - [10214.217379879337], [10214.217379879337], [10369.633608560018], - [10522.493213427248], [10561.102831034279], [10561.102831034279], - [10628.89921313077], [10700.84689461149], [10720.94842484514], - [10720.94842484514], [10759.7268947497], [10811.373374694173], - [10828.933975559758], [10828.933975559758], [10866.85055516194], - [10912.976573928156], [10924.787065056735], [10924.787065056735], - [10948.28098891448], [10967.163582971652], [10969.578328436102], - [10969.578328436102], [10971.188528219269], [10971.305320817934], - [10972.40306787028], [10972.40306787028], [10972.800000000001], - [10972.682828875833], [10972.8]] - expected_masses_kg = [ - [80179.25528304999], [79388.27899969438], [78357.5492916318], - [78038.12469387538], [78038.12469387538], [77318.48636094612], - [76344.12665022336], [76039.40895912607], [76039.40895912607], - [75347.90752400359], [74405.46275374181], [74109.60273338258], - [74109.60273338258], [73436.39272100825], [72516.3728326044], - [72227.22710472894], [72227.22710472894], [71569.02331279762], - [70669.56072490575], [70386.99122373879], [70386.99122373879], - [69743.47490624938], [68863.48019743375], [68586.78382987661], - [68586.78382987661], [67956.17424058718], [67092.43136900471], - [66820.49389265837], [66820.49389265837], [66200.47169407656], - [65350.50275054499], [65082.74154168183]] - expected_ranges_m = [ - [296875.60000000003], [554932.6549301515], [908399.8849826958], - [1019938.0213070473], [1019938.0213070473], [1274830.9442516388], - [1625714.5770829467], [1736624.0715069345], [1736624.0715069345], - [1990386.259724133], [2340154.5629672543], [2450786.080862452], - [2450786.080862452], [2704005.1890667905], [3053155.1477462808], - [3163604.8984363866], [3163604.8984363866], [3416419.8294669725], - [3765031.23567717], [3875315.9608939146], [3875315.9608939146], - [4127790.908533788], [4476045.826943081], [4586252.017090351], - [4586252.017090351], [4838601.188787049], [5186784.687764149], - [5296985.604312349], [5296985.604312349], [5549329.03066934], - [5897505.925045533], [6007702.8]] - expected_velocities_ms = [ - [239.49901683172416], [237.57721365239863], [236.1272332817375], - [235.83480578606836], [235.83480578606836], [235.29228140558052], - [234.76087668521515], [234.63268475430843], [234.63268475430843], - [234.3910317141664], [234.14254607637204], [234.07650600638797], - [234.07650600638797], [233.93612811601653], [233.75522209810927], - [233.69840302886462], [233.69840302886462], [233.56754384846963], - [233.4030426703855], [233.35949436934354], [233.35949436934354], - [233.28100688012185], [233.21763783283092], [233.20729273195352], - [233.20729273195352], [233.19770503012535], [233.1994910278998], - [233.19937577943125], [233.19937577943125], [233.19406389286172], - [233.19249705434646], [233.197992365194]] - expected_thrusts_N = [ - [46413.113617016286], [43959.216926887144], [42322.72191477366], - [42001.69876565644], [42001.698765656445], [41407.67462380937], - [40737.526959795134], [40531.856232353945], [40531.85623235394], - [40132.12747513132], [39640.66854140172], [39484.44541552107], - [39484.44541552107], [39159.04488467944], [38737.64967064259], - [38601.13281610918], [38601.13281610918], [38291.27389642972], - [37859.254019237305], [37729.15520426054], [37729.155204260525], - [37427.990254061384], [37028.69942780689], [36907.64255965252], - [36907.64255965253], [36649.2311134786], [36319.78199219473], - [36213.12929993469], [36213.12929994349], [35988.316744926444], - [35701.59647680185], [35614.98883340026]] - - expected_times_s = np.array(expected_times_s) - expected_altitudes_m = np.array(expected_altitudes_m) - expected_masses_kg = np.array(expected_masses_kg) - expected_ranges_m = np.array(expected_ranges_m) - expected_velocities_ms = np.array(expected_velocities_ms) - expected_thrusts_N = np.array(expected_thrusts_N) - - # Objective - - rtol = 1e-2 - - assert_near_equal(times[-1], expected_times_s[-1], tolerance=rtol) - - # Flight path - - # NOTE rtol = 0.01 = 1% different from truth (first timeseries) - # atol = 1 = no more than +/-1 meter difference between values - atol = 1e-2 - rtol = 1e-3 - - assert_timeseries_near_equal( - expected_times_s, expected_masses_kg, times, masses, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_ranges_m, times, ranges, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_velocities_ms, times, velocities, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_thrusts_N, times, thrusts, - abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py deleted file mode 100644 index c1b907a07..000000000 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py +++ /dev/null @@ -1,253 +0,0 @@ -''' -NOTES: -Includes: -Cruise -Computed Aero -Large Single Aisle 1 data -''' - -import unittest - -import dymos as dm -# Suppress the annoying warnings from matplotlib when running dymos. -import matplotlib as mpl -import numpy as np -import openmdao.api as om -import scipy.constants as _units - -from dymos.utils.testing_utils import assert_timeseries_near_equal -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import use_tempdirs -from packaging import version -from aviary.variable_info.variables_in import VariablesIn - -from aviary.utils.aviary_values import AviaryValues -from aviary.mission.flops_based.phases.cruise_phase import Cruise -from aviary.interface.default_phase_info.flops import prop, aero, geom -from aviary.subsystems.premission import CorePreMission -from aviary.utils.functions import set_aviary_initial_values -from aviary.utils.functions import get_path -from aviary.validation_cases.validation_tests import (get_flops_inputs, - get_flops_outputs) -from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Aircraft, Dynamic - -mpl.rc('figure', max_open_warning=0) - -try: - import pyoptsparse - -except ImportError: - pyoptsparse = None - - -# benchmark based on Large Single Aisle 1 (fixed cruise alt) FLOPS model - -def run_trajectory(): - prob = om.Problem(model=om.Group()) - - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 50 - driver.opt_settings["Major optimality tolerance"] = 1e-5 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-6 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - # TODO enable coloring once issue has been resolved: - # https://github.com/OpenMDAO/OpenMDAO/issues/2507 - # driver.declare_coloring() - - ########################## - # Problem Settings # - ########################## - alt_i_cruise = 35000*_units.foot # m - alt_f_cruise = 35000*_units.foot # m - alt_min_cruise = 35000*_units.foot # m - alt_max_cruise = 35000*_units.foot # m - mass_i_cruise = 176765*_units.lb # kg - mass_f_cruise = 143521*_units.lb # kg - v_i_cruise = 455.49*_units.knot # m/s - v_f_cruise = 455.49*_units.knot # m/s - mach_i_cruise = 0.79 - mach_f_cruise = 0.79 - mach_min_cruise = 0.79 - mach_max_cruise = 0.79 - range_i_cruise = 160.3*_units.nautical_mile # m - range_f_cruise = 3243.9*_units.nautical_mile # m - t_i_cruise = 26.20*_units.minute # sec - t_f_cruise = 432.38*_units.minute # sec - t_duration_cruise = t_f_cruise - t_i_cruise - - prob.set_solver_print(level=2) - - transcription = dm.Radau(num_segments=1, order=3, compressed=True) - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle1FLOPS') - aviary_outputs = get_flops_outputs('LargeSingleAisle1FLOPS') - - # replace debug_no_mass flag with list of subsystem builders without mass - core_subsystems = [prop, geom, aero] - - cruise_options = Cruise( - 'test_cruise', - user_options=AviaryValues({ - 'min_altitude': (alt_min_cruise, 'm'), - 'max_altitude': (alt_max_cruise, 'm'), - 'min_mach': (mach_min_cruise, 'unitless'), - 'max_mach': (mach_max_cruise, 'unitless'), - 'required_available_climb_rate': (300, 'ft/min'), - 'fix_initial': (True, 'unitless'), - 'fix_final': (True, 'unitless'), - }), - core_subsystems=core_subsystems, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - transcription=transcription, - ) - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'core_premission', - CorePreMission(aviary_options=aviary_inputs, subsystems=core_subsystems), - promotes_inputs=['aircraft:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - cruise = cruise_options.build_phase(aviary_options=aviary_inputs) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - traj.add_phase('cruise', cruise) - - cruise.timeseries_options['use_prefix'] = True - - cruise.set_time_options( - fix_initial=True, fix_duration=False, units='s', - duration_bounds=(1, t_duration_cruise*2), duration_ref=t_duration_cruise) - - cruise.add_objective(Dynamic.Mission.MASS, loc='final', ref=-1e4) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs, phases=['cruise']) - - prob.model.add_subsystem( - 'input_sink', - VariablesIn(aviary_options=aviary_inputs), - promotes_inputs=['*'], - promotes_outputs=['*'] - ) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - key = Aircraft.Engine.THRUST_REVERSERS_MASS - val, units = aviary_outputs.get_item(key) - prob.model.set_input_defaults(key, val, units) - - prob.setup() - - prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s') - prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s') - - prob.set_val('traj.cruise.states:altitude', cruise.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m') - prob.set_val('traj.cruise.states:velocity', cruise.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s') - prob.set_val('traj.cruise.states:mass', cruise.interp( - Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi - - prob.set_val('traj.cruise.controls:velocity_rate', - cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), - units='m/s**2') - prob.set_val('traj.cruise.controls:throttle', - cruise.interp(Dynamic.Mission.THROTTLE, ys=[0.5, 0.5]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=False, make_plots=False, - solution_record_file='cruise_max.db') - # TODO Simulate=True is crashing here so turned it off - - prob.cleanup() - prob.record("final") - - return prob - - -@use_tempdirs -class CruisePhaseTestCase(unittest.TestCase): - def bench_test_cruise_large_single_aisle_1(self): - - prob = run_trajectory() - - times = prob.get_val('traj.cruise.timeseries.time', units='s') - altitudes = prob.get_val('traj.cruise.timeseries.states:altitude', units='m') - masses = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.cruise.timeseries.states:range', units='m') - velocities = prob.get_val('traj.cruise.timeseries.states:velocity', units='m/s') - thrusts = prob.get_val('traj.cruise.timeseries.thrust_net_total', units='N') - - expected_times_s = [[1572.], [10227.56555775], - [22170.47940152], [25950.37079939]] - expected_altitudes_m = [[10668.], [10668.], [10668.], [10668.]] - expected_masses_kg = [[80179.25528305], [ - 74612.30190345], [67357.05992796], [65154.3328912]] - expected_ranges_m = [[296875.6], [2324510.6550793], - [5122233.1849208], [6007702.8]] - expected_velocities_ms = [[234.25795132], [ - 234.25795132], [234.25795132], [234.25795132]] - expected_thrusts_N = [[41817.82877662], [ - 39634.49609004], [36930.60549609], [36149.38784885]] - - expected_times_s = np.array(expected_times_s) - expected_altitudes_m = np.array(expected_altitudes_m) - expected_masses_kg = np.array(expected_masses_kg) - expected_ranges_m = np.array(expected_ranges_m) - expected_velocities_ms = np.array(expected_velocities_ms) - expected_thrusts_N = np.array(expected_thrusts_N) - - # NOTE rtol = 0.01 = 1% different from truth (first timeseries) - # atol = 1 = no more than +/-1 meter difference between values - atol = 1e-2 - rtol = 1e-3 - - assert_near_equal(times[-1], expected_times_s[-1], tolerance=rtol) - - # Flight path - - assert_timeseries_near_equal( - expected_times_s, expected_masses_kg, times, masses, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_ranges_m, times, ranges, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_velocities_ms, times, velocities, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_thrusts_N, times, thrusts, - abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py deleted file mode 100644 index 5990f8164..000000000 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py +++ /dev/null @@ -1,247 +0,0 @@ -''' -NOTES: -Includes: -Cruise -Computed Aero -Large Single Aisle 2 data -CURRENTLY REMOVED FROM BENCHMARK TEST SUITE -''' - -import unittest - -import dymos as dm -# Suppress the annoying warnings from matplotlib when running dymos. -import matplotlib as mpl -import numpy as np -import openmdao.api as om -import scipy.constants as _units - -from dymos.utils.testing_utils import assert_timeseries_near_equal -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.flops_based.ode.mission_ODE import MissionODE -from aviary.mission.flops_based.phases.cruise_phase import Cruise -from aviary.interface.default_phase_info.flops import prop, aero, geom -from aviary.subsystems.premission import CorePreMission -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.functions import setup_trajectory_params -from aviary.variable_info.variables import Aircraft, Dynamic - -mpl.rc('figure', max_open_warning=0) - -try: - import pyoptsparse - -except ImportError: - pyoptsparse = None - - -''' -NOTE benchmark currently hits iteration limit - problem only converges when velocity ref & ref0 in energyphase is changed to 1e3. - Changing velocity ref breaks some full-mission benchmarks, so is currently not - implemented -''' - - -def run_trajectory(): - prob = om.Problem(model=om.Group()) - - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 50 - driver.opt_settings["Major optimality tolerance"] = 1e-5 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-6 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - # TODO enable coloring once issue has been resolved: - # https://github.com/OpenMDAO/OpenMDAO/issues/2507 - # driver.declare_coloring() - - ########################## - # Problem Settings # - ########################## - alt_i_cruise = 35000*_units.foot # m - alt_f_cruise = 35000*_units.foot # m - alt_min_cruise = 35000*_units.foot # m - alt_max_cruise = 35000*_units.foot # m - mass_i_cruise = 169730*_units.lb # kg - mass_f_cruise = 139810*_units.lb # kg - v_i_cruise = 452.61*_units.knot # m/s - v_f_cruise = 452.61*_units.knot # m/s - mach_i_cruise = 0.785 - mach_f_cruise = 0.785 - mach_min_cruise = 0.785 - mach_max_cruise = 0.785 - range_i_cruise = 116.6*_units.nautical_mile # m - range_f_cruise = 2558.3*_units.nautical_mile # m - t_i_cruise = 19.08*_units.minute # sec - t_f_cruise = 342.77*_units.minute # sec - t_duration_cruise = t_f_cruise - t_i_cruise # sec - - prob.set_solver_print(level=2) - - transcription = dm.Radau(num_segments=1, order=3, compressed=True) - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle2FLOPS') - aviary_outputs = get_flops_outputs('LargeSingleAisle2FLOPS') - - cruise_options = Cruise( - 'test_cruise', - min_altitude=alt_min_cruise, # m - max_altitude=alt_max_cruise, # m - # note, Mach = 0.0 causes an error in aero, perhaps in other code - min_mach=mach_min_cruise, - max_mach=mach_max_cruise, - required_available_climb_rate=300*_units.foot/_units.minute, # ft/min to m/s - fix_initial=True, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - aviary_options=aviary_inputs, - ) - - # replace debug_no_mass flag with list of subsystem builders without mass - core_subsystems = [prop, geom, aero] - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'core_premission', - CorePreMission(aviary_options=aviary_inputs, subsystems=core_subsystems), - promotes_inputs=['aircraft:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - cruise = cruise_options.build_phase(MissionODE, transcription) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - traj.add_phase('cruise', cruise) - - cruise.set_time_options( - fix_initial=True, fix_duration=False, units='s', - duration_bounds=(1, t_duration_cruise*2), duration_ref=t_duration_cruise) - - cruise.add_objective(Dynamic.Mission.MASS, loc='final', ref=-1e4) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - key = Aircraft.Engine.THRUST_REVERSERS_MASS - val, units = aviary_outputs.get_item(key) - prob.model.set_input_defaults(key, val, units) - - prob.setup() - - prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s') - prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s') - - prob.set_val('traj.cruise.states:altitude', cruise.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m') - prob.set_val('traj.cruise.states:velocity', cruise.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s') - prob.set_val('traj.cruise.states:mass', cruise.interp( - Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi - - prob.set_val('traj.cruise.controls:velocity_rate', - cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), - units='m/s**2') - prob.set_val('traj.cruise.controls:throttle', - cruise.interp(Dynamic.Mission.THROTTLE, ys=[0.5, 0.5]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=False, make_plots=False, - solution_record_file='cruise_large_single_aisle_2.db') - # TODO Simulate=True is crashing here so turned it off - - prob.cleanup() - prob.record("final") - - return prob - - -@unittest.skip('benchmark_cruise_large_single_aisle_2 currently broken') -class CruisePhaseTestCase(unittest.TestCase): - def bench_test_cruise_large_single_asile_2(self): - - prob = run_trajectory() - - times = prob.get_val('traj.cruise.timeseries.time', units='s') - altitudes = prob.get_val('traj.cruise.timeseries.states:altitude', units='m') - masses = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.cruise.timeseries.states:range', units='m') - velocities = prob.get_val('traj.cruise.timeseries.states:velocity', units='m/s') - thrusts = prob.get_val('traj.cruise.timeseries.thrust_net', units='N') - - expected_times_s = [[1144.8], [8042.22760495], - [17559.26991489], [20571.38126654]] - expected_altitudes_m = [[10668.], [10668.], [10668.], [10668.]] - expected_masses_kg = [[76988.2329601], [ - 72122.85057432], [65811.40723995], [63888.48266274]] - expected_ranges_m = [[215943.2], [1821494.02176252], - [4036826.45823737], [4737971.6]] - expected_velocities_ms = [[232.77530606], [ - 232.77530606], [232.77530606], [232.77530606]] - expected_thrusts_N = [[40492.90002165], [ - 38252.99661427], [35778.79636585], [35144.49009256]] - - expected_times_s = np.array(expected_times_s) - expected_altitudes_m = np.array(expected_altitudes_m) - expected_masses_kg = np.array(expected_masses_kg) - expected_ranges_m = np.array(expected_ranges_m) - expected_velocities_ms = np.array(expected_velocities_ms) - expected_thrusts_N = np.array(expected_thrusts_N) - - # NOTE rtol = 0.01 = 1% different from truth (first timeseries) - # atol = 1 = no more than +/-1 meter difference between values - atol = 1e-2 - rtol = 1e-3 - - # Objective - assert_near_equal(times[-1], expected_times_s[-1], tolerance=rtol) - - # Flight path - - assert_timeseries_near_equal( - expected_times_s, expected_masses_kg, times, masses, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_ranges_m, times, ranges, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_velocities_ms, times, velocities, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_thrusts_N, times, thrusts, - abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == "__main__": - # Changes to hardcoded tabular aero data changed this benchmark. Update benchmark - # test's expected values when aircraft-specific tabluar aero is avaliable - unittest.main() diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py deleted file mode 100644 index f331ff733..000000000 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py +++ /dev/null @@ -1,255 +0,0 @@ -''' -NOTES: -Includes: -Descent -Computed Aero -Large Single Aisle 1 data -''' - -import unittest - -import dymos as dm -# Suppress the annoying warnings from matplotlib when running dymos. -import matplotlib as mpl -import numpy as np -import openmdao.api as om -import scipy.constants as _units - -from dymos.utils.testing_utils import assert_timeseries_near_equal -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.flops_based.ode.mission_ODE import MissionODE -from aviary.mission.flops_based.phases.descent_phase import Descent -from aviary.interface.default_phase_info.flops import prop, aero, geom -from aviary.subsystems.premission import CorePreMission -from aviary.utils.functions import set_aviary_initial_values -from aviary.utils.functions import get_path -from aviary.validation_cases.validation_tests import get_flops_inputs -from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Dynamic - -mpl.rc('figure', max_open_warning=0) - - -try: - import pyoptsparse - -except ImportError: - pyoptsparse = None - - -''' -NOTE descent profile is improved when velocity ref in EnergyPhase change to 1e3 - Implementing that velocity ref change breaks several mission benchmarks -''' -# benchmark based on Large Single Aisle 1 (fixed cruise alt) FLOPS model - - -def run_trajectory(): - prob = om.Problem(model=om.Group()) - - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 50 - driver.opt_settings["Major optimality tolerance"] = 5e-3 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-3 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - # TODO enable coloring once issue has been resolved: - # https://github.com/OpenMDAO/OpenMDAO/issues/2507 - # driver.declare_coloring() - - ########################## - # Problem Settings # - ########################## - alt_i_descent = 35000*_units.foot - alt_f_descent = 0*_units.foot - v_i_descent = 455.49*_units.knot - v_f_descent = 198.44*_units.knot - mach_i_descent = 0.79 - mach_f_descent = 0.3 - mass_i_descent = 143521*_units.pound - mass_f_descent = 143035*_units.pound - range_i_descent = 3243.9*_units.nautical_mile - range_f_descent = 3378.7*_units.nautical_mile - t_i_descent = 432.38*_units.minute - t_f_descent = 461.62*_units.minute - t_duration_descent = t_f_descent - t_i_descent - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle1FLOPS') - - descent_options = Descent( - 'test_descent', - final_altitude=alt_f_descent, - initial_altitude=alt_i_descent, - # note, Mach = 0.0 causes an error in aero, perhaps in other code - final_mach=mach_f_descent, - initial_mach=mach_i_descent, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - aviary_options=aviary_inputs, - ) - - # replace debug_no_mass flag with list of subsystem builders without mass - core_subsystems = [prop, geom, aero] - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'core_premission', - CorePreMission(aviary_options=aviary_inputs, subsystems=core_subsystems), - promotes_inputs=['aircraft:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - transcription = dm.Radau(num_segments=5, order=3, compressed=True) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - descent = descent_options.build_phase(MissionODE, transcription) - - # descent.add_objective(Dynamic.Mission.MASS, ref=-1e4, loc='final') - descent.add_objective(Dynamic.Mission.RANGE, ref=-1e5, loc='final') - - traj.add_phase('descent', descent) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - - prob.setup() - - # set initial conditions - prob.set_val('traj.descent.t_initial', t_i_descent, units='s') - prob.set_val('traj.descent.t_duration', t_duration_descent, units='s') - - prob.set_val('traj.descent.states:altitude', descent.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_descent, alt_f_descent]), units='m') - prob.set_val('traj.descent.states:velocity', descent.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_descent, v_f_descent]), units='m/s') - prob.set_val('traj.descent.states:mass', descent.interp( - Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') - prob.set_val('traj.descent.states:range', descent.interp( - Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m') - - prob.set_val('traj.descent.controls:velocity_rate', - descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), - units='m/s**2') - prob.set_val('traj.descent.controls:throttle', - descent.interp(Dynamic.Mission.THROTTLE, ys=[0.0, 0.0]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=False, make_plots=False, - solution_record_file='descent_max.db') - prob.record("final") - prob.cleanup() - - return prob - - -@unittest.skip('benchmark_descent_large_single_aisle_1 currently broken') -class DescentPhaseTestCase(unittest.TestCase): - def bench_test_descent_large_single_aisle_1(self): - - prob = run_trajectory() - - times = prob.get_val('traj.descent.timeseries.time', units='s') - altitudes = prob.get_val('traj.descent.timeseries.states:altitude', units='m') - masses = prob.get_val('traj.descent.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.descent.timeseries.states:range', units='m') - velocities = prob.get_val('traj.descent.timeseries.states:velocity', units='m/s') - thrusts = prob.get_val('traj.descent.timeseries.thrust_net', units='N') - - expected_times_s = [ - [25942.8], [26067.38110599], [26239.2776049], [26293.68225907], - [26293.68225907], [26418.26336507], [26590.15986397], [26644.56451815], - [26644.56451815], [26769.14562414], [26941.04212305], [26995.44677722], - [26995.44677722], [27120.02788321], [27291.92438212], [27346.3290363], - [27346.3290363], [27470.91014229], [27642.80664119], [27697.21129537]] - expected_altitudes_m = [ - [10668.], [9630.58727675], [8607.44716937], [8325.35146852], - [8325.35146852], [7618.26503578], [6519.12597312], [6144.16296733], - [6144.16296733], [5222.63590813], [3906.74184382], [3501.58245681], - [3501.58245681], [2693.56449806], [1613.14062128], [1227.34540813], - [1227.34540813], [472.05630168], [0.], [0.]] - expected_masses_kg = [ - [65100.03053477], [65068.4860871], [65009.01063053], [64988.47429787], - [64988.47429787], [64942.20142996], [64875.19680192], [64851.91888669], - [64851.91888669], [64793.85853886], [64706.58329093], [64678.30905669], - [64678.30905669], [64614.11135757], [64531.47572247], [64507.94243863], - [64507.94243863], [64464.03072407], [64420.28475648], [64408.7201039]] - expected_ranges_m = [ - [6007702.8], [6036868.3987895], [6077125.1955833], - [6089867.31136598], [6089867.31136598], [6119045.21397484], - [6159302.44709504], [6172042.94318126], [6172042.94318126], - [6201214.75820313], [6241466.48424821], [6254207.73380962], - [6254207.73380962], [6283402.65691348], [6322851.72600445], - [6334884.03220066], [6334884.03220066], [6360443.88994895], - [6388386.24507732], [6394712.53233535]] - expected_velocities_ms = [ - [234.25795132], [234.25795132], [234.25795132], [234.25795132], - [234.25795132], [234.25795132], [234.25795132], [234.25795132], - [234.25795132], [234.25795132], [234.25795132], [234.25795132], - [234.25795132], [233.47298378], [223.67831268], [216.71997882], - [216.71997882], [190.9857791], [129.0266439], [102.08605905]] - expected_thrusts_N = [ - [9516.07730964], [18867.54655988], [26134.27560127], [26569.54809341], - [26569.54809341], [26513.67959312], [27279.65638053], [27558.344662], - [27558.344662], [29558.29975054], [37141.0454636], [40960.56830135], - [40960.56830135], [46197.31464087], [36817.32495137], [29341.51748247], - [29341.51748247], [14369.16584473], [0.], [2.27381718e-11]] - - expected_times_s = np.array(expected_times_s) - expected_altitudes_m = np.array(expected_altitudes_m) - expected_masses_kg = np.array(expected_masses_kg) - expected_ranges_m = np.array(expected_ranges_m) - expected_velocities_ms = np.array(expected_velocities_ms) - expected_thrusts_N = np.array(expected_thrusts_N) - - # NOTE rtol = 0.01 = 1% different from truth (first timeseries) - # atol = 1 = no more than +/-1 meter difference between values - atol = 1e-2 - rtol = 1e-3 - - # Objective - assert_near_equal(times[-1], expected_times_s[-1], tolerance=rtol) - - # Flight path - - assert_timeseries_near_equal( - expected_times_s, expected_masses_kg, times, masses, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_ranges_m, times, ranges, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_velocities_ms, times, velocities, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_thrusts_N, times, thrusts, - abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py deleted file mode 100644 index a66015fc7..000000000 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py +++ /dev/null @@ -1,256 +0,0 @@ -''' -NOTES: -Includes: -Descent -Computed Aero -Large Single Aisle 2 data -CURRENTLY REMOVED FROM BENCHMARK TEST SUITE -''' - -import unittest - -import dymos as dm -# Suppress the annoying warnings from matplotlib when running dymos. -import matplotlib as mpl -import numpy as np -import openmdao.api as om -import scipy.constants as _units - -from dymos.utils.testing_utils import assert_timeseries_near_equal -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.flops_based.ode.mission_ODE import MissionODE -from aviary.mission.flops_based.phases.descent_phase import Descent -from aviary.interface.default_phase_info.flops import prop, aero, geom -from aviary.subsystems.premission import CorePreMission -from aviary.utils.functions import set_aviary_initial_values -from aviary.utils.functions import get_path -from aviary.validation_cases.validation_tests import get_flops_inputs -from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Dynamic - -mpl.rc('figure', max_open_warning=0) - - -try: - import pyoptsparse - -except ImportError: - pyoptsparse = None - - -''' -NOTE benchmark only reaches 0-3 after 50 iterations with bad plots - problem easily converges with 0-1 when velocity ref & ref0 in energyphase is changed - to 1e3. - Changing velocity ref breaks some full-mission benchmarks, so is currently not - implemented -''' - - -def run_trajectory(): - prob = om.Problem(model=om.Group()) - - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 50 - driver.opt_settings["Major optimality tolerance"] = 5e-3 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-3 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - # TODO enable coloring once issue has been resolved: - # https://github.com/OpenMDAO/OpenMDAO/issues/2507 - # driver.declare_coloring() - - ########################## - # Problem Settings # - ########################## - alt_i = 35000*_units.foot - alt_f = 35*_units.foot - v_i = 452.61*_units.knot - v_f = 198.44*_units.knot - mach_i = 0.785 - mach_f = 0.3 - mass_i = 140515*_units.pound - mass_f = 140002*_units.pound - range_i = 2830.8*_units.nautical_mile - range_f = 2960.0*_units.nautical_mile - t_i_descent = 0.0 - t_f_descent = 2000.0 - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle2FLOPS') - - descent_options = Descent( - 'test_descent', - final_altitude=alt_f, - initial_altitude=alt_i, - # note, Mach = 0.0 causes an error in aero, perhaps in other code - final_mach=mach_f, - initial_mach=mach_i, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - aviary_options=aviary_inputs, - ) - - # replace debug_no_mass flag with list of subsystem builders without mass - core_subsystems = [prop, geom, aero] - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'core_premission', - CorePreMission(aviary_options=aviary_inputs, subsystems=core_subsystems), - promotes_inputs=['aircraft:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - transcription = dm.Radau(num_segments=5, order=3, compressed=True) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - descent = descent_options.build_phase(MissionODE, transcription) - - descent.add_objective(Dynamic.Mission.RANGE, ref=-1e5, loc='final') - traj.add_phase('descent', descent) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - - prob.setup() - - # set initial conditions - prob.set_val('traj.descent.t_initial', t_i_descent, units='s') - prob.set_val('traj.descent.t_duration', t_f_descent, units='s') - - prob.set_val('traj.descent.states:altitude', descent.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i, alt_f]), units='m') - prob.set_val('traj.descent.states:velocity', descent.interp( - Dynamic.Mission.VELOCITY, ys=[v_i, v_f]), units='m/s') - prob.set_val('traj.descent.states:mass', descent.interp( - Dynamic.Mission.MASS, ys=[mass_i, mass_f]), units='kg') - prob.set_val('traj.descent.states:range', descent.interp( - Dynamic.Mission.RANGE, ys=[range_i, range_f]), units='m') - - prob.set_val('traj.descent.controls:velocity_rate', - descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), - units='m/s**2') - prob.set_val('traj.descent.controls:throttle', - descent.interp(Dynamic.Mission.THROTTLE, ys=[0.0, 0.0]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=False, make_plots=False, - solution_record_file='descent_large_single_aisle_2.db') - prob.record("final") - prob.cleanup() - - return prob - - -@unittest.skip('benchmark_descent_large_single_aisle_2 currently broken') -class DescentPhaseTestCase(unittest.TestCase): - def bench_test_descent_large_single_aisle_2(self): - - prob = run_trajectory() - - times = prob.get_val('traj.descent.timeseries.time', units='s') - altitudes = prob.get_val('traj.descent.timeseries.states:altitude', units='m') - masses = prob.get_val('traj.descent.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.descent.timeseries.states:range', units='m') - velocities = prob.get_val('traj.descent.timeseries.states:velocity', units='m/s') - thrusts = prob.get_val('traj.descent.timeseries.thrust_net', units='N') - - expected_times_s = [ - [0.], [142.02539503], [337.99145239], [400.01403952], - [400.01403952], [542.03943455], [738.0054919], [800.02807903], - [800.02807903], [942.05347406], [1138.01953142], [1200.04211855], - [1200.04211855], [1342.06751358], [1538.03357093], [1600.05615806], - [1600.05615806], [1742.08155309], [1938.04761045], [2000.07019758]] - expected_altitudes_m = [ - [10668.], [9548.97609287], [8538.42241675], [8275.01276129], - [8275.01276129], [7601.31902636], [6519.47805911], [6141.13701298], - [6141.13701298], [5205.26802003], [3963.90368243], [3634.87695679], - [3634.87695679], [3055.62551952], [2221.91470683], [1840.14771729], - [1840.14771729], [870.95857222], [10.668], [10.668]] - expected_masses_kg = [ - [63736.53187055], [63688.55056043], [63592.93766122], [63558.62366657], - [63558.62366657], [63480.12720033], [63368.68894184], [63331.87300229], - [63331.87300229], [63243.53017169], [63103.08546544], [63051.9162013], - [63051.9162013], [62922.36463692], [62748.94842397], [62704.12656931], - [62704.12656931], [62627.76510694], [62566.74093186], [62554.55364275]] - expected_ranges_m = [ - [5242641.6], [5275682.08024547], [5321287.43849558], - [5335722.05453227], [5335722.05453227], [5368775.18998604], - [5414378.40648958], [5428810.78044196], [5428810.78044196], - [5461857.5756481], [5507456.7101919], [5521890.39254914], - [5521890.39254914], [5554951.82532665], [5599686.46586361], - [5613370.90489204], [5613370.90489204], [5642618.8601419], - [5674799.0551216], [5682083.57281856]] - expected_velocities_ms = [ - [232.77530606], [232.77530606], [232.77530606], [232.77530606], - [232.77530606], [232.77530606], [232.77530606], [232.77530606], - [232.77530606], [232.77530606], [232.77530606], [232.77530606], - [232.77530606], [232.05265856], [223.03560479], [216.62970611], - [216.62970611], [192.53473927], [130.45545087], [102.07377559]] - expected_thrusts_N = [ - [10348.85799036], [20322.69938272], [27901.58834456], - [28262.62341568], [28262.62341568], [28062.43245824], - [28590.47833586], [28815.02361611], [28815.02361611], - [30869.45928917], [38383.90751338], [41973.2222718], - [41973.2222718], [46287.80542225], [36032.4169276], - [28755.10323868], [28755.10323868], [13691.34754408], [0.], [0.]] - - expected_times_s = np.array(expected_times_s) - expected_altitudes_m = np.array(expected_altitudes_m) - expected_masses_kg = np.array(expected_masses_kg) - expected_ranges_m = np.array(expected_ranges_m) - expected_velocities_ms = np.array(expected_velocities_ms) - expected_thrusts_N = np.array(expected_thrusts_N) - - # NOTE rtol = 0.01 = 1% different from truth (first timeseries) - # atol = 1 = no more than +/-1 meter difference between values - atol = 1e-2 - rtol = 1e-3 - - # Objective - assert_near_equal(times[-1], expected_times_s[-1], tolerance=rtol) - - # Flight path - - assert_timeseries_near_equal( - expected_times_s, expected_masses_kg, times, masses, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_ranges_m, times, ranges, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_velocities_ms, times, velocities, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_thrusts_N, times, thrusts, - abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/flops_based/phases/climb_phase.py b/aviary/mission/flops_based/phases/climb_phase.py deleted file mode 100644 index 977240d90..000000000 --- a/aviary/mission/flops_based/phases/climb_phase.py +++ /dev/null @@ -1,102 +0,0 @@ -from aviary.mission.flops_based.phases.energy_phase import EnergyPhase, register - - -Climb = None # forward declaration for type hints - - -@register -class Climb(EnergyPhase): - ''' - Define a phase builder class for a typical FLOPS based climb phase. - - Attributes - ---------- - name : str ('climb') - object label - - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - - user_options : AviaryValues () - state/path constraint values and flags - - supported options: - - num_segments : int (5) - transcription: number of segments - - order : int (3) - transcription: order of the state transcription; the order of the control - transcription is `order - 1` - - fix_initial : bool (True) - - fix_initial_time : bool (None) - - initial_ref : float (1.0, 's') - note: applied if, and only if, "fix_initial_time" is unspecified - - initial_bounds : pair ((0.0, 100.0) 's') - note: applied if, and only if, "fix_initial_time" is unspecified - - duration_ref : float (1.0, 's') - - duration_bounds : pair ((0.0, 100.0) 's') - - initial_altitude : float (0.0, 'ft) - starting true altitude from mean sea level - - final_altitude : float - ending true altitude from mean sea level - - initial_mach : float (0.0, 'ft) - starting Mach number - - final_mach : float - ending Mach number - - required_altitude_rate : float (None) - minimum avaliable climb rate - - no_climb : bool (False) - aircraft is not allowed to climb during phase - - no_descent : bool (False) - aircraft is not allowed to descend during phase - - fix_range : bool (False) - - input_initial : bool (False) - - initial_guesses : AviaryValues () - state/path beginning values to be set on the problem - - supported options: - - times - - range - - altitude - - velocity - - velocity_rate - - mass - - throttle - - ode_class : type (None) - advanced: the type of system defining the ODE - - transcription : "Dymos transcription object" (None) - advanced: an object providing the transcription technique of the - optimal control problem - - external_subsystems : Sequence["subsystem builder"] () - advanced - - meta_data : dict (<"builtin" meta data>) - advanced: meta data associated with variables in the Aviary data hierarchy - - default_name : str - class attribute: derived type customization point; the default value - for name - - default_ode_class : type - class attribute: derived type customization point; the default value - for ode_class used by build_phase - - default_meta_data : dict - class attribute: derived type customization point; the default value for - meta_data - - Methods - ------- - build_phase - make_default_transcription - validate_options - assign_default_options - ''' - # region : derived type customization points - __slots__ = () - - default_name = 'climb' - # endregion : derived type customization points diff --git a/aviary/mission/flops_based/phases/cruise_phase.py b/aviary/mission/flops_based/phases/cruise_phase.py deleted file mode 100644 index 2f861c585..000000000 --- a/aviary/mission/flops_based/phases/cruise_phase.py +++ /dev/null @@ -1,437 +0,0 @@ -from math import isclose - -import dymos as dm - -from aviary.mission.flops_based.phases.phase_builder_base import ( - register, PhaseBuilderBase, InitialGuessControl, InitialGuessParameter, - InitialGuessPolynomialControl, InitialGuessState, InitialGuessTime) - -from aviary.utils.aviary_values import AviaryValues - -from aviary.variable_info.variable_meta_data import _MetaData -from aviary.variable_info.variables import Dynamic -from aviary.mission.flops_based.phases.phase_utils import add_subsystem_variables_to_phase, get_initial - - -Cruise = None # forward declaration for type hints - - -# TODO: support/handle the following in the base class -# - phase.set_time_options() -# - currently handled in level 3 interface implementation -# - self.external_subsystems -# - self.meta_data, with cls.default_meta_data customization point -class Cruise(PhaseBuilderBase): - ''' - Define a phase builder base class for typical energy phases such as climb and - descent. - - Attributes - ---------- - name : str ('energy_phase') - object label - - subsystem_options (None) - dictionary of parameters to be passed to the subsystem builders - - user_options : AviaryValues () - state/path constraint values and flags - - supported options: - - num_segments : int (5) - transcription: number of segments - - order : int (3) - transcription: order of the state transcription; the order of the control - transcription is `order - 1` - - fix_initial : bool (True) - - fix_initial_time : bool (None) - - initial_ref : float (1.0, 's') - note: applied if, and only if, "fix_initial_time" is unspecified - - initial_bounds : pair ((0.0, 100.0) 's') - note: applied if, and only if, "fix_initial_time" is unspecified - - duration_ref : float (1.0, 's') - - duration_bounds : pair ((0.0, 100.0) 's') - - min_altitude : float (0.0, 'ft) - starting true altitude from mean sea level - - max_altitude : float - ending true altitude from mean sea level - - min_mach : float (0.0, 'ft) - starting Mach number - - max_mach : float - ending Mach number - - required_available_climb_rate : float (None) - minimum avaliable climb rate - - fix_final : bool (False) - - input_initial : bool (False) - - polynomial_control_order : None or int - When set to an integer value, replace controls with - polynomial controls of that specified order. - - initial_guesses : AviaryValues () - state/path beginning values to be set on the problem - - supported options: - - times - - range - - altitude - - velocity - - velocity_rate - - mass - - throttle - - ode_class : type (None) - advanced: the type of system defining the ODE - - transcription : "Dymos transcription object" (None) - advanced: an object providing the transcription technique of the - optimal control problem - - external_subsystems : Sequence["subsystem builder"] () - advanced - - meta_data : dict (<"builtin" meta data>) - advanced: meta data associated with variables in the Aviary data hierarchy - - default_name : str - class attribute: derived type customization point; the default value - for name - - default_ode_class : type - class attribute: derived type customization point; the default value - for ode_class used by build_phase - - default_meta_data : dict - class attribute: derived type customization point; the default value for - meta_data - - Methods - ------- - build_phase - make_default_transcription - validate_options - assign_default_options - ''' - __slots__ = ('external_subsystems', 'meta_data') - - # region : derived type customization points - _meta_data_ = {} - - _initial_guesses_meta_data_ = {} - - default_name = 'cruise_phase' - - # default_ode_class = MissionODE - - default_meta_data = _MetaData - - # endregion : derived type customization points - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, core_subsystems=core_subsystems, subsystem_options=subsystem_options, user_options=user_options, initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription) - - # TODO: support external_subsystems and meta_data in the base class - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - - def build_phase(self, aviary_options: AviaryValues = None): - ''' - Return a new cruise phase for analysis using these constraints. - - If ode_class is None, default_ode_class is used. - - If transcription is None, the return value from calling - make_default_transcription is used. - - Parameters - ---------- - aviary_options : AviaryValues () - collection of Aircraft/Mission specific options - - Returns - ------- - dymos.Phase - ''' - phase: dm.Phase = super().build_phase(aviary_options) - - user_options: AviaryValues = self.user_options - - fix_initial = user_options.get_val('fix_initial') - min_mach = user_options.get_val('min_mach') - max_mach = user_options.get_val('max_mach') - min_altitude = user_options.get_val('min_altitude', units='m') - max_altitude = user_options.get_val('max_altitude', units='m') - fix_final = user_options.get_val('fix_final') - input_initial = user_options.get_val('input_initial') - num_engines = len(aviary_options.get_val('engine_models')) - input_initial = user_options.get_val('input_initial') - mass_f_cruise = user_options.get_val('mass_f_cruise', units='kg') - range_f_cruise = user_options.get_val('range_f_cruise', units='m') - polynomial_control_order = user_options.get_item('polynomial_control_order')[0] - - ############## - # Add States # - ############## - - input_initial_alt = get_initial(input_initial, Dynamic.Mission.ALTITUDE) - fix_initial_alt = get_initial(fix_initial, Dynamic.Mission.ALTITUDE) - phase.add_state( - Dynamic.Mission.ALTITUDE, fix_initial=fix_initial_alt, fix_final=False, - lower=0.0, ref=max_altitude, defect_ref=max_altitude, units='m', - rate_source=Dynamic.Mission.ALTITUDE_RATE, targets=Dynamic.Mission.ALTITUDE, - input_initial=input_initial_alt - ) - - input_initial_vel = get_initial(input_initial, Dynamic.Mission.VELOCITY) - fix_initial_vel = get_initial(fix_initial, Dynamic.Mission.VELOCITY) - phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=fix_initial_vel, fix_final=False, - lower=0.0, ref=1e2, defect_ref=1e2, units='m/s', - rate_source=Dynamic.Mission.VELOCITY_RATE, targets=Dynamic.Mission.VELOCITY, - input_initial=input_initial_vel - ) - - input_initial_mass = get_initial(input_initial, Dynamic.Mission.MASS) - fix_initial_mass = get_initial(fix_initial, Dynamic.Mission.MASS, True) - phase.add_state( - Dynamic.Mission.MASS, fix_initial=fix_initial_mass, fix_final=False, - lower=0.0, ref=mass_f_cruise, defect_ref=mass_f_cruise, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - input_initial=input_initial_mass - ) - - input_initial_range = get_initial(input_initial, Dynamic.Mission.RANGE) - fix_initial_range = get_initial(fix_initial, Dynamic.Mission.RANGE, True) - phase.add_state( - Dynamic.Mission.RANGE, fix_initial=fix_initial_range, fix_final=fix_final, - lower=0.0, ref=range_f_cruise, defect_ref=range_f_cruise, units='m', - rate_source=Dynamic.Mission.RANGE_RATE, - input_initial=input_initial_range - ) - - phase = add_subsystem_variables_to_phase( - phase, self.name, self.external_subsystems) - - ################ - # Add Controls # - ################ - if polynomial_control_order is not None: - phase.add_polynomial_control( - Dynamic.Mission.VELOCITY_RATE, - targets=Dynamic.Mission.VELOCITY_RATE, units='m/s**2', - opt=True, lower=-2.12, upper=2.12, - order=polynomial_control_order, - ) - else: - phase.add_control( - Dynamic.Mission.VELOCITY_RATE, - targets=Dynamic.Mission.VELOCITY_RATE, units='m/s**2', - opt=True, lower=-2.12, upper=2.12, - ) - - if num_engines > 0: - if polynomial_control_order is not None: - phase.add_polynomial_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', - opt=True, lower=0.0, upper=1.0, scaler=1, - order=polynomial_control_order, - ) - else: - phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', - opt=True, lower=0.0, upper=1.0, scaler=1, - ) - - ################## - # Add Timeseries # - ################## - phase.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units='unitless' - ) - - phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' - ) - - phase.add_timeseries_output( - Dynamic.Mission.THRUST_MAX_TOTAL, - output_name=Dynamic.Mission.THRUST_MAX_TOTAL, units='lbf' - ) - - phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' - ) - - phase.add_timeseries_output( - Dynamic.Mission.SPECIFIC_ENERGY_RATE, - output_name=Dynamic.Mission.SPECIFIC_ENERGY_RATE, units='m/s' - ) - - phase.add_timeseries_output( - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, - output_name=Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, units='m/s' - ) - - phase.add_timeseries_output( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - output_name=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units='lbm/h' - ) - - phase.add_timeseries_output( - Dynamic.Mission.ALTITUDE_RATE, - output_name=Dynamic.Mission.ALTITUDE_RATE, units='ft/s' - ) - - phase.add_timeseries_output( - Dynamic.Mission.ALTITUDE_RATE_MAX, - output_name=Dynamic.Mission.ALTITUDE_RATE_MAX, units='ft/min' - ) - - ################### - # Add Constraints # - ################### - required_available_climb_rate = user_options.get_val( - 'required_available_climb_rate', 'm/s') - - if required_available_climb_rate is not None: - phase.add_path_constraint( - Dynamic.Mission.ALTITUDE_RATE_MAX, - ref=required_available_climb_rate, - constraint_name='altitude_rate_minimum', - lower=required_available_climb_rate, units='m/s' - ) - - if isclose(min_mach, max_mach): - phase.add_path_constraint( - Dynamic.Mission.MACH, - equals=min_mach, units='unitless', - # ref=1.e4, - ) - - else: - phase.add_path_constraint( - Dynamic.Mission.MACH, - lower=min_mach, upper=max_mach, units='unitless', - # ref=1.e4, - ) - - # avoid scaling constraints by zero - ref = max_altitude - if ref == 0: - ref = None - - if isclose(min_altitude, max_altitude): - phase.add_path_constraint( - Dynamic.Mission.ALTITUDE, - equals=min_altitude, units='m', ref=ref, - ) - - else: - phase.add_path_constraint( - Dynamic.Mission.ALTITUDE, - lower=min_altitude, upper=max_altitude, - units='m', ref=ref, - ) - - return phase - - def _extra_ode_init_kwargs(self): - """ - Return extra kwargs required for initializing the ODE. - """ - # TODO: support external_subsystems and meta_data in the base class - return { - 'external_subsystems': self.external_subsystems, - 'meta_data': self.meta_data} - - -Cruise._add_meta_data( - 'num_segments', val=1, desc='transcription: number of segments') - -Cruise._add_meta_data( - 'order', val=3, - desc='transcription: order of the state transcription; the order of the control' - ' transcription is `order - 1`') - -Cruise._add_meta_data('fix_initial', val=True) - -Cruise._add_meta_data('fix_initial_time', val=None) - -Cruise._add_meta_data('initial_ref', val=1., units='s') - -Cruise._add_meta_data('initial_bounds', val=(0., 100.), units='s') - -Cruise._add_meta_data('duration_ref', val=1., units='s') - -Cruise._add_meta_data('duration_bounds', val=(0., 100.), units='s') - -Cruise._add_meta_data( - 'min_altitude', val=0., units='m', - desc='starting true altitude from mean sea level') - -Cruise._add_meta_data( - 'max_altitude', val=None, units='m', - desc='ending true altitude from mean sea level') - -Cruise._add_meta_data('min_mach', val=0., desc='starting Mach number') - -Cruise._add_meta_data('max_mach', val=None, desc='ending Mach number') - -Cruise._add_meta_data('mass_i_cruise', val=1.e4, units='kg') - -Cruise._add_meta_data('mass_f_cruise', val=1.e4, units='kg') - -Cruise._add_meta_data('range_f_cruise', val=1.e6, units='m') - -Cruise._add_meta_data( - 'required_available_climb_rate', val=None, units='m/s', - desc='minimum avaliable climb rate') - -Cruise._add_meta_data('fix_final', val=True) - -Cruise._add_meta_data('input_initial', val=False) - -Cruise._add_meta_data('polynomial_control_order', val=None) - -Cruise._add_initial_guess_meta_data( - InitialGuessTime(), - desc='initial guess for initial time and duration specified as a tuple') - -Cruise._add_initial_guess_meta_data( - InitialGuessState('range'), - desc='initial guess for horizontal distance traveled') - -Cruise._add_initial_guess_meta_data( - InitialGuessState('altitude'), - desc='initial guess for vertical distances') - -Cruise._add_initial_guess_meta_data( - InitialGuessState('velocity'), - desc='initial guess for speed') - -Cruise._add_initial_guess_meta_data( - InitialGuessControl('velocity_rate'), - desc='initial guess for acceleration') - -Cruise._add_initial_guess_meta_data( - InitialGuessState('mass'), - desc='initial guess for mass') - -Cruise._add_initial_guess_meta_data( - InitialGuessControl('throttle'), - desc='initial guess for throttle') diff --git a/aviary/mission/flops_based/phases/descent_phase.py b/aviary/mission/flops_based/phases/descent_phase.py deleted file mode 100644 index 78ad93a90..000000000 --- a/aviary/mission/flops_based/phases/descent_phase.py +++ /dev/null @@ -1,103 +0,0 @@ -from aviary.mission.flops_based.phases.energy_phase import EnergyPhase, register - - -Descent = None # forward declaration for type hints - - -@register -class Descent(EnergyPhase): - ''' - Define a phase builder class for a typical FLOPS based descent phase. - - Attributes - ---------- - name : str ('descent') - object label - - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - - user_options : AviaryValues () - state/path constraint values and flags - - supported options: - - num_segments : int (5) - transcription: number of segments - - order : int (3) - transcription: order of the state transcription; the order of the control - transcription is `order - 1` - - fix_initial : bool (True) - - fix_initial_time : bool (None) - - initial_ref : float (1.0, 's') - note: applied if, and only if, "fix_initial_time" is unspecified - - initial_bounds : pair ((0.0, 100.0) 's') - note: applied if, and only if, "fix_initial_time" is unspecified - - duration_ref : float (1.0, 's') - - duration_bounds : pair ((0.0, 100.0) 's') - - initial_altitude : float (0.0, 'ft) - starting true altitude from mean sea level - - final_altitude : float - ending true altitude from mean sea level - - initial_mach : float (0.0, 'ft) - starting Mach number - - final_mach : float - ending Mach number - - required_altitude_rate : float (None) - minimum avaliable descent rate - - no_descent : bool (False) - aircraft is not allowed to descent during phase - - no_descent : bool (False) - aircraft is not allowed to descend during phase - - fix_range : bool (False) - - input_initial : bool (False) - - initial_guesses : AviaryValues () - state/path beginning values to be set on the problem - - supported options: - - times - - range - - altitude - - velocity - - velocity_rate - - mass - - throttle - - ode_class : type (None) - advanced: the type of system defining the ODE - - transcription : "Dymos transcription object" (None) - advanced: an object providing the transcription technique of the - optimal control problem - - external_subsystems : Sequence["subsystem builder"] () - advanced - - meta_data : dict (<"builtin" meta data>) - advanced: meta data associated with variables in the Aviary data hierarchy - - default_name : str - class attribute: derived type customization point; the default value - for name - - default_ode_class : type - class attribute: derived type customization point; the default value - for ode_class used by build_phase - - default_meta_data : dict - class attribute: derived type customization point; the default value for - meta_data - - Methods - ------- - build_phase - make_default_transcription - validate_options - assign_default_options - ''' - # region : derived type customization points - __slots__ = () - - default_name = 'descent' - - # endregion : derived type customization points diff --git a/aviary/mission/flops_based/phases/energy_phase.py b/aviary/mission/flops_based/phases/energy_phase.py deleted file mode 100644 index 94ac79e4a..000000000 --- a/aviary/mission/flops_based/phases/energy_phase.py +++ /dev/null @@ -1,541 +0,0 @@ -from math import isclose - -import dymos as dm - -from aviary.mission.flops_based.phases.phase_builder_base import ( - register, PhaseBuilderBase, InitialGuessControl, InitialGuessParameter, - InitialGuessPolynomialControl, InitialGuessState, InitialGuessTime) - -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.variable_meta_data import _MetaData -from aviary.mission.flops_based.phases.phase_utils import add_subsystem_variables_to_phase, get_initial -from aviary.variable_info.variables import Dynamic - - -# TODO: support/handle the following in the base class -# - phase.set_time_options() -# - currently handled in level 3 interface implementation -# - self.external_subsystems -# - self.meta_data, with cls.default_meta_data customization point -class EnergyPhase(PhaseBuilderBase): - ''' - Define a phase builder base class for typical energy phases such as climb and - descent. - - Attributes - ---------- - name : str ('energy_phase') - object label - - subsystem_options (None) - dictionary of parameters to be passed to the subsystem builders - - user_options : AviaryValues () - state/path constraint values and flags - - supported options: - - num_segments : int (5) - transcription: number of segments - - order : int (3) - transcription: order of the state transcription; the order of the control - transcription is `order - 1` - - fix_initial : bool (True) - - fix_initial_time : bool (None) - - initial_ref : float (1.0, 's') - note: applied if, and only if, "fix_initial_time" is unspecified - - initial_bounds : pair ((0.0, 100.0) 's') - note: applied if, and only if, "fix_initial_time" is unspecified - - duration_ref : float (1.0, 's') - - duration_bounds : pair ((0.0, 100.0) 's') - - initial_altitude : float (0.0, 'ft) - starting true altitude from mean sea level - - final_altitude : float - ending true altitude from mean sea level - - initial_mach : float (0.0, 'ft) - starting Mach number - - final_mach : float - ending Mach number - - required_altitude_rate : float (None) - minimum avaliable climb rate - - no_climb : bool (False) - aircraft is not allowed to climb during phase - - no_descent : bool (False) - aircraft is not allowed to descend during phase - - fix_range : bool (False) - - input_initial : bool (False) - - polynomial_control_order : None or int - When set to an integer value, replace controls with - polynomial controls of that specified order. - - - initial_guesses : AviaryValues () - state/path beginning values to be set on the problem - - supported options: - - times - - range - - altitude - - velocity - - velocity_rate - - mass - - throttle - - ode_class : type (None) - advanced: the type of system defining the ODE - - transcription : "Dymos transcription object" (None) - advanced: an object providing the transcription technique of the - optimal control problem - - external_subsystems : Sequence["subsystem builder"] () - advanced - - meta_data : dict (<"builtin" meta data>) - advanced: meta data associated with variables in the Aviary data hierarchy - - default_name : str - class attribute: derived type customization point; the default value - for name - - default_ode_class : type - class attribute: derived type customization point; the default value - for ode_class used by build_phase - - default_meta_data : dict - class attribute: derived type customization point; the default value for - meta_data - - Methods - ------- - build_phase - make_default_transcription - validate_options - assign_default_options - ''' - __slots__ = ('external_subsystems', 'meta_data') - - # region : derived type customization points - _meta_data_ = {} - - _initial_guesses_meta_data_ = {} - - default_name = 'energy_phase' - - # default_ode_class = MissionODE - - default_meta_data = _MetaData - # endregion : derived type customization points - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, core_subsystems=core_subsystems, subsystem_options=subsystem_options, user_options=user_options, initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription) - - # TODO: support external_subsystems and meta_data in the base class - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - - def build_phase(self, aviary_options: AviaryValues = None): - ''' - Return a new energy phase for analysis using these constraints. - - If ode_class is None, default_ode_class is used. - - If transcription is None, the return value from calling - make_default_transcription is used. - - Parameters - ---------- - aviary_options : AviaryValues () - collection of Aircraft/Mission specific options - - Returns - ------- - dymos.Phase - ''' - phase: dm.Phase = super().build_phase(aviary_options) - - user_options: AviaryValues = self.user_options - - fix_initial = user_options.get_val('fix_initial') - initial_mach = user_options.get_val('initial_mach') - final_mach = user_options.get_val('final_mach') - initial_altitude = user_options.get_val('initial_altitude', 'm') - final_altitude = user_options.get_val('final_altitude', 'm') - no_descent = user_options.get_val('no_descent') - no_climb = user_options.get_val('no_climb') - fix_range = user_options.get_val('fix_range') - input_initial = user_options.get_val('input_initial') - polynomial_control_order = user_options.get_item('polynomial_control_order')[0] - num_engines = len(aviary_options.get_val('engine_models')) - - # NOTE currently defaulting to climb if altitudes match. Review at future date - climb = final_altitude >= initial_altitude - descent = initial_altitude > final_altitude - - max_altitude = max(initial_altitude, final_altitude) - min_altitude = min(initial_altitude, final_altitude) - max_mach = max(initial_mach, final_mach) - min_mach = min(initial_mach, final_mach) - - if climb: - lower_accel = 0.0 - else: - lower_accel = -2.12 - - if descent: - upper_accel = 0.0 - else: - upper_accel = 2.12 - - ############## - # Add States # - ############## - # TODO: critically think about how we should handle fix_initial and input_initial defaults. - # In keeping with Dymos standards, the default should be False instead of True. - - input_initial_alt = get_initial(input_initial, Dynamic.Mission.ALTITUDE) - fix_initial_alt = get_initial(fix_initial, Dynamic.Mission.ALTITUDE) - phase.add_state( - Dynamic.Mission.ALTITUDE, fix_initial=fix_initial_alt, fix_final=False, - lower=0.0, ref=1e4, defect_ref=1e4, units='m', - rate_source=Dynamic.Mission.ALTITUDE_RATE, targets=Dynamic.Mission.ALTITUDE, - input_initial=input_initial_alt - ) - - input_initial_vel = get_initial(input_initial, Dynamic.Mission.VELOCITY) - fix_initial_vel = get_initial(fix_initial, Dynamic.Mission.VELOCITY) - phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=fix_initial_vel, fix_final=False, - lower=0.0, ref=1e2, defect_ref=1e2, units='m/s', - rate_source=Dynamic.Mission.VELOCITY_RATE, targets=Dynamic.Mission.VELOCITY, - input_initial=input_initial_vel - ) - - input_initial_mass = get_initial(input_initial, Dynamic.Mission.MASS) - fix_initial_mass = get_initial(fix_initial, Dynamic.Mission.MASS, True) - - # Experiment: use a constraint for mass instead of connected initial. - # This is due to some problems in mpi. - # This is needed for the cutting edge full subsystem integration. - # TODO: when a Dymos fix is in and we've verified that full case works with the fix, - # remove this argument. - if user_options.get_val('add_initial_mass_constraint'): - phase.add_constraint('rhs_all.initial_mass_residual', equals=0.0, ref=1e4) - input_initial_mass = False - - phase.add_state( - Dynamic.Mission.MASS, fix_initial=fix_initial_mass, fix_final=False, - lower=0.0, ref=1e4, defect_ref=1e4, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - input_initial=input_initial_mass - ) - - input_initial_range = get_initial(input_initial, Dynamic.Mission.RANGE) - fix_initial_range = get_initial(fix_initial, Dynamic.Mission.RANGE, True) - phase.add_state( - Dynamic.Mission.RANGE, fix_initial=fix_initial_range, fix_final=fix_range, - lower=0.0, ref=1e6, defect_ref=1e6, units='m', - rate_source=Dynamic.Mission.RANGE_RATE, - input_initial=input_initial_range - ) - - phase = add_subsystem_variables_to_phase( - phase, self.name, self.external_subsystems) - - ################ - # Add Controls # - ################ - if polynomial_control_order is not None: - phase.add_polynomial_control( - Dynamic.Mission.VELOCITY_RATE, - targets=Dynamic.Mission.VELOCITY_RATE, units='m/s**2', - opt=True, lower=lower_accel, upper=upper_accel, - order=polynomial_control_order, - ) - else: - phase.add_control( - Dynamic.Mission.VELOCITY_RATE, - targets=Dynamic.Mission.VELOCITY_RATE, units='m/s**2', - opt=True, lower=lower_accel, upper=upper_accel - ) - - if num_engines > 0: - if polynomial_control_order is not None: - phase.add_polynomial_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', - opt=True, lower=0.0, upper=1.0, scaler=1, - order=polynomial_control_order, - ) - else: - phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', - opt=True, lower=0.0, upper=1.0, scaler=1, - ) - if climb: - phase.add_path_constraint( - Dynamic.Mission.THROTTLE, - upper=1.0, - ) - - if descent: - phase.add_path_constraint( - Dynamic.Mission.THROTTLE, - lower=0.0, - ) - - # check if engine has use_hybrid_throttle - engine_models = aviary_options.get_val('engine_models') - if any([engine.use_hybrid_throttle for engine in engine_models]): - if polynomial_control_order is not None: - phase.add_polynomial_control( - Dynamic.Mission.HYBRID_THROTTLE, - targets=Dynamic.Mission.HYBRID_THROTTLE, units='unitless', - opt=True, lower=0.0, upper=1.0, scaler=1, - order=polynomial_control_order, - ) - else: - phase.add_control( - Dynamic.Mission.HYBRID_THROTTLE, - targets=Dynamic.Mission.HYBRID_THROTTLE, units='unitless', - opt=True, lower=0.0, upper=1.0, scaler=1, - ) - - ################## - # Add Timeseries # - ################## - phase.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units='unitless' - ) - - phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' - ) - - phase.add_timeseries_output( - Dynamic.Mission.THRUST_MAX_TOTAL, - output_name=Dynamic.Mission.THRUST_MAX_TOTAL, units='lbf' - ) - - phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' - ) - - phase.add_timeseries_output( - Dynamic.Mission.SPECIFIC_ENERGY_RATE, - output_name=Dynamic.Mission.SPECIFIC_ENERGY_RATE, units='m/s' - ) - - phase.add_timeseries_output( - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, - output_name=Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, units='m/s' - ) - - phase.add_timeseries_output( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - output_name=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units='lbm/h' - ) - - phase.add_timeseries_output( - Dynamic.Mission.ALTITUDE_RATE, - output_name=Dynamic.Mission.ALTITUDE_RATE, units='ft/s' - ) - - phase.add_timeseries_output( - Dynamic.Mission.ALTITUDE_RATE_MAX, - output_name=Dynamic.Mission.ALTITUDE_RATE_MAX, units='ft/min' - ) - - ################### - # Add Constraints # - ################### - if climb and no_descent: - phase.add_path_constraint( - Dynamic.Mission.ALTITUDE_RATE, constraint_name='no_descent', - lower=0.0 - ) - - if descent and no_climb: - phase.add_path_constraint( - Dynamic.Mission.ALTITUDE_RATE, constraint_name='no_climb', - upper=0.0 - ) - - if descent and num_engines > 0: - phase.add_boundary_constraint( - Dynamic.Mission.THROTTLE, - loc='final', - upper=1.0, - lower=0.0, - units='unitless') - - required_altitude_rate, units = user_options.get_item('required_altitude_rate') - - if required_altitude_rate is not None: - phase.add_path_constraint( - Dynamic.Mission.ALTITUDE_RATE_MAX, - lower=required_altitude_rate, units=units - ) - - phase.add_boundary_constraint( - Dynamic.Mission.MACH, loc='final', equals=final_mach - ) - - if isclose(initial_mach, final_mach): - phase.add_path_constraint( - Dynamic.Mission.MACH, - equals=min_mach, units='unitless', - # ref=1.e4, - ) - - else: - phase.add_path_constraint( - Dynamic.Mission.MACH, - lower=min_mach, upper=max_mach, units='unitless', - # ref=1.e4, - ) - - # avoid scaling constraints by zero - ref = final_altitude - if ref == 0: - ref = None - - phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc='final', equals=final_altitude, ref=ref - ) - - # avoid scaling constraints by zero - ref = max_altitude - if ref == 0: - ref = None - - phase.add_path_constraint( - Dynamic.Mission.ALTITUDE, - lower=min_altitude, upper=max_altitude, - units='m', ref=ref - ) - - return phase - - def make_default_transcription(self): - ''' - Return a transcription object to be used by default in build_phase. - ''' - user_options = self.user_options - - num_segments, _ = user_options.get_item('num_segments') - order, _ = user_options.get_item('order') - - seg_ends, _ = dm.utils.lgl.lgl(num_segments + 1) - - transcription = dm.Radau( - num_segments=num_segments, order=order, compressed=True, - segment_ends=seg_ends) - - return transcription - - def _extra_ode_init_kwargs(self): - """ - Return extra kwargs required for initializing the ODE. - """ - # TODO: support external_subsystems and meta_data in the base class - return { - 'external_subsystems': self.external_subsystems, - 'meta_data': self.meta_data, - 'subsystem_options': self.subsystem_options, - } - - -EnergyPhase._add_meta_data( - 'num_segments', val=5, desc='transcription: number of segments') - -EnergyPhase._add_meta_data( - 'order', val=3, - desc='transcription: order of the state transcription; the order of the control' - ' transcription is `order - 1`') - -EnergyPhase._add_meta_data('add_initial_mass_constraint', val=False) - -EnergyPhase._add_meta_data('fix_initial', val=True) - -EnergyPhase._add_meta_data('fix_initial_time', val=None) - -EnergyPhase._add_meta_data('initial_ref', val=1., units='s') - -EnergyPhase._add_meta_data('initial_bounds', val=(0., 100.), units='s') - -EnergyPhase._add_meta_data('duration_ref', val=1., units='s') - -EnergyPhase._add_meta_data('duration_bounds', val=(0., 100.), units='s') - -EnergyPhase._add_meta_data('cruise_alt', val=11.e3, units='m') - -EnergyPhase._add_meta_data( - 'initial_altitude', val=0., units='m', - desc='starting true altitude from mean sea level') - -EnergyPhase._add_meta_data( - 'final_altitude', val=None, units='m', - desc='ending true altitude from mean sea level') - -EnergyPhase._add_meta_data('initial_mach', val=0., desc='starting Mach number') - -EnergyPhase._add_meta_data('final_mach', val=None, desc='ending Mach number') - -EnergyPhase._add_meta_data( - 'required_altitude_rate', val=None, units='m/s', - desc='minimum avaliable climb rate') - -EnergyPhase._add_meta_data( - 'no_climb', val=False, desc='aircraft is not allowed to climb during phase') - -EnergyPhase._add_meta_data( - 'no_descent', val=False, desc='aircraft is not allowed to descend during phase') - -EnergyPhase._add_meta_data('fix_range', val=False) - -EnergyPhase._add_meta_data('input_initial', val=False) - -EnergyPhase._add_meta_data('polynomial_control_order', val=None) - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessTime(), - desc='initial guess for initial time and duration specified as a tuple') - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('range'), - desc='initial guess for horizontal distance traveled') - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('altitude'), - desc='initial guess for vertical distances') - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('velocity'), - desc='initial guess for speed') - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessControl('velocity_rate'), - desc='initial guess for acceleration') - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('mass'), - desc='initial guess for mass') - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessControl('throttle'), - desc='initial guess for throttle') diff --git a/aviary/mission/flops_based/phases/phase_builder_base.py b/aviary/mission/flops_based/phases/phase_builder_base.py index b299689c5..0ff2b77f4 100644 --- a/aviary/mission/flops_based/phases/phase_builder_base.py +++ b/aviary/mission/flops_based/phases/phase_builder_base.py @@ -28,7 +28,7 @@ import numpy as np import openmdao.api as om -from aviary.mission.flops_based.ode.mission_ODE import MissionODE +from aviary.mission.flops_based.ode.simple_mission_ODE import MissionODE from aviary.utils.aviary_values import AviaryValues, get_keys _require_new_meta_data_class_attr_ = \ diff --git a/aviary/mission/flops_based/phases/simple_energy_phase.py b/aviary/mission/flops_based/phases/simple_energy_phase.py index 3514be333..8dd017613 100644 --- a/aviary/mission/flops_based/phases/simple_energy_phase.py +++ b/aviary/mission/flops_based/phases/simple_energy_phase.py @@ -16,6 +16,7 @@ # - currently handled in level 3 interface implementation # - self.external_subsystems # - self.meta_data, with cls.default_meta_data customization point +@register class EnergyPhase(PhaseBuilderBase): ''' A phase builder for a simple energy phase. @@ -98,7 +99,7 @@ class attribute: derived type customization point; the default value for _initial_guesses_meta_data_ = {} - default_name = 'energy_phase' + default_name = 'cruise' default_ode_class = MissionODE diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py index 090a26b9f..ee2c4c157 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py @@ -17,12 +17,8 @@ from openmdao.utils.testing_utils import require_pyoptsparse, use_tempdirs from packaging import version -from aviary.mission.flops_based.ode.mission_ODE import MissionODE from aviary.mission.flops_based.phases.build_landing import Landing from aviary.mission.flops_based.phases.build_takeoff import Takeoff -from aviary.mission.flops_based.phases.climb_phase import Climb -from aviary.mission.flops_based.phases.cruise_phase import Cruise -from aviary.mission.flops_based.phases.descent_phase import Descent from aviary.utils.functions import set_aviary_initial_values from aviary.utils.test_utils.assert_utils import warn_timeseries_near_equal from aviary.utils.functions import get_path diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py index 44bf01c3f..5c8214267 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py @@ -13,19 +13,13 @@ import scipy.constants as _units from openmdao.utils.assert_utils import assert_near_equal from openmdao.utils.testing_utils import use_tempdirs -from packaging import version -from aviary.mission.flops_based.ode.mission_ODE import MissionODE from aviary.mission.flops_based.phases.build_landing import Landing from aviary.mission.flops_based.phases.build_takeoff import Takeoff -from aviary.mission.flops_based.phases.climb_phase import Climb -from aviary.mission.flops_based.phases.cruise_phase import Cruise -from aviary.mission.flops_based.phases.descent_phase import Descent from aviary.subsystems.premission import CorePreMission from aviary.utils.aviary_values import AviaryValues from aviary.utils.functions import set_aviary_initial_values from aviary.utils.test_utils.assert_utils import warn_timeseries_near_equal -from aviary.utils.functions import get_path from aviary.validation_cases.validation_tests import get_flops_inputs, get_flops_outputs from aviary.variable_info.functions import setup_trajectory_params from aviary.utils.preprocessors import preprocess_options diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py index 124c64e5b..a81566387 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py @@ -13,17 +13,12 @@ import scipy.constants as _units from openmdao.utils.assert_utils import assert_near_equal from openmdao.utils.testing_utils import use_tempdirs -from packaging import version from aviary.mission.flops_based.phases.build_landing import Landing from aviary.mission.flops_based.phases.build_takeoff import Takeoff -from aviary.mission.flops_based.phases.climb_phase import Climb -from aviary.mission.flops_based.phases.cruise_phase import Cruise -from aviary.mission.flops_based.phases.descent_phase import Descent from aviary.utils.aviary_values import AviaryValues from aviary.utils.functions import set_aviary_initial_values from aviary.utils.test_utils.assert_utils import warn_timeseries_near_equal -from aviary.utils.functions import get_path from aviary.validation_cases.validation_tests import get_flops_inputs from aviary.variable_info.functions import setup_trajectory_params from aviary.variable_info.variables import Aircraft, Dynamic, 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 69600d000..c195cff92 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 @@ -16,9 +16,6 @@ from aviary.mission.flops_based.phases.build_landing import Landing from aviary.mission.flops_based.phases.build_takeoff import Takeoff -from aviary.mission.flops_based.phases.climb_phase import Climb -from aviary.mission.flops_based.phases.cruise_phase import Cruise -from aviary.mission.flops_based.phases.descent_phase import Descent from aviary.utils.functions import set_aviary_initial_values from aviary.utils.test_utils.assert_utils import warn_timeseries_near_equal from aviary.utils.functions import get_path From 46b74bf34e22cd39077ef79f87c6cbcfd2938b17 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 8 Jan 2024 20:32:41 -0600 Subject: [PATCH 020/188] Removed old FLOPS based L3 missions --- .../flops_based/phases/simple_energy_phase.py | 2 +- .../test_FLOPS_based_full_mission_N3CC.py | 709 ------------------ ...based_full_mission_large_single_aisle_1.py | 664 ---------------- ...based_full_mission_large_single_aisle_2.py | 701 ----------------- .../test_FLOPS_based_sizing_N3CC.py | 174 ++--- 5 files changed, 49 insertions(+), 2201 deletions(-) delete mode 100644 aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py delete mode 100644 aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py delete mode 100644 aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py diff --git a/aviary/mission/flops_based/phases/simple_energy_phase.py b/aviary/mission/flops_based/phases/simple_energy_phase.py index 8dd017613..6da23cbdb 100644 --- a/aviary/mission/flops_based/phases/simple_energy_phase.py +++ b/aviary/mission/flops_based/phases/simple_energy_phase.py @@ -373,7 +373,7 @@ def _extra_ode_init_kwargs(self): desc='transcription: order of the state transcription; the order of the control' ' transcription is `order - 1`') -EnergyPhase._add_meta_data('polynomial_control_order', val=None) +EnergyPhase._add_meta_data('polynomial_control_order', val=3) EnergyPhase._add_meta_data('use_polynomial_control', val=True) diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py deleted file mode 100644 index ee2c4c157..000000000 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py +++ /dev/null @@ -1,709 +0,0 @@ -''' -NOTES: -Includes: -Takeoff, Climb, Cruise, Descent, Landing -Computed Aero -N3CC data -''' -import unittest -import warnings - -import dymos as dm -import numpy as np -import openmdao.api as om -import scipy.constants as _units -from openmdao.core.driver import Driver -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import require_pyoptsparse, use_tempdirs -from packaging import version - -from aviary.mission.flops_based.phases.build_landing import Landing -from aviary.mission.flops_based.phases.build_takeoff import Takeoff -from aviary.utils.functions import set_aviary_initial_values -from aviary.utils.test_utils.assert_utils import warn_timeseries_near_equal -from aviary.utils.functions import get_path -from aviary.validation_cases.validation_tests import get_flops_inputs -from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Aircraft, Dynamic, Mission -from aviary.variable_info.variables_in import VariablesIn -from aviary.subsystems.premission import CorePreMission -from aviary.interface.default_phase_info.flops import default_premission_subsystems, default_mission_subsystems -from aviary.utils.preprocessors import preprocess_crewpayload -from aviary.utils.aviary_values import AviaryValues - - -# benchmark based on N3CC (fixed cruise alt) FLOPS model - - -def run_trajectory(driver: Driver, sim=True): - prob = om.Problem(model=om.Group()) - prob.driver = driver - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('N3CC') - - aviary_inputs.set_val( - Mission.Landing.LIFT_COEFFICIENT_MAX, 2.4, units='unitless') - aviary_inputs.set_val( - Mission.Takeoff.LIFT_COEFFICIENT_MAX, 2.0, units='unitless') - aviary_inputs.set_val( - Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT, val=.0175, - units='unitless') - - takeoff_fuel_burned = 577 # lbm TODO: where should this get connected from? - takeoff_thrust_per_eng = 24555.5 # lbf TODO: where should this get connected from? - takeoff_L_over_D = 17.35 # TODO: should this come from aero? - - aviary_inputs.set_val( - Mission.Takeoff.FUEL_SIMPLE, takeoff_fuel_burned, units='lbm') - aviary_inputs.set_val( - Mission.Takeoff.LIFT_OVER_DRAG, takeoff_L_over_D, units='unitless') - aviary_inputs.set_val( - Mission.Design.THRUST_TAKEOFF_PER_ENG, takeoff_thrust_per_eng, units='lbf') - - alt_airport = 0 # ft - cruise_mach = .785 - - alt_i_climb = 0*_units.foot # m - alt_f_climb = 35000.0*_units.foot # m - mass_i_climb = 131000*_units.lb # kg - mass_f_climb = 126000*_units.lb # kg - v_i_climb = 198.44*_units.knot # m/s - v_f_climb = 455.49*_units.knot # m/s - # initial mach set to lower value so it can intersect with takeoff end mach - # mach_i_climb = 0.3 - mach_i_climb = 0.2 - mach_f_climb = cruise_mach - range_i_climb = 0*_units.nautical_mile # m - range_f_climb = 160.3*_units.nautical_mile # m - t_i_climb = 2 * _units.minute # sec - t_f_climb = 26.20*_units.minute # sec - t_duration_climb = t_f_climb - t_i_climb - - alt_i_cruise = 35000*_units.foot # m - alt_f_cruise = 35000*_units.foot # m - alt_min_cruise = 35000*_units.foot # m - alt_max_cruise = 35000*_units.foot # m - mass_i_cruise = 126000*_units.lb # kg - mass_f_cruise = 102000*_units.lb # kg - v_i_cruise = 455.49*_units.knot # m/s - v_f_cruise = 455.49*_units.knot # m/s - mach_min_cruise = cruise_mach - mach_max_cruise = cruise_mach - range_i_cruise = 160.3*_units.nautical_mile # m - range_f_cruise = 3243.9*_units.nautical_mile # m - t_i_cruise = 26.20*_units.minute # sec - t_f_cruise = 432.38*_units.minute # sec - t_duration_cruise = t_f_cruise - t_i_cruise - - alt_i_descent = 35000*_units.foot - # final altitude set to 35 to ensure landing is feasible point - # alt_f_descent = 0*_units.foot - alt_f_descent = 35*_units.foot - v_i_descent = 455.49*_units.knot - v_f_descent = 198.44*_units.knot - mach_i_descent = cruise_mach - mach_f_descent = 0.3 - mass_i_descent = 102000*_units.pound - mass_f_descent = 101000*_units.pound - range_i_descent = 3243.9*_units.nautical_mile - range_f_descent = 3378.7*_units.nautical_mile - t_i_descent = 432.38*_units.minute - t_f_descent = 461.62*_units.minute - t_duration_descent = t_f_descent - t_i_descent - - ################## - # Define Phases # - ################## - - num_segments_climb = 6 - num_segments_cruise = 1 - num_segments_descent = 5 - - climb_seg_ends, _ = dm.utils.lgl.lgl(num_segments_climb + 1) - descent_seg_ends, _ = dm.utils.lgl.lgl(num_segments_descent + 1) - - transcription_climb = dm.Radau( - num_segments=num_segments_climb, order=3, compressed=True, - segment_ends=climb_seg_ends) - transcription_cruise = dm.Radau( - num_segments=num_segments_cruise, order=3, compressed=True) - transcription_descent = dm.Radau( - num_segments=num_segments_descent, order=3, compressed=True, - segment_ends=descent_seg_ends) - - takeoff_options = Takeoff( - airport_altitude=alt_airport, # ft - num_engines=aviary_inputs.get_val(Aircraft.Engine.NUM_ENGINES) - ) - - climb_options = Climb( - 'test_climb', - user_options=AviaryValues({ - 'initial_altitude': (alt_i_climb, 'm'), - 'final_altitude': (alt_f_climb, 'm'), - 'initial_mach': (mach_i_climb, 'unitless'), - 'final_mach': (mach_f_climb, 'unitless'), - 'fix_initial': (False, 'unitless'), - 'fix_range': (False, 'unitless'), - 'input_initial': (True, 'unitless'), - }), - core_subsystems=default_mission_subsystems, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - transcription=transcription_climb, - ) - - cruise_options = Cruise( - 'test_cruise', - user_options=AviaryValues({ - 'min_altitude': (alt_min_cruise, 'm'), - 'max_altitude': (alt_max_cruise, 'm'), - 'min_mach': (mach_min_cruise, 'unitless'), - 'max_mach': (mach_max_cruise, 'unitless'), - 'required_available_climb_rate': (300, 'ft/min'), - 'fix_initial': (False, 'unitless'), - 'fix_final': (False, 'unitless'), - }), - core_subsystems=default_mission_subsystems, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - transcription=transcription_cruise, - ) - - descent_options = Descent( - 'test_descent', - user_options=AviaryValues({ - 'final_altitude': (alt_f_descent, 'm'), - 'initial_altitude': (alt_i_descent, 'm'), - 'initial_mach': (mach_i_descent, 'unitless'), - 'final_mach': (mach_f_descent, 'unitless'), - 'fix_initial': (False, 'unitless'), - 'fix_range': (True, 'unitless'), - }), - core_subsystems=default_mission_subsystems, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - transcription=transcription_descent, - ) - - landing_options = Landing( - ref_wing_area=aviary_inputs.get_val(Aircraft.Wing.AREA, 'ft**2'), - Cl_max_ldg=aviary_inputs.get_val(Mission.Landing.LIFT_COEFFICIENT_MAX) - ) - - preprocess_crewpayload(aviary_inputs) - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'pre_mission', - CorePreMission(aviary_options=aviary_inputs, - subsystems=default_premission_subsystems), - promotes_inputs=['aircraft:*', 'mission:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - # directly connect phases (strong_couple = True), or use linkage constraints (weak - # coupling / strong_couple=False) - strong_couple = False - - takeoff = takeoff_options.build_phase(False) - - climb = climb_options.build_phase(aviary_options=aviary_inputs) - - cruise = cruise_options.build_phase(aviary_options=aviary_inputs) - - descent = descent_options.build_phase(aviary_options=aviary_inputs) - - landing = landing_options.build_phase(False) - - prob.model.add_subsystem( - 'takeoff', takeoff, promotes_inputs=['aircraft:*', 'mission:*'], - promotes_outputs=['mission:*']) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - # if fix_initial is false, can we always set input_initial to be true for - # necessary states, and then ignore if we use a linkage? - climb.set_time_options( - fix_initial=True, fix_duration=False, units='s', - duration_bounds=(1, t_duration_climb*2), duration_ref=t_duration_climb) - cruise.set_time_options( - fix_initial=False, fix_duration=False, units='s', - duration_bounds=(1, t_duration_cruise*2), duration_ref=t_duration_cruise) - descent.set_time_options( - fix_initial=False, fix_duration=False, units='s', - duration_bounds=(1, t_duration_descent*2), duration_ref=t_duration_descent) - - traj.add_phase('climb', climb) - - traj.add_phase('cruise', cruise) - - traj.add_phase('descent', descent) - - climb.timeseries_options['use_prefix'] = True - cruise.timeseries_options['use_prefix'] = True - descent.timeseries_options['use_prefix'] = True - - prob.model.add_subsystem( - 'landing', landing, promotes_inputs=['aircraft:*', 'mission:*'], - promotes_outputs=['mission:*']) - - traj.link_phases(["climb", "cruise"], ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple) - traj.link_phases(["cruise", "descent"], ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs) - - ################################## - # Connect in Takeoff and Landing # - ################################## - - prob.model.add_subsystem( - "takeoff_constraints", - om.ExecComp( - [ - "takeoff_mass_con=takeoff_mass-climb_start_mass", - "takeoff_range_con=takeoff_range-climb_start_range", - "takeoff_vel_con=takeoff_vel-climb_start_vel", - "takeoff_alt_con=takeoff_alt-climb_start_alt" - ], - takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'}, - climb_start_mass={'units': 'lbm'}, - takeoff_range_con={'units': 'ft'}, takeoff_range={'units': 'ft'}, - climb_start_range={'units': 'ft'}, - takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'}, - climb_start_vel={'units': 'm/s'}, - takeoff_alt_con={'units': 'ft'}, takeoff_alt={'units': 'ft'}, - climb_start_alt={'units': 'ft'} - ), - promotes_inputs=[ - ("takeoff_mass", Mission.Takeoff.FINAL_MASS), - ("takeoff_range", Mission.Takeoff.GROUND_DISTANCE), - ("takeoff_vel", Mission.Takeoff.FINAL_VELOCITY), - ("takeoff_alt", Mission.Takeoff.FINAL_ALTITUDE), - ], - promotes_outputs=["takeoff_mass_con", "takeoff_range_con", - "takeoff_vel_con", "takeoff_alt_con"], - ) - - prob.model.connect('traj.climb.states:mass', - 'takeoff_constraints.climb_start_mass', src_indices=[0]) - prob.model.connect('traj.climb.states:range', - 'takeoff_constraints.climb_start_range', src_indices=[0]) - prob.model.connect('traj.climb.states:velocity', - 'takeoff_constraints.climb_start_vel', src_indices=[0]) - prob.model.connect('traj.climb.states:altitude', - 'takeoff_constraints.climb_start_alt', src_indices=[0]) - - prob.model.connect(Mission.Takeoff.FINAL_MASS, - 'traj.climb.initial_states:mass') - prob.model.connect(Mission.Takeoff.GROUND_DISTANCE, - 'traj.climb.initial_states:range') - prob.model.connect(Mission.Takeoff.FINAL_VELOCITY, - 'traj.climb.initial_states:velocity') - prob.model.connect(Mission.Takeoff.FINAL_ALTITUDE, - 'traj.climb.initial_states:altitude') - - prob.model.connect('traj.descent.states:mass', - Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1]) - prob.model.connect('traj.descent.states:altitude', Mission.Landing.INITIAL_ALTITUDE, - src_indices=[-1]) - ########################## - # Add Objective Function # - ########################## - - # This is an example of a overall mission objective - # create a compound objective that minimizes climb time and maximizes final mass - # we are maxing final mass b/c we don't have an independent value for fuel_mass yet - # we are going to normalize these (makign each of the sub-objectives approx = 1 ) - prob.model.add_subsystem( - "regularization", - om.ExecComp( - # TODO: change the scaling on climb_duration - "reg_objective = - descent_mass_final/60000", - reg_objective=0.0, - descent_mass_final={"units": "kg", "shape": 1}, - ), - promotes_outputs=['reg_objective'] - ) - # connect the final mass from cruise into the objective - prob.model.connect("traj.descent.states:mass", - "regularization.descent_mass_final", src_indices=[-1]) - - prob.model.add_objective('reg_objective', ref=1) - - prob.model.add_subsystem( - 'input_sink', - VariablesIn(aviary_options=aviary_inputs), - promotes_inputs=['*'], - promotes_outputs=['*'] - ) - - # suppress warnings: - # "input variable '...' promoted using '*' was already promoted using 'aircraft:*' - with warnings.catch_warnings(): - - # Set initial default values for all LEAPS aircraft variables. - warnings.simplefilter("ignore", om.PromotionWarning) - set_aviary_initial_values(prob.model, aviary_inputs) - - warnings.simplefilter("ignore", om.PromotionWarning) - prob.setup() - - ########################################### - # Intial Settings for States and Controls # - ########################################### - - prob.set_val('traj.climb.t_initial', t_i_climb, units='s') - prob.set_val('traj.climb.t_duration', t_duration_climb, units='s') - - prob.set_val('traj.climb.states:altitude', climb.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m') - # prob.set_val( - # 'traj.climb.states:velocity', climb.interp(Dynamic.Mission.VELOCITY, ys=[170, v_f_climb]), - # units='m/s') - prob.set_val('traj.climb.states:velocity', climb.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s') - prob.set_val('traj.climb.states:mass', climb.interp( - Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') - prob.set_val('traj.climb.states:range', climb.interp( - Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') # nmi - - prob.set_val('traj.climb.controls:velocity_rate', - climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.0]), - units='m/s**2') - prob.set_val('traj.climb.controls:throttle', - climb.interp(Dynamic.Mission.THROTTLE, ys=[1.0, 1.0]), - units='unitless') - - prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s') - prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s') - - prob.set_val('traj.cruise.states:altitude', cruise.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m') - prob.set_val('traj.cruise.states:velocity', cruise.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s') - prob.set_val('traj.cruise.states:mass', cruise.interp( - Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi - - prob.set_val('traj.cruise.controls:velocity_rate', - cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), - units='m/s**2') - prob.set_val('traj.cruise.controls:throttle', - cruise.interp(Dynamic.Mission.THROTTLE, ys=[0.8, 0.75]), - units='unitless') - - prob.set_val('traj.descent.t_initial', t_i_descent, units='s') - prob.set_val('traj.descent.t_duration', t_duration_descent, units='s') - - prob.set_val('traj.descent.states:altitude', descent.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_descent, alt_f_descent]), units='m') - prob.set_val('traj.descent.states:velocity', descent.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_descent, v_f_descent]), units='m/s') - prob.set_val('traj.descent.states:mass', descent.interp( - Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') - prob.set_val('traj.descent.states:range', descent.interp( - Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m') - - prob.set_val('traj.descent.controls:velocity_rate', - descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.0]), - units='m/s**2') - prob.set_val('traj.descent.controls:throttle', - descent.interp(Dynamic.Mission.THROTTLE, ys=[0.0, 0.0]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=sim, make_plots=False, simulate_kwargs={ - 'times_per_seg': 100, 'atol': 1e-9, 'rtol': 1e-9}, - solution_record_file='N3CC_full_mission.db') - prob.record("final") - prob.cleanup() - - return prob - - -@use_tempdirs -class ProblemPhaseTestCase(unittest.TestCase): - @require_pyoptsparse(optimizer='SNOPT') - def bench_test_full_mission_N3CC_SNOPT(self): - driver = _make_driver_SNOPT() - - self._do_run(driver) - - def _do_run(self, driver): - prob = run_trajectory(driver=driver, sim=False) - - times_climb = prob.get_val('traj.climb.timeseries.time', units='s') - altitudes_climb = prob.get_val( - 'traj.climb.timeseries.states:altitude', units='m') - masses_climb = prob.get_val('traj.climb.timeseries.states:mass', units='kg') - ranges_climb = prob.get_val('traj.climb.timeseries.states:range', units='m') - velocities_climb = prob.get_val( - 'traj.climb.timeseries.states:velocity', units='m/s') - thrusts_climb = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N') - times_cruise = prob.get_val('traj.cruise.timeseries.time', units='s') - altitudes_cruise = prob.get_val( - 'traj.cruise.timeseries.states:altitude', units='m') - masses_cruise = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges_cruise = prob.get_val('traj.cruise.timeseries.states:range', units='m') - velocities_cruise = prob.get_val( - 'traj.cruise.timeseries.states:velocity', units='m/s') - thrusts_cruise = prob.get_val( - 'traj.cruise.timeseries.thrust_net_total', units='N') - times_descent = prob.get_val('traj.descent.timeseries.time', units='s') - altitudes_descent = prob.get_val( - 'traj.descent.timeseries.states:altitude', units='m') - masses_descent = prob.get_val('traj.descent.timeseries.states:mass', units='kg') - ranges_descent = prob.get_val('traj.descent.timeseries.states:range', units='m') - velocities_descent = prob.get_val( - 'traj.descent.timeseries.states:velocity', units='m/s') - thrusts_descent = prob.get_val( - 'traj.descent.timeseries.thrust_net_total', units='N') - - expected_times_s_climb = [[120.], [163.76276502], [224.14644864], [243.25767805], - [243.25767805], [336.40844168], [464.93748315], - [505.61648533], [505.61648533], [626.47047555], - [793.2243154], [846.00133557], [846.00133557], - [966.85532579], [1133.60916564], [1186.38618581], - [1186.38618581], [1279.53694944], [1408.06599092], - [1448.74499309], [1448.74499309], [1492.50775811], - [1552.89144173], [1572.00267114]] - expected_altitudes_m_climb = [[10.668], [0.], [490.31464488], [720.34099124], - [720.34099124], [2288.74497628], [4816.40500694], - [5464.87951761], [5464.87951761], [7025.37127556], - [8437.78568802], [8802.40370192], [8802.40370192], - [9511.72639581], [10229.15884616], [10382.97088649], - [10382.97088649], [10560.94435598], [10660.37367157], - [10668.], [10668.], [10668.], [10666.66785248], [10668.]] - expected_masses_kg_climb = [[58584.62973209], [58553.30079295], [58486.19463517], - [58461.90146352], [58461.90146352], [58339.61987692], - [58184.14978151], [58144.99942835], [58144.99942835], - [58041.54301581], [57927.14314383], [57894.10156256], - [57894.10156256], [57825.05181264], [57740.72348501], - [57716.38705856], [57716.38705856], [57675.62128122], - [57622.73581734], [57606.53973509], [57606.53973509], - [57589.20468199], [57563.40774787], [57554.3064769]] - expected_ranges_m_climb = [[1469.37868509], [5605.65587129], [13572.59161311], - [16576.93576947], [16576.93576947], [33254.75438651], - [59051.61685726], [67185.62511739], [67185.62511739], - [91756.36399005], [126369.47577928], [137576.80855552], - [137576.80855552], [163427.52300246], [199432.46291748], - [210871.48231952], [210871.48231952], [231238.09772766], - [259750.51731468], [268890.90216347], [268890.90216347], - [278771.58755554], [292561.32064207], [296983.91583583]] - expected_velocities_ms_climb = [[77.35938331], [111.19901718], [151.93398907], - [162.39904508], [162.39904508], [193.79386032], - [202.92916455], [202.83097007], [202.83097007], - [204.9548312], [211.13800405], [212.81677487], - [212.81677487], [215.00414951], [216.65184841], - [217.5075073], [217.5075073], [219.8725371], - [223.95818114], [225.18659652], [225.18659652], - [226.57877443], [230.5555138], [232.77530606]] - expected_thrusts_N_climb = [[50269.53763097], [89221.79391729], [105944.78221328], - [104742.61384096], [104742.61384096], [102539.17538465], - [80894.5840539], [74287.02308141], [74287.02308141], - [59565.00613161], [48715.65056776], [46229.53984695], - [46229.53984695], [41551.41074213], [35939.62791236], - [34345.57880903], [34345.57880903], [32008.34687504], - [29668.0461344], [29061.17556918], [29061.17556918], - [29571.25377648], [34034.12209303], [36366.13242869]] - - expected_times_s_cruise = [[1572.00267114], [10224.88157184], - [22164.08837724], [25942.80651013]] - expected_altitudes_m_cruise = [[10668.], [10668.], [10668.], [10668.]] - expected_masses_kg_cruise = [[57554.3064769], [54168.16865196], - [49649.4641858], [48253.00754766]] - expected_ranges_m_cruise = [[296983.91583583], [2311160.45023764], - [5090312.96846673], [5969905.23836297]] - expected_velocities_ms_cruise = [[232.77530606], [232.77530606], - [232.77530606], [232.77530606]] - expected_thrusts_N_cruise = [[28599.34059358], [27655.863514], - [26491.25212162], [26155.81047559]] - - expected_times_s_descent = [[25942.80651013], [26025.25799534], [26139.02421633], - [26175.0308363], [26175.0308363], [26343.42020448], - [26575.76316382], [26649.29891605], [26649.29891605], - [26849.49721425], [27125.73000473], [27213.15673846], - [27213.15673846], [27381.54610664], [27613.88906597], - [27687.4248182], [27687.4248182], [27769.8763034], - [27883.6425244], [27919.64914437]] - expected_altitudes_m_descent = [[10668.], [10668.], [10142.61136584], - [9909.20496834], [9909.20496834], [8801.80844468], - [7273.17347505], [6802.45633892], [6802.45633892], - [5619.8230507], [4125.52995372], [3659.42225117], - [3659.42225117], [2735.99340162], [1425.57947265], - [1009.41898888], [1009.41898888], [561.99822911], - [94.31876192], [10.668]] - expected_masses_kg_descent = [[48253.00754766], [48247.14199102], [48243.08209003], - [48242.16864984], [48242.16864984], [48239.38631749], - [48238.09565644], [48238.10218909], [48238.10218909], - [48238.36804678], [48235.32226181], [48232.28685278], - [48232.28685278], [48219.23890964], [48194.77880065], - [48187.10389371], [48187.10389371], [48177.71262482], - [48164.36107545], [48160.10979474]] - expected_ranges_m_descent = [[5969905.23836297], [5987568.57791473], [6008764.81422574], - [6015233.86544087], [6015233.86544087], [ - 6044198.03874828], - [6081891.04303138], [6093386.547795], [6093386.547795], - [6123061.7076624], [6160342.11821306], [ - 6171307.0346796], - [6171307.0346796], [6192171.51704849], [ - 6220846.02761427], - [6230014.04117231], [6230014.04117231], [ - 6240198.28047116], - [6253503.06775949], [6257352.4]] - expected_velocities_ms_descent = [[232.77530606], [198.63654674], [179.66599067], - [176.95296882], [176.95296882], [167.50327408], - [157.55154249], [154.07756214], [154.07756214], - [142.57898741], [127.86775289], [125.11330664], - [125.11330664], [123.46196696], [124.28423824], - [124.03136002], [124.03136002], [122.19127487], - [109.94487807], [102.07377559]] - expected_thrusts_N_descent = [[4470.16874641], [2769.62977465], [1516.11359849], - [1315.10754789], [1315.10754789], [652.82279778], - [47.57054754], [-2.66626679e-13], [0.], - [4.84263343e-14], [1.42410958e-14], [-2.42743721e-14], - [0.], [0.], [1.77638636e-13], [2.84958986e-13], - [-1.39722436e-13], [0.], [0.], [-5.27816527e-14]] - - expected_times_s_climb = np.array(expected_times_s_climb) - expected_altitudes_m_climb = np.array(expected_altitudes_m_climb) - expected_masses_kg_climb = np.array(expected_masses_kg_climb) - expected_ranges_m_climb = np.array(expected_ranges_m_climb) - expected_velocities_ms_climb = np.array(expected_velocities_ms_climb) - expected_thrusts_N_climb = np.array(expected_thrusts_N_climb) - - expected_times_s_cruise = np.array(expected_times_s_cruise) - expected_altitudes_m_cruise = np.array(expected_altitudes_m_cruise) - expected_masses_kg_cruise = np.array(expected_masses_kg_cruise) - expected_ranges_m_cruise = np.array(expected_ranges_m_cruise) - expected_velocities_ms_cruise = np.array(expected_velocities_ms_cruise) - expected_thrusts_N_cruise = np.array(expected_thrusts_N_cruise) - - expected_times_s_descent = np.array(expected_times_s_descent) - expected_altitudes_m_descent = np.array(expected_altitudes_m_descent) - expected_masses_kg_descent = np.array(expected_masses_kg_descent) - expected_ranges_m_descent = np.array(expected_ranges_m_descent) - expected_velocities_ms_descent = np.array(expected_velocities_ms_descent) - expected_thrusts_N_descent = np.array(expected_thrusts_N_descent) - - # Check Objective and other key variables to a reasonably tight tolerance. - - rtol = 1e-2 - - # Mass at the end of Descent - assert_near_equal(masses_descent[-1], - expected_masses_kg_descent[-1], tolerance=rtol) - - # Range at the end of Descent - assert_near_equal(ranges_descent[-1], - expected_ranges_m_descent[-1], tolerance=rtol) - - # Flight time - assert_near_equal(times_descent[-1], - expected_times_s_descent[-1], tolerance=rtol) - - # Check mission values. - - # NOTE rtol = 0.05 = 5% different from truth (first timeseries) - # atol = 2 = no more than +/-2 meter/second/kg difference between values - # atol_altitude - 30 ft. There is occasional time-shifting with the N3CC - # model during climb and descent so we need a looser - # absolute tolerance for the points near the ground. - rtol = .05 - atol = 2.0 - atol_altitude = 30.0 - - # FLIGHT PATH - # CLIMB - warn_timeseries_near_equal( - times_climb, altitudes_climb, expected_times_s_climb, - expected_altitudes_m_climb, abs_tolerance=atol_altitude, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_climb, masses_climb, expected_times_s_climb, - expected_masses_kg_climb, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_climb, ranges_climb, expected_times_s_climb, - expected_ranges_m_climb, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_climb, velocities_climb, expected_times_s_climb, - expected_velocities_ms_climb, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_climb, thrusts_climb, expected_times_s_climb, - expected_thrusts_N_climb, abs_tolerance=atol, rel_tolerance=rtol) - - # CRUISE - warn_timeseries_near_equal( - times_cruise, altitudes_cruise, expected_times_s_cruise, - expected_altitudes_m_cruise, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_cruise, masses_cruise, expected_times_s_cruise, - expected_masses_kg_cruise, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_cruise, ranges_cruise, expected_times_s_cruise, - expected_ranges_m_cruise, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_cruise, velocities_cruise, expected_times_s_cruise, - expected_velocities_ms_cruise, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_cruise, thrusts_cruise, expected_times_s_cruise, - expected_thrusts_N_cruise, abs_tolerance=atol, rel_tolerance=rtol) - - # DESCENT - warn_timeseries_near_equal( - times_descent, altitudes_descent, expected_times_s_descent, - expected_altitudes_m_descent, abs_tolerance=atol_altitude, - rel_tolerance=rtol) - warn_timeseries_near_equal( - times_descent, masses_descent, expected_times_s_descent, - expected_masses_kg_descent, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_descent, ranges_descent, expected_times_s_descent, - expected_ranges_m_descent, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_descent, velocities_descent, expected_times_s_descent, - expected_velocities_ms_descent, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_descent, thrusts_descent, expected_times_s_descent, - expected_thrusts_N_descent, abs_tolerance=atol, rel_tolerance=rtol) - - -def _make_driver_IPOPT() -> Driver: - driver = om.pyOptSparseDriver(optimizer='IPOPT') - - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-3 - driver.opt_settings['print_level'] = 4 - - return driver - - -def _make_driver_SNOPT() -> Driver: - driver = om.pyOptSparseDriver(optimizer='SNOPT') - - driver.opt_settings["Major iterations limit"] = 45 - driver.opt_settings["Major optimality tolerance"] = 1e-4 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - - return driver - - -def _make_driver_SLSQP() -> Driver: - driver = om.ScipyOptimizeDriver(optimizer='SLSQP') - - driver.opt_settings['maxiter'] = 100 - driver.opt_settings['ftol'] = 5.0e-3 - driver.opt_settings['eps'] = 1e-2 - - return driver - - -if __name__ == '__main__': - temp = ProblemPhaseTestCase() - temp.bench_test_full_mission_N3CC_SNOPT() diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py deleted file mode 100644 index 5c8214267..000000000 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py +++ /dev/null @@ -1,664 +0,0 @@ -''' -NOTES: -Includes: -Takeoff, Climb, Cruise, Descent, Landing -Computed Aero -Large Single Aisle 1 data -''' -import unittest - -import dymos as dm -import numpy as np -import openmdao.api as om -import scipy.constants as _units -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import use_tempdirs - -from aviary.mission.flops_based.phases.build_landing import Landing -from aviary.mission.flops_based.phases.build_takeoff import Takeoff -from aviary.subsystems.premission import CorePreMission -from aviary.utils.aviary_values import AviaryValues -from aviary.utils.functions import set_aviary_initial_values -from aviary.utils.test_utils.assert_utils import warn_timeseries_near_equal -from aviary.validation_cases.validation_tests import get_flops_inputs, get_flops_outputs -from aviary.variable_info.functions import setup_trajectory_params -from aviary.utils.preprocessors import preprocess_options -from aviary.variable_info.variables import Aircraft, Dynamic, Mission -from aviary.variable_info.variables_in import VariablesIn -from aviary.interface.default_phase_info.flops import default_premission_subsystems, default_mission_subsystems - -try: - import pyoptsparse -except ImportError: - pyoptsparse = None - -# benchmark based on large single aisle 1 (fixed cruise alt) FLOPS model - - -def run_trajectory(sim=True): - prob = om.Problem() - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - # driver.declare_coloring() # currently disabled pending resolve of issue 2507 - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 45 - driver.opt_settings["Major optimality tolerance"] = 1e-4 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-3 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle1FLOPS') - aviary_outputs = get_flops_outputs('LargeSingleAisle1FLOPS') - - preprocess_options(aviary_inputs) - - alt_airport = 0 # ft - - alt_i_climb = 0*_units.foot # m - alt_f_climb = 35000.0*_units.foot # m - mass_i_climb = 180623*_units.lb # kg - mass_f_climb = 176765*_units.lb # kg - v_i_climb = 198.44*_units.knot # m/s - v_f_climb = 455.49*_units.knot # m/s - # initial mach set to lower value so it can intersect with takeoff end mach - # mach_i_climb = 0.3 - mach_i_climb = 0.2 - mach_f_climb = 0.79 - range_i_climb = 0*_units.nautical_mile # m - range_f_climb = 160.3*_units.nautical_mile # m - t_i_climb = 2 * _units.minute # sec - t_f_climb = 26.20*_units.minute # sec - t_duration_climb = t_f_climb - t_i_climb - - alt_i_cruise = 35000*_units.foot # m - alt_f_cruise = 35000*_units.foot # m - alt_min_cruise = 35000*_units.foot # m - alt_max_cruise = 35000*_units.foot # m - mass_i_cruise = 176765*_units.lb # kg - mass_f_cruise = 143521*_units.lb # kg - v_i_cruise = 455.49*_units.knot # m/s - v_f_cruise = 455.49*_units.knot # m/s - # mach_i_cruise = 0.79 - # mach_f_cruise = 0.79 - mach_min_cruise = 0.79 - mach_max_cruise = 0.79 - range_i_cruise = 160.3*_units.nautical_mile # m - range_f_cruise = 3243.9*_units.nautical_mile # m - t_i_cruise = 26.20*_units.minute # sec - t_f_cruise = 432.38*_units.minute # sec - t_duration_cruise = t_f_cruise - t_i_cruise - - alt_i_descent = 35000*_units.foot - # final altitude set to 35 to ensure landing is feasible point - # alt_f_descent = 0*_units.foot - alt_f_descent = 35*_units.foot - v_i_descent = 455.49*_units.knot - v_f_descent = 198.44*_units.knot - mach_i_descent = 0.79 - mach_f_descent = 0.3 - mass_i_descent = 143521*_units.pound - mass_f_descent = 143035*_units.pound - range_i_descent = 3243.9*_units.nautical_mile - range_f_descent = 3378.7*_units.nautical_mile - t_i_descent = 432.38*_units.minute - t_f_descent = 461.62*_units.minute - t_duration_descent = t_f_descent - t_i_descent - - ################## - # Define Phases # - ################## - - num_segments_climb = 6 - num_segments_cruise = 1 - num_segments_descent = 5 - - climb_seg_ends, _ = dm.utils.lgl.lgl(num_segments_climb + 1) - descent_seg_ends, _ = dm.utils.lgl.lgl(num_segments_descent + 1) - - transcription_climb = dm.Radau( - num_segments=num_segments_climb, order=3, compressed=True, - segment_ends=climb_seg_ends) - transcription_cruise = dm.Radau( - num_segments=num_segments_cruise, order=3, compressed=True) - transcription_descent = dm.Radau( - num_segments=num_segments_descent, order=3, compressed=True, - segment_ends=descent_seg_ends) - - takeoff_options = Takeoff( - airport_altitude=alt_airport, # ft - num_engines=aviary_inputs.get_val(Aircraft.Engine.NUM_ENGINES) - ) - - climb_options = Climb( - 'test_climb', - user_options=AviaryValues({ - 'initial_altitude': (alt_i_climb, 'm'), - 'final_altitude': (alt_f_climb, 'm'), - 'initial_mach': (mach_i_climb, 'unitless'), - 'final_mach': (mach_f_climb, 'unitless'), - 'fix_initial': (False, 'unitless'), - 'fix_range': (False, 'unitless'), - 'input_initial': (True, 'unitless'), - }), - core_subsystems=default_mission_subsystems, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - transcription=transcription_climb, - ) - - cruise_options = Cruise( - 'test_cruise', - user_options=AviaryValues({ - 'min_altitude': (alt_min_cruise, 'm'), - 'max_altitude': (alt_max_cruise, 'm'), - 'min_mach': (mach_min_cruise, 'unitless'), - 'max_mach': (mach_max_cruise, 'unitless'), - 'required_available_climb_rate': (300, 'ft/min'), - 'fix_initial': (False, 'unitless'), - 'fix_final': (False, 'unitless'), - }), - core_subsystems=default_mission_subsystems, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - transcription=transcription_cruise, - ) - - descent_options = Descent( - 'test_descent', - user_options=AviaryValues({ - 'final_altitude': (alt_f_descent, 'm'), - 'initial_altitude': (alt_i_descent, 'm'), - 'initial_mach': (mach_i_descent, 'unitless'), - 'final_mach': (mach_f_descent, 'unitless'), - 'fix_initial': (False, 'unitless'), - 'fix_range': (True, 'unitless'), - }), - core_subsystems=default_mission_subsystems, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - transcription=transcription_descent, - ) - - landing_options = Landing( - ref_wing_area=aviary_inputs.get_val(Aircraft.Wing.AREA, 'ft**2'), - Cl_max_ldg=aviary_inputs.get_val(Mission.Landing.LIFT_COEFFICIENT_MAX) - ) - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'pre_mission', - CorePreMission(aviary_options=aviary_inputs, - subsystems=default_premission_subsystems), - promotes_inputs=['aircraft:*', 'mission:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - # directly connect phases (strong_couple = True), or use linkage constraints (weak - # coupling / strong_couple=False) - strong_couple = False - - takeoff = takeoff_options.build_phase(False) - - climb = climb_options.build_phase(aviary_options=aviary_inputs) - - cruise = cruise_options.build_phase(aviary_options=aviary_inputs) - - descent = descent_options.build_phase(aviary_options=aviary_inputs) - - landing = landing_options.build_phase(False) - - prob.model.add_subsystem( - 'takeoff', takeoff, promotes_inputs=['aircraft:*', 'mission:*'], - promotes_outputs=['mission:*']) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - # if fix_initial is false, can we always set input_initial to be true for - # necessary states, and then ignore if we use a linkage? - climb.set_time_options( - fix_initial=True, fix_duration=False, units='s', - duration_bounds=(1, t_duration_climb*2), duration_ref=t_duration_climb) - cruise.set_time_options( - fix_initial=False, fix_duration=False, units='s', - duration_bounds=(1, t_duration_cruise*2), duration_ref=t_duration_cruise) - descent.set_time_options( - fix_initial=False, fix_duration=False, units='s', - duration_bounds=(1, t_duration_descent*2), duration_ref=t_duration_descent) - - traj.add_phase('climb', climb) - - traj.add_phase('cruise', cruise) - - traj.add_phase('descent', descent) - - climb.timeseries_options['use_prefix'] = True - cruise.timeseries_options['use_prefix'] = True - descent.timeseries_options['use_prefix'] = True - - prob.model.add_subsystem( - 'landing', landing, promotes_inputs=['aircraft:*', 'mission:*'], - promotes_outputs=['mission:*']) - - traj.link_phases(["climb", "cruise"], ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple) - traj.link_phases(["cruise", "descent"], ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs) - - ################################## - # Connect in Takeoff and Landing # - ################################## - - prob.model.add_subsystem( - "takeoff_constraints", - om.ExecComp( - [ - "takeoff_mass_con=takeoff_mass-climb_start_mass", - "takeoff_range_con=takeoff_range-climb_start_range", - "takeoff_vel_con=takeoff_vel-climb_start_vel", - "takeoff_alt_con=takeoff_alt-climb_start_alt" - ], - takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'}, - climb_start_mass={'units': 'lbm'}, - takeoff_range_con={'units': 'ft'}, takeoff_range={'units': 'ft'}, - climb_start_range={'units': 'ft'}, - takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'}, - climb_start_vel={'units': 'm/s'}, - takeoff_alt_con={'units': 'ft'}, takeoff_alt={'units': 'ft'}, - climb_start_alt={'units': 'ft'} - ), - promotes_inputs=[ - ("takeoff_mass", Mission.Takeoff.FINAL_MASS), - ("takeoff_range", Mission.Takeoff.GROUND_DISTANCE), - ("takeoff_vel", Mission.Takeoff.FINAL_VELOCITY), - ("takeoff_alt", Mission.Takeoff.FINAL_ALTITUDE), - ], - promotes_outputs=["takeoff_mass_con", "takeoff_range_con", - "takeoff_vel_con", "takeoff_alt_con"], - ) - - prob.model.connect('traj.climb.states:mass', - 'takeoff_constraints.climb_start_mass', src_indices=[0]) - prob.model.connect('traj.climb.states:range', - 'takeoff_constraints.climb_start_range', src_indices=[0]) - prob.model.connect('traj.climb.states:velocity', - 'takeoff_constraints.climb_start_vel', src_indices=[0]) - prob.model.connect('traj.climb.states:altitude', - 'takeoff_constraints.climb_start_alt', src_indices=[0]) - - prob.model.connect(Mission.Takeoff.FINAL_MASS, - 'traj.climb.initial_states:mass') - prob.model.connect(Mission.Takeoff.GROUND_DISTANCE, - 'traj.climb.initial_states:range') - prob.model.connect(Mission.Takeoff.FINAL_VELOCITY, - 'traj.climb.initial_states:velocity') - prob.model.connect(Mission.Takeoff.FINAL_ALTITUDE, - 'traj.climb.initial_states:altitude') - - prob.model.connect('traj.descent.states:mass', - Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1]) - prob.model.connect('traj.descent.states:altitude', Mission.Landing.INITIAL_ALTITUDE, - src_indices=[-1]) - - ########################## - # Add Objective Function # - ########################## - - # This is an example of a overall mission objective - # create a compound objective that minimizes climb time and maximizes final mass - # we are maxing final mass b/c we don't have an independent value for fuel_mass yet - # we are going to normalize these (makign each of the sub-objectives approx = 1 ) - prob.model.add_subsystem( - "regularization", - om.ExecComp( - # TODO: change the scaling on climb_duration - "reg_objective = - descent_mass_final/60000", - reg_objective=0.0, - descent_mass_final={"units": "kg", "shape": 1}, - ), - promotes_outputs=['reg_objective'] - ) - # connect the final mass from cruise into the objective - prob.model.connect("traj.descent.states:mass", - "regularization.descent_mass_final", src_indices=[-1]) - - prob.model.add_objective('reg_objective', ref=1) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - - # TODO: Why is this in outputs and not inputs? - key = Aircraft.Engine.THRUST_REVERSERS_MASS - val, units = aviary_outputs.get_item(key) - prob.model.set_input_defaults(key, val, units) - - prob.model.add_subsystem( - 'input_sink', - VariablesIn(aviary_options=aviary_inputs), - promotes_inputs=['*'], - promotes_outputs=['*'] - ) - - prob.setup() - - ########################################### - # Intial Settings for States and Controls # - ########################################### - - prob.set_val('traj.climb.t_initial', t_i_climb, units='s') - prob.set_val('traj.climb.t_duration', t_duration_climb, units='s') - - prob.set_val('traj.climb.states:altitude', climb.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m') - # prob.set_val( - # 'traj.climb.states:velocity', climb.interp(Dynamic.Mission.VELOCITY, ys=[170, v_f_climb]), - # units='m/s') - prob.set_val('traj.climb.states:velocity', climb.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s') - prob.set_val('traj.climb.states:mass', climb.interp( - Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') - prob.set_val('traj.climb.states:range', climb.interp( - Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') # nmi - - prob.set_val('traj.climb.controls:velocity_rate', - climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.05]), - units='m/s**2') - prob.set_val('traj.climb.controls:throttle', - climb.interp(Dynamic.Mission.THROTTLE, ys=[0.5, 0.5]), - units='unitless') - - prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s') - prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s') - - prob.set_val('traj.cruise.states:altitude', cruise.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m') - prob.set_val('traj.cruise.states:velocity', cruise.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s') - prob.set_val('traj.cruise.states:mass', cruise.interp( - Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi - - prob.set_val('traj.cruise.controls:velocity_rate', - cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), - units='m/s**2') - prob.set_val('traj.cruise.controls:throttle', - cruise.interp(Dynamic.Mission.THROTTLE, ys=[0.5, 0.5]), - units='unitless') - - prob.set_val('traj.descent.t_initial', t_i_descent, units='s') - prob.set_val('traj.descent.t_duration', t_duration_descent, units='s') - - prob.set_val('traj.descent.states:altitude', descent.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_descent, alt_f_descent]), units='m') - prob.set_val('traj.descent.states:velocity', descent.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_descent, v_f_descent]), units='m/s') - prob.set_val('traj.descent.states:mass', descent.interp( - Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') - prob.set_val('traj.descent.states:range', descent.interp( - Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m') - - prob.set_val('traj.descent.controls:velocity_rate', - descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.05]), - units='m/s**2') - prob.set_val('traj.descent.controls:throttle', - descent.interp(Dynamic.Mission.THROTTLE, ys=[0.0, 0.0]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=sim, make_plots=False, simulate_kwargs={ - 'times_per_seg': 100, 'atol': 1e-9, 'rtol': 1e-9}, - solution_record_file='large_single_aisle_1_solution.db') - prob.record("final") - prob.cleanup() - - return prob - - -@use_tempdirs -class ProblemPhaseTestCase(unittest.TestCase): - def bench_test_full_mission_large_single_aisle_1(self): - - prob = run_trajectory(sim=False) - - times_climb = prob.get_val('traj.climb.timeseries.time', units='s') - altitudes_climb = prob.get_val( - 'traj.climb.timeseries.states:altitude', units='m') - masses_climb = prob.get_val('traj.climb.timeseries.states:mass', units='kg') - ranges_climb = prob.get_val('traj.climb.timeseries.states:range', units='m') - velocities_climb = prob.get_val( - 'traj.climb.timeseries.states:velocity', units='m/s') - thrusts_climb = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N') - times_cruise = prob.get_val('traj.cruise.timeseries.time', units='s') - altitudes_cruise = prob.get_val( - 'traj.cruise.timeseries.states:altitude', units='m') - masses_cruise = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges_cruise = prob.get_val('traj.cruise.timeseries.states:range', units='m') - velocities_cruise = prob.get_val( - 'traj.cruise.timeseries.states:velocity', units='m/s') - thrusts_cruise = prob.get_val( - 'traj.cruise.timeseries.thrust_net_total', units='N') - times_descent = prob.get_val('traj.descent.timeseries.time', units='s') - altitudes_descent = prob.get_val( - 'traj.descent.timeseries.states:altitude', units='m') - masses_descent = prob.get_val('traj.descent.timeseries.states:mass', units='kg') - ranges_descent = prob.get_val('traj.descent.timeseries.states:range', units='m') - velocities_descent = prob.get_val( - 'traj.descent.timeseries.states:velocity', units='m/s') - thrusts_descent = prob.get_val( - 'traj.descent.timeseries.thrust_net_total', units='N') - - expected_times_s_climb = [ - [120.], [163.76325456], [224.14761365], [243.25905685], - [243.25905685], [336.41086249], [464.94134172], [505.62079895], - [505.62079895], [626.47614107], [793.23184628], [846.00945683], - [846.00945683], [966.86479896], [1133.62050417], [1186.39811471], - [1186.39811471], [1279.54992036], [1408.08039959], [1448.75985682], - [1448.75985682], [1492.52311138], [1552.90747047], [1572.01891366]] - expected_altitudes_m_climb = [ - [10.668], [0.], [1014.96376993], [1474.88490893], - [1474.88490893], [3450.8992731], [5549.58991137], [6073.60289567], - [6073.60289567], [7247.65102441], [8313.09660771], [8596.21261844], - [8596.21261844], [9175.1805832], [9807.17741861], [9956.37909202], - [9956.37909202], [10156.95278577], [10387.66964669], [10469.50089961], - [10469.50089961], [10565.21436037], [10659.11220277], [10668.]] - expected_masses_kg_climb = [ - [81929.21464651], [81845.89383716], [81698.07677997], [81651.72896811], - [81651.72896811], [81451.5201184], [81238.04517346], [81180.70309604], - [81180.70309604], [81030.90916993], [80852.63402635], [80799.37995098], - [80799.37995098], [80685.66441919], [80541.42480306], [80497.91293126], - [80497.91293126], [80422.58418106], [80320.79494098], [80289.0126768], - [80289.0126768], [80255.43650168], [80209.81935885], [80195.47487578]] - expected_ranges_m_climb = [ - [2023.13728418], [7309.29529844], [17625.33986498], [21042.26607802], - [21042.26607802], [38595.24976097], [63501.20931809], [71333.49759313], - [71333.49759313], [95066.70557732], [129238.42790298], [140520.59490531], - [140520.59490531], [166712.77513886], [203467.60377384], [215173.95317494], - [215173.95317494], [236133.6275649], [265602.08094631], [275049.96491681], - [275049.96491681], [285205.23036747], [299246.15306878], [303707.66300732]] - expected_velocities_ms_climb = [ - [86.27497122], [150.21937278], [181.89204952], [185.19401741], - [185.19401741], [193.05567218], [193.94250629], [194.2274308], - [194.2274308], [199.49589035], [211.4364855], [214.57351446], - [214.57351446], [218.7009295], [221.65884364], [223.09827293], - [223.09827293], [226.88054212], [231.57590395], [232.11980164], - [232.11980164], [232.10881873], [233.15980248], [234.25795132]] - expected_thrusts_N_climb = [ - [132715.85627327], [165245.22863773], [167448.73291722], [160900.8406642], - [160900.8406642], [127136.48651829], [98045.08452667], [90929.93404254], - [90929.93404254], [77481.47159379], [66945.17202854], [64341.32162839], - [64341.32162839], [59055.89956031], [54151.63303545], [53020.95829213], - [53020.95829213], [51622.0422889], [50045.94083626], [49417.41803104], - [49417.41803104], [48644.32827828], [47944.25167088], [47933.1465328]] - - expected_times_s_cruise = [[1572.01891366], [ - 10224.87387308], [22164.04764439], [25942.75532212]] - expected_altitudes_m_cruise = [[10668.], [10668.], [10668.], [10668.]] - expected_masses_kg_cruise = [[80195.47487578], [ - 74629.35731156], [67375.28255861], [65172.93890147]] - expected_ranges_m_cruise = [[303707.66300732], [ - 2330707.73887436], [5127554.12700399], [6012746.44622707]] - expected_velocities_ms_cruise = [[234.25795132], [ - 234.25795132], [234.25795132], [234.25795132]] - expected_thrusts_N_cruise = [[41824.96226832], [ - 39641.43620269], [36936.34901257], [36154.52769977]] - - expected_times_s_descent = [ - [25942.75532212], [26006.65447531], [26094.82226471], [26122.72706861], - [26122.72706861], [26253.22730164], [26433.29098775], [26490.28052876], - [26490.28052876], [26645.43239405], [26859.51030121], [26927.26522688], - [26927.26522688], [27057.76545992], [27237.82914603], [27294.81868703], - [27294.81868703], [27358.71784022], [27446.88562963], [27474.79043352]] - expected_altitudes_m_descent = [ - [1.06680000e+04], [1.06680000e+04], [1.01870034e+04], [9.98295734e+03], - [9.98295734e+03], [8.97976640e+03], [7.54858109e+03], [7.09637574e+03], - [7.09637574e+03], [5.88591590e+03], [4.22625069e+03], [3.69222380e+03], - [3.69222380e+03], [2.61250549e+03], [1.13888643e+03], [7.11625616e+02], - [7.11625616e+02], [3.06900655e+02], [1.06680000e+01], [1.06680000e+01]] - expected_masses_kg_descent = [ - [65172.93890147], [65166.80185527], [65159.70921571], [65157.42471584], - [65157.42471584], [65146.76382877], [65130.82732956], [65125.34524899], - [65125.34524899], [65109.28561058], [65083.64486622], [65074.44308601], - [65074.44308601], [65054.73517647], [65022.79856574], [65011.43379965], - [65011.43379965], [64998.13023434], [64979.19121811], [64973.1898506]] - expected_ranges_m_descent = [ - [6012746.44622707], [6026563.35875724], [6043156.61719684], - [6048186.41354773], [6048186.41354773], [6070643.2394269], - [6100144.8206876], [6109350.83226072], [6109350.83226072], - [6133985.78349596], [6167266.64464002], [6177671.71555852], - [6177671.71555852], [6197775.49290063], [6225243.66498946], - [6233748.78818454], [6233748.78818454], [6242933.61721041], - [6254285.51733338], [6257352.4]] - expected_velocities_ms_descent = [ - [234.25795132], [200.84994317], [180.71529791], [177.55751262], - [177.55751262], [167.72481926], [161.81636181], [160.6651682], - [160.6651682], [157.4025997], [154.14780084], [153.88934075], - [153.88934075], [154.23063023], [150.48828108], [146.76095672], - [146.76095672], [139.54419751], [115.31288595], [102.07377559]] - expected_thrusts_N_descent = [ - [0.00000000e+00], [8.47474799e-13], [1.05910816e-13], [-6.67104835e-13], - [0.00000000e+00], [2.74056170e-13], [6.93382542e-13], [8.33653923e-13], - [0.00000000e+00], [4.66122489e-14], [-1.43628962e-13], [-2.96621357e-13], - [0.00000000e+00], [0.00000000e+00], [-1.18597257e-14], [-1.95075855e-14], - [-9.53501847e-15], [0.00000000e+00], [0.00000000e+00], [-3.72692384e-15]] - - expected_times_s_climb = np.array(expected_times_s_climb) - expected_altitudes_m_climb = np.array(expected_altitudes_m_climb) - expected_masses_kg_climb = np.array(expected_masses_kg_climb) - expected_ranges_m_climb = np.array(expected_ranges_m_climb) - expected_velocities_ms_climb = np.array(expected_velocities_ms_climb) - expected_thrusts_N_climb = np.array(expected_thrusts_N_climb) - - expected_times_s_cruise = np.array(expected_times_s_cruise) - expected_altitudes_m_cruise = np.array(expected_altitudes_m_cruise) - expected_masses_kg_cruise = np.array(expected_masses_kg_cruise) - expected_ranges_m_cruise = np.array(expected_ranges_m_cruise) - expected_velocities_ms_cruise = np.array(expected_velocities_ms_cruise) - expected_thrusts_N_cruise = np.array(expected_thrusts_N_cruise) - - expected_times_s_descent = np.array(expected_times_s_descent) - expected_altitudes_m_descent = np.array(expected_altitudes_m_descent) - expected_masses_kg_descent = np.array(expected_masses_kg_descent) - expected_ranges_m_descent = np.array(expected_ranges_m_descent) - expected_velocities_ms_descent = np.array(expected_velocities_ms_descent) - expected_thrusts_N_descent = np.array(expected_thrusts_N_descent) - - # Check Objective and other key variables to a reasonably tight tolerance. - - rtol = 1e-2 - - # Mass at the end of Descent - assert_near_equal(masses_descent[-1], - expected_masses_kg_descent[-1], tolerance=rtol) - - # Range at the end of Descent - assert_near_equal(ranges_descent[-1], - expected_ranges_m_descent[-1], tolerance=rtol) - - # Flight time - assert_near_equal(times_descent[-1], - expected_times_s_descent[-1], tolerance=rtol) - - # Check mission values. - - # NOTE rtol = 0.05 = 5% different from truth (first timeseries) - # atol = 2 = no more than +/-2 meter/second/kg difference between values - # atol_altitude - 30 ft. There is occasional time-shifting with the N3CC - # model during climb and descent so we need a looser - # absolute tolerance for the points near the ground. - rtol = .05 - atol = 2.0 - atol_altitude = 30.0 - - # FLIGHT PATH - # CLIMB - warn_timeseries_near_equal( - times_climb, altitudes_climb, expected_times_s_climb, - expected_altitudes_m_climb, abs_tolerance=atol_altitude, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_climb, masses_climb, expected_times_s_climb, - expected_masses_kg_climb, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_climb, ranges_climb, expected_times_s_climb, - expected_ranges_m_climb, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_climb, velocities_climb, expected_times_s_climb, - expected_velocities_ms_climb, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_climb, thrusts_climb, expected_times_s_climb, - expected_thrusts_N_climb, abs_tolerance=atol, rel_tolerance=rtol) - - # CRUISE - warn_timeseries_near_equal( - times_cruise, altitudes_cruise, expected_times_s_cruise, - expected_altitudes_m_cruise, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_cruise, masses_cruise, expected_times_s_cruise, - expected_masses_kg_cruise, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_cruise, ranges_cruise, expected_times_s_cruise, - expected_ranges_m_cruise, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_cruise, velocities_cruise, expected_times_s_cruise, - expected_velocities_ms_cruise, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_cruise, thrusts_cruise, expected_times_s_cruise, - expected_thrusts_N_cruise, abs_tolerance=atol, rel_tolerance=rtol) - - # DESCENT - warn_timeseries_near_equal( - times_descent, altitudes_descent, expected_times_s_descent, - expected_altitudes_m_descent, abs_tolerance=atol_altitude, - rel_tolerance=rtol) - warn_timeseries_near_equal( - times_descent, masses_descent, expected_times_s_descent, - expected_masses_kg_descent, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_descent, ranges_descent, expected_times_s_descent, - expected_ranges_m_descent, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_descent, velocities_descent, expected_times_s_descent, - expected_velocities_ms_descent, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_descent, thrusts_descent, expected_times_s_descent, - expected_thrusts_N_descent, abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == '__main__': - unittest.main() diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py deleted file mode 100644 index a81566387..000000000 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py +++ /dev/null @@ -1,701 +0,0 @@ -''' -NOTES: -Includes: -Takeoff, Climb, Cruise, Descent, Landing -Computed Aero -Large Single Aisle 2 data -''' -import unittest - -import dymos as dm -import numpy as np -import openmdao.api as om -import scipy.constants as _units -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import use_tempdirs - -from aviary.mission.flops_based.phases.build_landing import Landing -from aviary.mission.flops_based.phases.build_takeoff import Takeoff -from aviary.utils.aviary_values import AviaryValues -from aviary.utils.functions import set_aviary_initial_values -from aviary.utils.test_utils.assert_utils import warn_timeseries_near_equal -from aviary.validation_cases.validation_tests import get_flops_inputs -from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Aircraft, Dynamic, Mission -from aviary.variable_info.variables_in import VariablesIn -from aviary.subsystems.premission import CorePreMission -from aviary.interface.default_phase_info.flops import default_premission_subsystems, default_mission_subsystems -from aviary.utils.preprocessors import preprocess_options - -try: - import pyoptsparse -except ImportError: - pyoptsparse = None - -# benchmark based on Large Single Aisle 2 (fixed cruise alt) FLOPS model - - -def run_trajectory(sim=True): - prob = om.Problem(model=om.Group()) - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - # driver.declare_coloring() # currently disabled pending resolve of issue 2507 - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 45 - driver.opt_settings["Major optimality tolerance"] = 1e-4 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-3 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle2FLOPS') - - preprocess_options(aviary_inputs) - - alt_airport = 0 # ft - - ref_wing_area = 1370 # ft^2 TODO: where should this get connected from? - - alt_i_climb = 35.0*_units.foot # m (comes from takeoff) - alt_f_climb = 35000.0*_units.foot # m - mass_i_climb = 178172*_units.lb # kg (comes from takeoff) - mass_f_climb = 174160*_units.lb # kg - v_i_climb = 198.44*_units.knot # m/s (comes from takeoff) - v_f_climb = 452.61*_units.knot # m/s - mach_i_climb = 0.2 # TODO: (need to compute this in takeoff) - mach_f_climb = 0.785 - range_i_climb = 0*_units.nautical_mile # m (comes from takeoff) - range_f_climb = 124*_units.nautical_mile # m - t_i_climb = 0 - t_duration_climb = 20.14*_units.minute # sec - - alt_i_cruise = 35000*_units.foot # m - alt_f_cruise = 35000*_units.foot # m - alt_min_cruise = 35000*_units.foot # m - alt_max_cruise = 35000*_units.foot # m - mass_i_cruise = 174160*_units.lb # kg - mass_f_cruise = 140515*_units.lb # kg - v_i_cruise = 452.61*_units.knot # m/s - v_f_cruise = 452.61*_units.knot # m/s - mach_f_cruise = 0.785 - mach_min_cruise = 0.785 - mach_max_cruise = 0.785 - range_i_cruise = 124*_units.nautical_mile # m - range_f_cruise = 2830.8*_units.nautical_mile # m - t_i_cruise = t_i_climb + t_duration_climb # sec - t_duration_cruise = (378.95)*_units.minute - t_duration_climb # sec - - alt_i_descent = 35000*_units.foot # m - alt_f_descent = 35*_units.foot # m - v_i_descent = 452.61*_units.knot # m/s - v_f_descent = 198.44*_units.knot # m/s - mass_i_descent = 140515*_units.pound # kg - mass_f_descent = 140002*_units.pound # kg - mach_i_descent = mach_f_cruise - mach_f_descent = 0.3 - range_i_descent = 2830.8*_units.nautical_mile # m - range_f_descent = 2960.0*_units.nautical_mile # m - t_i_descent = t_duration_cruise+t_duration_climb # sec - t_duration_descent = 2000 # sec - - Cl_max_ldg = 3 # TODO: should this come from aero? - - ################## - # Define Phases # - ################## - - num_segments_climb = 6 - num_segments_cruise = 1 - num_segments_descent = 5 - - climb_seg_ends, _ = dm.utils.lgl.lgl(num_segments_climb + 1) - descent_seg_ends, _ = dm.utils.lgl.lgl(num_segments_descent + 1) - - transcription_climb = dm.Radau( - num_segments=num_segments_climb, order=3, compressed=True, - segment_ends=climb_seg_ends) - transcription_cruise = dm.Radau( - num_segments=num_segments_cruise, order=3, compressed=True) - transcription_descent = dm.Radau( - num_segments=num_segments_descent, order=3, compressed=True, - segment_ends=descent_seg_ends) - - takeoff_options = Takeoff( - airport_altitude=alt_airport, # ft - num_engines=aviary_inputs.get_val(Aircraft.Engine.NUM_ENGINES) - ) - - climb_options = Climb( - 'test_climb', - user_options=AviaryValues({ - 'initial_altitude': (alt_i_climb, 'm'), - 'final_altitude': (alt_f_climb, 'm'), - 'initial_mach': (mach_i_climb, 'unitless'), - 'final_mach': (mach_f_climb, 'unitless'), - 'fix_initial': (False, 'unitless'), - 'fix_range': (False, 'unitless'), - 'input_initial': (True, 'unitless'), - }), - core_subsystems=default_mission_subsystems, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - transcription=transcription_climb, - ) - - cruise_options = Cruise( - 'test_cruise', - user_options=AviaryValues({ - 'min_altitude': (alt_min_cruise, 'm'), - 'max_altitude': (alt_max_cruise, 'm'), - 'min_mach': (mach_min_cruise, 'unitless'), - 'max_mach': (mach_max_cruise, 'unitless'), - 'required_available_climb_rate': (300, 'ft/min'), - 'fix_initial': (False, 'unitless'), - 'fix_final': (False, 'unitless'), - }), - core_subsystems=default_mission_subsystems, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - transcription=transcription_cruise, - ) - - descent_options = Descent( - 'test_descent', - user_options=AviaryValues({ - 'final_altitude': (alt_f_descent, 'm'), - 'initial_altitude': (alt_i_descent, 'm'), - 'initial_mach': (mach_i_descent, 'unitless'), - 'final_mach': (mach_f_descent, 'unitless'), - 'fix_initial': (False, 'unitless'), - 'fix_range': (True, 'unitless'), - }), - core_subsystems=default_mission_subsystems, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - transcription=transcription_descent, - ) - - landing_options = Landing( - ref_wing_area=ref_wing_area, # ft**2 - Cl_max_ldg=Cl_max_ldg # no units - ) - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'pre_mission', - CorePreMission(aviary_options=aviary_inputs, - subsystems=default_premission_subsystems), - promotes_inputs=['aircraft:*', 'mission:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - # directly connect phases (strong_couple = True), or use linkage constraints (weak - # coupling / strong_couple=False) - strong_couple = False - - takeoff = takeoff_options.build_phase(False) - - climb = climb_options.build_phase(aviary_options=aviary_inputs) - - cruise = cruise_options.build_phase(aviary_options=aviary_inputs) - - descent = descent_options.build_phase(aviary_options=aviary_inputs) - - landing = landing_options.build_phase(False) - - prob.model.add_subsystem( - 'takeoff', takeoff, promotes_inputs=['aircraft:*', 'mission:*'], - promotes_outputs=['mission:*']) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - # if fix_initial is false, can we always set input_initial to be true for - # necessary states, and then ignore if we use a linkage? - climb.set_time_options( - fix_initial=True, fix_duration=False, units='s', - duration_bounds=(1, t_duration_climb*2), duration_ref=t_duration_climb) - cruise.set_time_options( - fix_initial=False, fix_duration=False, units='s', - duration_bounds=(1, t_duration_cruise*2), duration_ref=t_duration_cruise) - descent.set_time_options( - fix_initial=False, fix_duration=False, units='s', - duration_bounds=(1, t_duration_descent*2), duration_ref=t_duration_descent) - - traj.add_phase('climb', climb) - - traj.add_phase('cruise', cruise) - - traj.add_phase('descent', descent) - - climb.timeseries_options['use_prefix'] = True - cruise.timeseries_options['use_prefix'] = True - descent.timeseries_options['use_prefix'] = True - - prob.model.add_subsystem( - 'landing', landing, promotes_inputs=['aircraft:*', 'mission:*'], - promotes_outputs=['mission:*']) - - traj.link_phases(["climb", "cruise"], ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple) - traj.link_phases(["cruise", "descent"], ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs) - - ################################## - # Connect in Takeoff and Landing # - ################################## - - prob.model.add_subsystem( - "takeoff_constraints", - om.ExecComp( - [ - "takeoff_mass_con=takeoff_mass-climb_start_mass", - "takeoff_range_con=takeoff_range-climb_start_range", - "takeoff_vel_con=takeoff_vel-climb_start_vel", - "takeoff_alt_con=takeoff_alt-climb_start_alt" - ], - takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'}, - climb_start_mass={'units': 'lbm'}, - takeoff_range_con={'units': 'ft'}, takeoff_range={'units': 'ft'}, - climb_start_range={'units': 'ft'}, - takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'}, - climb_start_vel={'units': 'm/s'}, - takeoff_alt_con={'units': 'ft'}, takeoff_alt={'units': 'ft'}, - climb_start_alt={'units': 'ft'} - ), - promotes_inputs=[ - ("takeoff_mass", Mission.Takeoff.FINAL_MASS), - ("takeoff_range", Mission.Takeoff.GROUND_DISTANCE), - ("takeoff_vel", Mission.Takeoff.FINAL_VELOCITY), - ("takeoff_alt", Mission.Takeoff.FINAL_ALTITUDE), - ], - promotes_outputs=["takeoff_mass_con", "takeoff_range_con", - "takeoff_vel_con", "takeoff_alt_con"], - ) - - prob.model.connect('traj.climb.states:mass', - 'takeoff_constraints.climb_start_mass', src_indices=[0]) - prob.model.connect('traj.climb.states:range', - 'takeoff_constraints.climb_start_range', src_indices=[0]) - prob.model.connect('traj.climb.states:velocity', - 'takeoff_constraints.climb_start_vel', src_indices=[0]) - prob.model.connect('traj.climb.states:altitude', - 'takeoff_constraints.climb_start_alt', src_indices=[0]) - - prob.model.connect(Mission.Takeoff.FINAL_MASS, - 'traj.climb.initial_states:mass') - prob.model.connect(Mission.Takeoff.GROUND_DISTANCE, - 'traj.climb.initial_states:range') - prob.model.connect(Mission.Takeoff.FINAL_VELOCITY, - 'traj.climb.initial_states:velocity') - prob.model.connect(Mission.Takeoff.FINAL_ALTITUDE, - 'traj.climb.initial_states:altitude') - - prob.model.connect('traj.descent.states:mass', - Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1]) - prob.model.connect('traj.descent.states:altitude', Mission.Landing.INITIAL_ALTITUDE, - src_indices=[-1]) - - ########################## - # Add Objective Function # - ########################## - - # This is an example of a overall mission objective - # create a compound objective that minimizes climb time and maximizes final mass - # we are maxing final mass b/c we don't have an independent value for fuel_mass yet - # we are going to normalize these (makign each of the sub-objectives approx = 1 ) - prob.model.add_subsystem( - "regularization", - om.ExecComp( - # TODO: change the scaling on climb_duration - "reg_objective = - descent_mass_final/60000", - reg_objective=0.0, - descent_mass_final={"units": "kg", "shape": 1}, - ), - promotes_outputs=['reg_objective'] - ) - # connect the final mass from cruise into the objective - prob.model.connect("traj.descent.states:mass", - "regularization.descent_mass_final", src_indices=[-1]) - - prob.model.add_objective('reg_objective', ref=1) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - - prob.model.add_subsystem( - 'input_sink', - VariablesIn(aviary_options=aviary_inputs), - promotes_inputs=['*'], - promotes_outputs=['*'] - ) - - prob.setup() - - ########################################### - # Intial Settings for States and Controls # - ########################################### - - prob.set_val('traj.climb.t_initial', t_i_climb, units='s') - prob.set_val('traj.climb.t_duration', t_duration_climb, units='s') - - prob.set_val('traj.climb.states:altitude', climb.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m') - prob.set_val('traj.climb.states:velocity', climb.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s') - prob.set_val('traj.climb.states:mass', climb.interp( - Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') - prob.set_val('traj.climb.states:range', climb.interp( - Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') # nmi - - prob.set_val('traj.climb.controls:velocity_rate', - climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.05]), - units='m/s**2') - prob.set_val('traj.climb.controls:throttle', - climb.interp(Dynamic.Mission.THROTTLE, ys=[0.5, 0.5]), - units='unitless') - - prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s') - prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s') - - prob.set_val('traj.cruise.states:altitude', cruise.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m') - prob.set_val('traj.cruise.states:velocity', cruise.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s') - prob.set_val('traj.cruise.states:mass', cruise.interp( - Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi - - prob.set_val('traj.cruise.controls:velocity_rate', - cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), - units='m/s**2') - prob.set_val('traj.cruise.controls:throttle', - cruise.interp(Dynamic.Mission.THROTTLE, ys=[0.5, 0.5]), - units='unitless') - - prob.set_val('traj.descent.t_initial', t_i_descent, units='s') - prob.set_val('traj.descent.t_duration', t_duration_descent, units='s') - - prob.set_val('traj.descent.states:altitude', descent.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_descent, alt_f_descent]), units='m') - prob.set_val('traj.descent.states:velocity', descent.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_descent, v_f_descent]), units='m/s') - prob.set_val('traj.descent.states:mass', descent.interp( - Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') - prob.set_val('traj.descent.states:range', descent.interp( - Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m') - - prob.set_val('traj.descent.controls:velocity_rate', - descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.0]), - units='m/s**2') - prob.set_val('traj.descent.controls:throttle', - descent.interp(Dynamic.Mission.THROTTLE, ys=[0.0, 0.0]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=sim, make_plots=False, simulate_kwargs={ - 'times_per_seg': 100, 'atol': 1e-9, 'rtol': 1e-9}, - solution_record_file='large_single_aisle_2_solution.db') - prob.record("final") - prob.cleanup() - - return prob - - -@use_tempdirs -class ProblemPhaseTestCase(unittest.TestCase): - def bench_test_full_mission_large_single_aisle_2(self): - - prob = run_trajectory(sim=False) - - times_climb = prob.get_val('traj.climb.timeseries.time', units='s') - altitudes_climb = prob.get_val( - 'traj.climb.timeseries.states:altitude', units='m') - masses_climb = prob.get_val('traj.climb.timeseries.states:mass', units='kg') - ranges_climb = prob.get_val('traj.climb.timeseries.states:range', units='m') - velocities_climb = prob.get_val( - 'traj.climb.timeseries.states:velocity', units='m/s') - thrusts_climb = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N') - times_cruise = prob.get_val('traj.cruise.timeseries.time', units='s') - altitudes_cruise = prob.get_val( - 'traj.cruise.timeseries.states:altitude', units='m') - masses_cruise = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges_cruise = prob.get_val('traj.cruise.timeseries.states:range', units='m') - velocities_cruise = prob.get_val( - 'traj.cruise.timeseries.states:velocity', units='m/s') - thrusts_cruise = prob.get_val( - 'traj.cruise.timeseries.thrust_net_total', units='N') - times_descent = prob.get_val('traj.descent.timeseries.time', units='s') - altitudes_descent = prob.get_val( - 'traj.descent.timeseries.states:altitude', units='m') - masses_descent = prob.get_val('traj.descent.timeseries.states:mass', units='kg') - ranges_descent = prob.get_val('traj.descent.timeseries.states:range', units='m') - velocities_descent = prob.get_val( - 'traj.descent.timeseries.states:velocity', units='m/s') - thrusts_descent = prob.get_val( - 'traj.descent.timeseries.thrust_net_total', units='N') - - expected_times_s_climb = [[0.], [36.42164779], [86.67608797], [102.58144646], - [102.58144646], [180.10635382], [287.07490293], - [320.93008299], [320.93008299], [421.51105549], - [560.29226869], [604.21604816], [604.21604816], - [704.79702067], [843.57823386], [887.50201334], - [887.50201334], [965.0269207], [1071.9954698], - [1105.85064986], [1105.85064986], [1142.27229765], - [1192.52673783], [1208.43209632]] - expected_altitudes_m_climb = [[10.668], [10.668], [756.40579584], [1094.69377576], - [1094.69377576], [2638.335354], [4474.82351314], - [4956.42872513], [4956.42872513], [6093.2556723], - [7216.10719049], [7539.50807227], [7539.50807227], - [8246.0164048], [9133.44034449], [9376.84106855], - [9376.84106855], [9769.35335562], [10235.21824927], - [10366.38189087], [10366.38189087], [10496.4112199], - [10637.33808625], [10668.]] - expected_masses_kg_climb = [[78716.87348217], [78630.56839717], [78501.99380919], - [78461.17568729], [78461.17568729], [78282.66956759], - [78079.48002171], [78024.13525417], [78024.13525417], - [77874.53619474], [77690.00183752], [77632.85287533], - [77632.85287533], [77506.6235826], [77341.2312645], - [77291.7130525], [77291.7130525], [77206.37945353], - [77094.28764289], [77060.26735586], [77060.26735586], - [77024.49553459], [76976.26878085], [76961.2011732]] - expected_ranges_m_climb = [[2020.172677], [6250.78127734], [14408.93179369], - [17152.5734179], [17152.5734179], [31361.95647109], - [51731.27335637], [58135.07173792], [58135.07173792], - [77558.59088335], [105627.83510378], [114946.12296084], - [114946.12296084], [136784.80542027], [167833.78601896], - [177796.59419893], [177796.59419893], [195533.43046681], - [220220.00511814], [228064.41792222], [228064.41792222], - [236500.76050256], [248152.97050119], [251848.92128258]] - expected_velocities_ms_climb = [[85.50188638], [142.5264918], [174.18896469], - [178.36168293], [178.36168293], [189.05364242], - [190.8409755], [191.10004849], [191.10004849], - [196.39829028], [209.55408002], [213.5660258], - [213.5660258], [220.53005733], [226.3795119], - [227.73490457], [227.73490457], [229.83816653], - [231.58844935], [231.71451888], [231.71451888], - [231.66373105], [232.22063654], [232.77530606]] - expected_thrusts_N_climb = [[189058.83725077], - [170072.62422304], - [158048.98358529], - [154385.46295721], - [154385.46295721], - [136940.62457029], - [116116.73671672], - [110355.92368163], - [110355.92368163], - [97102.32305726], - [84436.60128586], - [81321.06998036], - [81321.06998036], - [75575.9138158], - [69929.77214168], - [68233.54819255], - [68233.54819255], - [66906.31800496], - [64990.02370683], - [64226.67297361], - [64226.67297361], - [63890.14810601], - [62804.25695388], - [61976.46190808]] - - expected_times_s_cruise = [[1208.43209632], [8852.14330109], - [19398.90466014], [22736.91857014]] - expected_altitudes_m_cruise = [[10668.], [10668.], [10668.], [10668.]] - expected_masses_kg_cruise = [[76961.2011732], [71368.01841021], - [64248.23842657], [62092.78518296]] - expected_ranges_m_cruise = [[251848.92128258], [2031116.13639915], - [4486141.73968515], [5263148.9492152]] - expected_velocities_ms_cruise = [[232.77530606], [232.77530606], - [232.77530606], [232.77530606]] - expected_thrusts_N_cruise = [[42313.90859903], - [39067.24395088], - [35950.87557908], - [35318.16856753]] - - expected_times_s_descent = [[22736.91857014], [22787.42540336], [22857.11452461], - [22879.17089321], [22879.17089321], [22982.32020233], - [23124.64519584], [23169.69056966], [23169.69056966], - [23292.32489254], [23461.53522808], [23515.08972074], - [23515.08972074], [23618.23902986], [23760.56402336], - [23805.60939719], [23805.60939719], [23856.11623041], - [23925.80535166], [24317.03614505]] - expected_altitudes_m_descent = [[10668.], [10434.7028388], [9960.79015066], - [9784.8421005], [9784.8421005], [8895.17761059], - [7537.33136949], [7090.56116653], [7090.56116653], - [5841.93815892], [3999.27122775], [3377.71804494], - [3377.71804494], [2138.48831166], [663.47208745], - [344.68854352], [344.68854352], [122.72341358], - [10.668], [10.668]] - expected_masses_kg_descent = [[62092.78518296], [62087.36440032], [62080.05896866], - [62077.72767582], [62077.72767582], [62066.62726287], - [62050.05526861], [62044.32456475], [62044.32456475], - [62027.35019169], [62000.0762637], [61990.36426104], - [61990.36426104], [61969.97789242], [61939.03538935], - [61928.82648685], [61928.82648685], [61917.76865363], - [61902.72792251], [60998.50259339]] - expected_ranges_m_descent = [[5263148.9492152], [5274432.80167853], [5288836.80724673], - [5293223.61558423], [ - 5293223.61558423], [5313013.5415642], - [5339348.96176189], [5347671.94897183], [ - 5347671.94897183], - [5370259.6353939], [5401419.10034695], [ - 5411278.66121681], - [5411278.66121681], [5430273.70362962], [ - 5455475.25800144], - [5462914.27715932], [5462914.27715932], [ - 5470553.18510276], - [5479541.42534675], [5481920.]] - expected_velocities_ms_descent = [[232.77530606], [215.12062535], [200.3306912], - [197.18540872], [197.18540872], [187.8799993], - [184.51577102], [184.46836756], [184.46836756], - [184.46836756], [184.46836756], [184.46836756], - [184.46836756], [183.31878177], [168.97447568], - [158.78398844], [158.78398844], [143.03675256], - [113.40966999], [102.07377559]] - expected_thrusts_N_descent = [[-10826.40055652], - [-4402.33172934], - [3254.14270948], - [5235.45930457], - [5235.45930457], - [12007.31061759], - [13032.5411879], - [10960.76992506], - [10960.76992506], - [5671.53535014], - [1824.89872243], - [1525.32410053], - [1525.32410053], - [-329.33574306], - [-9335.05085191], - [-13485.38001055], - [-13485.38001055], - [-17391.90310498], - [-14884.85752283], - [-12642.43964087]] - - expected_times_s_climb = np.array(expected_times_s_climb) - expected_altitudes_m_climb = np.array(expected_altitudes_m_climb) - expected_masses_kg_climb = np.array(expected_masses_kg_climb) - expected_ranges_m_climb = np.array(expected_ranges_m_climb) - expected_velocities_ms_climb = np.array(expected_velocities_ms_climb) - expected_thrusts_N_climb = np.array(expected_thrusts_N_climb) - - expected_times_s_cruise = np.array(expected_times_s_cruise) - expected_altitudes_m_cruise = np.array(expected_altitudes_m_cruise) - expected_masses_kg_cruise = np.array(expected_masses_kg_cruise) - expected_ranges_m_cruise = np.array(expected_ranges_m_cruise) - expected_velocities_ms_cruise = np.array(expected_velocities_ms_cruise) - expected_thrusts_N_cruise = np.array(expected_thrusts_N_cruise) - - expected_times_s_descent = np.array(expected_times_s_descent) - expected_altitudes_m_descent = np.array(expected_altitudes_m_descent) - expected_masses_kg_descent = np.array(expected_masses_kg_descent) - expected_ranges_m_descent = np.array(expected_ranges_m_descent) - expected_velocities_ms_descent = np.array(expected_velocities_ms_descent) - expected_thrusts_N_descent = np.array(expected_thrusts_N_descent) - - # Check Objective and other key variables to a reasonably tight tolerance. - - rtol = 1e-3 - - # Mass at the end of Descent - assert_near_equal(masses_descent[-1], - expected_masses_kg_descent[-1], tolerance=rtol) - - # Range at the end of Descent - assert_near_equal(ranges_descent[-1], - expected_ranges_m_descent[-1], tolerance=rtol) - - # Flight time - assert_near_equal(times_descent[-1], - expected_times_s_descent[-1], tolerance=rtol) - - # Check mission values. - - # NOTE rtol = 0.05 = 5% different from truth (first timeseries) - # atol = 2 = no more than +/-2 meter/second/kg difference between values - # atol_altitude - 30 ft. There is occasional time-shifting with the N3CC - # model during climb and descent so we need a looser - # absolute tolerance for the points near the ground. - rtol = .05 - atol = 2.0 - atol_altitude = 30.0 - - # FLIGHT PATH - # CLIMB - warn_timeseries_near_equal( - times_climb, altitudes_climb, expected_times_s_climb, - expected_altitudes_m_climb, abs_tolerance=atol_altitude, rel_tolerance=rtol) - - warn_timeseries_near_equal( - times_climb, masses_climb, expected_times_s_climb, - expected_masses_kg_climb, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_climb, ranges_climb, expected_times_s_climb, - expected_ranges_m_climb, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_climb, velocities_climb, expected_times_s_climb, - expected_velocities_ms_climb, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_climb, thrusts_climb, expected_times_s_climb, - expected_thrusts_N_climb, abs_tolerance=atol, rel_tolerance=rtol) - - # FLIGHT PATH - # CRUISE - warn_timeseries_near_equal( - times_cruise, altitudes_cruise, expected_times_s_cruise, - expected_altitudes_m_cruise, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_cruise, masses_cruise, expected_times_s_cruise, - expected_masses_kg_cruise, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_cruise, ranges_cruise, expected_times_s_cruise, - expected_ranges_m_cruise, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_cruise, velocities_cruise, expected_times_s_cruise, - expected_velocities_ms_cruise, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_cruise, thrusts_cruise, expected_times_s_cruise, - expected_thrusts_N_cruise, abs_tolerance=atol, rel_tolerance=rtol) - - # FLIGHT PATH - # DESCENT - warn_timeseries_near_equal( - times_descent, altitudes_descent, expected_times_s_descent, - expected_altitudes_m_descent, abs_tolerance=atol_altitude, - rel_tolerance=rtol) - warn_timeseries_near_equal( - times_descent, masses_descent, expected_times_s_descent, - expected_masses_kg_descent, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_descent, ranges_descent, expected_times_s_descent, - expected_ranges_m_descent, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_descent, velocities_descent, expected_times_s_descent, - expected_velocities_ms_descent, abs_tolerance=atol, rel_tolerance=rtol) - warn_timeseries_near_equal( - times_descent, thrusts_descent, expected_times_s_descent, - expected_thrusts_N_descent, abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == '__main__': - z = ProblemPhaseTestCase() - z.bench_test_full_mission_large_single_aisle_2() 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 c195cff92..64b84c3dd 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 @@ -18,13 +18,13 @@ from aviary.mission.flops_based.phases.build_takeoff import Takeoff from aviary.utils.functions import set_aviary_initial_values from aviary.utils.test_utils.assert_utils import warn_timeseries_near_equal -from aviary.utils.functions import get_path from aviary.validation_cases.validation_tests import get_flops_inputs from aviary.variable_info.functions import setup_trajectory_params from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables_in import VariablesIn +from aviary.mission.flops_based.phases.simple_energy_phase import EnergyPhase -from aviary.variable_info.variables import Aircraft, Mission +from aviary.variable_info.variables import Aircraft, Dynamic, Mission from aviary.subsystems.premission import CorePreMission from aviary.interface.default_phase_info.flops import default_premission_subsystems, default_mission_subsystems from aviary.utils.preprocessors import preprocess_crewpayload @@ -92,8 +92,6 @@ def run_trajectory(sim=True): alt_f_climb = 35000.0*_units.foot # m mass_i_climb = 131000*_units.lb # kg mass_f_climb = 126000*_units.lb # kg - v_i_climb = 198.44*_units.knot # m/s - v_f_climb = 455.49*_units.knot # m/s # initial mach set to lower value so it can intersect with takeoff end mach # mach_i_climb = 0.3 mach_i_climb = 0.2 @@ -110,10 +108,7 @@ def run_trajectory(sim=True): alt_max_cruise = 35000*_units.foot # m mass_i_cruise = 126000*_units.lb # kg mass_f_cruise = 102000*_units.lb # kg - v_i_cruise = 455.49*_units.knot # m/s - v_f_cruise = 455.49*_units.knot # m/s - mach_min_cruise = 0.79 - mach_max_cruise = 0.79 + cruise_mach = 0.79 range_i_cruise = 160.3*_units.nautical_mile # m range_f_cruise = 3243.9*_units.nautical_mile # m t_i_cruise = 26.20*_units.minute # sec @@ -124,8 +119,6 @@ def run_trajectory(sim=True): # final altitude set to 35 to ensure landing is feasible point # alt_f_descent = 0*_units.foot alt_f_descent = 35*_units.foot - v_i_descent = 455.49*_units.knot - v_f_descent = 198.44*_units.knot mach_i_descent = 0.79 mach_f_descent = 0.3 mass_i_descent = 102000*_units.pound @@ -171,7 +164,7 @@ def run_trajectory(sim=True): num_segments=num_segments_descent, order=3, compressed=True, segment_ends=descent_seg_ends) - climb_options = Climb( + climb_options = EnergyPhase( 'test_climb', user_options=AviaryValues({ 'initial_altitude': (alt_i_climb, 'm'), @@ -179,31 +172,30 @@ def run_trajectory(sim=True): 'initial_mach': (mach_i_climb, 'unitless'), 'final_mach': (mach_f_climb, 'unitless'), 'fix_initial': (False, 'unitless'), - 'fix_range': (False, 'unitless'), 'input_initial': (True, 'unitless'), + 'use_polynomial_control': (False, 'unitless'), }), core_subsystems=default_mission_subsystems, subsystem_options={'core_aerodynamics': {'method': 'computed'}}, transcription=transcription_climb, ) - cruise_options = Cruise( + cruise_options = EnergyPhase( 'test_cruise', user_options=AviaryValues({ - 'min_altitude': (alt_min_cruise, 'm'), - 'max_altitude': (alt_max_cruise, 'm'), - 'min_mach': (mach_min_cruise, 'unitless'), - 'max_mach': (mach_max_cruise, 'unitless'), + 'initial_altitude': (alt_min_cruise, 'm'), + 'final_altitude': (alt_max_cruise, 'm'), + 'initial_mach': (cruise_mach, 'unitless'), + 'final_mach': (cruise_mach, 'unitless'), 'required_available_climb_rate': (300, 'ft/min'), 'fix_initial': (False, 'unitless'), - 'fix_final': (False, 'unitless'), }), core_subsystems=default_mission_subsystems, subsystem_options={'core_aerodynamics': {'method': 'computed'}}, transcription=transcription_cruise, ) - descent_options = Descent( + descent_options = EnergyPhase( 'test_descent', user_options=AviaryValues({ 'final_altitude': (alt_f_descent, 'm'), @@ -211,7 +203,7 @@ def run_trajectory(sim=True): 'initial_mach': (mach_i_descent, 'unitless'), 'final_mach': (mach_f_descent, 'unitless'), 'fix_initial': (False, 'unitless'), - 'fix_range': (True, 'unitless'), + 'use_polynomial_control': (False, 'unitless'), }), core_subsystems=default_mission_subsystems, subsystem_options={'core_aerodynamics': {'method': 'computed'}}, @@ -277,78 +269,27 @@ def run_trajectory(sim=True): traj.add_phase('descent', descent) - try: - climb.timeseries_options['use_prefix'] = True - cruise.timeseries_options['use_prefix'] = True - descent.timeseries_options['use_prefix'] = True - except KeyError: - pass - prob.model.add_subsystem( 'landing', landing, promotes_inputs=['aircraft:*', 'mission:*'], promotes_outputs=['mission:*']) - traj.link_phases(["climb", "cruise"], ["time", "altitude", - "velocity", "mass", "range"], connected=strong_couple) - traj.link_phases(["cruise", "descent"], ["time", "altitude", - "velocity", "mass", "range"], connected=strong_couple) + traj.link_phases(["climb", "cruise", "descent"], [ + "time", "mass", "range"], connected=strong_couple) traj = setup_trajectory_params(prob.model, traj, aviary_inputs) ################################## # Connect in Takeoff and Landing # ################################## - - prob.model.add_subsystem( - "takeoff_constraints", - om.ExecComp( - [ - "takeoff_mass_con=takeoff_mass-climb_start_mass", - "takeoff_range_con=takeoff_range-climb_start_range", - "takeoff_vel_con=takeoff_vel-climb_start_vel", - "takeoff_alt_con=takeoff_alt-climb_start_alt" - ], - takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'}, - climb_start_mass={'units': 'lbm'}, - takeoff_range_con={'units': 'ft'}, takeoff_range={'units': 'ft'}, - climb_start_range={'units': 'ft'}, - takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'}, - climb_start_vel={'units': 'm/s'}, - takeoff_alt_con={'units': 'ft'}, takeoff_alt={'units': 'ft'}, - climb_start_alt={'units': 'ft'} - ), - promotes_inputs=[ - ("takeoff_mass", Mission.Takeoff.FINAL_MASS), - ("takeoff_range", Mission.Takeoff.GROUND_DISTANCE), - ("takeoff_vel", Mission.Takeoff.FINAL_VELOCITY), - ("takeoff_alt", Mission.Takeoff.FINAL_ALTITUDE), - ], - promotes_outputs=["takeoff_mass_con", "takeoff_range_con", - "takeoff_vel_con", "takeoff_alt_con"], - ) - - prob.model.connect('traj.climb.states:mass', - 'takeoff_constraints.climb_start_mass', src_indices=[0]) - prob.model.connect('traj.climb.states:range', - 'takeoff_constraints.climb_start_range', src_indices=[0]) - prob.model.connect('traj.climb.states:velocity', - 'takeoff_constraints.climb_start_vel', src_indices=[0]) - prob.model.connect('traj.climb.states:altitude', - 'takeoff_constraints.climb_start_alt', src_indices=[0]) - prob.model.connect(Mission.Takeoff.FINAL_MASS, 'traj.climb.initial_states:mass') prob.model.connect(Mission.Takeoff.GROUND_DISTANCE, 'traj.climb.initial_states:range') - prob.model.connect(Mission.Takeoff.FINAL_VELOCITY, - 'traj.climb.initial_states:velocity') - prob.model.connect(Mission.Takeoff.FINAL_ALTITUDE, - 'traj.climb.initial_states:altitude') prob.model.connect('traj.descent.states:mass', Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1]) # TODO: approach velocity should likely be connected - prob.model.connect('traj.descent.states:altitude', Mission.Landing.INITIAL_ALTITUDE, + prob.model.connect('traj.descent.control_values:altitude', Mission.Landing.INITIAL_ALTITUDE, src_indices=[-1]) ########################## @@ -443,60 +384,41 @@ def run_trajectory(sim=True): prob.set_val('traj.climb.t_initial', t_i_climb, units='s') prob.set_val('traj.climb.t_duration', t_duration_climb, units='s') - prob.set_val('traj.climb.states:altitude', climb.interp( - 'altitude', ys=[alt_i_climb, alt_f_climb]), units='m') - # prob.set_val('traj.climb.states:velocity', climb.interp('velocity', ys=[170, v_f_climb]), units='m/s') - prob.set_val('traj.climb.states:velocity', climb.interp( - 'velocity', ys=[v_i_climb, v_f_climb]), units='m/s') + prob.set_val('traj.climb.controls:altitude', climb.interp( + Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m') + prob.set_val( + 'traj.climb.controls:mach', climb.interp( + Dynamic.Mission.MACH, ys=[mach_i_climb, mach_f_climb]), units='unitless') prob.set_val('traj.climb.states:mass', climb.interp( - 'mass', ys=[mass_i_climb, mass_f_climb]), units='kg') + Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') prob.set_val('traj.climb.states:range', climb.interp( - 'range', ys=[range_i_climb, range_f_climb]), units='m') # nmi - - prob.set_val('traj.climb.controls:velocity_rate', - climb.interp('velocity_rate', ys=[0.25, 0.05]), - units='m/s**2') - prob.set_val('traj.climb.controls:throttle', - climb.interp('throttle', ys=[0.5, 0.5]), - units=None) + Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s') prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s') - prob.set_val('traj.cruise.states:altitude', cruise.interp( - 'altitude', ys=[alt_i_cruise, alt_f_cruise]), units='m') - prob.set_val('traj.cruise.states:velocity', cruise.interp( - 'velocity', ys=[v_i_cruise, v_f_cruise]), units='m/s') + prob.set_val('traj.cruise.polynomial_controls:altitude', cruise.interp( + Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m') + prob.set_val( + 'traj.cruise.polynomial_controls:mach', cruise.interp( + Dynamic.Mission.MACH, ys=[cruise_mach, cruise_mach]), units='unitless') prob.set_val('traj.cruise.states:mass', cruise.interp( - 'mass', ys=[mass_i_cruise, mass_f_cruise]), units='kg') + Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') prob.set_val('traj.cruise.states:range', cruise.interp( - 'range', ys=[range_i_cruise, range_f_cruise]), units='m') # nmi - - prob.set_val('traj.cruise.controls:velocity_rate', - cruise.interp('velocity_rate', ys=[0.0, 0.0]), - units='m/s**2') - prob.set_val('traj.cruise.controls:throttle', - cruise.interp('throttle', ys=[0.5, 0.5]), - units=None) + Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') prob.set_val('traj.descent.t_initial', t_i_descent, units='s') prob.set_val('traj.descent.t_duration', t_duration_descent, units='s') - prob.set_val('traj.descent.states:altitude', descent.interp( - 'altitude', ys=[alt_i_descent, alt_f_descent]), units='m') - prob.set_val('traj.descent.states:velocity', descent.interp( - 'velocity', ys=[v_i_descent, v_f_descent]), units='m/s') + prob.set_val('traj.descent.controls:altitude', descent.interp( + Dynamic.Mission.ALTITUDE, ys=[alt_i_descent, alt_f_descent]), units='m') + prob.set_val( + 'traj.descent.controls:mach', descent.interp( + Dynamic.Mission.MACH, ys=[mach_i_descent, mach_f_descent]), units='unitless') prob.set_val('traj.descent.states:mass', descent.interp( - 'mass', ys=[mass_i_descent, mass_f_descent]), units='kg') + Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') prob.set_val('traj.descent.states:range', descent.interp( - 'range', ys=[range_i_descent, range_f_descent]), units='m') - - prob.set_val('traj.descent.controls:velocity_rate', - descent.interp('velocity_rate', ys=[-0.25, 0.05]), - units='m/s**2') - prob.set_val('traj.descent.controls:throttle', - descent.interp('throttle', ys=[0.0, 0.0]), - units=None) + Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m') # Turn off solver printing so that the SNOPT output is readable. prob.set_solver_print(level=0) @@ -521,28 +443,28 @@ def bench_test_sizing_N3CC(self): times_climb = prob.get_val('traj.climb.timeseries.time', units='s') altitudes_climb = prob.get_val( - 'traj.climb.timeseries.states:altitude', units='m') - masses_climb = prob.get_val('traj.climb.timeseries.states:mass', units='kg') - ranges_climb = prob.get_val('traj.climb.timeseries.states:range', units='m') + 'traj.climb.timeseries.altitude', units='m') + masses_climb = prob.get_val('traj.climb.timeseries.mass', units='kg') + ranges_climb = prob.get_val('traj.climb.timeseries.range', units='m') velocities_climb = prob.get_val( - 'traj.climb.timeseries.states:velocity', units='m/s') + 'traj.climb.timeseries.velocity', units='m/s') thrusts_climb = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N') times_cruise = prob.get_val('traj.cruise.timeseries.time', units='s') altitudes_cruise = prob.get_val( - 'traj.cruise.timeseries.states:altitude', units='m') - masses_cruise = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges_cruise = prob.get_val('traj.cruise.timeseries.states:range', units='m') + 'traj.cruise.timeseries.altitude', units='m') + masses_cruise = prob.get_val('traj.cruise.timeseries.mass', units='kg') + ranges_cruise = prob.get_val('traj.cruise.timeseries.range', units='m') velocities_cruise = prob.get_val( - 'traj.cruise.timeseries.states:velocity', units='m/s') + 'traj.cruise.timeseries.velocity', units='m/s') thrusts_cruise = prob.get_val( 'traj.cruise.timeseries.thrust_net_total', units='N') times_descent = prob.get_val('traj.descent.timeseries.time', units='s') altitudes_descent = prob.get_val( - 'traj.descent.timeseries.states:altitude', units='m') - masses_descent = prob.get_val('traj.descent.timeseries.states:mass', units='kg') - ranges_descent = prob.get_val('traj.descent.timeseries.states:range', units='m') + 'traj.descent.timeseries.altitude', units='m') + masses_descent = prob.get_val('traj.descent.timeseries.mass', units='kg') + ranges_descent = prob.get_val('traj.descent.timeseries.range', units='m') velocities_descent = prob.get_val( - 'traj.descent.timeseries.states:velocity', units='m/s') + 'traj.descent.timeseries.velocity', units='m/s') thrusts_descent = prob.get_val( 'traj.descent.timeseries.thrust_net_total', units='N') From e0af92b75868645f09b5da7a2548c7a8a1ed5e91 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Tue, 9 Jan 2024 11:52:04 -0600 Subject: [PATCH 021/188] Updating docs --- aviary/api.py | 1 + .../getting_started/onboarding_level2.ipynb | 2511 ++++++++++++++++- .../getting_started/onboarding_level3.ipynb | 1328 ++++----- 3 files changed, 2958 insertions(+), 882 deletions(-) diff --git a/aviary/api.py b/aviary/api.py index a7e55c7a5..4dd11f0fb 100644 --- a/aviary/api.py +++ b/aviary/api.py @@ -86,6 +86,7 @@ # Phase builders from aviary.mission.flops_based.phases.phase_builder_base import PhaseBuilderBase # note that this is only for simplified right now +from aviary.mission.flops_based.phases.simple_energy_phase import EnergyPhase as HeightEnergyPhaseBuilder from aviary.mission.flops_based.phases.build_landing import Landing as HeightEnergyLandingPhaseBuilder # note that this is only for simplified right now from aviary.mission.flops_based.phases.build_takeoff import Takeoff as HeightEnergyTakeoffPhaseBuilder diff --git a/aviary/docs/getting_started/onboarding_level2.ipynb b/aviary/docs/getting_started/onboarding_level2.ipynb index a0db18448..64557fd83 100644 --- a/aviary/docs/getting_started/onboarding_level2.ipynb +++ b/aviary/docs/getting_started/onboarding_level2.ipynb @@ -71,10 +71,770 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "fe134855", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/om-Aviary/aviary/subsystems/propulsion/engine_deck.py:198: UserWarning: is a required option for EngineDecks, but has not been specified for EngineDeck . The default value will be used.\n", + " warnings.warn(\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/group.py:333: PromotionWarning:: Setting input defaults for input 'mission:takeoff:ascent_duration' which override previously set defaults for ['auto', 'prom', 'src_shape', 'val'].\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.speeds' : d(*)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.params' : d(max_mach)/d(max_airspeed): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.params' : d(density_ratio)/d(max_airspeed): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.params' : d(V9)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.factors' : d(aircraft:wing:ultimate_load_factor)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.fixed_mass.params' : d(c_gear_loc)/d(aircraft:landing_gear:main_gear_location): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.equip_and_useful_mass' : d(aircraft:design:fixed_useful_load)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.equip_and_useful_mass' : d(aircraft:design:fixed_equipment_mass)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'groundroll': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.groundroll.rhs_all.eoms' : d(alpha_rate)/d(('*',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2185: UserWarning: Phase time options have no effect because fix_initial=True or input_initial=True for phase 'traj.phases.rotation': initial_ref\n", + " warnings.warn(f'Phase time options have no effect because fix_initial=True '\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'rotation': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.rotation.rhs_all.eoms' : d(alpha_rate)/d(('*',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'ascent': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2185: UserWarning: Phase time options have no effect because fix_initial=True or input_initial=True for phase 'traj.phases.accel': initial_bounds\n", + " warnings.warn(f'Phase time options have no effect because fix_initial=True '\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'accel': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2185: UserWarning: Phase time options have no effect because fix_initial=True or input_initial=True for phase 'traj.phases.climb1': initial_bounds\n", + " warnings.warn(f'Phase time options have no effect because fix_initial=True '\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'climb1': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2185: UserWarning: Phase time options have no effect because fix_initial=True or input_initial=True for phase 'traj.phases.climb2': initial_bounds\n", + " warnings.warn(f'Phase time options have no effect because fix_initial=True '\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'climb2': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2185: UserWarning: Phase time options have no effect because fix_initial=True or input_initial=True for phase 'traj.phases.desc1': initial_bounds, initial_ref\n", + " warnings.warn(f'Phase time options have no effect because fix_initial=True '\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'desc1': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2185: UserWarning: Phase time options have no effect because fix_initial=True or input_initial=True for phase 'traj.phases.desc2': initial_bounds, initial_ref\n", + " warnings.warn(f'Phase time options have no effect because fix_initial=True '\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'desc2': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "The following variables have been overridden:\n", + " 'aircraft:engine:scale_factor\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.accel: The following timeseries outputs were requested but not found in the ODE: aero.CD, aero.CL\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.accel' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.accel.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.accel.nonlinear_solver to override.\n", + " Setting `traj.phases.accel.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.accel.linear_solver to override.\n", + " Set `traj.phases.accel.options[\"auto_solvers\"] = False` to disable this behavior.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.ascent' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.ascent.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.ascent.nonlinear_solver to override.\n", + " Setting `traj.phases.ascent.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.ascent.linear_solver to override.\n", + " Set `traj.phases.ascent.options[\"auto_solvers\"] = False` to disable this behavior.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.climb1: The following timeseries outputs were requested but not found in the ODE: aero.CD, aero.CL\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.climb1' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.climb1.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.climb1.nonlinear_solver to override.\n", + " Setting `traj.phases.climb1.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.climb1.linear_solver to override.\n", + " Set `traj.phases.climb1.options[\"auto_solvers\"] = False` to disable this behavior.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.climb2: The following timeseries outputs were requested but not found in the ODE: aero.CD, aero.CL\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.climb2' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.climb2.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.climb2.nonlinear_solver to override.\n", + " Setting `traj.phases.climb2.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.climb2.linear_solver to override.\n", + " Set `traj.phases.climb2.options[\"auto_solvers\"] = False` to disable this behavior.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.desc1: The following timeseries outputs were requested but not found in the ODE: aero.CD, aero.CL\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.desc1' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.desc1.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.desc1.nonlinear_solver to override.\n", + " Setting `traj.phases.desc1.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.desc1.linear_solver to override.\n", + " Set `traj.phases.desc1.options[\"auto_solvers\"] = False` to disable this behavior.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.desc2: The following timeseries outputs were requested but not found in the ODE: aero.CD, aero.CL\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.desc2' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.desc2.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.desc2.nonlinear_solver to override.\n", + " Setting `traj.phases.desc2.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.desc2.linear_solver to override.\n", + " Set `traj.phases.desc2.options[\"auto_solvers\"] = False` to disable this behavior.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.rotation' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.rotation.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.rotation.nonlinear_solver to override.\n", + " Setting `traj.phases.rotation.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.rotation.linear_solver to override.\n", + " Set `traj.phases.rotation.options[\"auto_solvers\"] = False` to disable this behavior.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "--- Constraint Report [traj] ---\n", + " --- groundroll ---\n", + " None\n", + " --- rotation ---\n", + " [final] 0.0000e+00 == normal_force [lbf]\n", + " --- ascent ---\n", + " [final] 5.0000e+02 == altitude [ft]\n", + " [path] 0.0000e+00 <= load_factor <= 1.1000e+00 [unitless]\n", + " [path] 0.0000e+00 <= fuselage_pitch <= 1.5000e+01 [deg]\n", + " --- accel ---\n", + " [final] 2.5000e+02 == EAS [kn]\n", + " --- climb1 ---\n", + " [final] 1.0000e+04 == altitude [ft]\n", + " --- climb2 ---\n", + " [final] 3.7500e+04 == altitude [ft]\n", + " [final] 1.0000e-01 <= altitude_rate [ft/min]\n", + " [final] 8.0000e-01 == mach [unitless]\n", + " --- cruise ---\n", + " None\n", + " --- desc1 ---\n", + " [final] 1.0000e+04 == altitude [ft]\n", + " --- desc2 ---\n", + " [final] 1.0000e+03 == altitude [ft]\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'landing.aero_app.lift_coef' : d(CL_base)/d(('CL_max_flaps',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'landing.aero_td.lift_coef' : d(CL_base)/d(('CL_max_flaps',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.ascent.rhs_all.core_aerodynamics.lift_coef' : d(CL_base)/d(('CL_max_flaps',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.groundroll.rhs_all.core_aerodynamics.lift_coef' : d(CL_base)/d(('CL_max_flaps',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.rotation.rhs_all.core_aerodynamics.lift_coef' : d(CL_base)/d(('CL_max_flaps',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, aviary_history.db, is being overwritten.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model viewer data has already been recorded for Driver.\n", + "Model viewer data has already been recorded for Driver.\n", + "\n", + "Coloring for 'event_xform' (class ExecComp)\n", + "\n", + "Jacobian shape: (2, 4) (75.00% nonzero)\n", + "FWD solves: 3 REV solves: 0\n", + "Total colors vs. total size: 3 vs 4 (25.00% improvement)\n", + "\n", + "Sparsity computed using tolerance: 1e-25\n", + "Time to compute sparsity: 0.0003 sec\n", + "Time to compute coloring: 0.0021 sec\n", + "Memory to compute coloring: 0.0391 MB\n", + "Full total jacobian was computed 3 times, taking 1.928283 seconds.\n", + "Total jacobian shape: (232, 203) \n", + "\n", + "\n", + "Jacobian shape: (232, 203) (7.47% nonzero)\n", + "FWD solves: 45 REV solves: 0\n", + "Total colors vs. total size: 45 vs 203 (77.83% improvement)\n", + "\n", + "Sparsity computed using tolerance: 1e-25\n", + "Time to compute sparsity: 1.9283 sec\n", + "Time to compute coloring: 0.1703 sec\n", + "Memory to compute coloring: 0.6680 MB\n", + "Coloring created on: 2024-01-09 11:24:16\n", + "\n", + "List of user-set options:\n", + "\n", + " Name Value used\n", + " alpha_for_y = safer-min-dual-infeas yes\n", + " file_print_level = 5 yes\n", + " hessian_approximation = limited-memory yes\n", + " linear_solver = mumps yes\n", + " max_iter = 0 yes\n", + " mu_init = 1e-05 yes\n", + " mu_strategy = monotone yes\n", + " nlp_scaling_method = gradient-based yes\n", + " output_file = reports/problem/IPOPT.out yes\n", + " print_level = 5 yes\n", + " print_user_options = yes yes\n", + " sb = yes yes\n", + " tol = 1e-06 yes\n", + "This is Ipopt version 3.14.12, running with linear solver MUMPS 5.2.1.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 2343\n", + "Number of nonzeros in inequality constraint Jacobian.: 568\n", + "Number of nonzeros in Lagrangian Hessian.............: 0\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/total_jac.py:1759: DerivativesWarning:Constraints or objectives [('traj.phases.climb2.timeseries.timeseries_comp.mach', inds=[(11, 0)])] cannot be impacted by the design variables of the problem.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Total number of variables............................: 203\n", + " variables with only lower bounds: 0\n", + " variables with lower and upper bounds: 203\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 198\n", + "Total number of inequality constraints...............: 33\n", + " inequality constraints with only lower bounds: 1\n", + " inequality constraints with lower and upper bounds: 32\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 5.2731333e+00 1.30e+01 1.75e+01 -5.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "\n", + "Number of Iterations....: 0\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 5.2731333333333330e+00 5.2731333333333330e+00\n", + "Dual infeasibility......: 1.7500000000000000e+01 1.7500000000000000e+01\n", + "Constraint violation....: 3.4411291654724301e+00 1.2999999999999952e+01\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 7.1428571428571420e+15 7.1428571428571420e+15\n", + "Overall NLP error.......: 7.1428571428571420e+15 7.1428571428571420e+15\n", + "\n", + "\n", + "Number of objective function evaluations = 1\n", + "Number of objective gradient evaluations = 1\n", + "Number of equality constraint evaluations = 1\n", + "Number of inequality constraint evaluations = 1\n", + "Number of equality constraint Jacobian evaluations = 1\n", + "Number of inequality constraint Jacobian evaluations = 1\n", + "Number of Lagrangian Hessian evaluations = 0\n", + "Total seconds in IPOPT = 2.265\n", + "\n", + "EXIT: Maximum Number of Iterations Exceeded.\n", + "\n", + "\n", + "Optimization Problem -- Optimization using pyOpt_sparse\n", + "================================================================================\n", + " Objective Function: _objfunc\n", + "\n", + " Solution: \n", + "--------------------------------------------------------------------------------\n", + " Total Time: 2.2837\n", + " User Objective Time : 0.2671\n", + " User Sensitivity Time : 1.9735\n", + " Interface Time : 0.0132\n", + " Opt Solver Time: 0.0298\n", + " Calls to Objective Function : 2\n", + " Calls to Sens Function : 2\n", + "\n", + "\n", + " Objectives\n", + " Index Name Value\n", + " 0 mission:objectives:fuel 5.273133E+00\n", + "\n", + " Variables (c - continuous, i - integer, d - discrete)\n", + " Index Name Type Lower Bound Value Upper Bound Status\n", + " 0 mission:takeoff:ascent_t_initial_0 c 0.000000E+00 3.333333E-01 3.333333E+00 \n", + " 1 mission:takeoff:ascent_duration_0 c 1.000000E-01 2.500000E+00 1.000000E+02 \n", + " 2 tau_gear_0 c 1.000000E-02 2.000000E-01 1.000000E+00 \n", + " 3 tau_flaps_0 c 1.000000E-02 9.000000E-01 1.000000E+00 \n", + " 4 mission:design:gross_mass_0 c 5.714286E-05 1.002286E+00 2.285714E+00 \n", + " 5 mission:summary:gross_mass_0 c 5.714286E-05 1.002286E+00 2.285714E+00 \n", + " 6 traj.accel.t_duration_0 c 1.000000E-03 1.300000E-02 2.000000E-01 \n", + " 7 traj.accel.states:TAS_0 c 0.000000E+00 5.807832E-01 1.200000E+00 \n", + " 8 traj.accel.states:TAS_1 c 0.000000E+00 8.992168E-01 1.200000E+00 \n", + " 9 traj.accel.states:TAS_2 c 0.000000E+00 1.000000E+00 1.200000E+00 \n", + " 10 traj.accel.states:mass_0 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 11 traj.accel.states:mass_1 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 12 traj.accel.states:mass_2 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 13 traj.accel.states:distance_0 c 0.000000E+00 3.291577E-01 3.000000E+01 \n", + " 14 traj.accel.states:distance_1 c 0.000000E+00 4.460254E-01 3.000000E+01 \n", + " 15 traj.accel.states:distance_2 c 0.000000E+00 6.072791E-01 3.000000E+01 \n", + " 16 traj.accel.states:distance_3 c 0.000000E+00 6.583153E-01 3.000000E+01 \n", + " 17 traj.ascent.states:flight_path_angle_0 c -1.000000E+01 1.239362E-02 2.000000E+01 \n", + " 18 traj.ascent.states:flight_path_angle_1 c -1.000000E+01 2.949428E-02 2.000000E+01 \n", + " 19 traj.ascent.states:flight_path_angle_2 c -1.000000E+01 3.490659E-02 2.000000E+01 \n", + " 20 traj.ascent.states:flight_path_angle_3 c -1.000000E+01 4.730020E-02 2.000000E+01 \n", + " 21 traj.ascent.states:flight_path_angle_4 c -1.000000E+01 6.440087E-02 2.000000E+01 \n", + " 22 traj.ascent.states:flight_path_angle_5 c -1.000000E+01 6.981317E-02 2.000000E+01 \n", + " 23 traj.ascent.states:flight_path_angle_6 c -1.000000E+01 8.220679E-02 2.000000E+01 \n", + " 24 traj.ascent.states:flight_path_angle_7 c -1.000000E+01 9.930745E-02 2.000000E+01 \n", + " 25 traj.ascent.states:flight_path_angle_8 c -1.000000E+01 1.047198E-01 2.000000E+01 \n", + " 26 traj.ascent.states:flight_path_angle_9 c -1.000000E+01 1.171134E-01 2.000000E+01 \n", + " 27 traj.ascent.states:flight_path_angle_10 c -1.000000E+01 1.342140E-01 2.000000E+01 \n", + " 28 traj.ascent.states:flight_path_angle_11 c -1.000000E+01 1.396263E-01 2.000000E+01 \n", + " 29 traj.ascent.states:altitude_0 c 0.000000E+00 4.438138E-02 7.000000E-01 \n", + " 30 traj.ascent.states:altitude_1 c 0.000000E+00 1.056186E-01 7.000000E-01 \n", + " 31 traj.ascent.states:altitude_2 c 0.000000E+00 1.250000E-01 7.000000E-01 \n", + " 32 traj.ascent.states:altitude_3 c 0.000000E+00 1.693814E-01 7.000000E-01 \n", + " 33 traj.ascent.states:altitude_4 c 0.000000E+00 2.306186E-01 7.000000E-01 \n", + " 34 traj.ascent.states:altitude_5 c 0.000000E+00 2.500000E-01 7.000000E-01 \n", + " 35 traj.ascent.states:altitude_6 c 0.000000E+00 2.943814E-01 7.000000E-01 \n", + " 36 traj.ascent.states:altitude_7 c 0.000000E+00 3.556186E-01 7.000000E-01 \n", + " 37 traj.ascent.states:altitude_8 c 0.000000E+00 3.750000E-01 7.000000E-01 \n", + " 38 traj.ascent.states:altitude_9 c 0.000000E+00 4.193814E-01 7.000000E-01 \n", + " 39 traj.ascent.states:altitude_10 c 0.000000E+00 4.806186E-01 7.000000E-01 \n", + " 40 traj.ascent.states:altitude_11 c 0.000000E+00 5.000000E-01 7.000000E-01 \n", + " 41 traj.ascent.states:TAS_0 c 0.000000E+00 7.655335E-01 3.500000E+00 \n", + " 42 traj.ascent.states:TAS_1 c 0.000000E+00 7.869665E-01 3.500000E+00 \n", + " 43 traj.ascent.states:TAS_2 c 0.000000E+00 7.937500E-01 3.500000E+00 \n", + " 44 traj.ascent.states:TAS_3 c 0.000000E+00 8.092835E-01 3.500000E+00 \n", + " 45 traj.ascent.states:TAS_4 c 0.000000E+00 8.307165E-01 3.500000E+00 \n", + " 46 traj.ascent.states:TAS_5 c 0.000000E+00 8.375000E-01 3.500000E+00 \n", + " 47 traj.ascent.states:TAS_6 c 0.000000E+00 8.530335E-01 3.500000E+00 \n", + " 48 traj.ascent.states:TAS_7 c 0.000000E+00 8.744665E-01 3.500000E+00 \n", + " 49 traj.ascent.states:TAS_8 c 0.000000E+00 8.812500E-01 3.500000E+00 \n", + " 50 traj.ascent.states:TAS_9 c 0.000000E+00 8.967835E-01 3.500000E+00 \n", + " 51 traj.ascent.states:TAS_10 c 0.000000E+00 9.182165E-01 3.500000E+00 \n", + " 52 traj.ascent.states:TAS_11 c 0.000000E+00 9.250000E-01 3.500000E+00 \n", + " 53 traj.ascent.states:mass_0 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 54 traj.ascent.states:mass_1 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 55 traj.ascent.states:mass_2 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 56 traj.ascent.states:mass_3 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 57 traj.ascent.states:mass_4 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 58 traj.ascent.states:mass_5 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 59 traj.ascent.states:mass_6 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 60 traj.ascent.states:mass_7 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 61 traj.ascent.states:mass_8 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 62 traj.ascent.states:mass_9 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 63 traj.ascent.states:mass_10 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 64 traj.ascent.states:mass_11 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 65 traj.ascent.states:distance_0 c 0.000000E+00 4.532577E-01 1.500000E+00 \n", + " 66 traj.ascent.states:distance_1 c 0.000000E+00 5.267423E-01 1.500000E+00 \n", + " 67 traj.ascent.states:distance_2 c 0.000000E+00 5.500000E-01 1.500000E+00 \n", + " 68 traj.ascent.states:distance_3 c 0.000000E+00 6.032577E-01 1.500000E+00 \n", + " 69 traj.ascent.states:distance_4 c 0.000000E+00 6.767423E-01 1.500000E+00 \n", + " 70 traj.ascent.states:distance_5 c 0.000000E+00 7.000000E-01 1.500000E+00 \n", + " 71 traj.ascent.states:distance_6 c 0.000000E+00 7.532577E-01 1.500000E+00 \n", + " 72 traj.ascent.states:distance_7 c 0.000000E+00 8.267423E-01 1.500000E+00 \n", + " 73 traj.ascent.states:distance_8 c 0.000000E+00 8.500000E-01 1.500000E+00 \n", + " 74 traj.ascent.states:distance_9 c 0.000000E+00 9.032577E-01 1.500000E+00 \n", + " 75 traj.ascent.states:distance_10 c 0.000000E+00 9.767423E-01 1.500000E+00 \n", + " 76 traj.ascent.states:distance_11 c 0.000000E+00 1.000000E+00 1.500000E+00 \n", + " 77 traj.ascent.controls:alpha_0 c -6.000000E+00 5.000000E-01 6.000000E+00 \n", + " 78 traj.ascent.controls:alpha_1 c -6.000000E+00 4.822474E-01 6.000000E+00 \n", + " 79 traj.ascent.controls:alpha_2 c -6.000000E+00 4.577526E-01 6.000000E+00 \n", + " 80 traj.ascent.controls:alpha_3 c -6.000000E+00 4.500000E-01 6.000000E+00 \n", + " 81 traj.ascent.controls:alpha_4 c -6.000000E+00 4.322474E-01 6.000000E+00 \n", + " 82 traj.ascent.controls:alpha_5 c -6.000000E+00 4.077526E-01 6.000000E+00 \n", + " 83 traj.ascent.controls:alpha_6 c -6.000000E+00 4.000000E-01 6.000000E+00 \n", + " 84 traj.ascent.controls:alpha_7 c -6.000000E+00 3.822474E-01 6.000000E+00 \n", + " 85 traj.ascent.controls:alpha_8 c -6.000000E+00 3.577526E-01 6.000000E+00 \n", + " 86 traj.ascent.controls:alpha_9 c -6.000000E+00 3.500000E-01 6.000000E+00 \n", + " 87 traj.ascent.controls:alpha_10 c -6.000000E+00 3.322474E-01 6.000000E+00 \n", + " 88 traj.ascent.controls:alpha_11 c -6.000000E+00 3.077526E-01 6.000000E+00 \n", + " 89 traj.climb1.t_duration_0 c 3.000000E-02 1.200000E-01 3.000000E-01 \n", + " 90 traj.climb1.states:altitude_0 c 4.000000E-02 3.872985E-01 1.100000E+00 \n", + " 91 traj.climb1.states:altitude_1 c 4.000000E-02 8.527015E-01 1.100000E+00 \n", + " 92 traj.climb1.states:altitude_2 c 4.000000E-02 1.000000E+00 1.100000E+00 \n", + " 93 traj.climb1.states:mass_0 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 94 traj.climb1.states:mass_1 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 95 traj.climb1.states:mass_2 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 96 traj.climb1.states:distance_0 c 0.000000E+00 7.966287E-01 5.000000E+01 \n", + " 97 traj.climb1.states:distance_1 c 0.000000E+00 1.441643E+00 5.000000E+01 \n", + " 98 traj.climb1.states:distance_2 c 0.000000E+00 1.645788E+00 5.000000E+01 \n", + " 99 traj.climb2.t_duration_0 c 4.000000E-02 2.600000E-01 3.400000E+00 \n", + " 100 traj.climb2.states:altitude_0 c 3.000000E-01 4.418211E-01 1.333333E+00 \n", + " 101 traj.climb2.states:altitude_1 c 3.000000E-01 5.915122E-01 1.333333E+00 \n", + " 102 traj.climb2.states:altitude_2 c 3.000000E-01 6.388889E-01 1.333333E+00 \n", + " 103 traj.climb2.states:altitude_3 c 3.000000E-01 7.473767E-01 1.333333E+00 \n", + " 104 traj.climb2.states:altitude_4 c 3.000000E-01 8.970677E-01 1.333333E+00 \n", + " 105 traj.climb2.states:altitude_5 c 3.000000E-01 9.444444E-01 1.333333E+00 \n", + " 106 traj.climb2.states:altitude_6 c 3.000000E-01 1.052932E+00 1.333333E+00 \n", + " 107 traj.climb2.states:altitude_7 c 3.000000E-01 1.202623E+00 1.333333E+00 \n", + " 108 traj.climb2.states:altitude_8 c 3.000000E-01 1.250000E+00 1.333333E+00 \n", + " 109 traj.climb2.states:mass_0 c 0.000000E+00 1.146064E+00 6.666667E+15 \n", + " 110 traj.climb2.states:mass_1 c 0.000000E+00 1.146064E+00 6.666667E+15 \n", + " 111 traj.climb2.states:mass_2 c 0.000000E+00 1.146064E+00 6.666667E+15 \n", + " 112 traj.climb2.states:mass_3 c 0.000000E+00 1.146064E+00 6.666667E+15 \n", + " 113 traj.climb2.states:mass_4 c 0.000000E+00 1.146064E+00 6.666667E+15 \n", + " 114 traj.climb2.states:mass_5 c 0.000000E+00 1.146064E+00 6.666667E+15 \n", + " 115 traj.climb2.states:mass_6 c 0.000000E+00 1.146064E+00 6.666667E+15 \n", + " 116 traj.climb2.states:mass_7 c 0.000000E+00 1.146064E+00 6.666667E+15 \n", + " 117 traj.climb2.states:mass_8 c 0.000000E+00 1.146064E+00 6.666667E+15 \n", + " 118 traj.climb2.states:distance_0 c 2.000000E-02 3.681136E-02 2.000000E+00 \n", + " 119 traj.climb2.states:distance_1 c 2.000000E-02 4.218648E-02 2.000000E+00 \n", + " 120 traj.climb2.states:distance_2 c 2.000000E-02 4.388769E-02 2.000000E+00 \n", + " 121 traj.climb2.states:distance_3 c 2.000000E-02 4.778328E-02 2.000000E+00 \n", + " 122 traj.climb2.states:distance_4 c 2.000000E-02 5.315840E-02 2.000000E+00 \n", + " 123 traj.climb2.states:distance_5 c 2.000000E-02 5.485961E-02 2.000000E+00 \n", + " 124 traj.climb2.states:distance_6 c 2.000000E-02 5.875520E-02 2.000000E+00 \n", + " 125 traj.climb2.states:distance_7 c 2.000000E-02 6.413033E-02 2.000000E+00 \n", + " 126 traj.climb2.states:distance_8 c 2.000000E-02 6.583153E-02 2.000000E+00 \n", + " 127 traj.cruise.t_initial_0 c 1.000000E-01 1.714810E+00 5.000000E+00 \n", + " 128 traj.cruise.t_duration_0 c -1.000000E+00 -7.000000E-01 -2.000000E-04 \n", + " 129 traj.desc1.t_duration_0 c 3.000000E-01 5.000000E-01 9.000000E-01 \n", + " 130 traj.desc1.states:altitude_0 c 3.333333E-02 1.141512E+00 1.333333E+00 \n", + " 131 traj.desc1.states:altitude_1 c 3.333333E-02 9.918211E-01 1.333333E+00 \n", + " 132 traj.desc1.states:altitude_2 c 3.333333E-02 9.444444E-01 1.333333E+00 \n", + " 133 traj.desc1.states:altitude_3 c 3.333333E-02 8.359566E-01 1.333333E+00 \n", + " 134 traj.desc1.states:altitude_4 c 3.333333E-02 6.862656E-01 1.333333E+00 \n", + " 135 traj.desc1.states:altitude_5 c 3.333333E-02 6.388889E-01 1.333333E+00 \n", + " 136 traj.desc1.states:altitude_6 c 3.333333E-02 5.304011E-01 1.333333E+00 \n", + " 137 traj.desc1.states:altitude_7 c 3.333333E-02 3.807100E-01 1.333333E+00 \n", + " 138 traj.desc1.states:altitude_8 c 3.333333E-02 3.333333E-01 1.333333E+00 \n", + " 139 traj.desc1.states:mass_0 c 0.000000E+00 9.714286E-01 7.142857E+15 \n", + " 140 traj.desc1.states:mass_1 c 0.000000E+00 9.714286E-01 7.142857E+15 \n", + " 141 traj.desc1.states:mass_2 c 0.000000E+00 9.714286E-01 7.142857E+15 \n", + " 142 traj.desc1.states:mass_3 c 0.000000E+00 9.714286E-01 7.142857E+15 \n", + " 143 traj.desc1.states:mass_4 c 0.000000E+00 9.714286E-01 7.142857E+15 \n", + " 144 traj.desc1.states:mass_5 c 0.000000E+00 9.714286E-01 7.142857E+15 \n", + " 145 traj.desc1.states:mass_6 c 0.000000E+00 9.714286E-01 7.142857E+15 \n", + " 146 traj.desc1.states:mass_7 c 0.000000E+00 9.714286E-01 7.142857E+15 \n", + " 147 traj.desc1.states:mass_8 c 0.000000E+00 9.714286E-01 7.142857E+15 \n", + " 148 traj.desc1.states:distance_0 c 8.163265E-01 9.247340E-01 1.360544E+00 \n", + " 149 traj.desc1.states:distance_1 c 8.163265E-01 9.312660E-01 1.360544E+00 \n", + " 150 traj.desc1.states:distance_2 c 8.163265E-01 9.333333E-01 1.360544E+00 \n", + " 151 traj.desc1.states:distance_3 c 8.163265E-01 9.380673E-01 1.360544E+00 \n", + " 152 traj.desc1.states:distance_4 c 8.163265E-01 9.445993E-01 1.360544E+00 \n", + " 153 traj.desc1.states:distance_5 c 8.163265E-01 9.466667E-01 1.360544E+00 \n", + " 154 traj.desc1.states:distance_6 c 8.163265E-01 9.514007E-01 1.360544E+00 \n", + " 155 traj.desc1.states:distance_7 c 8.163265E-01 9.579327E-01 1.360544E+00 \n", + " 156 traj.desc1.states:distance_8 c 8.163265E-01 9.600000E-01 1.360544E+00 \n", + " 157 traj.desc2.t_duration_0 c 2.000000E-01 1.000000E+00 1.000000E+01 \n", + " 158 traj.desc2.states:altitude_0 c -5.555556E-02 9.269457E-01 1.111111E+00 \n", + " 159 traj.desc2.states:altitude_1 c -5.555556E-02 7.692339E-01 1.111111E+00 \n", + " 160 traj.desc2.states:altitude_2 c -5.555556E-02 5.586715E-01 1.111111E+00 \n", + " 161 traj.desc2.states:altitude_3 c -5.555556E-02 3.369847E-01 1.111111E+00 \n", + " 162 traj.desc2.states:altitude_4 c -5.555556E-02 1.480786E-01 1.111111E+00 \n", + " 163 traj.desc2.states:altitude_5 c -5.555556E-02 2.931643E-02 1.111111E+00 \n", + " 164 traj.desc2.states:altitude_6 c -5.555556E-02 0.000000E+00 1.111111E+00 \n", + " 165 traj.desc2.states:mass_0 c 0.000000E+00 9.066667E-01 6.666667E+15 \n", + " 166 traj.desc2.states:mass_1 c 0.000000E+00 9.066667E-01 6.666667E+15 \n", + " 167 traj.desc2.states:mass_2 c 0.000000E+00 9.066667E-01 6.666667E+15 \n", + " 168 traj.desc2.states:mass_3 c 0.000000E+00 9.066667E-01 6.666667E+15 \n", + " 169 traj.desc2.states:mass_4 c 0.000000E+00 9.066667E-01 6.666667E+15 \n", + " 170 traj.desc2.states:mass_5 c 0.000000E+00 9.066667E-01 6.666667E+15 \n", + " 171 traj.desc2.states:mass_6 c 0.000000E+00 9.066667E-01 6.666667E+15 \n", + " 172 traj.desc2.states:distance_0 c 0.000000E+00 1.011068E+00 1.428571E+00 \n", + " 173 traj.desc2.states:distance_1 c 0.000000E+00 1.017692E+00 1.428571E+00 \n", + " 174 traj.desc2.states:distance_2 c 0.000000E+00 1.026536E+00 1.428571E+00 \n", + " 175 traj.desc2.states:distance_3 c 0.000000E+00 1.035847E+00 1.428571E+00 \n", + " 176 traj.desc2.states:distance_4 c 0.000000E+00 1.043781E+00 1.428571E+00 \n", + " 177 traj.desc2.states:distance_5 c 0.000000E+00 1.048769E+00 1.428571E+00 \n", + " 178 traj.desc2.states:distance_6 c 0.000000E+00 1.050000E+00 1.428571E+00 \n", + " 179 traj.groundroll.t_duration_0 c 2.000000E-02 8.000000E-01 2.000000E+00 \n", + " 180 traj.groundroll.states:TAS_0 c 0.000000E+00 3.390025E-01 6.666667E+00 \n", + " 181 traj.groundroll.states:TAS_1 c 0.000000E+00 8.061495E-01 6.666667E+00 \n", + " 182 traj.groundroll.states:TAS_2 c 0.000000E+00 9.540000E-01 6.666667E+00 \n", + " 183 traj.groundroll.states:mass_0 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 184 traj.groundroll.states:mass_1 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 185 traj.groundroll.states:mass_2 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 186 traj.groundroll.states:mass_3 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 187 traj.groundroll.states:distance_0 c 0.000000E+00 1.183503E-01 3.333333E+00 \n", + " 188 traj.groundroll.states:distance_1 c 0.000000E+00 2.816497E-01 3.333333E+00 \n", + " 189 traj.groundroll.states:distance_2 c 0.000000E+00 3.333333E-01 3.333333E+00 \n", + " 190 traj.rotation.t_duration_0 c 2.000000E-02 1.000000E-01 2.000000E+00 \n", + " 191 traj.rotation.states:alpha_0 c 0.000000E+00 9.999990E-03 1.000000E+00 \n", + " 192 traj.rotation.states:alpha_1 c 0.000000E+00 9.999990E-03 1.000000E+00 \n", + " 193 traj.rotation.states:alpha_2 c 0.000000E+00 9.999990E-03 1.000000E+00 \n", + " 194 traj.rotation.states:TAS_0 c 0.000000E+00 1.454854E+00 1.000000E+01 \n", + " 195 traj.rotation.states:TAS_1 c 0.000000E+00 1.489146E+00 1.000000E+01 \n", + " 196 traj.rotation.states:TAS_2 c 0.000000E+00 1.500000E+00 1.000000E+01 \n", + " 197 traj.rotation.states:mass_0 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 198 traj.rotation.states:mass_1 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 199 traj.rotation.states:mass_2 c 0.000000E+00 1.157640E+00 6.666667E+15 \n", + " 200 traj.rotation.states:distance_0 c 0.000000E+00 7.587713E-01 2.000000E+00 \n", + " 201 traj.rotation.states:distance_1 c 0.000000E+00 7.900883E-01 2.000000E+00 \n", + " 202 traj.rotation.states:distance_2 c 0.000000E+00 8.000000E-01 2.000000E+00 \n", + "\n", + " Constraints (i - inequality, e - equality)\n", + " Index Name Type Lower Value Upper Status Lagrange Multiplier (N/A)\n", + " 0 h_fit.h_init_gear e 1.000000E+00 -1.200000E+01 1.000000E+00 E 9.00000E+100\n", + " 1 h_fit.h_init_flaps e 1.000000E+00 -6.250000E-01 1.000000E+00 E 9.00000E+100\n", + " 2 mission:constraints:range_residual e 0.000000E+00 4.547474E-14 0.000000E+00 9.00000E+100\n", + " 3 groundroll_boundary.TAS e 0.000000E+00 -2.184640E-02 0.000000E+00 E 9.00000E+100\n", + " 4 gtow_constraint.GTOW e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", + " 5 link_taxi_groundroll.mass e 0.000000E+00 -1.545558E-01 0.000000E+00 E 9.00000E+100\n", + " 6 mission:constraints:mass_residual e 0.000000E+00 8.370367E-03 0.000000E+00 E 9.00000E+100\n", + " 7 traj.linkages.rotation:alpha_final|ascent:alpha_initial e 0.000000E+00 1.273344E-04 0.000000E+00 E 9.00000E+100\n", + " 8 traj.linkages.ascent:distance_final|accel:distance_initial e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", + " 9 traj.linkages.climb2:mass_final|cruise:mass_initial e 0.000000E+00 4.285400E-03 0.000000E+00 E 9.00000E+100\n", + " 10 traj.phases.accel->final_boundary_constraint->EAS e 1.000000E+00 9.927554E-01 1.000000E+00 E 9.00000E+100\n", + " 11 traj.accel.collocation_constraint.defects:TAS e 0.000000E+00 5.831548E-02 0.000000E+00 E 9.00000E+100\n", + " 12 traj.accel.collocation_constraint.defects:TAS e 0.000000E+00 5.874534E-02 0.000000E+00 E 9.00000E+100\n", + " 13 traj.accel.collocation_constraint.defects:TAS e 0.000000E+00 6.150213E-02 0.000000E+00 E 9.00000E+100\n", + " 14 traj.accel.collocation_constraint.defects:mass e 0.000000E+00 1.596440E-04 0.000000E+00 E 9.00000E+100\n", + " 15 traj.accel.collocation_constraint.defects:mass e 0.000000E+00 1.608753E-04 0.000000E+00 E 9.00000E+100\n", + " 16 traj.accel.collocation_constraint.defects:mass e 0.000000E+00 1.626472E-04 0.000000E+00 E 9.00000E+100\n", + " 17 traj.accel.collocation_constraint.defects:distance e 0.000000E+00 9.777328E-02 0.000000E+00 E 9.00000E+100\n", + " 18 traj.accel.collocation_constraint.defects:distance e 0.000000E+00 8.943944E-02 0.000000E+00 E 9.00000E+100\n", + " 19 traj.accel.collocation_constraint.defects:distance e 0.000000E+00 7.794045E-02 0.000000E+00 E 9.00000E+100\n", + " 20 traj.phases.ascent->final_boundary_constraint->altitude e 1.000000E+00 1.000000E+00 1.000000E+00 9.00000E+100\n", + " 21 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 3.242586E-01 0.000000E+00 E 9.00000E+100\n", + " 22 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 3.239934E-01 0.000000E+00 E 9.00000E+100\n", + " 23 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 3.153739E-01 0.000000E+00 E 9.00000E+100\n", + " 24 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 3.124580E-01 0.000000E+00 E 9.00000E+100\n", + " 25 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 3.058679E-01 0.000000E+00 E 9.00000E+100\n", + " 26 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.971450E-01 0.000000E+00 E 9.00000E+100\n", + " 27 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.944936E-01 0.000000E+00 E 9.00000E+100\n", + " 28 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.886166E-01 0.000000E+00 E 9.00000E+100\n", + " 29 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.809363E-01 0.000000E+00 E 9.00000E+100\n", + " 30 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.786055E-01 0.000000E+00 E 9.00000E+100\n", + " 31 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.734430E-01 0.000000E+00 E 9.00000E+100\n", + " 32 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.667064E-01 0.000000E+00 E 9.00000E+100\n", + " 33 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 6.250000E-02 0.000000E+00 E 9.00000E+100\n", + " 34 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 5.249183E-02 0.000000E+00 E 9.00000E+100\n", + " 35 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 3.801869E-02 0.000000E+00 E 9.00000E+100\n", + " 36 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 3.327824E-02 0.000000E+00 E 9.00000E+100\n", + " 37 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 2.213497E-02 0.000000E+00 E 9.00000E+100\n", + " 38 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 6.104057E-03 0.000000E+00 E 9.00000E+100\n", + " 39 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 8.727384E-04 0.000000E+00 E 9.00000E+100\n", + " 40 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 -1.139040E-02 0.000000E+00 E 9.00000E+100\n", + " 41 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 -2.895648E-02 0.000000E+00 E 9.00000E+100\n", + " 42 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 -3.467113E-02 0.000000E+00 E 9.00000E+100\n", + " 43 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 -4.803617E-02 0.000000E+00 E 9.00000E+100\n", + " 44 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 -6.711102E-02 0.000000E+00 E 9.00000E+100\n", + " 45 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -3.782017E-02 0.000000E+00 E 9.00000E+100\n", + " 46 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -3.222433E-02 0.000000E+00 E 9.00000E+100\n", + " 47 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -2.621911E-02 0.000000E+00 E 9.00000E+100\n", + " 48 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -2.437244E-02 0.000000E+00 E 9.00000E+100\n", + " 49 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -2.016566E-02 0.000000E+00 E 9.00000E+100\n", + " 50 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -1.438596E-02 0.000000E+00 E 9.00000E+100\n", + " 51 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -1.256933E-02 0.000000E+00 E 9.00000E+100\n", + " 52 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -8.413797E-03 0.000000E+00 E 9.00000E+100\n", + " 53 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -2.689611E-03 0.000000E+00 E 9.00000E+100\n", + " 54 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -8.803422E-04 0.000000E+00 E 9.00000E+100\n", + " 55 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 3.257993E-03 0.000000E+00 E 9.00000E+100\n", + " 56 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 8.956421E-03 0.000000E+00 E 9.00000E+100\n", + " 57 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 7.680938E-05 0.000000E+00 E 9.00000E+100\n", + " 58 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 7.681276E-05 0.000000E+00 E 9.00000E+100\n", + " 59 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 7.680776E-05 0.000000E+00 E 9.00000E+100\n", + " 60 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 7.680384E-05 0.000000E+00 E 9.00000E+100\n", + " 61 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 7.679065E-05 0.000000E+00 E 9.00000E+100\n", + " 62 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 7.676870E-05 0.000000E+00 E 9.00000E+100\n", + " 63 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 7.676740E-05 0.000000E+00 E 9.00000E+100\n", + " 64 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 7.676449E-05 0.000000E+00 E 9.00000E+100\n", + " 65 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 7.676058E-05 0.000000E+00 E 9.00000E+100\n", + " 66 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 7.675938E-05 0.000000E+00 E 9.00000E+100\n", + " 67 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 7.675667E-05 0.000000E+00 E 9.00000E+100\n", + " 68 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 7.675305E-05 0.000000E+00 E 9.00000E+100\n", + " 69 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -4.116087E-03 0.000000E+00 E 9.00000E+100\n", + " 70 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -5.748483E-03 0.000000E+00 E 9.00000E+100\n", + " 71 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -7.979510E-03 0.000000E+00 E 9.00000E+100\n", + " 72 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -8.680185E-03 0.000000E+00 E 9.00000E+100\n", + " 73 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -1.027431E-02 0.000000E+00 E 9.00000E+100\n", + " 74 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -1.244906E-02 0.000000E+00 E 9.00000E+100\n", + " 75 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -1.313109E-02 0.000000E+00 E 9.00000E+100\n", + " 76 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -1.468101E-02 0.000000E+00 E 9.00000E+100\n", + " 77 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -1.679134E-02 0.000000E+00 E 9.00000E+100\n", + " 78 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -1.745215E-02 0.000000E+00 E 9.00000E+100\n", + " 79 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -1.895200E-02 0.000000E+00 E 9.00000E+100\n", + " 80 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -2.098984E-02 0.000000E+00 E 9.00000E+100\n", + " 81 traj.ascent.continuity_comp.defect_control_rates:alpha_rate e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", + " 82 traj.ascent.continuity_comp.defect_control_rates:alpha_rate e 0.000000E+00 -5.556536E-17 0.000000E+00 9.00000E+100\n", + " 83 traj.ascent.continuity_comp.defect_control_rates:alpha_rate e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", + " 84 traj.ascent.continuity_comp.defect_controls:alpha e 0.000000E+00 1.387779E-17 0.000000E+00 9.00000E+100\n", + " 85 traj.ascent.continuity_comp.defect_controls:alpha e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", + " 86 traj.ascent.continuity_comp.defect_controls:alpha e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", + " 87 traj.phases.climb1->final_boundary_constraint->altitude e 1.000000E+00 1.000000E+00 1.000000E+00 9.00000E+100\n", + " 88 traj.climb1.collocation_constraint.defects:altitude e 0.000000E+00 1.295515E-01 0.000000E+00 E 9.00000E+100\n", + " 89 traj.climb1.collocation_constraint.defects:altitude e 0.000000E+00 1.349127E-01 0.000000E+00 E 9.00000E+100\n", + " 90 traj.climb1.collocation_constraint.defects:altitude e 0.000000E+00 1.615414E-01 0.000000E+00 E 9.00000E+100\n", + " 91 traj.climb1.collocation_constraint.defects:mass e 0.000000E+00 1.507414E-03 0.000000E+00 E 9.00000E+100\n", + " 92 traj.climb1.collocation_constraint.defects:mass e 0.000000E+00 1.426534E-03 0.000000E+00 E 9.00000E+100\n", + " 93 traj.climb1.collocation_constraint.defects:mass e 0.000000E+00 1.317088E-03 0.000000E+00 E 9.00000E+100\n", + " 94 traj.climb1.collocation_constraint.defects:distance e 0.000000E+00 2.424766E-01 0.000000E+00 E 9.00000E+100\n", + " 95 traj.climb1.collocation_constraint.defects:distance e 0.000000E+00 2.206075E-01 0.000000E+00 E 9.00000E+100\n", + " 96 traj.climb1.collocation_constraint.defects:distance e 0.000000E+00 1.873288E-01 0.000000E+00 E 9.00000E+100\n", + " 97 traj.phases.climb2->final_boundary_constraint->altitude e 1.000000E+00 1.000000E+00 1.000000E+00 9.00000E+100\n", + " 98 traj.phases.climb2->final_boundary_constraint->mach e 8.000000E-01 8.000000E-01 8.000000E-01 9.00000E+100\n", + " 99 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 -2.255353E-01 0.000000E+00 E 9.00000E+100\n", + " 100 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 -1.993872E-01 0.000000E+00 E 9.00000E+100\n", + " 101 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 -1.543238E-01 0.000000E+00 E 9.00000E+100\n", + " 102 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 -1.414243E-01 0.000000E+00 E 9.00000E+100\n", + " 103 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 -1.059912E-01 0.000000E+00 E 9.00000E+100\n", + " 104 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 -5.304664E-02 0.000000E+00 E 9.00000E+100\n", + " 105 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 -3.776842E-02 0.000000E+00 E 9.00000E+100\n", + " 106 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 9.545807E-04 0.000000E+00 E 9.00000E+100\n", + " 107 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 8.172580E-02 0.000000E+00 E 9.00000E+100\n", + " 108 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 -2.426644E-02 0.000000E+00 E 9.00000E+100\n", + " 109 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 -1.726371E-03 0.000000E+00 E 9.00000E+100\n", + " 110 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 5.430194E-03 0.000000E+00 E 9.00000E+100\n", + " 111 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 3.872597E-03 0.000000E+00 E 9.00000E+100\n", + " 112 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 3.618909E-03 0.000000E+00 E 9.00000E+100\n", + " 113 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 3.286245E-03 0.000000E+00 E 9.00000E+100\n", + " 114 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 3.191289E-03 0.000000E+00 E 9.00000E+100\n", + " 115 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 2.964754E-03 0.000000E+00 E 9.00000E+100\n", + " 116 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 2.548933E-03 0.000000E+00 E 9.00000E+100\n", + " 117 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -3.214629E-02 0.000000E+00 E 9.00000E+100\n", + " 118 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -3.418797E-02 0.000000E+00 E 9.00000E+100\n", + " 119 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -3.727218E-02 0.000000E+00 E 9.00000E+100\n", + " 120 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -3.831655E-02 0.000000E+00 E 9.00000E+100\n", + " 121 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -4.085065E-02 0.000000E+00 E 9.00000E+100\n", + " 122 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -4.470143E-02 0.000000E+00 E 9.00000E+100\n", + " 123 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -4.601426E-02 0.000000E+00 E 9.00000E+100\n", + " 124 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -4.921350E-02 0.000000E+00 E 9.00000E+100\n", + " 125 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -4.974632E-02 0.000000E+00 E 9.00000E+100\n", + " 126 traj.phases.desc1->final_boundary_constraint->altitude e 1.000000E+00 1.000000E+00 1.000000E+00 9.00000E+100\n", + " 127 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 -4.277848E-02 0.000000E+00 E 9.00000E+100\n", + " 128 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 -3.895954E-02 0.000000E+00 E 9.00000E+100\n", + " 129 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 -2.787700E-02 0.000000E+00 E 9.00000E+100\n", + " 130 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 -2.332833E-02 0.000000E+00 E 9.00000E+100\n", + " 131 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 -1.102907E-02 0.000000E+00 E 9.00000E+100\n", + " 132 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 5.409284E-03 0.000000E+00 E 9.00000E+100\n", + " 133 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 1.272129E-03 0.000000E+00 E 9.00000E+100\n", + " 134 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 -7.793018E-03 0.000000E+00 E 9.00000E+100\n", + " 135 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 -1.948962E-02 0.000000E+00 E 9.00000E+100\n", + " 136 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 -8.518117E-03 0.000000E+00 E 9.00000E+100\n", + " 137 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 -1.726843E-03 0.000000E+00 E 9.00000E+100\n", + " 138 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 5.343179E-04 0.000000E+00 E 9.00000E+100\n", + " 139 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 1.054056E-04 0.000000E+00 E 9.00000E+100\n", + " 140 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 1.200624E-04 0.000000E+00 E 9.00000E+100\n", + " 141 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 1.416797E-04 0.000000E+00 E 9.00000E+100\n", + " 142 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 1.467613E-04 0.000000E+00 E 9.00000E+100\n", + " 143 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 1.591485E-04 0.000000E+00 E 9.00000E+100\n", + " 144 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 1.785953E-04 0.000000E+00 E 9.00000E+100\n", + " 145 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 -4.841115E+00 0.000000E+00 E 9.00000E+100\n", + " 146 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 -9.109513E-01 0.000000E+00 E 9.00000E+100\n", + " 147 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 3.881133E-01 0.000000E+00 E 9.00000E+100\n", + " 148 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 1.352695E-01 0.000000E+00 E 9.00000E+100\n", + " 149 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 1.337867E-01 0.000000E+00 E 9.00000E+100\n", + " 150 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 1.331703E-01 0.000000E+00 E 9.00000E+100\n", + " 151 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 1.358305E-01 0.000000E+00 E 9.00000E+100\n", + " 152 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 1.415815E-01 0.000000E+00 E 9.00000E+100\n", + " 153 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 1.488110E-01 0.000000E+00 E 9.00000E+100\n", + " 154 traj.phases.desc2->final_boundary_constraint->altitude e 1.000000E+00 1.000000E+00 1.000000E+00 9.00000E+100\n", + " 155 traj.desc2.collocation_constraint.defects:altitude e 0.000000E+00 1.250331E-01 0.000000E+00 E 9.00000E+100\n", + " 156 traj.desc2.collocation_constraint.defects:altitude e 0.000000E+00 1.172366E-01 0.000000E+00 E 9.00000E+100\n", + " 157 traj.desc2.collocation_constraint.defects:altitude e 0.000000E+00 1.004951E-01 0.000000E+00 E 9.00000E+100\n", + " 158 traj.desc2.collocation_constraint.defects:altitude e 0.000000E+00 7.895862E-02 0.000000E+00 E 9.00000E+100\n", + " 159 traj.desc2.collocation_constraint.defects:altitude e 0.000000E+00 5.687274E-02 0.000000E+00 E 9.00000E+100\n", + " 160 traj.desc2.collocation_constraint.defects:altitude e 0.000000E+00 3.869760E-02 0.000000E+00 E 9.00000E+100\n", + " 161 traj.desc2.collocation_constraint.defects:altitude e 0.000000E+00 2.746677E-02 0.000000E+00 E 9.00000E+100\n", + " 162 traj.desc2.collocation_constraint.defects:mass e 0.000000E+00 4.638632E-04 0.000000E+00 E 9.00000E+100\n", + " 163 traj.desc2.collocation_constraint.defects:mass e 0.000000E+00 4.729111E-04 0.000000E+00 E 9.00000E+100\n", + " 164 traj.desc2.collocation_constraint.defects:mass e 0.000000E+00 4.941796E-04 0.000000E+00 E 9.00000E+100\n", + " 165 traj.desc2.collocation_constraint.defects:mass e 0.000000E+00 5.229304E-04 0.000000E+00 E 9.00000E+100\n", + " 166 traj.desc2.collocation_constraint.defects:mass e 0.000000E+00 5.557022E-04 0.000000E+00 E 9.00000E+100\n", + " 167 traj.desc2.collocation_constraint.defects:mass e 0.000000E+00 5.846184E-04 0.000000E+00 E 9.00000E+100\n", + " 168 traj.desc2.collocation_constraint.defects:mass e 0.000000E+00 6.038235E-04 0.000000E+00 E 9.00000E+100\n", + " 169 traj.desc2.collocation_constraint.defects:distance e 0.000000E+00 5.332067E-01 0.000000E+00 E 9.00000E+100\n", + " 170 traj.desc2.collocation_constraint.defects:distance e 0.000000E+00 5.352741E-01 0.000000E+00 E 9.00000E+100\n", + " 171 traj.desc2.collocation_constraint.defects:distance e 0.000000E+00 5.396321E-01 0.000000E+00 E 9.00000E+100\n", + " 172 traj.desc2.collocation_constraint.defects:distance e 0.000000E+00 5.452352E-01 0.000000E+00 E 9.00000E+100\n", + " 173 traj.desc2.collocation_constraint.defects:distance e 0.000000E+00 5.508830E-01 0.000000E+00 E 9.00000E+100\n", + " 174 traj.desc2.collocation_constraint.defects:distance e 0.000000E+00 5.555022E-01 0.000000E+00 E 9.00000E+100\n", + " 175 traj.desc2.collocation_constraint.defects:distance e 0.000000E+00 5.583195E-01 0.000000E+00 E 9.00000E+100\n", + " 176 traj.groundroll.collocation_constraint.defects:TAS e 0.000000E+00 -1.689955E-01 0.000000E+00 E 9.00000E+100\n", + " 177 traj.groundroll.collocation_constraint.defects:TAS e 0.000000E+00 -1.065200E-01 0.000000E+00 E 9.00000E+100\n", + " 178 traj.groundroll.collocation_constraint.defects:TAS e 0.000000E+00 2.199958E-03 0.000000E+00 E 9.00000E+100\n", + " 179 traj.groundroll.collocation_constraint.defects:mass e 0.000000E+00 4.765410E-04 0.000000E+00 E 9.00000E+100\n", + " 180 traj.groundroll.collocation_constraint.defects:mass e 0.000000E+00 4.811469E-04 0.000000E+00 E 9.00000E+100\n", + " 181 traj.groundroll.collocation_constraint.defects:mass e 0.000000E+00 4.875537E-04 0.000000E+00 E 9.00000E+100\n", + " 182 traj.groundroll.collocation_constraint.defects:distance e 0.000000E+00 1.659240E-01 0.000000E+00 E 9.00000E+100\n", + " 183 traj.groundroll.collocation_constraint.defects:distance e 0.000000E+00 -4.055050E-01 0.000000E+00 E 9.00000E+100\n", + " 184 traj.groundroll.collocation_constraint.defects:distance e 0.000000E+00 -1.193960E+00 0.000000E+00 E 9.00000E+100\n", + " 185 traj.phases.rotation->final_boundary_constraint->normal_force e 0.000000E+00 8.409179E+00 0.000000E+00 E 9.00000E+100\n", + " 186 traj.rotation.collocation_constraint.defects:alpha e 0.000000E+00 -4.059757E-03 0.000000E+00 E 9.00000E+100\n", + " 187 traj.rotation.collocation_constraint.defects:alpha e 0.000000E+00 -2.379375E-02 0.000000E+00 E 9.00000E+100\n", + " 188 traj.rotation.collocation_constraint.defects:alpha e 0.000000E+00 -3.032572E-02 0.000000E+00 E 9.00000E+100\n", + " 189 traj.rotation.collocation_constraint.defects:TAS e 0.000000E+00 -4.947590E-02 0.000000E+00 E 9.00000E+100\n", + " 190 traj.rotation.collocation_constraint.defects:TAS e 0.000000E+00 -4.694172E-02 0.000000E+00 E 9.00000E+100\n", + " 191 traj.rotation.collocation_constraint.defects:TAS e 0.000000E+00 -4.521174E-02 0.000000E+00 E 9.00000E+100\n", + " 192 traj.rotation.collocation_constraint.defects:mass e 0.000000E+00 6.132037E-05 0.000000E+00 E 9.00000E+100\n", + " 193 traj.rotation.collocation_constraint.defects:mass e 0.000000E+00 6.136432E-05 0.000000E+00 E 9.00000E+100\n", + " 194 traj.rotation.collocation_constraint.defects:mass e 0.000000E+00 6.142751E-05 0.000000E+00 E 9.00000E+100\n", + " 195 traj.rotation.collocation_constraint.defects:distance e 0.000000E+00 1.251386E+00 0.000000E+00 E 9.00000E+100\n", + " 196 traj.rotation.collocation_constraint.defects:distance e 0.000000E+00 1.914830E-01 0.000000E+00 E 9.00000E+100\n", + " 197 traj.rotation.collocation_constraint.defects:distance e 0.000000E+00 -1.615733E-01 0.000000E+00 E 9.00000E+100\n", + " 198 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.280810E-01 1.100000E+00 9.00000E+100\n", + " 199 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.127141E-01 1.100000E+00 9.00000E+100\n", + " 200 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.131475E-01 1.100000E+00 9.00000E+100\n", + " 201 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.139957E-01 1.100000E+00 9.00000E+100\n", + " 202 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.139957E-01 1.100000E+00 9.00000E+100\n", + " 203 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.161165E-01 1.100000E+00 9.00000E+100\n", + " 204 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.189456E-01 1.100000E+00 9.00000E+100\n", + " 205 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.197486E-01 1.100000E+00 9.00000E+100\n", + " 206 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.197486E-01 1.100000E+00 9.00000E+100\n", + " 207 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.214011E-01 1.100000E+00 9.00000E+100\n", + " 208 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.232370E-01 1.100000E+00 9.00000E+100\n", + " 209 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.237063E-01 1.100000E+00 9.00000E+100\n", + " 210 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.237063E-01 1.100000E+00 9.00000E+100\n", + " 211 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.245697E-01 1.100000E+00 9.00000E+100\n", + " 212 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.252587E-01 1.100000E+00 9.00000E+100\n", + " 213 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.253505E-01 1.100000E+00 9.00000E+100\n", + " 214 traj.phases.ascent->path_constraint->theta i 0.000000E+00 1.000000E+00 1.500000E+01 9.00000E+100\n", + " 215 traj.phases.ascent->path_constraint->theta i 0.000000E+00 1.621339E+00 1.500000E+01 9.00000E+100\n", + " 216 traj.phases.ascent->path_constraint->theta i 0.000000E+00 2.478661E+00 1.500000E+01 9.00000E+100\n", + " 217 traj.phases.ascent->path_constraint->theta i 0.000000E+00 2.750000E+00 1.500000E+01 9.00000E+100\n", + " 218 traj.phases.ascent->path_constraint->theta i 0.000000E+00 2.750000E+00 1.500000E+01 9.00000E+100\n", + " 219 traj.phases.ascent->path_constraint->theta i 0.000000E+00 3.371339E+00 1.500000E+01 9.00000E+100\n", + " 220 traj.phases.ascent->path_constraint->theta i 0.000000E+00 4.228661E+00 1.500000E+01 9.00000E+100\n", + " 221 traj.phases.ascent->path_constraint->theta i 0.000000E+00 4.500000E+00 1.500000E+01 9.00000E+100\n", + " 222 traj.phases.ascent->path_constraint->theta i 0.000000E+00 4.500000E+00 1.500000E+01 9.00000E+100\n", + " 223 traj.phases.ascent->path_constraint->theta i 0.000000E+00 5.121339E+00 1.500000E+01 9.00000E+100\n", + " 224 traj.phases.ascent->path_constraint->theta i 0.000000E+00 5.978661E+00 1.500000E+01 9.00000E+100\n", + " 225 traj.phases.ascent->path_constraint->theta i 0.000000E+00 6.250000E+00 1.500000E+01 9.00000E+100\n", + " 226 traj.phases.ascent->path_constraint->theta i 0.000000E+00 6.250000E+00 1.500000E+01 9.00000E+100\n", + " 227 traj.phases.ascent->path_constraint->theta i 0.000000E+00 6.871339E+00 1.500000E+01 9.00000E+100\n", + " 228 traj.phases.ascent->path_constraint->theta i 0.000000E+00 7.728661E+00 1.500000E+01 9.00000E+100\n", + " 229 traj.phases.ascent->path_constraint->theta i 0.000000E+00 8.000000E+00 1.500000E+01 9.00000E+100\n", + " 230 traj.phases.climb2->final_boundary_constraint->altitude_rate i 1.000000E-01 3.314185E+02 1.000000E+30 9.00000E+100\n", + "\n", + "\n", + " Exit Status\n", + " Inform Description\n", + " -1 Maximum Iterations Exceeded\n", + "--------------------------------------------------------------------------------\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from aviary.api import Aircraft, Mission\n", "import aviary.api as av\n", @@ -150,7 +910,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "b0baac27", "metadata": {}, "outputs": [], @@ -200,10 +960,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "8cac423c", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'aircraft:blended_wing_body_design:num_bays': (0, 'unitless'), 'aircraft:crew_and_payload:mass_per_passenger': (165.0, 'lbm'), 'aircraft:crew_and_payload:num_business_class': (0, 'unitless'), 'aircraft:crew_and_payload:num_first_class': (0, 'unitless'), 'aircraft:crew_and_payload:num_passengers': (180, 'unitless'), 'aircraft:crew_and_payload:num_tourist_class': (0, 'unitless'), 'aircraft:crew_and_payload:passenger_mass_with_bags': (200, 'lbm'), 'aircraft:design:compute_htail_volume_coeff': (False, 'unitless'), 'aircraft:design:compute_vtail_volume_coeff': (False, 'unitless'), 'aircraft:design:part25_structural_category': (3, 'unitless'), 'aircraft:design:reserves': (4998, 'unitless'), 'aircraft:design:smooth_mass_discontinuities': (False, 'unitless'), 'aircraft:design:ulf_calculated_from_maneuver': (False, 'unitless'), 'aircraft:design:use_alt_mass': (False, 'unitless'), 'aircraft:electrical:has_hybrid_system': (False, 'unitless'), 'aircraft:engine:constant_fuel_consumption': (array([0.]), 'lbm/h'), 'aircraft:engine:flight_idle_max_fraction': (array([1.]), 'unitless'), 'aircraft:engine:flight_idle_min_fraction': (array([0.08]), 'unitless'), 'aircraft:engine:flight_idle_thrust_fraction': (array([0.]), 'unitless'), 'aircraft:engine:fuel_flow_scaler_constant_term': (array([0.]), 'unitless'), 'aircraft:engine:fuel_flow_scaler_linear_term': (array([0.]), 'unitless'), 'aircraft:engine:generate_flight_idle': ([False], 'unitless'), 'aircraft:engine:geopotential_alt': ([False], 'unitless'), 'aircraft:engine:has_propellers': ([False], 'unitless'), 'aircraft:engine:ignore_negative_thrust': ([False], 'unitless'), 'aircraft:engine:interpolation_method': (['slinear'], 'unitless'), 'aircraft:engine:num_engines': (array([2]), 'unitless'), 'aircraft:engine:num_fuselage_engines': (array([0]), 'unitless'), 'aircraft:engine:num_wing_engines': (array([2]), 'unitless'), 'aircraft:engine:scale_mass': ([True], 'unitless'), 'aircraft:engine:scale_performance': ([True], 'unitless'), 'aircraft:engine:subsonic_fuel_flow_scaler': (array([1.]), 'unitless'), 'aircraft:engine:supersonic_fuel_flow_scaler': (array([1.]), 'unitless'), 'aircraft:engine:type': ([], 'unitless'), 'aircraft:fins:num_fins': (0, 'unitless'), 'aircraft:fuel:num_tanks': (7, 'unitless'), 'aircraft:fuselage:aisle_width': (24, 'inch'), 'aircraft:fuselage:military_cargo_floor': (False, 'unitless'), 'aircraft:fuselage:num_aisles': (1, 'unitless'), 'aircraft:fuselage:num_fuselages': (1, 'unitless'), 'aircraft:fuselage:num_seats_abreast': (6, 'unitless'), 'aircraft:fuselage:provide_surface_area': (True, 'unitless'), 'aircraft:fuselage:seat_pitch': (29, 'inch'), 'aircraft:fuselage:seat_width': (20.2, 'inch'), 'aircraft:landing_gear:carrier_based': (False, 'unitless'), 'aircraft:landing_gear:drag_coefficient': (0.0, 'unitless'), 'aircraft:landing_gear:fixed_gear': (False, 'unitless'), 'aircraft:strut:dimensional_location_specified': (False, 'unitless'), 'aircraft:vertical_tail:num_tails': (1, 'unitless'), 'aircraft:wing:airfoil_technology': (1.0, 'unitless'), 'aircraft:wing:choose_fold_location': (True, 'unitless'), 'aircraft:wing:detailed_wing': (False, 'unitless'), 'aircraft:wing:flap_type': (, 'unitless'), 'aircraft:wing:fold_dimensional_location_specified': (False, 'unitless'), 'aircraft:wing:has_fold': (False, 'unitless'), 'aircraft:wing:has_strut': (False, 'unitless'), 'aircraft:wing:load_distribution_control': (2.0, 'unitless'), 'aircraft:wing:loading_above_20': (True, 'unitless'), 'aircraft:wing:num_flap_segments': (2, 'unitless'), 'aircraft:wing:num_integration_stations': (50, 'unitless'), 'aircraft:wing:span_efficiency_reduction': (False, 'unitless'), 'mission:design:cruise_altitude': (37500, 'ft'), 'mission:design:rate_of_climb_at_top_of_climb': (0.0, 'ft/min'), 'mission:summary:fuel_flow_scaler': (1, 'unitless'), 'mission:takeoff:angle_of_attack_runway': (0.0, 'deg'), 'mission:takeoff:obstacle_height': (35.0, 'ft'), 'mission:takeoff:thrust_incidence': (0.0, 'deg'), 'mission:taxi:duration': (0.1677, 'h'), 'mission:taxi:mach': (0.0001, 'unitless'), 'debug_mode': (False, 'unitless'), 'INGASP.JENGSZ': (4, 'unitless'), 'test_mode': (False, 'unitless'), 'use_surrogates': (True, 'unitless'), 'mass_defect': (10000, 'lbm'), 'problem_type': (, 'unitless'), 'aircraft:controls:cockpit_control_mass_scaler': (1, 'unitless'), 'aircraft:controls:control_mass_increment': (0, 'lbm'), 'aircraft:controls:stability_augmentation_system_mass': (0, 'lbm'), 'aircraft:controls:stability_augmentation_system_mass_scaler': (1, 'unitless'), 'aircraft:crew_and_payload:cargo_mass': (10040, 'lbm'), 'aircraft:design:cg_delta': (0.25, 'unitless'), 'aircraft:design:cockpit_control_mass_coefficient': (16.5, 'unitless'), 'aircraft:design:drag_increment': (0.00175, 'unitless'), 'aircraft:design:equipment_mass_coefficients': ([928, 0.0736, 0.112, 0.14, 1959, 1.65, 551, 11192, 5, 3, 50, 7.6, 12], 'unitless'), 'aircraft:design:max_structural_speed': (402.5, 'mi/h'), 'aircraft:design:static_margin': (0.03, 'unitless'), 'aircraft:design:structural_mass_increment': (0, 'lbm'), 'aircraft:design:supercritical_drag_shift': (0.033, 'unitless'), 'aircraft:engine:additional_mass_fraction': (array([0.135]), 'unitless'), 'aircraft:engine:data_file': (['models/engines/turbofan_23k_1.deck'], 'unitless'), 'aircraft:engine:mass_scaler': (array([1]), 'unitless'), 'aircraft:engine:mass_specific': (array([0.21366]), 'lbm/lbf'), 'aircraft:engine:pod_mass_scaler': (array([1]), 'unitless'), 'aircraft:engine:pylon_factor': (array([1.25]), 'unitless'), 'aircraft:engine:reference_diameter': (array([5.8]), 'ft'), 'aircraft:engine:reference_sls_thrust': (array([28690]), 'lbf'), 'aircraft:engine:scale_factor': (array([1]), 'unitless'), 'aircraft:engine:scaled_sls_thrust': (array([28690]), 'lbf'), 'aircraft:engine:wing_locations': (array([0.35]), 'unitless'), 'aircraft:fuel:density': (6.687, 'lbm/galUS'), 'aircraft:fuel:fuel_margin': (0, 'unitless'), 'aircraft:fuel:fuel_system_mass_coefficient': (0.041, 'unitless'), 'aircraft:fuel:fuel_system_mass_scaler': (1, 'unitless'), 'aircraft:fuel:wing_fuel_fraction': (0.6, 'unitless'), 'aircraft:fuselage:delta_diameter': (4.5, 'ft'), 'aircraft:fuselage:flat_plate_area_increment': (0.25, 'ft**2'), 'aircraft:fuselage:form_factor': (1.25, 'unitless'), 'aircraft:fuselage:mass_coefficient': (128, 'unitless'), 'aircraft:fuselage:nose_fineness': (1, 'unitless'), 'aircraft:fuselage:pilot_compartment_length': (9.5, 'ft'), 'aircraft:fuselage:pressure_differential': (7.5, 'psi'), 'aircraft:fuselage:tail_fineness': (3, 'unitless'), 'aircraft:fuselage:wetted_area_factor': (4000, 'unitless'), 'aircraft:horizontal_tail:area': (0, 'ft**2'), 'aircraft:horizontal_tail:aspect_ratio': (4.75, 'unitless'), 'aircraft:horizontal_tail:form_factor': (1.25, 'unitless'), 'aircraft:horizontal_tail:mass_coefficient': (0.232, 'unitless'), 'aircraft:horizontal_tail:moment_ratio': (0.2307, 'unitless'), 'aircraft:horizontal_tail:sweep': (25, 'deg'), 'aircraft:horizontal_tail:taper_ratio': (0.352, 'unitless'), 'aircraft:horizontal_tail:thickness_to_chord': (0.12, 'unitless'), 'aircraft:horizontal_tail:vertical_tail_fraction': (0, 'unitless'), 'aircraft:horizontal_tail:volume_coefficient': (1.189, 'unitless'), 'aircraft:landing_gear:main_gear_location': (0.15, 'unitless'), 'aircraft:landing_gear:main_gear_mass_coefficient': (0.85, 'unitless'), 'aircraft:landing_gear:mass_coefficient': (0.04, 'unitless'), 'aircraft:landing_gear:tail_hook_mass_scaler': (1, 'unitless'), 'aircraft:landing_gear:total_mass_scaler': (1, 'unitless'), 'aircraft:nacelle:clearance_ratio': (array([0.2]), 'unitless'), 'aircraft:nacelle:core_diameter_ratio': (array([1.25]), 'unitless'), 'aircraft:nacelle:fineness': (array([2]), 'unitless'), 'aircraft:nacelle:form_factor': (array([1.5]), 'unitless'), 'aircraft:nacelle:mass_specific': (array([3]), 'lbm/ft**2'), 'aircraft:strut:area_ratio': (0, 'unitless'), 'aircraft:strut:attachment_location': (0, 'ft'), 'aircraft:strut:attachment_location_dimensionless': (0, 'unitless'), 'aircraft:strut:fuselage_interference_factor': (0, 'unitless'), 'aircraft:strut:mass_coefficient': (0, 'unitless'), 'aircraft:strut:thickness_to_chord': (0, 'unitless'), 'aircraft:vertical_tail:area': (0, 'ft**2'), 'aircraft:vertical_tail:aspect_ratio': (1.67, 'unitless'), 'aircraft:vertical_tail:form_factor': (1.25, 'unitless'), 'aircraft:vertical_tail:mass_coefficient': (0.289, 'unitless'), 'aircraft:vertical_tail:moment_ratio': (2.362, 'unitless'), 'aircraft:vertical_tail:sweep': (35, 'deg'), 'aircraft:vertical_tail:taper_ratio': (0.801, 'unitless'), 'aircraft:vertical_tail:thickness_to_chord': (0.12, 'unitless'), 'aircraft:vertical_tail:volume_coefficient': (0.145, 'unitless'), 'aircraft:wing:aspect_ratio': (10.13, 'unitless'), 'aircraft:wing:center_distance': (0.463, 'unitless'), 'aircraft:wing:flap_chord_ratio': (0.3, 'unitless'), 'aircraft:wing:flap_deflection_landing': (40, 'deg'), 'aircraft:wing:flap_deflection_takeoff': (10, 'deg'), 'aircraft:wing:flap_drag_increment_optimum': (0.1, 'unitless'), 'aircraft:wing:flap_lift_increment_optimum': (1.5, 'unitless'), 'aircraft:wing:flap_span_ratio': (0.65, 'unitless'), 'aircraft:wing:fold_mass_coefficient': (0, 'unitless'), 'aircraft:wing:folded_span': (0, 'ft'), 'aircraft:wing:form_factor': (1.25, 'unitless'), 'aircraft:wing:fuselage_interference_factor': (1.1, 'unitless'), 'aircraft:wing:height': (8, 'ft'), 'aircraft:wing:high_lift_mass_coefficient': (1.9, 'unitless'), 'aircraft:wing:incidence': (1.5, 'deg'), 'aircraft:wing:loading': (128, 'lbf/ft**2'), 'aircraft:wing:mass_coefficient': (102.5, 'unitless'), 'aircraft:wing:max_lift_ref': (1.15, 'unitless'), 'aircraft:wing:max_slat_deflection_landing': (10, 'deg'), 'aircraft:wing:max_slat_deflection_takeoff': (10, 'deg'), 'aircraft:wing:max_thickness_location': (0.4, 'unitless'), 'aircraft:wing:min_pressure_location': (0.3, 'unitless'), 'aircraft:wing:mounting_type': (0, 'unitless'), 'aircraft:wing:optimum_flap_deflection': (55, 'deg'), 'aircraft:wing:optimum_slat_deflection': (20, 'deg'), 'aircraft:wing:slat_chord_ratio': (0.15, 'unitless'), 'aircraft:wing:slat_lift_increment_optimum': (0.93, 'unitless'), 'aircraft:wing:surface_ctrl_mass_coefficient': (0.95, 'unitless'), 'aircraft:wing:sweep': (25, 'deg'), 'aircraft:wing:taper_ratio': (0.33, 'unitless'), 'aircraft:wing:thickness_to_chord_root': (0.15, 'unitless'), 'aircraft:wing:thickness_to_chord_tip': (0.12, 'unitless'), 'aircraft:wing:zero_lift_angle': (-1.2, 'deg'), 'mission:design:gross_mass': (175400, 'lbm'), 'mission:design:mach': (0.8, 'unitless'), 'mission:design:range': (3675, 'NM'), 'mission:landing:braking_delay': (1, 's'), 'mission:landing:glide_to_stall_ratio': (1.3, 'unitless'), 'mission:landing:maximum_flare_load_factor': (1.15, 'unitless'), 'mission:landing:maximum_sink_rate': (900, 'ft/min'), 'mission:landing:obstacle_height': (50, 'ft'), 'mission:landing:touchdown_sink_rate': (5, 'ft/s'), 'mission:takeoff:decision_speed_increment': (10, 'kn'), 'mission:takeoff:rotation_speed_increment': (5, 'kn'), 'mission:summary:cruise_mass_final': (140320.0, 'lbm'), 'mission:summary:gross_mass': (175400, 'lbm'), 'engine_models': ([], 'unitless'), 'aircraft:propulsion:total_num_engines': (2, 'unitless'), 'aircraft:propulsion:total_num_fuselage_engines': (0, 'unitless'), 'aircraft:propulsion:total_num_wing_engines': (2, 'unitless')}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "prob.load_inputs(aircraft_filename)" ] @@ -242,7 +1013,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "e3d91612", "metadata": {}, "outputs": [], @@ -262,7 +1033,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "00de09c8", "metadata": {}, "outputs": [], @@ -284,14 +1055,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "b17b6637", "metadata": { "tags": [ "hide-output" ] }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "prob.add_phases()" ] @@ -308,7 +1090,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "af5ba774", "metadata": {}, "outputs": [], @@ -328,7 +1110,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "f765815b", "metadata": {}, "outputs": [], @@ -352,7 +1134,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "87e863bc", "metadata": {}, "outputs": [], @@ -380,7 +1162,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "0a408e2e", "metadata": {}, "outputs": [], @@ -427,7 +1209,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "46eee283", "metadata": {}, "outputs": [], @@ -482,10 +1264,177 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "id": "dbfca715", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/group.py:333: PromotionWarning:: Setting input defaults for input 'mission:takeoff:ascent_duration' which override previously set defaults for ['auto', 'prom', 'src_shape', 'val'].\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.speeds' : d(*)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.params' : d(max_mach)/d(max_airspeed): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.params' : d(density_ratio)/d(max_airspeed): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.params' : d(V9)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.factors' : d(aircraft:wing:ultimate_load_factor)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.fixed_mass.params' : d(c_gear_loc)/d(aircraft:landing_gear:main_gear_location): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.equip_and_useful_mass' : d(aircraft:design:fixed_useful_load)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.equip_and_useful_mass' : d(aircraft:design:fixed_equipment_mass)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'groundroll': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.groundroll.rhs_all.eoms' : d(alpha_rate)/d(('*',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2185: UserWarning: Phase time options have no effect because fix_initial=True or input_initial=True for phase 'traj.phases.rotation': initial_ref\n", + " warnings.warn(f'Phase time options have no effect because fix_initial=True '\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'rotation': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.rotation.rhs_all.eoms' : d(alpha_rate)/d(('*',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'ascent': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2185: UserWarning: Phase time options have no effect because fix_initial=True or input_initial=True for phase 'traj.phases.accel': initial_bounds\n", + " warnings.warn(f'Phase time options have no effect because fix_initial=True '\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'accel': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2185: UserWarning: Phase time options have no effect because fix_initial=True or input_initial=True for phase 'traj.phases.climb1': initial_bounds\n", + " warnings.warn(f'Phase time options have no effect because fix_initial=True '\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'climb1': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2185: UserWarning: Phase time options have no effect because fix_initial=True or input_initial=True for phase 'traj.phases.climb2': initial_bounds\n", + " warnings.warn(f'Phase time options have no effect because fix_initial=True '\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'climb2': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2185: UserWarning: Phase time options have no effect because fix_initial=True or input_initial=True for phase 'traj.phases.desc1': initial_bounds, initial_ref\n", + " warnings.warn(f'Phase time options have no effect because fix_initial=True '\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'desc1': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2185: UserWarning: Phase time options have no effect because fix_initial=True or input_initial=True for phase 'traj.phases.desc2': initial_bounds, initial_ref\n", + " warnings.warn(f'Phase time options have no effect because fix_initial=True '\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'throttle' in phase 'desc2': lower, upper\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "The following variables have been overridden:\n", + " 'aircraft:engine:scale_factor\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.accel: The following timeseries outputs were requested but not found in the ODE: aero.CD, aero.CL\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.accel' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.accel.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.accel.nonlinear_solver to override.\n", + " Setting `traj.phases.accel.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.accel.linear_solver to override.\n", + " Set `traj.phases.accel.options[\"auto_solvers\"] = False` to disable this behavior.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.ascent' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.ascent.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.ascent.nonlinear_solver to override.\n", + " Setting `traj.phases.ascent.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.ascent.linear_solver to override.\n", + " Set `traj.phases.ascent.options[\"auto_solvers\"] = False` to disable this behavior.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.climb1: The following timeseries outputs were requested but not found in the ODE: aero.CD, aero.CL\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.climb1' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.climb1.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.climb1.nonlinear_solver to override.\n", + " Setting `traj.phases.climb1.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.climb1.linear_solver to override.\n", + " Set `traj.phases.climb1.options[\"auto_solvers\"] = False` to disable this behavior.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.climb2: The following timeseries outputs were requested but not found in the ODE: aero.CD, aero.CL\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.climb2' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.climb2.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.climb2.nonlinear_solver to override.\n", + " Setting `traj.phases.climb2.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.climb2.linear_solver to override.\n", + " Set `traj.phases.climb2.options[\"auto_solvers\"] = False` to disable this behavior.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.desc1: The following timeseries outputs were requested but not found in the ODE: aero.CD, aero.CL\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.desc1' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.desc1.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.desc1.nonlinear_solver to override.\n", + " Setting `traj.phases.desc1.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.desc1.linear_solver to override.\n", + " Set `traj.phases.desc1.options[\"auto_solvers\"] = False` to disable this behavior.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.desc2: The following timeseries outputs were requested but not found in the ODE: aero.CD, aero.CL\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.desc2' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.desc2.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.desc2.nonlinear_solver to override.\n", + " Setting `traj.phases.desc2.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.desc2.linear_solver to override.\n", + " Set `traj.phases.desc2.options[\"auto_solvers\"] = False` to disable this behavior.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.rotation' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.rotation.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.rotation.nonlinear_solver to override.\n", + " Setting `traj.phases.rotation.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.rotation.linear_solver to override.\n", + " Set `traj.phases.rotation.options[\"auto_solvers\"] = False` to disable this behavior.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "--- Constraint Report [traj] ---\n", + " --- groundroll ---\n", + " None\n", + " --- rotation ---\n", + " [final] 0.0000e+00 == normal_force [lbf]\n", + " --- ascent ---\n", + " [final] 5.0000e+02 == altitude [ft]\n", + " [path] 0.0000e+00 <= load_factor <= 1.1000e+00 [unitless]\n", + " [path] 0.0000e+00 <= fuselage_pitch <= 1.5000e+01 [deg]\n", + " --- accel ---\n", + " [final] 2.5000e+02 == EAS [kn]\n", + " --- climb1 ---\n", + " [final] 1.0000e+04 == altitude [ft]\n", + " --- climb2 ---\n", + " [final] 3.7500e+04 == altitude [ft]\n", + " [final] 1.0000e-01 <= altitude_rate [ft/min]\n", + " [final] 8.0000e-01 == mach [unitless]\n", + " --- cruise ---\n", + " None\n", + " --- desc1 ---\n", + " [final] 1.0000e+04 == altitude [ft]\n", + " --- desc2 ---\n", + " [final] 1.0000e+03 == altitude [ft]\n", + "\n" + ] + } + ], "source": [ "prob.setup()" ] @@ -506,7 +1455,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "afdf6203", "metadata": {}, "outputs": [], @@ -526,10 +1475,603 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "2f1a2b82", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'landing.aero_app.lift_coef' : d(CL_base)/d(('CL_max_flaps',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'landing.aero_td.lift_coef' : d(CL_base)/d(('CL_max_flaps',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.ascent.rhs_all.core_aerodynamics.lift_coef' : d(CL_base)/d(('CL_max_flaps',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.groundroll.rhs_all.core_aerodynamics.lift_coef' : d(CL_base)/d(('CL_max_flaps',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.rotation.rhs_all.core_aerodynamics.lift_coef' : d(CL_base)/d(('CL_max_flaps',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, aviary_history.db, is being overwritten.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model viewer data has already been recorded for Driver.\n", + "Model viewer data has already been recorded for Driver.\n", + "\n", + "Coloring for 'event_xform' (class ExecComp)\n", + "\n", + "Jacobian shape: (2, 4) (75.00% nonzero)\n", + "FWD solves: 3 REV solves: 0\n", + "Total colors vs. total size: 3 vs 4 (25.00% improvement)\n", + "\n", + "Sparsity computed using tolerance: 1e-25\n", + "Time to compute sparsity: 0.0005 sec\n", + "Time to compute coloring: 0.0009 sec\n", + "Memory to compute coloring: 0.0000 MB\n", + "Full total jacobian was computed 3 times, taking 2.002681 seconds.\n", + "Total jacobian shape: (232, 203) \n", + "\n", + "\n", + "Jacobian shape: (232, 203) (7.47% nonzero)\n", + "FWD solves: 45 REV solves: 0\n", + "Total colors vs. total size: 45 vs 203 (77.83% improvement)\n", + "\n", + "Sparsity computed using tolerance: 1e-25\n", + "Time to compute sparsity: 2.0027 sec\n", + "Time to compute coloring: 0.1893 sec\n", + "Memory to compute coloring: 0.0000 MB\n", + "Coloring created on: 2024-01-09 11:24:45\n", + "\n", + "List of user-set options:\n", + "\n", + " Name Value used\n", + " alpha_for_y = safer-min-dual-infeas yes\n", + " file_print_level = 5 yes\n", + " hessian_approximation = limited-memory yes\n", + " linear_solver = mumps yes\n", + " max_iter = 1 yes\n", + " mu_init = 1e-05 yes\n", + " mu_strategy = monotone yes\n", + " nlp_scaling_method = gradient-based yes\n", + " output_file = reports/problem2/IPOPT.out yes\n", + " print_level = 5 yes\n", + " print_user_options = yes yes\n", + " sb = yes yes\n", + " tol = 1e-06 yes\n", + "This is Ipopt version 3.14.12, running with linear solver MUMPS 5.2.1.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 2343\n", + "Number of nonzeros in inequality constraint Jacobian.: 568\n", + "Number of nonzeros in Lagrangian Hessian.............: 0\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/total_jac.py:1759: DerivativesWarning:Constraints or objectives [('traj.phases.climb2.timeseries.timeseries_comp.mach', inds=[(11, 0)])] cannot be impacted by the design variables of the problem.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Total number of variables............................: 203\n", + " variables with only lower bounds: 0\n", + " variables with lower and upper bounds: 203\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 198\n", + "Total number of inequality constraints...............: 33\n", + " inequality constraints with only lower bounds: 1\n", + " inequality constraints with lower and upper bounds: 32\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 5.2731333e+00 1.30e+01 1.75e+01 -5.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 5.0168614e+00 8.67e+00 1.50e+01 -5.0 1.59e+01 - 1.17e-01 3.00e-01h 1\n", + "\n", + "Number of Iterations....: 1\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 5.0168613936496804e+00 5.0168613936496804e+00\n", + "Dual infeasibility......: 1.4970544949172231e+01 1.4970544949172231e+01\n", + "Constraint violation....: 2.4092945450656864e+00 8.6732536855893478e+00\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 1.0000016687732632e+05 1.0000016687732632e+05\n", + "Overall NLP error.......: 1.0000016687732632e+05 1.0000016687732632e+05\n", + "\n", + "\n", + "Number of objective function evaluations = 2\n", + "Number of objective gradient evaluations = 2\n", + "Number of equality constraint evaluations = 2\n", + "Number of inequality constraint evaluations = 2\n", + "Number of equality constraint Jacobian evaluations = 2\n", + "Number of inequality constraint Jacobian evaluations = 2\n", + "Number of Lagrangian Hessian evaluations = 0\n", + "Total seconds in IPOPT = 3.834\n", + "\n", + "EXIT: Maximum Number of Iterations Exceeded.\n", + "\n", + "\n", + "Optimization Problem -- Optimization using pyOpt_sparse\n", + "================================================================================\n", + " Objective Function: _objfunc\n", + "\n", + " Solution: \n", + "--------------------------------------------------------------------------------\n", + " Total Time: 3.8360\n", + " User Objective Time : 0.8133\n", + " User Sensitivity Time : 2.9721\n", + " Interface Time : 0.0214\n", + " Opt Solver Time: 0.0292\n", + " Calls to Objective Function : 3\n", + " Calls to Sens Function : 3\n", + "\n", + "\n", + " Objectives\n", + " Index Name Value\n", + " 0 mission:objectives:fuel 5.016861E+00\n", + "\n", + " Variables (c - continuous, i - integer, d - discrete)\n", + " Index Name Type Lower Bound Value Upper Bound Status\n", + " 0 mission:takeoff:ascent_t_initial_0 c 0.000000E+00 6.663289E-01 3.333333E+00 \n", + " 1 mission:takeoff:ascent_duration_0 c 1.000000E-01 1.903980E+00 1.000000E+02 \n", + " 2 tau_gear_0 c 1.000000E-02 1.986843E-01 1.000000E+00 \n", + " 3 tau_flaps_0 c 1.000000E-02 9.999990E-01 1.000000E+00 u\n", + " 4 mission:design:gross_mass_0 c 5.714286E-05 9.998350E-01 2.285714E+00 \n", + " 5 mission:summary:gross_mass_0 c 5.714286E-05 9.998349E-01 2.285714E+00 \n", + " 6 traj.accel.t_duration_0 c 1.000000E-03 2.212205E-02 2.000000E-01 \n", + " 7 traj.accel.states:TAS_0 c 0.000000E+00 4.861863E-01 1.200000E+00 \n", + " 8 traj.accel.states:TAS_1 c 0.000000E+00 8.822185E-01 1.200000E+00 \n", + " 9 traj.accel.states:TAS_2 c 0.000000E+00 1.005468E+00 1.200000E+00 \n", + " 10 traj.accel.states:mass_0 c 0.000000E+00 1.157434E+00 6.666667E+15 \n", + " 11 traj.accel.states:mass_1 c 0.000000E+00 1.157276E+00 6.666667E+15 \n", + " 12 traj.accel.states:mass_2 c 0.000000E+00 1.157225E+00 6.666667E+15 \n", + " 13 traj.accel.states:distance_0 c 0.000000E+00 2.927784E-01 3.000000E+01 \n", + " 14 traj.accel.states:distance_1 c 0.000000E+00 4.219190E-01 3.000000E+01 \n", + " 15 traj.accel.states:distance_2 c 0.000000E+00 6.122452E-01 3.000000E+01 \n", + " 16 traj.accel.states:distance_3 c 0.000000E+00 6.753987E-01 3.000000E+01 \n", + " 17 traj.ascent.states:flight_path_angle_0 c -1.000000E+01 2.360690E-02 2.000000E+01 \n", + " 18 traj.ascent.states:flight_path_angle_1 c -1.000000E+01 3.040127E-02 2.000000E+01 \n", + " 19 traj.ascent.states:flight_path_angle_2 c -1.000000E+01 3.345939E-02 2.000000E+01 \n", + " 20 traj.ascent.states:flight_path_angle_3 c -1.000000E+01 5.069081E-02 2.000000E+01 \n", + " 21 traj.ascent.states:flight_path_angle_4 c -1.000000E+01 8.385235E-02 2.000000E+01 \n", + " 22 traj.ascent.states:flight_path_angle_5 c -1.000000E+01 9.279566E-02 2.000000E+01 \n", + " 23 traj.ascent.states:flight_path_angle_6 c -1.000000E+01 1.061651E-01 2.000000E+01 \n", + " 24 traj.ascent.states:flight_path_angle_7 c -1.000000E+01 1.229399E-01 2.000000E+01 \n", + " 25 traj.ascent.states:flight_path_angle_8 c -1.000000E+01 1.316649E-01 2.000000E+01 \n", + " 26 traj.ascent.states:flight_path_angle_9 c -1.000000E+01 1.589271E-01 2.000000E+01 \n", + " 27 traj.ascent.states:flight_path_angle_10 c -1.000000E+01 1.719337E-01 2.000000E+01 \n", + " 28 traj.ascent.states:flight_path_angle_11 c -1.000000E+01 1.595008E-01 2.000000E+01 \n", + " 29 traj.ascent.states:altitude_0 c 0.000000E+00 3.528809E-02 7.000000E-01 \n", + " 30 traj.ascent.states:altitude_1 c 0.000000E+00 8.599337E-02 7.000000E-01 \n", + " 31 traj.ascent.states:altitude_2 c 0.000000E+00 9.915362E-02 7.000000E-01 \n", + " 32 traj.ascent.states:altitude_3 c 0.000000E+00 1.318988E-01 7.000000E-01 \n", + " 33 traj.ascent.states:altitude_4 c 0.000000E+00 1.860149E-01 7.000000E-01 \n", + " 34 traj.ascent.states:altitude_5 c 0.000000E+00 2.066068E-01 7.000000E-01 \n", + " 35 traj.ascent.states:altitude_6 c 0.000000E+00 2.541925E-01 7.000000E-01 \n", + " 36 traj.ascent.states:altitude_7 c 0.000000E+00 3.201926E-01 7.000000E-01 \n", + " 37 traj.ascent.states:altitude_8 c 0.000000E+00 3.408680E-01 7.000000E-01 \n", + " 38 traj.ascent.states:altitude_9 c 0.000000E+00 3.960025E-01 7.000000E-01 \n", + " 39 traj.ascent.states:altitude_10 c 0.000000E+00 4.769747E-01 7.000000E-01 \n", + " 40 traj.ascent.states:altitude_11 c 0.000000E+00 5.000000E-01 7.000000E-01 \n", + " 41 traj.ascent.states:TAS_0 c 0.000000E+00 7.698851E-01 3.500000E+00 \n", + " 42 traj.ascent.states:TAS_1 c 0.000000E+00 7.849464E-01 3.500000E+00 \n", + " 43 traj.ascent.states:TAS_2 c 0.000000E+00 7.908113E-01 3.500000E+00 \n", + " 44 traj.ascent.states:TAS_3 c 0.000000E+00 8.027727E-01 3.500000E+00 \n", + " 45 traj.ascent.states:TAS_4 c 0.000000E+00 8.157842E-01 3.500000E+00 \n", + " 46 traj.ascent.states:TAS_5 c 0.000000E+00 8.187634E-01 3.500000E+00 \n", + " 47 traj.ascent.states:TAS_6 c 0.000000E+00 8.257023E-01 3.500000E+00 \n", + " 48 traj.ascent.states:TAS_7 c 0.000000E+00 8.351067E-01 3.500000E+00 \n", + " 49 traj.ascent.states:TAS_8 c 0.000000E+00 8.379758E-01 3.500000E+00 \n", + " 50 traj.ascent.states:TAS_9 c 0.000000E+00 8.416706E-01 3.500000E+00 \n", + " 51 traj.ascent.states:TAS_10 c 0.000000E+00 8.458506E-01 3.500000E+00 \n", + " 52 traj.ascent.states:TAS_11 c 0.000000E+00 8.485488E-01 3.500000E+00 \n", + " 53 traj.ascent.states:mass_0 c 0.000000E+00 1.157581E+00 6.666667E+15 \n", + " 54 traj.ascent.states:mass_1 c 0.000000E+00 1.157576E+00 6.666667E+15 \n", + " 55 traj.ascent.states:mass_2 c 0.000000E+00 1.157575E+00 6.666667E+15 \n", + " 56 traj.ascent.states:mass_3 c 0.000000E+00 1.157571E+00 6.666667E+15 \n", + " 57 traj.ascent.states:mass_4 c 0.000000E+00 1.157567E+00 6.666667E+15 \n", + " 58 traj.ascent.states:mass_5 c 0.000000E+00 1.157565E+00 6.666667E+15 \n", + " 59 traj.ascent.states:mass_6 c 0.000000E+00 1.157562E+00 6.666667E+15 \n", + " 60 traj.ascent.states:mass_7 c 0.000000E+00 1.157557E+00 6.666667E+15 \n", + " 61 traj.ascent.states:mass_8 c 0.000000E+00 1.157556E+00 6.666667E+15 \n", + " 62 traj.ascent.states:mass_9 c 0.000000E+00 1.157553E+00 6.666667E+15 \n", + " 63 traj.ascent.states:mass_10 c 0.000000E+00 1.157549E+00 6.666667E+15 \n", + " 64 traj.ascent.states:mass_11 c 0.000000E+00 1.157547E+00 6.666667E+15 \n", + " 65 traj.ascent.states:distance_0 c 0.000000E+00 4.893272E-01 1.500000E+00 \n", + " 66 traj.ascent.states:distance_1 c 0.000000E+00 5.458208E-01 1.500000E+00 \n", + " 67 traj.ascent.states:distance_2 c 0.000000E+00 5.635920E-01 1.500000E+00 \n", + " 68 traj.ascent.states:distance_3 c 0.000000E+00 6.042240E-01 1.500000E+00 \n", + " 69 traj.ascent.states:distance_4 c 0.000000E+00 6.597467E-01 1.500000E+00 \n", + " 70 traj.ascent.states:distance_5 c 0.000000E+00 6.771180E-01 1.500000E+00 \n", + " 71 traj.ascent.states:distance_6 c 0.000000E+00 7.164507E-01 1.500000E+00 \n", + " 72 traj.ascent.states:distance_7 c 0.000000E+00 7.697374E-01 1.500000E+00 \n", + " 73 traj.ascent.states:distance_8 c 0.000000E+00 7.863637E-01 1.500000E+00 \n", + " 74 traj.ascent.states:distance_9 c 0.000000E+00 8.237919E-01 1.500000E+00 \n", + " 75 traj.ascent.states:distance_10 c 0.000000E+00 8.739409E-01 1.500000E+00 \n", + " 76 traj.ascent.states:distance_11 c 0.000000E+00 8.894776E-01 1.500000E+00 \n", + " 77 traj.ascent.controls:alpha_0 c -6.000000E+00 9.525205E-01 6.000000E+00 \n", + " 78 traj.ascent.controls:alpha_1 c -6.000000E+00 6.452198E-01 6.000000E+00 \n", + " 79 traj.ascent.controls:alpha_2 c -6.000000E+00 5.707324E-01 6.000000E+00 \n", + " 80 traj.ascent.controls:alpha_3 c -6.000000E+00 6.315962E-01 6.000000E+00 \n", + " 81 traj.ascent.controls:alpha_4 c -6.000000E+00 7.611327E-01 6.000000E+00 \n", + " 82 traj.ascent.controls:alpha_5 c -6.000000E+00 7.549333E-01 6.000000E+00 \n", + " 83 traj.ascent.controls:alpha_6 c -6.000000E+00 7.082950E-01 6.000000E+00 \n", + " 84 traj.ascent.controls:alpha_7 c -6.000000E+00 6.317224E-01 6.000000E+00 \n", + " 85 traj.ascent.controls:alpha_8 c -6.000000E+00 7.060758E-01 6.000000E+00 \n", + " 86 traj.ascent.controls:alpha_9 c -6.000000E+00 7.730952E-01 6.000000E+00 \n", + " 87 traj.ascent.controls:alpha_10 c -6.000000E+00 8.061957E-01 6.000000E+00 \n", + " 88 traj.ascent.controls:alpha_11 c -6.000000E+00 3.780179E-01 6.000000E+00 \n", + " 89 traj.climb1.t_duration_0 c 3.000000E-02 1.356431E-01 3.000000E-01 \n", + " 90 traj.climb1.states:altitude_0 c 4.000000E-02 3.912255E-01 1.100000E+00 \n", + " 91 traj.climb1.states:altitude_1 c 4.000000E-02 8.557734E-01 1.100000E+00 \n", + " 92 traj.climb1.states:altitude_2 c 4.000000E-02 1.000000E+00 1.100000E+00 \n", + " 93 traj.climb1.states:mass_0 c 0.000000E+00 1.156777E+00 6.666667E+15 \n", + " 94 traj.climb1.states:mass_1 c 0.000000E+00 1.156200E+00 6.666667E+15 \n", + " 95 traj.climb1.states:mass_2 c 0.000000E+00 1.156027E+00 6.666667E+15 \n", + " 96 traj.climb1.states:distance_0 c 0.000000E+00 7.954574E-01 5.000000E+01 \n", + " 97 traj.climb1.states:distance_1 c 0.000000E+00 1.438757E+00 5.000000E+01 \n", + " 98 traj.climb1.states:distance_2 c 0.000000E+00 1.645332E+00 5.000000E+01 \n", + " 99 traj.climb2.t_duration_0 c 4.000000E-02 2.490175E-01 3.400000E+00 \n", + " 100 traj.climb2.states:altitude_0 c 3.000000E-01 4.725790E-01 1.333333E+00 \n", + " 101 traj.climb2.states:altitude_1 c 3.000000E-01 6.468055E-01 1.333333E+00 \n", + " 102 traj.climb2.states:altitude_2 c 3.000000E-01 6.984855E-01 1.333333E+00 \n", + " 103 traj.climb2.states:altitude_3 c 3.000000E-01 8.110606E-01 1.333333E+00 \n", + " 104 traj.climb2.states:altitude_4 c 3.000000E-01 9.523468E-01 1.333333E+00 \n", + " 105 traj.climb2.states:altitude_5 c 3.000000E-01 9.951949E-01 1.333333E+00 \n", + " 106 traj.climb2.states:altitude_6 c 3.000000E-01 1.091361E+00 1.333333E+00 \n", + " 107 traj.climb2.states:altitude_7 c 3.000000E-01 1.213786E+00 1.333333E+00 \n", + " 108 traj.climb2.states:altitude_8 c 3.000000E-01 1.250000E+00 1.333333E+00 \n", + " 109 traj.climb2.states:mass_0 c 0.000000E+00 1.147127E+00 6.666667E+15 \n", + " 110 traj.climb2.states:mass_1 c 0.000000E+00 1.146197E+00 6.666667E+15 \n", + " 111 traj.climb2.states:mass_2 c 0.000000E+00 1.145931E+00 6.666667E+15 \n", + " 112 traj.climb2.states:mass_3 c 0.000000E+00 1.145338E+00 6.666667E+15 \n", + " 113 traj.climb2.states:mass_4 c 0.000000E+00 1.144607E+00 6.666667E+15 \n", + " 114 traj.climb2.states:mass_5 c 0.000000E+00 1.144386E+00 6.666667E+15 \n", + " 115 traj.climb2.states:mass_6 c 0.000000E+00 1.143888E+00 6.666667E+15 \n", + " 116 traj.climb2.states:mass_7 c 0.000000E+00 1.143253E+00 6.666667E+15 \n", + " 117 traj.climb2.states:mass_8 c 0.000000E+00 1.143067E+00 6.666667E+15 \n", + " 118 traj.climb2.states:distance_0 c 2.000000E-02 4.292125E-02 2.000000E+00 \n", + " 119 traj.climb2.states:distance_1 c 2.000000E-02 5.798145E-02 2.000000E+00 \n", + " 120 traj.climb2.states:distance_2 c 2.000000E-02 6.302122E-02 2.000000E+00 \n", + " 121 traj.climb2.states:distance_3 c 2.000000E-02 7.502213E-02 2.000000E+00 \n", + " 122 traj.climb2.states:distance_4 c 2.000000E-02 9.248009E-02 2.000000E+00 \n", + " 123 traj.climb2.states:distance_5 c 2.000000E-02 9.818311E-02 2.000000E+00 \n", + " 124 traj.climb2.states:distance_6 c 2.000000E-02 1.116167E-01 2.000000E+00 \n", + " 125 traj.climb2.states:distance_7 c 2.000000E-02 1.299764E-01 2.000000E+00 \n", + " 126 traj.climb2.states:distance_8 c 2.000000E-02 1.354385E-01 2.000000E+00 \n", + " 127 traj.cruise.t_initial_0 c 1.000000E-01 1.711600E+00 5.000000E+00 \n", + " 128 traj.cruise.t_duration_0 c -1.000000E+00 -6.919790E-01 -2.000000E-04 \n", + " 129 traj.desc1.t_duration_0 c 3.000000E-01 5.212906E-01 9.000000E-01 \n", + " 130 traj.desc1.states:altitude_0 c 3.333333E-02 1.147024E+00 1.333333E+00 \n", + " 131 traj.desc1.states:altitude_1 c 3.333333E-02 1.003060E+00 1.333333E+00 \n", + " 132 traj.desc1.states:altitude_2 c 3.333333E-02 9.567620E-01 1.333333E+00 \n", + " 133 traj.desc1.states:altitude_3 c 3.333333E-02 8.490486E-01 1.333333E+00 \n", + " 134 traj.desc1.states:altitude_4 c 3.333333E-02 6.947753E-01 1.333333E+00 \n", + " 135 traj.desc1.states:altitude_5 c 3.333333E-02 6.441368E-01 1.333333E+00 \n", + " 136 traj.desc1.states:altitude_6 c 3.333333E-02 5.317612E-01 1.333333E+00 \n", + " 137 traj.desc1.states:altitude_7 c 3.333333E-02 3.804288E-01 1.333333E+00 \n", + " 138 traj.desc1.states:altitude_8 c 3.333333E-02 3.333333E-01 1.333333E+00 \n", + " 139 traj.desc1.states:mass_0 c 0.000000E+00 9.730119E-01 7.142857E+15 \n", + " 140 traj.desc1.states:mass_1 c 0.000000E+00 9.729825E-01 7.142857E+15 \n", + " 141 traj.desc1.states:mass_2 c 0.000000E+00 9.729722E-01 7.142857E+15 \n", + " 142 traj.desc1.states:mass_3 c 0.000000E+00 9.729461E-01 7.142857E+15 \n", + " 143 traj.desc1.states:mass_4 c 0.000000E+00 9.729039E-01 7.142857E+15 \n", + " 144 traj.desc1.states:mass_5 c 0.000000E+00 9.728887E-01 7.142857E+15 \n", + " 145 traj.desc1.states:mass_6 c 0.000000E+00 9.728518E-01 7.142857E+15 \n", + " 146 traj.desc1.states:mass_7 c 0.000000E+00 9.727954E-01 7.142857E+15 \n", + " 147 traj.desc1.states:mass_8 c 0.000000E+00 9.727761E-01 7.142857E+15 \n", + " 148 traj.desc1.states:distance_0 c 8.163265E-01 9.393802E-01 1.360544E+00 \n", + " 149 traj.desc1.states:distance_1 c 8.163265E-01 9.449362E-01 1.360544E+00 \n", + " 150 traj.desc1.states:distance_2 c 8.163265E-01 9.466988E-01 1.360544E+00 \n", + " 151 traj.desc1.states:distance_3 c 8.163265E-01 9.507412E-01 1.360544E+00 \n", + " 152 traj.desc1.states:distance_4 c 8.163265E-01 9.563368E-01 1.360544E+00 \n", + " 153 traj.desc1.states:distance_5 c 8.163265E-01 9.581130E-01 1.360544E+00 \n", + " 154 traj.desc1.states:distance_6 c 8.163265E-01 9.621343E-01 1.360544E+00 \n", + " 155 traj.desc1.states:distance_7 c 8.163265E-01 9.676189E-01 1.360544E+00 \n", + " 156 traj.desc1.states:distance_8 c 8.163265E-01 9.693414E-01 1.360544E+00 \n", + " 157 traj.desc2.t_duration_0 c 2.000000E-01 9.590130E-01 1.000000E+01 \n", + " 158 traj.desc2.states:altitude_0 c -5.555556E-02 9.248982E-01 1.111111E+00 \n", + " 159 traj.desc2.states:altitude_1 c -5.555556E-02 7.639805E-01 1.111111E+00 \n", + " 160 traj.desc2.states:altitude_2 c -5.555556E-02 5.515687E-01 1.111111E+00 \n", + " 161 traj.desc2.states:altitude_3 c -5.555556E-02 3.307153E-01 1.111111E+00 \n", + " 162 traj.desc2.states:altitude_4 c -5.555556E-02 1.446192E-01 1.111111E+00 \n", + " 163 traj.desc2.states:altitude_5 c -5.555556E-02 2.854545E-02 1.111111E+00 \n", + " 164 traj.desc2.states:altitude_6 c -5.555556E-02 -1.444509E-12 1.111111E+00 \n", + " 165 traj.desc2.states:mass_0 c 0.000000E+00 9.079066E-01 6.666667E+15 \n", + " 166 traj.desc2.states:mass_1 c 0.000000E+00 9.078670E-01 6.666667E+15 \n", + " 167 traj.desc2.states:mass_2 c 0.000000E+00 9.078113E-01 6.666667E+15 \n", + " 168 traj.desc2.states:mass_3 c 0.000000E+00 9.077490E-01 6.666667E+15 \n", + " 169 traj.desc2.states:mass_4 c 0.000000E+00 9.076930E-01 6.666667E+15 \n", + " 170 traj.desc2.states:mass_5 c 0.000000E+00 9.076565E-01 6.666667E+15 \n", + " 171 traj.desc2.states:mass_6 c 0.000000E+00 9.076473E-01 6.666667E+15 \n", + " 172 traj.desc2.states:distance_0 c 0.000000E+00 1.020174E+00 1.428571E+00 \n", + " 173 traj.desc2.states:distance_1 c 0.000000E+00 1.025272E+00 1.428571E+00 \n", + " 174 traj.desc2.states:distance_2 c 0.000000E+00 1.032063E+00 1.428571E+00 \n", + " 175 traj.desc2.states:distance_3 c 0.000000E+00 1.039193E+00 1.428571E+00 \n", + " 176 traj.desc2.states:distance_4 c 0.000000E+00 1.045256E+00 1.428571E+00 \n", + " 177 traj.desc2.states:distance_5 c 0.000000E+00 1.049061E+00 1.428571E+00 \n", + " 178 traj.desc2.states:distance_6 c 0.000000E+00 1.050000E+00 1.428571E+00 \n", + " 179 traj.groundroll.t_duration_0 c 2.000000E-02 7.774100E-01 2.000000E+00 \n", + " 180 traj.groundroll.states:TAS_0 c 0.000000E+00 3.546835E-01 6.666667E+00 \n", + " 181 traj.groundroll.states:TAS_1 c 0.000000E+00 8.192727E-01 6.666667E+00 \n", + " 182 traj.groundroll.states:TAS_2 c 0.000000E+00 9.603467E-01 6.666667E+00 \n", + " 183 traj.groundroll.states:mass_0 c 0.000000E+00 1.157869E+00 6.666667E+15 \n", + " 184 traj.groundroll.states:mass_1 c 0.000000E+00 1.157776E+00 6.666667E+15 \n", + " 185 traj.groundroll.states:mass_2 c 0.000000E+00 1.157647E+00 6.666667E+15 \n", + " 186 traj.groundroll.states:mass_3 c 0.000000E+00 1.157606E+00 6.666667E+15 \n", + " 187 traj.groundroll.states:distance_0 c 0.000000E+00 1.489693E-01 3.333333E+00 \n", + " 188 traj.groundroll.states:distance_1 c 0.000000E+00 5.480568E-01 3.333333E+00 \n", + " 189 traj.groundroll.states:distance_2 c 0.000000E+00 7.145455E-01 3.333333E+00 \n", + " 190 traj.rotation.t_duration_0 c 2.000000E-02 8.819567E-02 2.000000E+00 \n", + " 191 traj.rotation.states:alpha_0 c 0.000000E+00 1.075149E-02 1.000000E+00 \n", + " 192 traj.rotation.states:alpha_1 c 0.000000E+00 1.592364E-02 1.000000E+00 \n", + " 193 traj.rotation.states:alpha_2 c 0.000000E+00 1.756065E-02 1.000000E+00 \n", + " 194 traj.rotation.states:TAS_0 c 0.000000E+00 1.467531E+00 1.000000E+01 \n", + " 195 traj.rotation.states:TAS_1 c 0.000000E+00 1.505432E+00 1.000000E+01 \n", + " 196 traj.rotation.states:TAS_2 c 0.000000E+00 1.517320E+00 1.000000E+01 \n", + " 197 traj.rotation.states:mass_0 c 0.000000E+00 1.157598E+00 6.666667E+15 \n", + " 198 traj.rotation.states:mass_1 c 0.000000E+00 1.157587E+00 6.666667E+15 \n", + " 199 traj.rotation.states:mass_2 c 0.000000E+00 1.157584E+00 6.666667E+15 \n", + " 200 traj.rotation.states:distance_0 c 0.000000E+00 8.364062E-01 2.000000E+00 \n", + " 201 traj.rotation.states:distance_1 c 0.000000E+00 8.816494E-01 2.000000E+00 \n", + " 202 traj.rotation.states:distance_2 c 0.000000E+00 8.961355E-01 2.000000E+00 \n", + "\n", + " Constraints (i - inequality, e - equality)\n", + " Index Name Type Lower Value Upper Status Lagrange Multiplier (N/A)\n", + " 0 h_fit.h_init_gear e 1.000000E+00 -7.673254E+00 1.000000E+00 E 9.00000E+100\n", + " 1 h_fit.h_init_flaps e 1.000000E+00 -1.910130E-01 1.000000E+00 E 9.00000E+100\n", + " 2 mission:constraints:range_residual e 0.000000E+00 9.431005E-10 0.000000E+00 9.00000E+100\n", + " 3 groundroll_boundary.TAS e 0.000000E+00 -1.529849E-02 0.000000E+00 E 9.00000E+100\n", + " 4 gtow_constraint.GTOW e 0.000000E+00 8.019436E-08 0.000000E+00 9.00000E+100\n", + " 5 link_taxi_groundroll.mass e 0.000000E+00 -1.082345E-01 0.000000E+00 E 9.00000E+100\n", + " 6 mission:constraints:mass_residual e 0.000000E+00 5.861874E-03 0.000000E+00 E 9.00000E+100\n", + " 7 traj.linkages.rotation:alpha_final|ascent:alpha_initial e 0.000000E+00 9.360302E-05 0.000000E+00 E 9.00000E+100\n", + " 8 traj.linkages.ascent:distance_final|accel:distance_initial e 0.000000E+00 -1.288790E-11 0.000000E+00 9.00000E+100\n", + " 9 traj.linkages.climb2:mass_final|cruise:mass_initial e 0.000000E+00 3.000972E-03 0.000000E+00 E 9.00000E+100\n", + " 10 traj.phases.accel->final_boundary_constraint->EAS e 1.000000E+00 9.949266E-01 1.000000E+00 E 9.00000E+100\n", + " 11 traj.accel.collocation_constraint.defects:TAS e 0.000000E+00 4.202854E-02 0.000000E+00 E 9.00000E+100\n", + " 12 traj.accel.collocation_constraint.defects:TAS e 0.000000E+00 4.105398E-02 0.000000E+00 E 9.00000E+100\n", + " 13 traj.accel.collocation_constraint.defects:TAS e 0.000000E+00 4.292782E-02 0.000000E+00 E 9.00000E+100\n", + " 14 traj.accel.collocation_constraint.defects:mass e 0.000000E+00 1.112674E-04 0.000000E+00 E 9.00000E+100\n", + " 15 traj.accel.collocation_constraint.defects:mass e 0.000000E+00 1.123894E-04 0.000000E+00 E 9.00000E+100\n", + " 16 traj.accel.collocation_constraint.defects:mass e 0.000000E+00 1.139086E-04 0.000000E+00 E 9.00000E+100\n", + " 17 traj.accel.collocation_constraint.defects:distance e 0.000000E+00 7.234443E-02 0.000000E+00 E 9.00000E+100\n", + " 18 traj.accel.collocation_constraint.defects:distance e 0.000000E+00 6.503089E-02 0.000000E+00 E 9.00000E+100\n", + " 19 traj.accel.collocation_constraint.defects:distance e 0.000000E+00 5.501194E-02 0.000000E+00 E 9.00000E+100\n", + " 20 traj.phases.ascent->final_boundary_constraint->altitude e 1.000000E+00 1.000000E+00 1.000000E+00 9.00000E+100\n", + " 21 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.422690E-01 0.000000E+00 E 9.00000E+100\n", + " 22 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.320765E-01 0.000000E+00 E 9.00000E+100\n", + " 23 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.238205E-01 0.000000E+00 E 9.00000E+100\n", + " 24 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.236970E-01 0.000000E+00 E 9.00000E+100\n", + " 25 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.232805E-01 0.000000E+00 E 9.00000E+100\n", + " 26 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.173854E-01 0.000000E+00 E 9.00000E+100\n", + " 27 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.140920E-01 0.000000E+00 E 9.00000E+100\n", + " 28 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.076273E-01 0.000000E+00 E 9.00000E+100\n", + " 29 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.053536E-01 0.000000E+00 E 9.00000E+100\n", + " 30 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.064095E-01 0.000000E+00 E 9.00000E+100\n", + " 31 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 2.047183E-01 0.000000E+00 E 9.00000E+100\n", + " 32 traj.ascent.collocation_constraint.defects:flight_path_angle e 0.000000E+00 1.838454E-01 0.000000E+00 E 9.00000E+100\n", + " 33 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 4.376839E-02 0.000000E+00 E 9.00000E+100\n", + " 34 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 3.889346E-02 0.000000E+00 E 9.00000E+100\n", + " 35 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 2.679024E-02 0.000000E+00 E 9.00000E+100\n", + " 36 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 2.298666E-02 0.000000E+00 E 9.00000E+100\n", + " 37 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 1.613087E-02 0.000000E+00 E 9.00000E+100\n", + " 38 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 8.330021E-03 0.000000E+00 E 9.00000E+100\n", + " 39 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 5.469934E-03 0.000000E+00 E 9.00000E+100\n", + " 40 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 -2.877066E-03 0.000000E+00 E 9.00000E+100\n", + " 41 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 -1.532406E-02 0.000000E+00 E 9.00000E+100\n", + " 42 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 -1.851911E-02 0.000000E+00 E 9.00000E+100\n", + " 43 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 -2.397713E-02 0.000000E+00 E 9.00000E+100\n", + " 44 traj.ascent.collocation_constraint.defects:altitude e 0.000000E+00 -3.855669E-02 0.000000E+00 E 9.00000E+100\n", + " 45 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -2.662088E-02 0.000000E+00 E 9.00000E+100\n", + " 46 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -2.352679E-02 0.000000E+00 E 9.00000E+100\n", + " 47 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -1.851361E-02 0.000000E+00 E 9.00000E+100\n", + " 48 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -1.709857E-02 0.000000E+00 E 9.00000E+100\n", + " 49 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -1.453933E-02 0.000000E+00 E 9.00000E+100\n", + " 50 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -1.161423E-02 0.000000E+00 E 9.00000E+100\n", + " 51 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -1.055806E-02 0.000000E+00 E 9.00000E+100\n", + " 52 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -7.629152E-03 0.000000E+00 E 9.00000E+100\n", + " 53 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -3.594065E-03 0.000000E+00 E 9.00000E+100\n", + " 54 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -2.577067E-03 0.000000E+00 E 9.00000E+100\n", + " 55 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 -7.133023E-04 0.000000E+00 E 9.00000E+100\n", + " 56 traj.ascent.collocation_constraint.defects:TAS e 0.000000E+00 4.081281E-03 0.000000E+00 E 9.00000E+100\n", + " 57 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 5.378800E-05 0.000000E+00 E 9.00000E+100\n", + " 58 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 5.382985E-05 0.000000E+00 E 9.00000E+100\n", + " 59 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 5.382364E-05 0.000000E+00 E 9.00000E+100\n", + " 60 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 5.379057E-05 0.000000E+00 E 9.00000E+100\n", + " 61 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 5.383271E-05 0.000000E+00 E 9.00000E+100\n", + " 62 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 5.382356E-05 0.000000E+00 E 9.00000E+100\n", + " 63 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 5.378701E-05 0.000000E+00 E 9.00000E+100\n", + " 64 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 5.385800E-05 0.000000E+00 E 9.00000E+100\n", + " 65 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 5.385324E-05 0.000000E+00 E 9.00000E+100\n", + " 66 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 5.381060E-05 0.000000E+00 E 9.00000E+100\n", + " 67 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 5.390402E-05 0.000000E+00 E 9.00000E+100\n", + " 68 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 5.390676E-05 0.000000E+00 E 9.00000E+100\n", + " 69 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -2.664678E-03 0.000000E+00 E 9.00000E+100\n", + " 70 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -3.914933E-03 0.000000E+00 E 9.00000E+100\n", + " 71 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -5.639292E-03 0.000000E+00 E 9.00000E+100\n", + " 72 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -6.151455E-03 0.000000E+00 E 9.00000E+100\n", + " 73 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -7.361568E-03 0.000000E+00 E 9.00000E+100\n", + " 74 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -9.108046E-03 0.000000E+00 E 9.00000E+100\n", + " 75 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -9.684546E-03 0.000000E+00 E 9.00000E+100\n", + " 76 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -1.099362E-02 0.000000E+00 E 9.00000E+100\n", + " 77 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -1.278417E-02 0.000000E+00 E 9.00000E+100\n", + " 78 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -1.335192E-02 0.000000E+00 E 9.00000E+100\n", + " 79 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -1.472174E-02 0.000000E+00 E 9.00000E+100\n", + " 80 traj.ascent.collocation_constraint.defects:distance e 0.000000E+00 -1.660071E-02 0.000000E+00 E 9.00000E+100\n", + " 81 traj.ascent.continuity_comp.defect_control_rates:alpha_rate e 0.000000E+00 -3.980793E-10 0.000000E+00 9.00000E+100\n", + " 82 traj.ascent.continuity_comp.defect_control_rates:alpha_rate e 0.000000E+00 2.209845E-09 0.000000E+00 9.00000E+100\n", + " 83 traj.ascent.continuity_comp.defect_control_rates:alpha_rate e 0.000000E+00 3.808057E-09 0.000000E+00 9.00000E+100\n", + " 84 traj.ascent.continuity_comp.defect_controls:alpha e 0.000000E+00 5.753061E-09 0.000000E+00 9.00000E+100\n", + " 85 traj.ascent.continuity_comp.defect_controls:alpha e 0.000000E+00 2.457302E-08 0.000000E+00 9.00000E+100\n", + " 86 traj.ascent.continuity_comp.defect_controls:alpha e 0.000000E+00 1.571372E-08 0.000000E+00 9.00000E+100\n", + " 87 traj.phases.climb1->final_boundary_constraint->altitude e 1.000000E+00 1.000000E+00 1.000000E+00 9.00000E+100\n", + " 88 traj.climb1.collocation_constraint.defects:altitude e 0.000000E+00 9.071308E-02 0.000000E+00 E 9.00000E+100\n", + " 89 traj.climb1.collocation_constraint.defects:altitude e 0.000000E+00 9.447156E-02 0.000000E+00 E 9.00000E+100\n", + " 90 traj.climb1.collocation_constraint.defects:altitude e 0.000000E+00 1.130860E-01 0.000000E+00 E 9.00000E+100\n", + " 91 traj.climb1.collocation_constraint.defects:mass e 0.000000E+00 1.055655E-03 0.000000E+00 E 9.00000E+100\n", + " 92 traj.climb1.collocation_constraint.defects:mass e 0.000000E+00 9.989756E-04 0.000000E+00 E 9.00000E+100\n", + " 93 traj.climb1.collocation_constraint.defects:mass e 0.000000E+00 9.223484E-04 0.000000E+00 E 9.00000E+100\n", + " 94 traj.climb1.collocation_constraint.defects:distance e 0.000000E+00 1.698051E-01 0.000000E+00 E 9.00000E+100\n", + " 95 traj.climb1.collocation_constraint.defects:distance e 0.000000E+00 1.544559E-01 0.000000E+00 E 9.00000E+100\n", + " 96 traj.climb1.collocation_constraint.defects:distance e 0.000000E+00 1.311562E-01 0.000000E+00 E 9.00000E+100\n", + " 97 traj.phases.climb2->final_boundary_constraint->altitude e 1.000000E+00 1.000000E+00 1.000000E+00 9.00000E+100\n", + " 98 traj.phases.climb2->final_boundary_constraint->mach e 8.000000E-01 8.000000E-01 8.000000E-01 9.00000E+100\n", + " 99 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 -1.579133E-01 0.000000E+00 E 9.00000E+100\n", + " 100 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 -1.401012E-01 0.000000E+00 E 9.00000E+100\n", + " 101 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 -1.106180E-01 0.000000E+00 E 9.00000E+100\n", + " 102 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 -9.840772E-02 0.000000E+00 E 9.00000E+100\n", + " 103 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 -7.637198E-02 0.000000E+00 E 9.00000E+100\n", + " 104 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 -4.132898E-02 0.000000E+00 E 9.00000E+100\n", + " 105 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 -2.638984E-02 0.000000E+00 E 9.00000E+100\n", + " 106 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 3.408285E-03 0.000000E+00 E 9.00000E+100\n", + " 107 traj.climb2.collocation_constraint.defects:altitude e 0.000000E+00 5.699044E-02 0.000000E+00 E 9.00000E+100\n", + " 108 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 -1.699362E-02 0.000000E+00 E 9.00000E+100\n", + " 109 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 -1.203943E-03 0.000000E+00 E 9.00000E+100\n", + " 110 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 3.845217E-03 0.000000E+00 E 9.00000E+100\n", + " 111 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 2.697633E-03 0.000000E+00 E 9.00000E+100\n", + " 112 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 2.554055E-03 0.000000E+00 E 9.00000E+100\n", + " 113 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 2.325253E-03 0.000000E+00 E 9.00000E+100\n", + " 114 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 2.238527E-03 0.000000E+00 E 9.00000E+100\n", + " 115 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 2.080800E-03 0.000000E+00 E 9.00000E+100\n", + " 116 traj.climb2.collocation_constraint.defects:mass e 0.000000E+00 1.786942E-03 0.000000E+00 E 9.00000E+100\n", + " 117 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -2.251188E-02 0.000000E+00 E 9.00000E+100\n", + " 118 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -2.392211E-02 0.000000E+00 E 9.00000E+100\n", + " 119 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -2.607250E-02 0.000000E+00 E 9.00000E+100\n", + " 120 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -2.680535E-02 0.000000E+00 E 9.00000E+100\n", + " 121 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -2.857679E-02 0.000000E+00 E 9.00000E+100\n", + " 122 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -3.127094E-02 0.000000E+00 E 9.00000E+100\n", + " 123 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -3.219105E-02 0.000000E+00 E 9.00000E+100\n", + " 124 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -3.443245E-02 0.000000E+00 E 9.00000E+100\n", + " 125 traj.climb2.collocation_constraint.defects:distance e 0.000000E+00 -3.487377E-02 0.000000E+00 E 9.00000E+100\n", + " 126 traj.phases.desc1->final_boundary_constraint->altitude e 1.000000E+00 1.000000E+00 1.000000E+00 9.00000E+100\n", + " 127 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 -2.995787E-02 0.000000E+00 E 9.00000E+100\n", + " 128 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 -2.729299E-02 0.000000E+00 E 9.00000E+100\n", + " 129 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 -1.955422E-02 0.000000E+00 E 9.00000E+100\n", + " 130 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 -1.637241E-02 0.000000E+00 E 9.00000E+100\n", + " 131 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 -7.774740E-03 0.000000E+00 E 9.00000E+100\n", + " 132 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 3.813592E-03 0.000000E+00 E 9.00000E+100\n", + " 133 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 9.033048E-04 0.000000E+00 E 9.00000E+100\n", + " 134 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 -5.459134E-03 0.000000E+00 E 9.00000E+100\n", + " 135 traj.desc1.collocation_constraint.defects:altitude e 0.000000E+00 -1.365492E-02 0.000000E+00 E 9.00000E+100\n", + " 136 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 -5.965159E-03 0.000000E+00 E 9.00000E+100\n", + " 137 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 -1.209201E-03 0.000000E+00 E 9.00000E+100\n", + " 138 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 3.742452E-04 0.000000E+00 E 9.00000E+100\n", + " 139 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 7.377422E-05 0.000000E+00 E 9.00000E+100\n", + " 140 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 8.412177E-05 0.000000E+00 E 9.00000E+100\n", + " 141 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 9.926342E-05 0.000000E+00 E 9.00000E+100\n", + " 142 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 1.027776E-04 0.000000E+00 E 9.00000E+100\n", + " 143 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 1.115648E-04 0.000000E+00 E 9.00000E+100\n", + " 144 traj.desc1.collocation_constraint.defects:mass e 0.000000E+00 1.251597E-04 0.000000E+00 E 9.00000E+100\n", + " 145 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 -3.389489E+00 0.000000E+00 E 9.00000E+100\n", + " 146 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 -6.377799E-01 0.000000E+00 E 9.00000E+100\n", + " 147 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 2.717641E-01 0.000000E+00 E 9.00000E+100\n", + " 148 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 9.473588E-02 0.000000E+00 E 9.00000E+100\n", + " 149 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 9.369777E-02 0.000000E+00 E 9.00000E+100\n", + " 150 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 9.323599E-02 0.000000E+00 E 9.00000E+100\n", + " 151 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 9.510829E-02 0.000000E+00 E 9.00000E+100\n", + " 152 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 9.914566E-02 0.000000E+00 E 9.00000E+100\n", + " 153 traj.desc1.collocation_constraint.defects:distance e 0.000000E+00 1.042120E-01 0.000000E+00 E 9.00000E+100\n", + " 154 traj.phases.desc2->final_boundary_constraint->altitude e 1.000000E+00 1.000000E+00 1.000000E+00 9.00000E+100\n", + " 155 traj.desc2.collocation_constraint.defects:altitude e 0.000000E+00 8.756788E-02 0.000000E+00 E 9.00000E+100\n", + " 156 traj.desc2.collocation_constraint.defects:altitude e 0.000000E+00 8.211682E-02 0.000000E+00 E 9.00000E+100\n", + " 157 traj.desc2.collocation_constraint.defects:altitude e 0.000000E+00 7.040623E-02 0.000000E+00 E 9.00000E+100\n", + " 158 traj.desc2.collocation_constraint.defects:altitude e 0.000000E+00 5.532126E-02 0.000000E+00 E 9.00000E+100\n", + " 159 traj.desc2.collocation_constraint.defects:altitude e 0.000000E+00 3.985860E-02 0.000000E+00 E 9.00000E+100\n", + " 160 traj.desc2.collocation_constraint.defects:altitude e 0.000000E+00 2.711817E-02 0.000000E+00 E 9.00000E+100\n", + " 161 traj.desc2.collocation_constraint.defects:altitude e 0.000000E+00 1.924199E-02 0.000000E+00 E 9.00000E+100\n", + " 162 traj.desc2.collocation_constraint.defects:mass e 0.000000E+00 3.248458E-04 0.000000E+00 E 9.00000E+100\n", + " 163 traj.desc2.collocation_constraint.defects:mass e 0.000000E+00 3.311964E-04 0.000000E+00 E 9.00000E+100\n", + " 164 traj.desc2.collocation_constraint.defects:mass e 0.000000E+00 3.460895E-04 0.000000E+00 E 9.00000E+100\n", + " 165 traj.desc2.collocation_constraint.defects:mass e 0.000000E+00 3.662714E-04 0.000000E+00 E 9.00000E+100\n", + " 166 traj.desc2.collocation_constraint.defects:mass e 0.000000E+00 3.891705E-04 0.000000E+00 E 9.00000E+100\n", + " 167 traj.desc2.collocation_constraint.defects:mass e 0.000000E+00 4.094219E-04 0.000000E+00 E 9.00000E+100\n", + " 168 traj.desc2.collocation_constraint.defects:mass e 0.000000E+00 4.228676E-04 0.000000E+00 E 9.00000E+100\n", + " 169 traj.desc2.collocation_constraint.defects:distance e 0.000000E+00 3.734014E-01 0.000000E+00 E 9.00000E+100\n", + " 170 traj.desc2.collocation_constraint.defects:distance e 0.000000E+00 3.748468E-01 0.000000E+00 E 9.00000E+100\n", + " 171 traj.desc2.collocation_constraint.defects:distance e 0.000000E+00 3.778952E-01 0.000000E+00 E 9.00000E+100\n", + " 172 traj.desc2.collocation_constraint.defects:distance e 0.000000E+00 3.818172E-01 0.000000E+00 E 9.00000E+100\n", + " 173 traj.desc2.collocation_constraint.defects:distance e 0.000000E+00 3.857735E-01 0.000000E+00 E 9.00000E+100\n", + " 174 traj.desc2.collocation_constraint.defects:distance e 0.000000E+00 3.890114E-01 0.000000E+00 E 9.00000E+100\n", + " 175 traj.desc2.collocation_constraint.defects:distance e 0.000000E+00 3.909870E-01 0.000000E+00 E 9.00000E+100\n", + " 176 traj.groundroll.collocation_constraint.defects:TAS e 0.000000E+00 -1.183504E-01 0.000000E+00 E 9.00000E+100\n", + " 177 traj.groundroll.collocation_constraint.defects:TAS e 0.000000E+00 -7.468176E-02 0.000000E+00 E 9.00000E+100\n", + " 178 traj.groundroll.collocation_constraint.defects:TAS e 0.000000E+00 1.461444E-03 0.000000E+00 E 9.00000E+100\n", + " 179 traj.groundroll.collocation_constraint.defects:mass e 0.000000E+00 3.337212E-04 0.000000E+00 E 9.00000E+100\n", + " 180 traj.groundroll.collocation_constraint.defects:mass e 0.000000E+00 3.369527E-04 0.000000E+00 E 9.00000E+100\n", + " 181 traj.groundroll.collocation_constraint.defects:mass e 0.000000E+00 3.414340E-04 0.000000E+00 E 9.00000E+100\n", + " 182 traj.groundroll.collocation_constraint.defects:distance e 0.000000E+00 1.161956E-01 0.000000E+00 E 9.00000E+100\n", + " 183 traj.groundroll.collocation_constraint.defects:distance e 0.000000E+00 -2.832254E-01 0.000000E+00 E 9.00000E+100\n", + " 184 traj.groundroll.collocation_constraint.defects:distance e 0.000000E+00 -8.354978E-01 0.000000E+00 E 9.00000E+100\n", + " 185 traj.phases.rotation->final_boundary_constraint->normal_force e 0.000000E+00 5.885612E+00 0.000000E+00 E 9.00000E+100\n", + " 186 traj.rotation.collocation_constraint.defects:alpha e 0.000000E+00 -2.843081E-03 0.000000E+00 E 9.00000E+100\n", + " 187 traj.rotation.collocation_constraint.defects:alpha e 0.000000E+00 -1.666288E-02 0.000000E+00 E 9.00000E+100\n", + " 188 traj.rotation.collocation_constraint.defects:alpha e 0.000000E+00 -2.123711E-02 0.000000E+00 E 9.00000E+100\n", + " 189 traj.rotation.collocation_constraint.defects:TAS e 0.000000E+00 -3.467974E-02 0.000000E+00 E 9.00000E+100\n", + " 190 traj.rotation.collocation_constraint.defects:TAS e 0.000000E+00 -3.291650E-02 0.000000E+00 E 9.00000E+100\n", + " 191 traj.rotation.collocation_constraint.defects:TAS e 0.000000E+00 -3.158894E-02 0.000000E+00 E 9.00000E+100\n", + " 192 traj.rotation.collocation_constraint.defects:mass e 0.000000E+00 4.294338E-05 0.000000E+00 E 9.00000E+100\n", + " 193 traj.rotation.collocation_constraint.defects:mass e 0.000000E+00 4.299013E-05 0.000000E+00 E 9.00000E+100\n", + " 194 traj.rotation.collocation_constraint.defects:mass e 0.000000E+00 4.303371E-05 0.000000E+00 E 9.00000E+100\n", + " 195 traj.rotation.collocation_constraint.defects:distance e 0.000000E+00 8.764329E-01 0.000000E+00 E 9.00000E+100\n", + " 196 traj.rotation.collocation_constraint.defects:distance e 0.000000E+00 1.342207E-01 0.000000E+00 E 9.00000E+100\n", + " 197 traj.rotation.collocation_constraint.defects:distance e 0.000000E+00 -1.129866E-01 0.000000E+00 E 9.00000E+100\n", + " 198 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 3.742054E-01 1.100000E+00 9.00000E+100\n", + " 199 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.669844E-01 1.100000E+00 9.00000E+100\n", + " 200 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.480818E-01 1.100000E+00 9.00000E+100\n", + " 201 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.709240E-01 1.100000E+00 9.00000E+100\n", + " 202 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.709240E-01 1.100000E+00 9.00000E+100\n", + " 203 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 3.213843E-01 1.100000E+00 9.00000E+100\n", + " 204 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 3.296702E-01 1.100000E+00 9.00000E+100\n", + " 205 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 3.160906E-01 1.100000E+00 9.00000E+100\n", + " 206 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 3.160907E-01 1.100000E+00 9.00000E+100\n", + " 207 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.946641E-01 1.100000E+00 9.00000E+100\n", + " 208 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 3.279602E-01 1.100000E+00 9.00000E+100\n", + " 209 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 3.544860E-01 1.100000E+00 9.00000E+100\n", + " 210 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 3.544861E-01 1.100000E+00 9.00000E+100\n", + " 211 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 3.704937E-01 1.100000E+00 9.00000E+100\n", + " 212 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 2.169131E-01 1.100000E+00 9.00000E+100\n", + " 213 traj.phases.ascent->path_constraint->load_factor i 0.000000E+00 1.256349E-01 1.100000E+00 9.00000E+100\n", + " 214 traj.phases.ascent->path_constraint->theta i 0.000000E+00 3.262602E+00 1.500000E+01 9.00000E+100\n", + " 215 traj.phases.ascent->path_constraint->theta i 0.000000E+00 3.078675E+00 1.500000E+01 9.00000E+100\n", + " 216 traj.phases.ascent->path_constraint->theta i 0.000000E+00 3.095527E+00 1.500000E+01 9.00000E+100\n", + " 217 traj.phases.ascent->path_constraint->theta i 0.000000E+00 3.575063E+00 1.500000E+01 9.00000E+100\n", + " 218 traj.phases.ascent->path_constraint->theta i 0.000000E+00 3.575063E+00 1.500000E+01 9.00000E+100\n", + " 219 traj.phases.ascent->path_constraint->theta i 0.000000E+00 5.210033E+00 1.500000E+01 9.00000E+100\n", + " 220 traj.phases.ascent->path_constraint->theta i 0.000000E+00 7.079052E+00 1.500000E+01 9.00000E+100\n", + " 221 traj.phases.ascent->path_constraint->theta i 0.000000E+00 7.358273E+00 1.500000E+01 9.00000E+100\n", + " 222 traj.phases.ascent->path_constraint->theta i 0.000000E+00 7.358275E+00 1.500000E+01 9.00000E+100\n", + " 223 traj.phases.ascent->path_constraint->theta i 0.000000E+00 7.741424E+00 1.500000E+01 9.00000E+100\n", + " 224 traj.phases.ascent->path_constraint->theta i 0.000000E+00 9.074316E+00 1.500000E+01 9.00000E+100\n", + " 225 traj.phases.ascent->path_constraint->theta i 0.000000E+00 9.909319E+00 1.500000E+01 9.00000E+100\n", + " 226 traj.phases.ascent->path_constraint->theta i 0.000000E+00 9.909320E+00 1.500000E+01 9.00000E+100\n", + " 227 traj.phases.ascent->path_constraint->theta i 0.000000E+00 1.163683E+01 1.500000E+01 9.00000E+100\n", + " 228 traj.phases.ascent->path_constraint->theta i 0.000000E+00 1.024117E+01 1.500000E+01 9.00000E+100\n", + " 229 traj.phases.ascent->path_constraint->theta i 0.000000E+00 8.278860E+00 1.500000E+01 9.00000E+100\n", + " 230 traj.phases.climb2->final_boundary_constraint->altitude_rate i 1.000000E-01 3.369349E+02 1.000000E+30 9.00000E+100\n", + "\n", + "\n", + " Exit Status\n", + " Inform Description\n", + " -1 Maximum Iterations Exceeded\n", + "--------------------------------------------------------------------------------\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "prob.run_aviary_problem()" ] @@ -546,10 +2088,35 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "cb152e48", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Zero Fuel Mass (lbm) [0.]\n", + "Mission.Objectives.FUEL [5.01686139]\n", + "Mission.Design.FUEL_MASS [43235.82667616]\n", + "Mission.Design.FUEL_MASS_REQUIRED [43235.82667616]\n", + "Mission.Summary.TOTAL_FUEL_MASS [43822.01406862]\n", + "Mission.Summary.GROSS_MASS (takeoff_mass) [174971.10305558]\n", + "Mission.Landing.TOUCHDOWN_MASS (final_mass) [136147.08898696]\n", + "\n", + "Groundroll Final Mass (lbm) [173640.93424536]\n", + "Rotation Final Mass (lbm) [173637.58677183]\n", + "Ascent Final Mass (lbm) [173632.10142675]\n", + "Accel Final Mass (lbm) [173583.75432292]\n", + "Climb1 Final Mass (lbm) [173404.08534669]\n", + "Climb2 Final Mass (lbm) [171460.12339658]\n", + "Cruise Final Mass (lbm) 136561.07448090267\n", + "Desc1 Final Mass (lbm) [136188.65336602]\n", + "Desc2 Final Mass (lbm) [136147.08898696]\n", + "done\n" + ] + } + ], "source": [ "print(\"Zero Fuel Mass (lbm)\",\n", " prob.get_val(Aircraft.Design.ZERO_FUEL_MASS, units='lbm'))\n", @@ -608,10 +2175,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "0da2bfee", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Traceback (most recent call last):\n", + " File \"/home/john/anaconda3/envs/dev/bin/aviary\", line 8, in \n", + " sys.exit(aviary_cmd())\n", + " File \"/mnt/c/Users/John/Dropbox/git/om-Aviary/aviary/interface/cmd_entry_points.py\", line 141, in aviary_cmd\n", + " options.executor(options, user_args)\n", + " File \"/mnt/c/Users/John/Dropbox/git/om-Aviary/aviary/interface/methods_for_level1.py\", line 236, in _exec_level1\n", + " prob = run_level_1(\n", + " File \"/mnt/c/Users/John/Dropbox/git/om-Aviary/aviary/interface/methods_for_level1.py\", line 158, in run_level_1\n", + " prob = run_aviary(input_deck, phase_info, mission_method=mission_method,\n", + " File \"/mnt/c/Users/John/Dropbox/git/om-Aviary/aviary/interface/methods_for_level1.py\", line 70, in run_aviary\n", + " prob = AviaryProblem(phase_info, mission_method, mass_method, analysis_scheme)\n", + " File \"/mnt/c/Users/John/Dropbox/git/om-Aviary/aviary/interface/methods_for_level2.py\", line 147, in __init__\n", + " raise NotImplementedError(\n", + "NotImplementedError: The FLOPS mission method is no longer supported in Aviary. Please use the `simple` mission method. This might require updating your `phase_info` object defintion.\n" + ] + } + ], "source": [ "!aviary run_mission models/test_aircraft/aircraft_for_bench_FwFm.csv --mission_method FLOPS --mass_origin FLOPS --max_iter 0 --optimizer IPOPT" ] @@ -628,10 +2216,107 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "id": "807902e2", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "The following variables have been overridden:\n", + " 'aircraft:design:touchdown_mass\n", + " 'aircraft:engine:mass\n", + " 'aircraft:fins:mass\n", + " 'aircraft:fuel:auxiliary_fuel_capacity\n", + " 'aircraft:fuel:fuselage_fuel_capacity\n", + " 'aircraft:fuel:total_capacity\n", + " 'aircraft:fuselage:planform_area\n", + " 'aircraft:fuselage:wetted_area\n", + " 'aircraft:horizontal_tail:wetted_area\n", + " 'aircraft:landing_gear:main_gear_oleo_length\n", + " 'aircraft:landing_gear:nose_gear_oleo_length\n", + " 'aircraft:vertical_tail:wetted_area\n", + " 'aircraft:wing:aspect_ratio\n", + " 'aircraft:wing:control_surface_area\n", + " 'aircraft:wing:wetted_area\n", + "\n", + "--- Constraint Report [traj] ---\n", + " --- cruise ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, history.db, is being overwritten.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model viewer data has already been recorded for Driver.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/driver.py:469: DriverWarning:The following design variable initial conditions are out of their specified bounds:\n", + " traj.cruise.t_duration\n", + " val: [1800.]\n", + " lower: 600.0\n", + " upper: 1799.9999999999998\n", + "Set the initial value of the design variable to a valid value or set the driver option['invalid_desvar_behavior'] to 'ignore'.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Full total jacobian was computed 3 times, taking 0.041699 seconds.\n", + "Total jacobian shape: (16, 13) \n", + "\n", + "\n", + "Jacobian shape: (16, 13) (31.73% nonzero)\n", + "FWD solves: 6 REV solves: 0\n", + "Total colors vs. total size: 6 vs 13 (53.85% improvement)\n", + "\n", + "Sparsity computed using tolerance: 1e-25\n", + "Time to compute sparsity: 0.0417 sec\n", + "Time to compute coloring: 0.0076 sec\n", + "Memory to compute coloring: 0.0000 MB\n", + "Coloring created on: 2024-01-09 11:26:48\n", + "Iteration limit reached (Exit mode 9)\n", + " Current function value: 0.0\n", + " Iterations: 1\n", + " Function evaluations: 1\n", + " Gradient evaluations: 1\n", + "Optimization FAILED.\n", + "Iteration limit reached\n", + "-----------------------------------\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/total_jac.py:1759: DerivativesWarning:Constraints or objectives [('traj.phases.cruise.timeseries.timeseries_comp.throttle', inds=[(0, 0)])] cannot be impacted by the design variables of the problem.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "done\n" + ] + } + ], "source": [ "phase_info = {\n", " 'pre_mission': {\n", @@ -643,32 +2328,26 @@ " 'core_aerodynamics': {'method': 'computed'}\n", " },\n", " 'user_options': {\n", - " 'fix_initial': False,\n", - " 'fix_duration': True,\n", - " 'num_segments': 1,\n", + " 'optimize_mach': False,\n", + " 'optimize_altitude': False,\n", + " 'polynomial_control_order': 1,\n", + " 'num_segments': 2,\n", " 'order': 3,\n", - " 'initial_bounds': ((500., 4000.), 's'),\n", - " 'initial_ref': (1., 's'),\n", - " 'duration_ref': (24370.8, 's'),\n", - " 'duration_bounds': ((726., 48741.6), 's'),\n", - " 'min_altitude': (10.668e3, 'm'),\n", - " 'max_altitude': (10.668e3, 'm'),\n", - " 'min_mach': 0.79,\n", - " 'max_mach': 0.79,\n", - " 'fix_final': False,\n", - " 'required_available_climb_rate': (1.524, 'm/s'),\n", - " 'mass_f_cruise': (1.e4, 'lbm'),\n", - " 'range_f_cruise': (1.e6, 'm'),\n", + " 'solve_for_range': False,\n", + " 'initial_mach': (0.72, 'unitless'),\n", + " 'final_mach': (0.72, 'unitless'),\n", + " 'mach_bounds': ((0.7, 0.74), 'unitless'),\n", + " 'initial_altitude': (35000.0, 'ft'),\n", + " 'final_altitude': (35000.0, 'ft'),\n", + " 'altitude_bounds': ((23000.0, 38000.0), 'ft'),\n", + " 'throttle_enforcement': 'boundary_constraint',\n", + " 'fix_initial': True,\n", + " 'constrain_final': False,\n", + " 'fix_duration': False,\n", + " 'initial_bounds': ((0.0, 0.0), 'min'),\n", + " 'duration_bounds': ((10., 30.), 'min'),\n", " },\n", - " 'initial_guesses': {\n", - " 'times': ([26.2, 406.18], 'min'),\n", - " 'altitude': ([35.e3, 35.e3], 'ft'),\n", - " 'velocity': ([455.49, 455.49], 'kn'),\n", - " 'mass': ([165.e3, 140.e3], 'lbm'),\n", - " 'range': ([160.3, 3243.9], 'nmi'),\n", - " 'velocity_rate': ([0., 0.], 'm/s**2'),\n", - " 'throttle': ([0.95, 0.9], 'unitless'),\n", - " }\n", + " 'initial_guesses': {'times': ([0, 30], 'min')},\n", " },\n", " 'post_mission': {\n", " 'include_landing': False,\n", @@ -677,7 +2356,7 @@ "\n", "# inputs that run_aviary() requires\n", "aircraft_filename = \"models/test_aircraft/aircraft_for_bench_FwFm.csv\"\n", - "mission_method = \"FLOPS\"\n", + "mission_method = \"simple\"\n", "mass_method = \"FLOPS\"\n", "optimizer = \"SLSQP\"\n", "analysis_scheme = av.AnalysisScheme.COLLOCATION\n", @@ -731,33 +2410,8 @@ "\n", "We will see more details for what users can do in [level 3](onboarding_level3.ipynb).\n", "\n", - "Level 2 is where you can integrate user-defined [external subsystems](https://github.com/OpenMDAO/Aviary/blob/main/aviary/docs/user_guide/subsystems.md), which is one of the main features of the Aviary tool. [Examples](https://github.com/OpenMDAO/Aviary/blob/main/aviary/docs/user_guide/using_external_subsystems.md) of external subsystems are: acoustics, battery modeling, etc.\n", - "Assume that you already have an external subsystem that you want to incorporate it into your model. We show how to add external subsystems via `external_subsystems` key in `phase_info`. External subsystems can be added in all phases. For example, we can have:\n", - "\n", - "```\n", - "from aviary.subsystems.test.test_dummy_subsystem import PreOnlyBuilder, PostOnlyBuilder, \\\n", - " ArrayGuessSubsystemBuilder, AdditionalArrayGuessSubsystemBuilder\n", - "\n", - "phase_info = {\n", - "\t'pre_mission': {\n", - "\t\t'include_takeoff': True,\n", - "\t\t'external_subsystems': [ArrayGuessSubsystemBuilder()],\n", - "\t\t'optimize_mass': False,\n", - "\t},\n", - "\t'cruise': {\n", - "\t\t...\n", - " 'external_subsystems': \n", - " [\n", - " ArrayGuessSubsystemBuilder(),\n", - " AdditionalArrayGuessSubsystemBuilder()\n", - " ],\n", - "\t},\n", - "\t'post_mission': {\n", - "\t\t'include_landing': False,\n", - "\t\t'external_subsystems': [PostOnlyBuilder()],\n", - "\t}\n", - "}\n", - "```\n", + "Level 2 is where you can integrate user-defined [external subsystems](../user_guide/subsystems.md), which is one of the main features of the Aviary tool. [Examples](../user_guide/using_external_subsystems.md) of external subsystems are: acoustics, battery modeling, etc.\n", + "Assume that you already have an external subsystem that you want to incorporate it into your model. We show how to add external subsystems via `external_subsystems` key in `phase_info`.\n", "\n", "We will cover external subsystems in details in [Models with External Subsystems](onboarding_ext_subsystem.ipynb) page.\n" ] @@ -782,7 +2436,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "id": "8ad02f55", "metadata": {}, "outputs": [], @@ -805,7 +2459,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "id": "7481beb5", "metadata": {}, "outputs": [], @@ -826,10 +2480,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "id": "15027bcc", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'aircraft:blended_wing_body_design:num_bays': (0, 'unitless'), 'aircraft:crew_and_payload:mass_per_passenger': (165.0, 'lbm'), 'aircraft:crew_and_payload:num_business_class': (0, 'unitless'), 'aircraft:crew_and_payload:num_first_class': (0, 'unitless'), 'aircraft:crew_and_payload:num_passengers': (180, 'unitless'), 'aircraft:crew_and_payload:num_tourist_class': (0, 'unitless'), 'aircraft:crew_and_payload:passenger_mass_with_bags': (200, 'lbm'), 'aircraft:design:compute_htail_volume_coeff': (False, 'unitless'), 'aircraft:design:compute_vtail_volume_coeff': (False, 'unitless'), 'aircraft:design:part25_structural_category': (3, 'unitless'), 'aircraft:design:reserves': (4998, 'unitless'), 'aircraft:design:smooth_mass_discontinuities': (False, 'unitless'), 'aircraft:design:ulf_calculated_from_maneuver': (False, 'unitless'), 'aircraft:design:use_alt_mass': (False, 'unitless'), 'aircraft:electrical:has_hybrid_system': (False, 'unitless'), 'aircraft:engine:constant_fuel_consumption': (array([0.]), 'lbm/h'), 'aircraft:engine:flight_idle_max_fraction': (array([1.]), 'unitless'), 'aircraft:engine:flight_idle_min_fraction': (array([0.08]), 'unitless'), 'aircraft:engine:flight_idle_thrust_fraction': (array([0.]), 'unitless'), 'aircraft:engine:fuel_flow_scaler_constant_term': (array([0.]), 'unitless'), 'aircraft:engine:fuel_flow_scaler_linear_term': (array([0.]), 'unitless'), 'aircraft:engine:generate_flight_idle': ([False], 'unitless'), 'aircraft:engine:geopotential_alt': ([False], 'unitless'), 'aircraft:engine:has_propellers': ([False], 'unitless'), 'aircraft:engine:ignore_negative_thrust': ([False], 'unitless'), 'aircraft:engine:interpolation_method': (['slinear'], 'unitless'), 'aircraft:engine:num_engines': (array([2]), 'unitless'), 'aircraft:engine:num_fuselage_engines': (array([0]), 'unitless'), 'aircraft:engine:num_wing_engines': (array([2]), 'unitless'), 'aircraft:engine:scale_mass': ([True], 'unitless'), 'aircraft:engine:scale_performance': ([True], 'unitless'), 'aircraft:engine:subsonic_fuel_flow_scaler': (array([1.]), 'unitless'), 'aircraft:engine:supersonic_fuel_flow_scaler': (array([1.]), 'unitless'), 'aircraft:engine:type': ([], 'unitless'), 'aircraft:fins:num_fins': (0, 'unitless'), 'aircraft:fuel:num_tanks': (7, 'unitless'), 'aircraft:fuselage:aisle_width': (24, 'inch'), 'aircraft:fuselage:military_cargo_floor': (False, 'unitless'), 'aircraft:fuselage:num_aisles': (1, 'unitless'), 'aircraft:fuselage:num_fuselages': (1, 'unitless'), 'aircraft:fuselage:num_seats_abreast': (6, 'unitless'), 'aircraft:fuselage:provide_surface_area': (True, 'unitless'), 'aircraft:fuselage:seat_pitch': (29, 'inch'), 'aircraft:fuselage:seat_width': (20.2, 'inch'), 'aircraft:landing_gear:carrier_based': (False, 'unitless'), 'aircraft:landing_gear:drag_coefficient': (0.0, 'unitless'), 'aircraft:landing_gear:fixed_gear': (False, 'unitless'), 'aircraft:strut:dimensional_location_specified': (False, 'unitless'), 'aircraft:vertical_tail:num_tails': (1, 'unitless'), 'aircraft:wing:airfoil_technology': (1.0, 'unitless'), 'aircraft:wing:choose_fold_location': (True, 'unitless'), 'aircraft:wing:detailed_wing': (False, 'unitless'), 'aircraft:wing:flap_type': (, 'unitless'), 'aircraft:wing:fold_dimensional_location_specified': (False, 'unitless'), 'aircraft:wing:has_fold': (False, 'unitless'), 'aircraft:wing:has_strut': (False, 'unitless'), 'aircraft:wing:load_distribution_control': (2.0, 'unitless'), 'aircraft:wing:loading_above_20': (True, 'unitless'), 'aircraft:wing:num_flap_segments': (2, 'unitless'), 'aircraft:wing:num_integration_stations': (50, 'unitless'), 'aircraft:wing:span_efficiency_reduction': (False, 'unitless'), 'mission:design:cruise_altitude': (37500, 'ft'), 'mission:design:rate_of_climb_at_top_of_climb': (0.0, 'ft/min'), 'mission:summary:fuel_flow_scaler': (1, 'unitless'), 'mission:takeoff:angle_of_attack_runway': (0.0, 'deg'), 'mission:takeoff:obstacle_height': (35.0, 'ft'), 'mission:takeoff:thrust_incidence': (0.0, 'deg'), 'mission:taxi:duration': (0.1677, 'h'), 'mission:taxi:mach': (0.0001, 'unitless'), 'debug_mode': (False, 'unitless'), 'INGASP.JENGSZ': (4, 'unitless'), 'test_mode': (False, 'unitless'), 'use_surrogates': (True, 'unitless'), 'mass_defect': (10000, 'lbm'), 'problem_type': (, 'unitless'), 'aircraft:controls:cockpit_control_mass_scaler': (1, 'unitless'), 'aircraft:controls:control_mass_increment': (0, 'lbm'), 'aircraft:controls:stability_augmentation_system_mass': (0, 'lbm'), 'aircraft:controls:stability_augmentation_system_mass_scaler': (1, 'unitless'), 'aircraft:crew_and_payload:cargo_mass': (10040, 'lbm'), 'aircraft:design:cg_delta': (0.25, 'unitless'), 'aircraft:design:cockpit_control_mass_coefficient': (16.5, 'unitless'), 'aircraft:design:drag_increment': (0.00175, 'unitless'), 'aircraft:design:equipment_mass_coefficients': ([928, 0.0736, 0.112, 0.14, 1959, 1.65, 551, 11192, 5, 3, 50, 7.6, 12], 'unitless'), 'aircraft:design:max_structural_speed': (402.5, 'mi/h'), 'aircraft:design:static_margin': (0.03, 'unitless'), 'aircraft:design:structural_mass_increment': (0, 'lbm'), 'aircraft:design:supercritical_drag_shift': (0.033, 'unitless'), 'aircraft:engine:additional_mass_fraction': (array([0.135]), 'unitless'), 'aircraft:engine:data_file': (['models/engines/turbofan_23k_1.deck'], 'unitless'), 'aircraft:engine:mass_scaler': (array([1]), 'unitless'), 'aircraft:engine:mass_specific': (array([0.21366]), 'lbm/lbf'), 'aircraft:engine:pod_mass_scaler': (array([1]), 'unitless'), 'aircraft:engine:pylon_factor': (array([1.25]), 'unitless'), 'aircraft:engine:reference_diameter': (array([5.8]), 'ft'), 'aircraft:engine:reference_sls_thrust': (array([28690]), 'lbf'), 'aircraft:engine:scale_factor': (array([1]), 'unitless'), 'aircraft:engine:scaled_sls_thrust': (array([28690]), 'lbf'), 'aircraft:engine:wing_locations': (array([0.35]), 'unitless'), 'aircraft:fuel:density': (6.687, 'lbm/galUS'), 'aircraft:fuel:fuel_margin': (0, 'unitless'), 'aircraft:fuel:fuel_system_mass_coefficient': (0.041, 'unitless'), 'aircraft:fuel:fuel_system_mass_scaler': (1, 'unitless'), 'aircraft:fuel:wing_fuel_fraction': (0.6, 'unitless'), 'aircraft:fuselage:delta_diameter': (4.5, 'ft'), 'aircraft:fuselage:flat_plate_area_increment': (0.25, 'ft**2'), 'aircraft:fuselage:form_factor': (1.25, 'unitless'), 'aircraft:fuselage:mass_coefficient': (128, 'unitless'), 'aircraft:fuselage:nose_fineness': (1, 'unitless'), 'aircraft:fuselage:pilot_compartment_length': (9.5, 'ft'), 'aircraft:fuselage:pressure_differential': (7.5, 'psi'), 'aircraft:fuselage:tail_fineness': (3, 'unitless'), 'aircraft:fuselage:wetted_area_factor': (4000, 'unitless'), 'aircraft:horizontal_tail:area': (0, 'ft**2'), 'aircraft:horizontal_tail:aspect_ratio': (4.75, 'unitless'), 'aircraft:horizontal_tail:form_factor': (1.25, 'unitless'), 'aircraft:horizontal_tail:mass_coefficient': (0.232, 'unitless'), 'aircraft:horizontal_tail:moment_ratio': (0.2307, 'unitless'), 'aircraft:horizontal_tail:sweep': (25, 'deg'), 'aircraft:horizontal_tail:taper_ratio': (0.352, 'unitless'), 'aircraft:horizontal_tail:thickness_to_chord': (0.12, 'unitless'), 'aircraft:horizontal_tail:vertical_tail_fraction': (0, 'unitless'), 'aircraft:horizontal_tail:volume_coefficient': (1.189, 'unitless'), 'aircraft:landing_gear:main_gear_location': (0.15, 'unitless'), 'aircraft:landing_gear:main_gear_mass_coefficient': (0.85, 'unitless'), 'aircraft:landing_gear:mass_coefficient': (0.04, 'unitless'), 'aircraft:landing_gear:tail_hook_mass_scaler': (1, 'unitless'), 'aircraft:landing_gear:total_mass_scaler': (1, 'unitless'), 'aircraft:nacelle:clearance_ratio': (array([0.2]), 'unitless'), 'aircraft:nacelle:core_diameter_ratio': (array([1.25]), 'unitless'), 'aircraft:nacelle:fineness': (array([2]), 'unitless'), 'aircraft:nacelle:form_factor': (array([1.5]), 'unitless'), 'aircraft:nacelle:mass_specific': (array([3]), 'lbm/ft**2'), 'aircraft:strut:area_ratio': (0, 'unitless'), 'aircraft:strut:attachment_location': (0, 'ft'), 'aircraft:strut:attachment_location_dimensionless': (0, 'unitless'), 'aircraft:strut:fuselage_interference_factor': (0, 'unitless'), 'aircraft:strut:mass_coefficient': (0, 'unitless'), 'aircraft:strut:thickness_to_chord': (0, 'unitless'), 'aircraft:vertical_tail:area': (0, 'ft**2'), 'aircraft:vertical_tail:aspect_ratio': (1.67, 'unitless'), 'aircraft:vertical_tail:form_factor': (1.25, 'unitless'), 'aircraft:vertical_tail:mass_coefficient': (0.289, 'unitless'), 'aircraft:vertical_tail:moment_ratio': (2.362, 'unitless'), 'aircraft:vertical_tail:sweep': (35, 'deg'), 'aircraft:vertical_tail:taper_ratio': (0.801, 'unitless'), 'aircraft:vertical_tail:thickness_to_chord': (0.12, 'unitless'), 'aircraft:vertical_tail:volume_coefficient': (0.145, 'unitless'), 'aircraft:wing:aspect_ratio': (10.13, 'unitless'), 'aircraft:wing:center_distance': (0.463, 'unitless'), 'aircraft:wing:flap_chord_ratio': (0.3, 'unitless'), 'aircraft:wing:flap_deflection_landing': (40, 'deg'), 'aircraft:wing:flap_deflection_takeoff': (10, 'deg'), 'aircraft:wing:flap_drag_increment_optimum': (0.1, 'unitless'), 'aircraft:wing:flap_lift_increment_optimum': (1.5, 'unitless'), 'aircraft:wing:flap_span_ratio': (0.65, 'unitless'), 'aircraft:wing:fold_mass_coefficient': (0, 'unitless'), 'aircraft:wing:folded_span': (0, 'ft'), 'aircraft:wing:form_factor': (1.25, 'unitless'), 'aircraft:wing:fuselage_interference_factor': (1.1, 'unitless'), 'aircraft:wing:height': (8, 'ft'), 'aircraft:wing:high_lift_mass_coefficient': (1.9, 'unitless'), 'aircraft:wing:incidence': (1.5, 'deg'), 'aircraft:wing:loading': (128, 'lbf/ft**2'), 'aircraft:wing:mass_coefficient': (102.5, 'unitless'), 'aircraft:wing:max_lift_ref': (1.15, 'unitless'), 'aircraft:wing:max_slat_deflection_landing': (10, 'deg'), 'aircraft:wing:max_slat_deflection_takeoff': (10, 'deg'), 'aircraft:wing:max_thickness_location': (0.4, 'unitless'), 'aircraft:wing:min_pressure_location': (0.3, 'unitless'), 'aircraft:wing:mounting_type': (0, 'unitless'), 'aircraft:wing:optimum_flap_deflection': (55, 'deg'), 'aircraft:wing:optimum_slat_deflection': (20, 'deg'), 'aircraft:wing:slat_chord_ratio': (0.15, 'unitless'), 'aircraft:wing:slat_lift_increment_optimum': (0.93, 'unitless'), 'aircraft:wing:surface_ctrl_mass_coefficient': (0.95, 'unitless'), 'aircraft:wing:sweep': (25, 'deg'), 'aircraft:wing:taper_ratio': (0.33, 'unitless'), 'aircraft:wing:thickness_to_chord_root': (0.15, 'unitless'), 'aircraft:wing:thickness_to_chord_tip': (0.12, 'unitless'), 'aircraft:wing:zero_lift_angle': (-1.2, 'deg'), 'mission:design:gross_mass': (175400, 'lbm'), 'mission:design:mach': (0.8, 'unitless'), 'mission:design:range': (3675, 'NM'), 'mission:landing:braking_delay': (1, 's'), 'mission:landing:glide_to_stall_ratio': (1.3, 'unitless'), 'mission:landing:maximum_flare_load_factor': (1.15, 'unitless'), 'mission:landing:maximum_sink_rate': (900, 'ft/min'), 'mission:landing:obstacle_height': (50, 'ft'), 'mission:landing:touchdown_sink_rate': (5, 'ft/s'), 'mission:takeoff:decision_speed_increment': (10, 'kn'), 'mission:takeoff:rotation_speed_increment': (5, 'kn'), 'engine_models': ([], 'unitless'), 'aircraft:propulsion:total_num_engines': (2, 'unitless'), 'aircraft:propulsion:total_num_fuselage_engines': (0, 'unitless'), 'aircraft:propulsion:total_num_wing_engines': (2, 'unitless')}" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# Build problem\n", "prob = av.AviaryProblem(av.default_solved_phase_info, mission_method, mass_method, analysis_scheme)\n", @@ -849,7 +2514,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "id": "5036d584", "metadata": {}, "outputs": [], @@ -869,10 +2534,686 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "id": "502d1eda", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.speeds' : d(*)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.params' : d(max_mach)/d(max_airspeed): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.params' : d(density_ratio)/d(max_airspeed): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.params' : d(V9)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.design_load.factors' : d(aircraft:wing:ultimate_load_factor)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.fixed_mass.params' : d(c_gear_loc)/d(aircraft:landing_gear:main_gear_location): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.equip_and_useful_mass' : d(aircraft:design:fixed_useful_load)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'pre_mission.core_subsystems.core_mass.equip_and_useful_mass' : d(aircraft:design:fixed_equipment_mass)/d(*): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2185: UserWarning: Phase time options have no effect because fix_initial=True or input_initial=True for phase 'traj.phases.groundroll': initial_ref\n", + " warnings.warn(f'Phase time options have no effect because fix_initial=True '\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.groundroll.rhs_all.eoms' : d(alpha_rate)/d(('*',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "The following variables have been overridden:\n", + " 'aircraft:engine:scale_factor\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.ascent: The following timeseries outputs were requested but not found in the ODE: flap_factor, gear_factor\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.climb_at_constant_EAS: The following timeseries outputs were requested but not found in the ODE: flap_factor, gear_factor\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.climb_at_constant_EAS_to_mach: The following timeseries outputs were requested but not found in the ODE: flap_factor, gear_factor\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.climb_at_constant_TAS: The following timeseries outputs were requested but not found in the ODE: flap_factor, gear_factor\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.climb_at_constant_mach: The following timeseries outputs were requested but not found in the ODE: flap_factor, gear_factor\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.cruise: The following timeseries outputs were requested but not found in the ODE: flap_factor, gear_factor\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.descent: The following timeseries outputs were requested but not found in the ODE: flap_factor, gear_factor\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/pseudospectral/components/state_independents.py:80: OpenMDAOWarning:: State mass has bounds but they are not enforced when using `solve_segments.` Apply a path constraint to mass to enforce bounds.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/pseudospectral/components/state_independents.py:80: OpenMDAOWarning:: State range has bounds but they are not enforced when using `solve_segments.` Apply a path constraint to range to enforce bounds.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/utils/introspection.py:924: OpenMDAOWarning:traj.phases.groundroll: The following timeseries outputs were requested but not found in the ODE: altitude, thrust_req\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.groundroll' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: True\n", + " input initial: False\n", + " Setting `traj.phases.groundroll.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.groundroll.nonlinear_solver to override.\n", + " Setting `traj.phases.groundroll.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.groundroll.linear_solver to override.\n", + " Set `traj.phases.groundroll.options[\"auto_solvers\"] = False` to disable this behavior.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "--- Constraint Report [traj] ---\n", + " --- groundroll ---\n", + " None\n", + " --- rotation ---\n", + " [final] TAS <= 2.0000e+02 [kn]\n", + " [final] 0.0000e+00 == normal_force [lbf]\n", + " [path] fuselage_pitch <= 1.5000e+01 [deg]\n", + " --- ascent_to_gear_retract ---\n", + " [path] fuselage_pitch <= 1.5000e+01 [deg]\n", + " [path] 0.0000e+00 <= load_factor <= 1.1000e+00 [unitless]\n", + " --- ascent_to_flap_retract ---\n", + " [path] 0.0000e+00 <= load_factor <= 1.1000e+00 [unitless]\n", + " --- ascent ---\n", + " [path] EAS <= 2.5000e+02 [kn]\n", + " --- climb_at_constant_TAS ---\n", + " [final] 2.5000e+02 == EAS [kn]\n", + " --- climb_at_constant_EAS ---\n", + " None\n", + " --- climb_at_constant_EAS_to_mach ---\n", + " [final] 8.0000e-01 == mach [unitless]\n", + " --- climb_at_constant_mach ---\n", + " None\n", + " --- cruise ---\n", + " None\n", + " --- descent ---\n", + " [final] 2.0000e+03 == range [NM]\n", + " [final] 1.0000e+04 == altitude [ft]\n", + " [final] 2.5000e+02 == TAS [kn]\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.ascent_to_flap_retract.rhs_all.control_iter_group.core_aerodynamics.lift_coef' : d(CL_base)/d(('CL_max_flaps',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.ascent_to_gear_retract.rhs_all.control_iter_group.core_aerodynamics.lift_coef' : d(CL_base)/d(('CL_max_flaps',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.groundroll.rhs_all.core_aerodynamics.lift_coef' : d(CL_base)/d(('CL_max_flaps',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/component.py:1151: OMDeprecationWarning:'traj.phases.rotation.rhs_all.control_iter_group.core_aerodynamics.lift_coef' : d(CL_base)/d(('CL_max_flaps',)): Partial was declared to be exactly zero. This is inefficient and the declaration should be removed. In a future version of OpenMDAO this behavior will raise an error.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, aviary_history.db, is being overwritten.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model viewer data has already been recorded for Driver.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/driver.py:469: DriverWarning:The following design variable initial conditions are out of their specified bounds:\n", + " traj.descent.t_duration\n", + " val: [200000.]\n", + " lower: 150000.0\n", + " upper: 199999.99999999997\n", + "Set the initial value of the design variable to a valid value or set the driver option['invalid_desvar_behavior'] to 'ignore'.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model viewer data has already been recorded for Driver.\n", + "Full total jacobian was computed 3 times, taking 2.734579 seconds.\n", + "Total jacobian shape: (232, 205) \n", + "\n", + "\n", + "Jacobian shape: (232, 205) (2.59% nonzero)\n", + "FWD solves: 12 REV solves: 0\n", + "Total colors vs. total size: 12 vs 205 (94.15% improvement)\n", + "\n", + "Sparsity computed using tolerance: 1e-25\n", + "Time to compute sparsity: 2.7346 sec\n", + "Time to compute coloring: 0.0898 sec\n", + "Memory to compute coloring: 0.0000 MB\n", + "Coloring created on: 2024-01-09 11:27:17\n", + "\n", + "List of user-set options:\n", + "\n", + " Name Value used\n", + " alpha_for_y = safer-min-dual-infeas yes\n", + " file_print_level = 5 yes\n", + " hessian_approximation = limited-memory yes\n", + " linear_solver = mumps yes\n", + " max_iter = 1 yes\n", + " mu_init = 1e-05 yes\n", + " mu_strategy = monotone yes\n", + " nlp_scaling_method = gradient-based yes\n", + " output_file = reports/problem5/IPOPT.out yes\n", + " print_level = 5 yes\n", + " print_user_options = yes yes\n", + " sb = yes yes\n", + " tol = 1e-06 yes\n", + "This is Ipopt version 3.14.12, running with linear solver MUMPS 5.2.1.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 1053\n", + "Number of nonzeros in inequality constraint Jacobian.: 175\n", + "Number of nonzeros in Lagrangian Hessian.............: 0\n", + "\n", + "Total number of variables............................: 205\n", + " variables with only lower bounds: 0\n", + " variables with lower and upper bounds: 149\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 190\n", + "Total number of inequality constraints...............: 41\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 16\n", + " inequality constraints with only upper bounds: 25\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 -5.0098936e-03 2.25e+00 1.00e+00 -5.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 4.9419858e-02 5.00e-02 8.41e-01 -5.0 4.65e-01 - 5.70e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 1\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 4.9419858298412112e-02 4.9419858298412112e-02\n", + "Dual infeasibility......: 8.4107122267553258e-01 8.4107122267553258e-01\n", + "Constraint violation....: 4.9974004887564878e-02 4.9974004887564878e-02\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 1.0000007358127383e+05 1.0000007358127383e+05\n", + "Overall NLP error.......: 1.0000007358127383e+05 1.0000007358127383e+05\n", + "\n", + "\n", + "Number of objective function evaluations = 2\n", + "Number of objective gradient evaluations = 2\n", + "Number of equality constraint evaluations = 2\n", + "Number of inequality constraint evaluations = 2\n", + "Number of equality constraint Jacobian evaluations = 2\n", + "Number of inequality constraint Jacobian evaluations = 2\n", + "Number of Lagrangian Hessian evaluations = 0\n", + "Total seconds in IPOPT = 3.946\n", + "\n", + "EXIT: Maximum Number of Iterations Exceeded.\n", + "\n", + "\n", + "Optimization Problem -- Optimization using pyOpt_sparse\n", + "================================================================================\n", + " Objective Function: _objfunc\n", + "\n", + " Solution: \n", + "--------------------------------------------------------------------------------\n", + " Total Time: 3.9479\n", + " User Objective Time : 1.7465\n", + " User Sensitivity Time : 2.1768\n", + " Interface Time : 0.0177\n", + " Opt Solver Time: 0.0070\n", + " Calls to Objective Function : 3\n", + " Calls to Sens Function : 3\n", + "\n", + "\n", + " Objectives\n", + " Index Name Value\n", + " 0 obj_comp.obj 4.941986E-02\n", + "\n", + " Variables (c - continuous, i - integer, d - discrete)\n", + " Index Name Type Lower Bound Value Upper Bound Status\n", + " 0 traj.ascent.t_initial_0 c 1.000000E-02 2.459292E+00 2.000000E+02 \n", + " 1 traj.ascent.t_duration_0 c 5.000000E-01 1.007184E+00 1.000000E+01 \n", + " 2 traj.ascent.states:time_0 c -1.000000E+19 4.317144E-01 1.000000E+19 \n", + " 3 traj.ascent.states:time_1 c -1.000000E+19 4.488850E-01 1.000000E+19 \n", + " 4 traj.ascent.states:time_2 c -1.000000E+19 4.719806E-01 1.000000E+19 \n", + " 5 traj.ascent.states:time_3 c -1.000000E+19 4.791523E-01 1.000000E+19 \n", + " 6 traj.ascent.states:time_4 c -1.000000E+19 4.953339E-01 1.000000E+19 \n", + " 7 traj.ascent.states:time_5 c -1.000000E+19 5.171307E-01 1.000000E+19 \n", + " 8 traj.ascent.states:time_6 c -1.000000E+19 5.239064E-01 1.000000E+19 \n", + " 9 traj.ascent.states:mass_0 c 5.882353E-02 1.030757E+00 5.882353E+15 \n", + " 10 traj.ascent.states:mass_1 c 5.882353E-02 1.030717E+00 5.882353E+15 \n", + " 11 traj.ascent.states:mass_2 c 5.882353E-02 1.030664E+00 5.882353E+15 \n", + " 12 traj.ascent.states:mass_3 c 5.882353E-02 1.030647E+00 5.882353E+15 \n", + " 13 traj.ascent.states:mass_4 c 5.882353E-02 1.030609E+00 5.882353E+15 \n", + " 14 traj.ascent.states:mass_5 c 5.882353E-02 1.030560E+00 5.882353E+15 \n", + " 15 traj.ascent.states:mass_6 c 5.882353E-02 1.030544E+00 5.882353E+15 \n", + " 16 traj.ascent.polynomial_controls:TAS_0 c 4.000000E-03 8.012488E-01 2.000000E+00 \n", + " 17 traj.ascent.polynomial_controls:TAS_1 c 4.000000E-03 9.002717E-01 2.000000E+00 \n", + " 18 traj.ascent_to_flap_retract.t_initial_0 c 1.000000E-02 1.948640E+00 2.000000E+02 \n", + " 19 traj.ascent_to_flap_retract.t_duration_0 c 5.000000E-01 5.106520E-01 1.000000E+01 \n", + " 20 traj.ascent_to_flap_retract.states:time_0 c -1.000000E+19 3.812183E-01 1.000000E+19 \n", + " 21 traj.ascent_to_flap_retract.states:time_1 c -1.000000E+19 3.901652E-01 1.000000E+19 \n", + " 22 traj.ascent_to_flap_retract.states:time_2 c -1.000000E+19 4.025219E-01 1.000000E+19 \n", + " 23 traj.ascent_to_flap_retract.states:time_3 c -1.000000E+19 4.064361E-01 1.000000E+19 \n", + " 24 traj.ascent_to_flap_retract.states:time_4 c -1.000000E+19 4.154045E-01 1.000000E+19 \n", + " 25 traj.ascent_to_flap_retract.states:time_5 c -1.000000E+19 4.277909E-01 1.000000E+19 \n", + " 26 traj.ascent_to_flap_retract.states:time_6 c -1.000000E+19 4.317144E-01 1.000000E+19 \n", + " 27 traj.ascent_to_flap_retract.states:mass_0 c 5.882353E-02 1.030865E+00 5.882353E+15 \n", + " 28 traj.ascent_to_flap_retract.states:mass_1 c 5.882353E-02 1.030845E+00 5.882353E+15 \n", + " 29 traj.ascent_to_flap_retract.states:mass_2 c 5.882353E-02 1.030820E+00 5.882353E+15 \n", + " 30 traj.ascent_to_flap_retract.states:mass_3 c 5.882353E-02 1.030811E+00 5.882353E+15 \n", + " 31 traj.ascent_to_flap_retract.states:mass_4 c 5.882353E-02 1.030791E+00 5.882353E+15 \n", + " 32 traj.ascent_to_flap_retract.states:mass_5 c 5.882353E-02 1.030766E+00 5.882353E+15 \n", + " 33 traj.ascent_to_flap_retract.states:mass_6 c 5.882353E-02 1.030757E+00 5.882353E+15 \n", + " 34 traj.ascent_to_flap_retract.polynomial_controls:TAS_0 c 4.000000E-03 8.050453E-01 2.000000E+00 \n", + " 35 traj.ascent_to_flap_retract.polynomial_controls:TAS_1 c 4.000000E-03 8.012488E-01 2.000000E+00 \n", + " 36 traj.ascent_to_gear_retract.t_initial_0 c 1.000000E-02 1.437182E+00 2.000000E+00 \n", + " 37 traj.ascent_to_gear_retract.t_duration_0 c 5.000000E-01 5.114581E-01 1.000000E+01 \n", + " 38 traj.ascent_to_gear_retract.states:time_0 c -1.000000E+19 3.312175E-01 1.000000E+19 \n", + " 39 traj.ascent_to_gear_retract.states:time_1 c -1.000000E+19 3.401805E-01 1.000000E+19 \n", + " 40 traj.ascent_to_gear_retract.states:time_2 c -1.000000E+19 3.524854E-01 1.000000E+19 \n", + " 41 traj.ascent_to_gear_retract.states:time_3 c -1.000000E+19 3.563656E-01 1.000000E+19 \n", + " 42 traj.ascent_to_gear_retract.states:time_4 c -1.000000E+19 3.652237E-01 1.000000E+19 \n", + " 43 traj.ascent_to_gear_retract.states:time_5 c -1.000000E+19 3.773840E-01 1.000000E+19 \n", + " 44 traj.ascent_to_gear_retract.states:time_6 c -1.000000E+19 3.812183E-01 1.000000E+19 \n", + " 45 traj.ascent_to_gear_retract.states:mass_0 c 5.882353E-02 1.030972E+00 5.882353E+15 \n", + " 46 traj.ascent_to_gear_retract.states:mass_1 c 5.882353E-02 1.030952E+00 5.882353E+15 \n", + " 47 traj.ascent_to_gear_retract.states:mass_2 c 5.882353E-02 1.030927E+00 5.882353E+15 \n", + " 48 traj.ascent_to_gear_retract.states:mass_3 c 5.882353E-02 1.030918E+00 5.882353E+15 \n", + " 49 traj.ascent_to_gear_retract.states:mass_4 c 5.882353E-02 1.030898E+00 5.882353E+15 \n", + " 50 traj.ascent_to_gear_retract.states:mass_5 c 5.882353E-02 1.030874E+00 5.882353E+15 \n", + " 51 traj.ascent_to_gear_retract.states:mass_6 c 5.882353E-02 1.030865E+00 5.882353E+15 \n", + " 52 traj.ascent_to_gear_retract.polynomial_controls:TAS_0 c 4.000000E-03 7.859530E-01 2.000000E+00 \n", + " 53 traj.ascent_to_gear_retract.polynomial_controls:TAS_1 c 4.000000E-03 8.050453E-01 2.000000E+00 \n", + " 54 traj.climb_at_constant_EAS.t_initial_0 c 1.000000E-03 4.464615E-02 1.000000E+02 \n", + " 55 traj.climb_at_constant_EAS.t_duration_0 c 1.000000E-01 2.425742E-01 5.000000E-01 \n", + " 56 traj.climb_at_constant_EAS.states:time_0 c -1.000000E+19 6.053591E-01 1.000000E+19 \n", + " 57 traj.climb_at_constant_EAS.states:time_1 c -1.000000E+19 9.359677E-01 1.000000E+19 \n", + " 58 traj.climb_at_constant_EAS.states:time_2 c -1.000000E+19 1.378734E+00 1.000000E+19 \n", + " 59 traj.climb_at_constant_EAS.states:time_3 c -1.000000E+19 1.515670E+00 1.000000E+19 \n", + " 60 traj.climb_at_constant_EAS.states:time_4 c -1.000000E+19 1.823518E+00 1.000000E+19 \n", + " 61 traj.climb_at_constant_EAS.states:time_5 c -1.000000E+19 2.235380E+00 1.000000E+19 \n", + " 62 traj.climb_at_constant_EAS.states:time_6 c -1.000000E+19 2.362656E+00 1.000000E+19 \n", + " 63 traj.climb_at_constant_EAS.states:mass_0 c 5.882353E-02 1.030356E+00 5.882353E+15 \n", + " 64 traj.climb_at_constant_EAS.states:mass_1 c 5.882353E-02 1.029637E+00 5.882353E+15 \n", + " 65 traj.climb_at_constant_EAS.states:mass_2 c 5.882353E-02 1.028707E+00 5.882353E+15 \n", + " 66 traj.climb_at_constant_EAS.states:mass_3 c 5.882353E-02 1.028426E+00 5.882353E+15 \n", + " 67 traj.climb_at_constant_EAS.states:mass_4 c 5.882353E-02 1.027808E+00 5.882353E+15 \n", + " 68 traj.climb_at_constant_EAS.states:mass_5 c 5.882353E-02 1.027012E+00 5.882353E+15 \n", + " 69 traj.climb_at_constant_EAS.states:mass_6 c 5.882353E-02 1.026771E+00 5.882353E+15 \n", + " 70 traj.climb_at_constant_EAS_to_mach.t_initial_0 c 1.000000E-03 2.872203E-01 1.000000E+02 \n", + " 71 traj.climb_at_constant_EAS_to_mach.t_duration_0 c 1.000000E-01 2.670316E+00 1.000000E+01 \n", + " 72 traj.climb_at_constant_EAS_to_mach.states:time_0 c -1.000000E+19 2.362656E+00 1.000000E+19 \n", + " 73 traj.climb_at_constant_EAS_to_mach.states:time_1 c -1.000000E+19 5.204204E+00 1.000000E+19 \n", + " 74 traj.climb_at_constant_EAS_to_mach.states:time_2 c -1.000000E+19 8.829514E+00 1.000000E+19 \n", + " 75 traj.climb_at_constant_EAS_to_mach.states:time_3 c -1.000000E+19 9.907883E+00 1.000000E+19 \n", + " 76 traj.climb_at_constant_EAS_to_mach.states:time_4 c -1.000000E+19 1.225643E+01 1.000000E+19 \n", + " 77 traj.climb_at_constant_EAS_to_mach.states:time_5 c -1.000000E+19 1.523042E+01 1.000000E+19 \n", + " 78 traj.climb_at_constant_EAS_to_mach.states:time_6 c -1.000000E+19 1.610961E+01 1.000000E+19 \n", + " 79 traj.climb_at_constant_EAS_to_mach.states:mass_0 c 5.882353E-02 1.026771E+00 5.882353E+15 \n", + " 80 traj.climb_at_constant_EAS_to_mach.states:mass_1 c 5.882353E-02 1.021586E+00 5.882353E+15 \n", + " 81 traj.climb_at_constant_EAS_to_mach.states:mass_2 c 5.882353E-02 1.015594E+00 5.882353E+15 \n", + " 82 traj.climb_at_constant_EAS_to_mach.states:mass_3 c 5.882353E-02 1.013935E+00 5.882353E+15 \n", + " 83 traj.climb_at_constant_EAS_to_mach.states:mass_4 c 5.882353E-02 1.010543E+00 5.882353E+15 \n", + " 84 traj.climb_at_constant_EAS_to_mach.states:mass_5 c 5.882353E-02 1.006673E+00 5.882353E+15 \n", + " 85 traj.climb_at_constant_EAS_to_mach.states:mass_6 c 5.882353E-02 1.005622E+00 5.882353E+15 \n", + " 86 traj.climb_at_constant_EAS_to_mach.polynomial_controls:altitude_0 c -3.333333E-05 3.333333E-01 1.333333E+00 \n", + " 87 traj.climb_at_constant_EAS_to_mach.polynomial_controls:altitude_1 c -3.333333E-05 1.095259E+00 1.333333E+00 \n", + " 88 traj.climb_at_constant_TAS.t_initial_0 c 1.000000E-02 3.466476E+00 2.000000E+02 \n", + " 89 traj.climb_at_constant_TAS.t_duration_0 c 5.000000E-01 9.981389E-01 1.000000E+01 \n", + " 90 traj.climb_at_constant_TAS.states:time_0 c -1.000000E+19 5.239064E-01 1.000000E+19 \n", + " 91 traj.climb_at_constant_TAS.states:time_1 c -1.000000E+19 5.390506E-01 1.000000E+19 \n", + " 92 traj.climb_at_constant_TAS.states:time_2 c -1.000000E+19 5.594399E-01 1.000000E+19 \n", + " 93 traj.climb_at_constant_TAS.states:time_3 c -1.000000E+19 5.657757E-01 1.000000E+19 \n", + " 94 traj.climb_at_constant_TAS.states:time_4 c -1.000000E+19 5.800786E-01 1.000000E+19 \n", + " 95 traj.climb_at_constant_TAS.states:time_5 c -1.000000E+19 5.993613E-01 1.000000E+19 \n", + " 96 traj.climb_at_constant_TAS.states:time_6 c -1.000000E+19 6.053591E-01 1.000000E+19 \n", + " 97 traj.climb_at_constant_TAS.states:mass_0 c 5.882353E-02 1.030544E+00 5.882353E+15 \n", + " 98 traj.climb_at_constant_TAS.states:mass_1 c 5.882353E-02 1.030508E+00 5.882353E+15 \n", + " 99 traj.climb_at_constant_TAS.states:mass_2 c 5.882353E-02 1.030462E+00 5.882353E+15 \n", + " 100 traj.climb_at_constant_TAS.states:mass_3 c 5.882353E-02 1.030447E+00 5.882353E+15 \n", + " 101 traj.climb_at_constant_TAS.states:mass_4 c 5.882353E-02 1.030413E+00 5.882353E+15 \n", + " 102 traj.climb_at_constant_TAS.states:mass_5 c 5.882353E-02 1.030370E+00 5.882353E+15 \n", + " 103 traj.climb_at_constant_TAS.states:mass_6 c 5.882353E-02 1.030356E+00 5.882353E+15 \n", + " 104 traj.climb_at_constant_TAS.polynomial_controls:TAS_0 c 4.000000E-03 9.002717E-01 2.000000E+00 \n", + " 105 traj.climb_at_constant_TAS.polynomial_controls:TAS_1 c 4.000000E-03 1.007296E+00 2.000000E+00 \n", + " 106 traj.climb_at_constant_mach.t_initial_0 c 1.000000E-03 2.957537E+00 1.000000E+02 \n", + " 107 traj.climb_at_constant_mach.t_duration_0 c 1.000000E-01 3.063195E+00 1.000000E+01 \n", + " 108 traj.climb_at_constant_mach.states:time_0 c -1.000000E+19 1.610961E+01 1.000000E+19 \n", + " 109 traj.climb_at_constant_mach.states:time_1 c -1.000000E+19 1.838422E+01 1.000000E+19 \n", + " 110 traj.climb_at_constant_mach.states:time_2 c -1.000000E+19 2.153654E+01 1.000000E+19 \n", + " 111 traj.climb_at_constant_mach.states:time_3 c -1.000000E+19 2.253761E+01 1.000000E+19 \n", + " 112 traj.climb_at_constant_mach.states:time_4 c -1.000000E+19 2.483670E+01 1.000000E+19 \n", + " 113 traj.climb_at_constant_mach.states:time_5 c -1.000000E+19 2.801624E+01 1.000000E+19 \n", + " 114 traj.climb_at_constant_mach.states:time_6 c -1.000000E+19 2.902182E+01 1.000000E+19 \n", + " 115 traj.climb_at_constant_mach.states:mass_0 c 5.882353E-02 1.005622E+00 5.882353E+15 \n", + " 116 traj.climb_at_constant_mach.states:mass_1 c 5.882353E-02 1.003000E+00 5.882353E+15 \n", + " 117 traj.climb_at_constant_mach.states:mass_2 c 5.882353E-02 9.994947E-01 5.882353E+15 \n", + " 118 traj.climb_at_constant_mach.states:mass_3 c 5.882353E-02 9.984115E-01 5.882353E+15 \n", + " 119 traj.climb_at_constant_mach.states:mass_4 c 5.882353E-02 9.959787E-01 5.882353E+15 \n", + " 120 traj.climb_at_constant_mach.states:mass_5 c 5.882353E-02 9.927654E-01 5.882353E+15 \n", + " 121 traj.climb_at_constant_mach.states:mass_6 c 5.882353E-02 9.917915E-01 5.882353E+15 \n", + " 122 traj.climb_at_constant_mach.polynomial_controls:altitude_0 c -3.333333E-05 1.095259E+00 1.333333E+00 \n", + " 123 traj.climb_at_constant_mach.polynomial_controls:altitude_1 c -3.333333E-05 1.250000E+00 1.333333E+00 \n", + " 124 traj.cruise.t_initial_0 c 1.000000E-02 6.020731E-01 2.000000E+01 \n", + " 125 traj.cruise.t_duration_0 c 2.000000E-01 5.804812E-01 6.000000E+00 \n", + " 126 traj.cruise.states:time_0 c -1.000000E+17 2.902182E-01 1.000000E+17 \n", + " 127 traj.cruise.states:time_1 c -1.000000E+17 3.775248E-01 1.000000E+17 \n", + " 128 traj.cruise.states:time_2 c -1.000000E+17 4.979868E-01 1.000000E+17 \n", + " 129 traj.cruise.states:time_3 c -1.000000E+17 5.361142E-01 1.000000E+17 \n", + " 130 traj.cruise.states:time_4 c -1.000000E+17 6.234210E-01 1.000000E+17 \n", + " 131 traj.cruise.states:time_5 c -1.000000E+17 7.438832E-01 1.000000E+17 \n", + " 132 traj.cruise.states:time_6 c -1.000000E+17 7.820106E-01 1.000000E+17 \n", + " 133 traj.cruise.states:time_7 c -1.000000E+17 8.693176E-01 1.000000E+17 \n", + " 134 traj.cruise.states:time_8 c -1.000000E+17 9.897804E-01 1.000000E+17 \n", + " 135 traj.cruise.states:time_9 c -1.000000E+17 1.027908E+00 1.000000E+17 \n", + " 136 traj.cruise.states:time_10 c -1.000000E+17 1.115215E+00 1.000000E+17 \n", + " 137 traj.cruise.states:time_11 c -1.000000E+17 1.235679E+00 1.000000E+17 \n", + " 138 traj.cruise.states:time_12 c -1.000000E+17 1.273807E+00 1.000000E+17 \n", + " 139 traj.cruise.states:time_13 c -1.000000E+17 1.361114E+00 1.000000E+17 \n", + " 140 traj.cruise.states:time_14 c -1.000000E+17 1.481579E+00 1.000000E+17 \n", + " 141 traj.cruise.states:time_15 c -1.000000E+17 1.519707E+00 1.000000E+17 \n", + " 142 traj.cruise.states:mass_0 c 5.882353E-02 9.917915E-01 5.882353E+15 \n", + " 143 traj.cruise.states:mass_1 c 5.882353E-02 9.841493E-01 5.882353E+15 \n", + " 144 traj.cruise.states:mass_2 c 5.882353E-02 9.736073E-01 5.882353E+15 \n", + " 145 traj.cruise.states:mass_3 c 5.882353E-02 9.702696E-01 5.882353E+15 \n", + " 146 traj.cruise.states:mass_4 c 5.882353E-02 9.626275E-01 5.882353E+15 \n", + " 147 traj.cruise.states:mass_5 c 5.882353E-02 9.520856E-01 5.882353E+15 \n", + " 148 traj.cruise.states:mass_6 c 5.882353E-02 9.487480E-01 5.882353E+15 \n", + " 149 traj.cruise.states:mass_7 c 5.882353E-02 9.411059E-01 5.882353E+15 \n", + " 150 traj.cruise.states:mass_8 c 5.882353E-02 9.305640E-01 5.882353E+15 \n", + " 151 traj.cruise.states:mass_9 c 5.882353E-02 9.272264E-01 5.882353E+15 \n", + " 152 traj.cruise.states:mass_10 c 5.882353E-02 9.195842E-01 5.882353E+15 \n", + " 153 traj.cruise.states:mass_11 c 5.882353E-02 9.090421E-01 5.882353E+15 \n", + " 154 traj.cruise.states:mass_12 c 5.882353E-02 9.057044E-01 5.882353E+15 \n", + " 155 traj.cruise.states:mass_13 c 5.882353E-02 8.980620E-01 5.882353E+15 \n", + " 156 traj.cruise.states:mass_14 c 5.882353E-02 8.875195E-01 5.882353E+15 \n", + " 157 traj.cruise.states:mass_15 c 5.882353E-02 8.841817E-01 5.882353E+15 \n", + " 158 traj.descent.t_initial_0 c 1.000000E-04 3.504479E+00 1.000000E+01 \n", + " 159 traj.descent.t_duration_0 c 1.500000E+00 1.995209E+00 2.000000E+00 \n", + " 160 traj.descent.states:time_0 c -1.000000E+17 1.519707E+00 1.000000E+17 \n", + " 161 traj.descent.states:time_1 c -1.000000E+17 1.529487E+00 1.000000E+17 \n", + " 162 traj.descent.states:time_2 c -1.000000E+17 1.544005E+00 1.000000E+17 \n", + " 163 traj.descent.states:time_3 c -1.000000E+17 1.548876E+00 1.000000E+17 \n", + " 164 traj.descent.states:time_4 c -1.000000E+17 1.560601E+00 1.000000E+17 \n", + " 165 traj.descent.states:time_5 c -1.000000E+17 1.578276E+00 1.000000E+17 \n", + " 166 traj.descent.states:time_6 c -1.000000E+17 1.584282E+00 1.000000E+17 \n", + " 167 traj.descent.states:time_7 c -1.000000E+17 1.598916E+00 1.000000E+17 \n", + " 168 traj.descent.states:time_8 c -1.000000E+17 1.621505E+00 1.000000E+17 \n", + " 169 traj.descent.states:time_9 c -1.000000E+17 1.629335E+00 1.000000E+17 \n", + " 170 traj.descent.states:mass_0 c 5.882353E-02 8.841817E-01 5.882353E+15 \n", + " 171 traj.descent.states:mass_1 c 5.882353E-02 8.841099E-01 5.882353E+15 \n", + " 172 traj.descent.states:mass_2 c 5.882353E-02 8.839917E-01 5.882353E+15 \n", + " 173 traj.descent.states:mass_3 c 5.882353E-02 8.839476E-01 5.882353E+15 \n", + " 174 traj.descent.states:mass_4 c 5.882353E-02 8.838342E-01 5.882353E+15 \n", + " 175 traj.descent.states:mass_5 c 5.882353E-02 8.836446E-01 5.882353E+15 \n", + " 176 traj.descent.states:mass_6 c 5.882353E-02 8.835735E-01 5.882353E+15 \n", + " 177 traj.descent.states:mass_7 c 5.882353E-02 8.833886E-01 5.882353E+15 \n", + " 178 traj.descent.states:mass_8 c 5.882353E-02 8.830703E-01 5.882353E+15 \n", + " 179 traj.descent.states:mass_9 c 5.882353E-02 8.829497E-01 5.882353E+15 \n", + " 180 traj.descent.polynomial_controls:TAS_0 c 4.000000E-03 1.933931E+00 2.000000E+00 \n", + " 181 traj.descent.polynomial_controls:TAS_1 c 4.000000E-03 1.000000E+00 2.000000E+00 \n", + " 182 traj.descent.polynomial_controls:altitude_0 c -3.333333E-05 1.250000E+00 1.333333E+00 \n", + " 183 traj.descent.polynomial_controls:altitude_1 c -3.333333E-05 3.333333E-01 1.333333E+00 \n", + " 184 traj.groundroll.t_duration_0 c 5.000000E-01 1.275084E+00 1.000000E+01 \n", + " 185 traj.rotation.t_initial_0 c 5.000000E-02 8.501371E-01 5.000000E+00 \n", + " 186 traj.rotation.t_duration_0 c 5.000000E-02 5.870445E-01 2.000000E+00 \n", + " 187 traj.rotation.states:time_0 c -1.000000E+19 2.610672E-01 1.000000E+19 \n", + " 188 traj.rotation.states:time_1 c -1.000000E+19 2.756966E-01 1.000000E+19 \n", + " 189 traj.rotation.states:time_2 c -1.000000E+19 2.941133E-01 1.000000E+19 \n", + " 190 traj.rotation.states:time_3 c -1.000000E+19 2.995725E-01 1.000000E+19 \n", + " 191 traj.rotation.states:time_4 c -1.000000E+19 3.114718E-01 1.000000E+19 \n", + " 192 traj.rotation.states:time_5 c -1.000000E+19 3.266686E-01 1.000000E+19 \n", + " 193 traj.rotation.states:time_6 c -1.000000E+19 3.312175E-01 1.000000E+19 \n", + " 194 traj.rotation.states:mass_0 c 5.882353E-02 1.031122E+00 5.882353E+15 \n", + " 195 traj.rotation.states:mass_1 c 5.882353E-02 1.031089E+00 5.882353E+15 \n", + " 196 traj.rotation.states:mass_2 c 5.882353E-02 1.031051E+00 5.882353E+15 \n", + " 197 traj.rotation.states:mass_3 c 5.882353E-02 1.031039E+00 5.882353E+15 \n", + " 198 traj.rotation.states:mass_4 c 5.882353E-02 1.031013E+00 5.882353E+15 \n", + " 199 traj.rotation.states:mass_5 c 5.882353E-02 1.030982E+00 5.882353E+15 \n", + " 200 traj.rotation.states:mass_6 c 5.882353E-02 1.030972E+00 5.882353E+15 \n", + " 201 traj.rotation.polynomial_controls:TAS_0 c 4.000000E-03 5.100334E-01 2.000000E+00 \n", + " 202 traj.rotation.polynomial_controls:TAS_1 c 4.000000E-03 7.859530E-01 2.000000E+00 \n", + " 203 traj.rotation.polynomial_controls:alpha_0 c -4.000000E-01 1.012082E-02 1.500000E+00 \n", + " 204 traj.rotation.polynomial_controls:alpha_1 c -4.000000E-01 4.131361E-01 1.500000E+00 \n", + "\n", + " Constraints (i - inequality, e - equality)\n", + " Index Name Type Lower Value Upper Status Lagrange Multiplier (N/A)\n", + " 0 traj.linkages.ascent_to_gear_retract:time_final|ascent_to_flap_retract:time_initial e 0.000000E+00 2.612882E-10 0.000000E+00 9.00000E+100\n", + " 1 traj.linkages.ascent_to_gear_retract:mass_final|ascent_to_flap_retract:mass_initial e 0.000000E+00 -3.708701E-11 0.000000E+00 9.00000E+100\n", + " 2 traj.linkages.ascent_to_gear_retract:range_final|ascent_to_flap_retract:range_initial e 0.000000E+00 -1.016768E-09 0.000000E+00 9.00000E+100\n", + " 3 traj.linkages.ascent_to_gear_retract:TAS_final|ascent_to_flap_retract:TAS_initial e 0.000000E+00 9.981704E-13 0.000000E+00 9.00000E+100\n", + " 4 traj.linkages.ascent_to_flap_retract:time_final|ascent:time_initial e 0.000000E+00 1.838906E-10 0.000000E+00 9.00000E+100\n", + " 5 traj.linkages.ascent_to_flap_retract:mass_final|ascent:mass_initial e 0.000000E+00 -3.737514E-11 0.000000E+00 9.00000E+100\n", + " 6 traj.linkages.ascent_to_flap_retract:range_final|ascent:range_initial e 0.000000E+00 -5.813266E-10 0.000000E+00 9.00000E+100\n", + " 7 traj.linkages.ascent_to_flap_retract:TAS_final|ascent:TAS_initial e 0.000000E+00 3.759482E-12 0.000000E+00 9.00000E+100\n", + " 8 traj.linkages.climb_at_constant_EAS:altitude_final|climb_at_constant_EAS_to_mach:altitude_initial e 0.000000E+00 -2.229988E-10 0.000000E+00 9.00000E+100\n", + " 9 traj.linkages.climb_at_constant_EAS:time_final|climb_at_constant_EAS_to_mach:time_initial e 0.000000E+00 3.076860E-10 0.000000E+00 9.00000E+100\n", + " 10 traj.linkages.climb_at_constant_EAS:mass_final|climb_at_constant_EAS_to_mach:mass_initial e 0.000000E+00 -3.959867E-11 0.000000E+00 9.00000E+100\n", + " 11 traj.linkages.climb_at_constant_EAS:range_final|climb_at_constant_EAS_to_mach:range_initial e 0.000000E+00 -1.529515E-11 0.000000E+00 9.00000E+100\n", + " 12 traj.linkages.climb_at_constant_EAS_to_mach:altitude_final|climb_at_constant_mach:altitude_initial e 0.000000E+00 -1.644003E-11 0.000000E+00 9.00000E+100\n", + " 13 traj.linkages.climb_at_constant_EAS_to_mach:time_final|climb_at_constant_mach:time_initial e 0.000000E+00 -2.818933E-10 0.000000E+00 9.00000E+100\n", + " 14 traj.linkages.climb_at_constant_EAS_to_mach:mass_final|climb_at_constant_mach:mass_initial e 0.000000E+00 -4.168542E-11 0.000000E+00 9.00000E+100\n", + " 15 traj.linkages.climb_at_constant_EAS_to_mach:range_final|climb_at_constant_mach:range_initial e 0.000000E+00 -7.654307E-12 0.000000E+00 9.00000E+100\n", + " 16 traj.linkages.climb_at_constant_mach:altitude_final|cruise:altitude_initial e 0.000000E+00 -3.365130E-12 0.000000E+00 9.00000E+100\n", + " 17 traj.linkages.climb_at_constant_mach:time_final|cruise:time_initial e 0.000000E+00 1.073658E-11 0.000000E+00 9.00000E+100\n", + " 18 traj.linkages.climb_at_constant_mach:mass_final|cruise:mass_initial e 0.000000E+00 -4.561734E-11 0.000000E+00 9.00000E+100\n", + " 19 traj.linkages.climb_at_constant_mach:range_final|cruise:range_initial e 0.000000E+00 -4.435424E-12 0.000000E+00 9.00000E+100\n", + " 20 traj.linkages.cruise:altitude_final|descent:altitude_initial e 0.000000E+00 -6.111804E-14 0.000000E+00 9.00000E+100\n", + " 21 traj.linkages.cruise:time_final|descent:time_initial e 0.000000E+00 7.203198E-12 0.000000E+00 9.00000E+100\n", + " 22 traj.linkages.cruise:mass_final|descent:mass_initial e 0.000000E+00 -4.171452E-11 0.000000E+00 9.00000E+100\n", + " 23 traj.linkages.cruise:range_final|descent:range_initial e 0.000000E+00 -1.118518E-10 0.000000E+00 9.00000E+100\n", + " 24 traj.linkages.groundroll:time_final|rotation:time_initial e 0.000000E+00 2.400125E-03 0.000000E+00 E 9.00000E+100\n", + " 25 traj.linkages.groundroll:mass_final|rotation:mass_initial e 0.000000E+00 -1.127567E-04 0.000000E+00 E 9.00000E+100\n", + " 26 traj.linkages.groundroll:range_final|rotation:range_initial e 0.000000E+00 1.134792E-02 0.000000E+00 E 9.00000E+100\n", + " 27 traj.linkages.groundroll:TAS_final|rotation:TAS_initial e 0.000000E+00 -1.505480E-10 0.000000E+00 9.00000E+100\n", + " 28 traj.linkages.rotation:time_final|ascent_to_gear_retract:time_initial e 0.000000E+00 3.321197E-10 0.000000E+00 9.00000E+100\n", + " 29 traj.linkages.rotation:mass_final|ascent_to_gear_retract:mass_initial e 0.000000E+00 -3.536406E-11 0.000000E+00 9.00000E+100\n", + " 30 traj.linkages.rotation:range_final|ascent_to_gear_retract:range_initial e 0.000000E+00 -2.313537E-09 0.000000E+00 9.00000E+100\n", + " 31 traj.linkages.rotation:TAS_final|ascent_to_gear_retract:TAS_initial e 0.000000E+00 -8.480143E-11 0.000000E+00 9.00000E+100\n", + " 32 traj.linkages.ascent:time_final|climb_at_constant_TAS:time_initial e 0.000000E+00 9.804999E-11 0.000000E+00 9.00000E+100\n", + " 33 traj.linkages.ascent:mass_final|climb_at_constant_TAS:mass_initial e 0.000000E+00 -3.781461E-11 0.000000E+00 9.00000E+100\n", + " 34 traj.linkages.ascent:range_final|climb_at_constant_TAS:range_initial e 0.000000E+00 -2.592907E-10 0.000000E+00 9.00000E+100\n", + " 35 traj.linkages.ascent:TAS_final|climb_at_constant_TAS:TAS_initial e 0.000000E+00 -2.165734E-12 0.000000E+00 9.00000E+100\n", + " 36 traj.linkages.climb_at_constant_TAS:time_final|climb_at_constant_EAS:time_initial e 0.000000E+00 1.108418E-11 0.000000E+00 9.00000E+100\n", + " 37 traj.linkages.climb_at_constant_TAS:mass_final|climb_at_constant_EAS:mass_initial e 0.000000E+00 -3.816385E-11 0.000000E+00 9.00000E+100\n", + " 38 traj.linkages.climb_at_constant_TAS:range_final|climb_at_constant_EAS:range_initial e 0.000000E+00 -1.578019E-11 0.000000E+00 9.00000E+100\n", + " 39 traj.linkages.climb_at_constant_TAS:TAS_final|climb_at_constant_EAS:TAS_initial e 0.000000E+00 -1.763567E-12 0.000000E+00 9.00000E+100\n", + " 40 traj.ascent.collocation_constraint.defects:time e 0.000000E+00 -1.747681E-09 0.000000E+00 9.00000E+100\n", + " 41 traj.ascent.collocation_constraint.defects:time e 0.000000E+00 -1.528990E-08 0.000000E+00 9.00000E+100\n", + " 42 traj.ascent.collocation_constraint.defects:time e 0.000000E+00 -1.010842E-08 0.000000E+00 9.00000E+100\n", + " 43 traj.ascent.collocation_constraint.defects:time e 0.000000E+00 -1.767186E-09 0.000000E+00 9.00000E+100\n", + " 44 traj.ascent.collocation_constraint.defects:time e 0.000000E+00 -1.228403E-08 0.000000E+00 9.00000E+100\n", + " 45 traj.ascent.collocation_constraint.defects:time e 0.000000E+00 -8.116669E-09 0.000000E+00 9.00000E+100\n", + " 46 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 1.413781E-08 0.000000E+00 9.00000E+100\n", + " 47 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 6.530079E-08 0.000000E+00 9.00000E+100\n", + " 48 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 4.805608E-08 0.000000E+00 9.00000E+100\n", + " 49 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 1.421405E-08 0.000000E+00 9.00000E+100\n", + " 50 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 6.563756E-08 0.000000E+00 9.00000E+100\n", + " 51 traj.ascent.collocation_constraint.defects:mass e 0.000000E+00 4.829367E-08 0.000000E+00 9.00000E+100\n", + " 52 traj.ascent_to_flap_retract.collocation_constraint.defects:time e 0.000000E+00 -9.646602E-09 0.000000E+00 9.00000E+100\n", + " 53 traj.ascent_to_flap_retract.collocation_constraint.defects:time e 0.000000E+00 -2.814928E-08 0.000000E+00 9.00000E+100\n", + " 54 traj.ascent_to_flap_retract.collocation_constraint.defects:time e 0.000000E+00 -1.928297E-08 0.000000E+00 9.00000E+100\n", + " 55 traj.ascent_to_flap_retract.collocation_constraint.defects:time e 0.000000E+00 -6.235639E-09 0.000000E+00 9.00000E+100\n", + " 56 traj.ascent_to_flap_retract.collocation_constraint.defects:time e 0.000000E+00 -2.259348E-08 0.000000E+00 9.00000E+100\n", + " 57 traj.ascent_to_flap_retract.collocation_constraint.defects:time e 0.000000E+00 -1.526477E-08 0.000000E+00 9.00000E+100\n", + " 58 traj.ascent_to_flap_retract.collocation_constraint.defects:mass e 0.000000E+00 1.402417E-08 0.000000E+00 9.00000E+100\n", + " 59 traj.ascent_to_flap_retract.collocation_constraint.defects:mass e 0.000000E+00 6.465865E-08 0.000000E+00 9.00000E+100\n", + " 60 traj.ascent_to_flap_retract.collocation_constraint.defects:mass e 0.000000E+00 4.752926E-08 0.000000E+00 9.00000E+100\n", + " 61 traj.ascent_to_flap_retract.collocation_constraint.defects:mass e 0.000000E+00 1.405129E-08 0.000000E+00 9.00000E+100\n", + " 62 traj.ascent_to_flap_retract.collocation_constraint.defects:mass e 0.000000E+00 6.484071E-08 0.000000E+00 9.00000E+100\n", + " 63 traj.ascent_to_flap_retract.collocation_constraint.defects:mass e 0.000000E+00 4.770808E-08 0.000000E+00 9.00000E+100\n", + " 64 traj.ascent_to_gear_retract.collocation_constraint.defects:time e 0.000000E+00 -5.243622E-08 0.000000E+00 9.00000E+100\n", + " 65 traj.ascent_to_gear_retract.collocation_constraint.defects:time e 0.000000E+00 -5.969421E-08 0.000000E+00 9.00000E+100\n", + " 66 traj.ascent_to_gear_retract.collocation_constraint.defects:time e 0.000000E+00 -3.275561E-08 0.000000E+00 9.00000E+100\n", + " 67 traj.ascent_to_gear_retract.collocation_constraint.defects:time e 0.000000E+00 -1.248545E-08 0.000000E+00 9.00000E+100\n", + " 68 traj.ascent_to_gear_retract.collocation_constraint.defects:time e 0.000000E+00 -3.024618E-08 0.000000E+00 9.00000E+100\n", + " 69 traj.ascent_to_gear_retract.collocation_constraint.defects:time e 0.000000E+00 -2.167643E-08 0.000000E+00 9.00000E+100\n", + " 70 traj.ascent_to_gear_retract.collocation_constraint.defects:mass e 0.000000E+00 1.369197E-08 0.000000E+00 9.00000E+100\n", + " 71 traj.ascent_to_gear_retract.collocation_constraint.defects:mass e 0.000000E+00 6.347131E-08 0.000000E+00 9.00000E+100\n", + " 72 traj.ascent_to_gear_retract.collocation_constraint.defects:mass e 0.000000E+00 4.722671E-08 0.000000E+00 9.00000E+100\n", + " 73 traj.ascent_to_gear_retract.collocation_constraint.defects:mass e 0.000000E+00 1.416163E-08 0.000000E+00 9.00000E+100\n", + " 74 traj.ascent_to_gear_retract.collocation_constraint.defects:mass e 0.000000E+00 6.548642E-08 0.000000E+00 9.00000E+100\n", + " 75 traj.ascent_to_gear_retract.collocation_constraint.defects:mass e 0.000000E+00 4.796910E-08 0.000000E+00 9.00000E+100\n", + " 76 traj.climb_at_constant_EAS.collocation_constraint.defects:time e 0.000000E+00 -4.554809E-07 0.000000E+00 9.00000E+100\n", + " 77 traj.climb_at_constant_EAS.collocation_constraint.defects:time e 0.000000E+00 -4.437427E-07 0.000000E+00 9.00000E+100\n", + " 78 traj.climb_at_constant_EAS.collocation_constraint.defects:time e 0.000000E+00 -4.296671E-07 0.000000E+00 9.00000E+100\n", + " 79 traj.climb_at_constant_EAS.collocation_constraint.defects:time e 0.000000E+00 -4.253305E-07 0.000000E+00 9.00000E+100\n", + " 80 traj.climb_at_constant_EAS.collocation_constraint.defects:time e 0.000000E+00 -4.205060E-07 0.000000E+00 9.00000E+100\n", + " 81 traj.climb_at_constant_EAS.collocation_constraint.defects:time e 0.000000E+00 -4.105684E-07 0.000000E+00 9.00000E+100\n", + " 82 traj.climb_at_constant_EAS.collocation_constraint.defects:mass e 0.000000E+00 1.544382E-08 0.000000E+00 9.00000E+100\n", + " 83 traj.climb_at_constant_EAS.collocation_constraint.defects:mass e 0.000000E+00 6.758758E-08 0.000000E+00 9.00000E+100\n", + " 84 traj.climb_at_constant_EAS.collocation_constraint.defects:mass e 0.000000E+00 5.002537E-08 0.000000E+00 9.00000E+100\n", + " 85 traj.climb_at_constant_EAS.collocation_constraint.defects:mass e 0.000000E+00 1.546570E-08 0.000000E+00 9.00000E+100\n", + " 86 traj.climb_at_constant_EAS.collocation_constraint.defects:mass e 0.000000E+00 6.835801E-08 0.000000E+00 9.00000E+100\n", + " 87 traj.climb_at_constant_EAS.collocation_constraint.defects:mass e 0.000000E+00 5.079527E-08 0.000000E+00 9.00000E+100\n", + " 88 traj.phases.climb_at_constant_EAS_to_mach->final_boundary_constraint->mach e 8.000000E-01 8.000000E-01 8.000000E-01 9.00000E+100\n", + " 89 traj.climb_at_constant_EAS_to_mach.collocation_constraint.defects:time e 0.000000E+00 -9.175639E-09 0.000000E+00 9.00000E+100\n", + " 90 traj.climb_at_constant_EAS_to_mach.collocation_constraint.defects:time e 0.000000E+00 -3.986398E-08 0.000000E+00 9.00000E+100\n", + " 91 traj.climb_at_constant_EAS_to_mach.collocation_constraint.defects:time e 0.000000E+00 -1.315770E-08 0.000000E+00 9.00000E+100\n", + " 92 traj.climb_at_constant_EAS_to_mach.collocation_constraint.defects:time e 0.000000E+00 1.985971E-09 0.000000E+00 9.00000E+100\n", + " 93 traj.climb_at_constant_EAS_to_mach.collocation_constraint.defects:time e 0.000000E+00 3.315513E-08 0.000000E+00 9.00000E+100\n", + " 94 traj.climb_at_constant_EAS_to_mach.collocation_constraint.defects:time e 0.000000E+00 3.034072E-08 0.000000E+00 9.00000E+100\n", + " 95 traj.climb_at_constant_EAS_to_mach.collocation_constraint.defects:mass e 0.000000E+00 1.507579E-08 0.000000E+00 9.00000E+100\n", + " 96 traj.climb_at_constant_EAS_to_mach.collocation_constraint.defects:mass e 0.000000E+00 6.984450E-08 0.000000E+00 9.00000E+100\n", + " 97 traj.climb_at_constant_EAS_to_mach.collocation_constraint.defects:mass e 0.000000E+00 5.165021E-08 0.000000E+00 9.00000E+100\n", + " 98 traj.climb_at_constant_EAS_to_mach.collocation_constraint.defects:mass e 0.000000E+00 1.536210E-08 0.000000E+00 9.00000E+100\n", + " 99 traj.climb_at_constant_EAS_to_mach.collocation_constraint.defects:mass e 0.000000E+00 7.105449E-08 0.000000E+00 9.00000E+100\n", + " 100 traj.climb_at_constant_EAS_to_mach.collocation_constraint.defects:mass e 0.000000E+00 5.264093E-08 0.000000E+00 9.00000E+100\n", + " 101 traj.phases.climb_at_constant_TAS->final_boundary_constraint->EAS e 1.000000E+00 1.000000E+00 1.000000E+00 9.00000E+100\n", + " 102 traj.climb_at_constant_TAS.collocation_constraint.defects:time e 0.000000E+00 -2.094251E-09 0.000000E+00 9.00000E+100\n", + " 103 traj.climb_at_constant_TAS.collocation_constraint.defects:time e 0.000000E+00 -8.757735E-09 0.000000E+00 9.00000E+100\n", + " 104 traj.climb_at_constant_TAS.collocation_constraint.defects:time e 0.000000E+00 -6.167356E-09 0.000000E+00 9.00000E+100\n", + " 105 traj.climb_at_constant_TAS.collocation_constraint.defects:time e 0.000000E+00 -2.540299E-09 0.000000E+00 9.00000E+100\n", + " 106 traj.climb_at_constant_TAS.collocation_constraint.defects:time e 0.000000E+00 -6.377448E-09 0.000000E+00 9.00000E+100\n", + " 107 traj.climb_at_constant_TAS.collocation_constraint.defects:time e 0.000000E+00 -5.088869E-09 0.000000E+00 9.00000E+100\n", + " 108 traj.climb_at_constant_TAS.collocation_constraint.defects:mass e 0.000000E+00 1.430483E-08 0.000000E+00 9.00000E+100\n", + " 109 traj.climb_at_constant_TAS.collocation_constraint.defects:mass e 0.000000E+00 6.603719E-08 0.000000E+00 9.00000E+100\n", + " 110 traj.climb_at_constant_TAS.collocation_constraint.defects:mass e 0.000000E+00 4.857910E-08 0.000000E+00 9.00000E+100\n", + " 111 traj.climb_at_constant_TAS.collocation_constraint.defects:mass e 0.000000E+00 1.436652E-08 0.000000E+00 9.00000E+100\n", + " 112 traj.climb_at_constant_TAS.collocation_constraint.defects:mass e 0.000000E+00 6.630470E-08 0.000000E+00 9.00000E+100\n", + " 113 traj.climb_at_constant_TAS.collocation_constraint.defects:mass e 0.000000E+00 4.876806E-08 0.000000E+00 9.00000E+100\n", + " 114 traj.climb_at_constant_mach.collocation_constraint.defects:time e 0.000000E+00 1.617965E-09 0.000000E+00 9.00000E+100\n", + " 115 traj.climb_at_constant_mach.collocation_constraint.defects:time e 0.000000E+00 9.057018E-09 0.000000E+00 9.00000E+100\n", + " 116 traj.climb_at_constant_mach.collocation_constraint.defects:time e 0.000000E+00 -3.724665E-10 0.000000E+00 9.00000E+100\n", + " 117 traj.climb_at_constant_mach.collocation_constraint.defects:time e 0.000000E+00 -2.501975E-09 0.000000E+00 9.00000E+100\n", + " 118 traj.climb_at_constant_mach.collocation_constraint.defects:time e 0.000000E+00 -9.323672E-09 0.000000E+00 9.00000E+100\n", + " 119 traj.climb_at_constant_mach.collocation_constraint.defects:time e 0.000000E+00 -5.594376E-09 0.000000E+00 9.00000E+100\n", + " 120 traj.climb_at_constant_mach.collocation_constraint.defects:mass e 0.000000E+00 1.585982E-08 0.000000E+00 9.00000E+100\n", + " 121 traj.climb_at_constant_mach.collocation_constraint.defects:mass e 0.000000E+00 7.364000E-08 0.000000E+00 9.00000E+100\n", + " 122 traj.climb_at_constant_mach.collocation_constraint.defects:mass e 0.000000E+00 5.478994E-08 0.000000E+00 9.00000E+100\n", + " 123 traj.climb_at_constant_mach.collocation_constraint.defects:mass e 0.000000E+00 1.642883E-08 0.000000E+00 9.00000E+100\n", + " 124 traj.climb_at_constant_mach.collocation_constraint.defects:mass e 0.000000E+00 7.638733E-08 0.000000E+00 9.00000E+100\n", + " 125 traj.climb_at_constant_mach.collocation_constraint.defects:mass e 0.000000E+00 5.705677E-08 0.000000E+00 9.00000E+100\n", + " 126 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -2.383472E-08 0.000000E+00 9.00000E+100\n", + " 127 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -1.098661E-07 0.000000E+00 9.00000E+100\n", + " 128 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -8.019704E-08 0.000000E+00 9.00000E+100\n", + " 129 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -2.342182E-08 0.000000E+00 9.00000E+100\n", + " 130 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -1.074414E-07 0.000000E+00 9.00000E+100\n", + " 131 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -7.769977E-08 0.000000E+00 9.00000E+100\n", + " 132 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -2.244684E-08 0.000000E+00 9.00000E+100\n", + " 133 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -1.024242E-07 0.000000E+00 9.00000E+100\n", + " 134 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -7.329834E-08 0.000000E+00 9.00000E+100\n", + " 135 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -2.090975E-08 0.000000E+00 9.00000E+100\n", + " 136 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -9.481425E-08 0.000000E+00 9.00000E+100\n", + " 137 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -6.699262E-08 0.000000E+00 9.00000E+100\n", + " 138 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -1.881051E-08 0.000000E+00 9.00000E+100\n", + " 139 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -8.461144E-08 0.000000E+00 9.00000E+100\n", + " 140 traj.cruise.collocation_constraint.defects:time e 0.000000E+00 -5.878244E-08 0.000000E+00 9.00000E+100\n", + " 141 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 1.745807E-08 0.000000E+00 9.00000E+100\n", + " 142 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 8.125911E-08 0.000000E+00 9.00000E+100\n", + " 143 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 6.039479E-08 0.000000E+00 9.00000E+100\n", + " 144 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 1.799912E-08 0.000000E+00 9.00000E+100\n", + " 145 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 8.336510E-08 0.000000E+00 9.00000E+100\n", + " 146 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 6.139961E-08 0.000000E+00 9.00000E+100\n", + " 147 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 1.811460E-08 0.000000E+00 9.00000E+100\n", + " 148 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 8.350098E-08 0.000000E+00 9.00000E+100\n", + " 149 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 6.094711E-08 0.000000E+00 9.00000E+100\n", + " 150 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 1.779639E-08 0.000000E+00 9.00000E+100\n", + " 151 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 8.162881E-08 0.000000E+00 9.00000E+100\n", + " 152 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 5.900883E-08 0.000000E+00 9.00000E+100\n", + " 153 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 1.703587E-08 0.000000E+00 9.00000E+100\n", + " 154 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 7.770845E-08 0.000000E+00 9.00000E+100\n", + " 155 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 5.555462E-08 0.000000E+00 9.00000E+100\n", + " 156 traj.phases.descent->final_boundary_constraint->range e 2.000000E+00 2.000000E+00 2.000000E+00 9.00000E+100\n", + " 157 traj.phases.descent->final_boundary_constraint->altitude e 1.000000E+00 1.000000E+00 1.000000E+00 9.00000E+100\n", + " 158 traj.phases.descent->final_boundary_constraint->TAS e 1.000000E+00 1.000000E+00 1.000000E+00 9.00000E+100\n", + " 159 traj.descent.collocation_constraint.defects:time e 0.000000E+00 -1.533251E-08 0.000000E+00 9.00000E+100\n", + " 160 traj.descent.collocation_constraint.defects:time e 0.000000E+00 -6.768821E-08 0.000000E+00 9.00000E+100\n", + " 161 traj.descent.collocation_constraint.defects:time e 0.000000E+00 -4.631342E-08 0.000000E+00 9.00000E+100\n", + " 162 traj.descent.collocation_constraint.defects:time e 0.000000E+00 -1.262178E-08 0.000000E+00 9.00000E+100\n", + " 163 traj.descent.collocation_constraint.defects:time e 0.000000E+00 -5.550315E-08 0.000000E+00 9.00000E+100\n", + " 164 traj.descent.collocation_constraint.defects:time e 0.000000E+00 -3.745740E-08 0.000000E+00 9.00000E+100\n", + " 165 traj.descent.collocation_constraint.defects:time e 0.000000E+00 -9.966721E-09 0.000000E+00 9.00000E+100\n", + " 166 traj.descent.collocation_constraint.defects:time e 0.000000E+00 -4.342516E-08 0.000000E+00 9.00000E+100\n", + " 167 traj.descent.collocation_constraint.defects:time e 0.000000E+00 -2.829954E-08 0.000000E+00 9.00000E+100\n", + " 168 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 1.538186E-08 0.000000E+00 9.00000E+100\n", + " 169 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 6.970283E-08 0.000000E+00 9.00000E+100\n", + " 170 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 4.960815E-08 0.000000E+00 9.00000E+100\n", + " 171 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 1.414450E-08 0.000000E+00 9.00000E+100\n", + " 172 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 6.415823E-08 0.000000E+00 9.00000E+100\n", + " 173 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 4.575235E-08 0.000000E+00 9.00000E+100\n", + " 174 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 1.307599E-08 0.000000E+00 9.00000E+100\n", + " 175 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 5.938336E-08 0.000000E+00 9.00000E+100\n", + " 176 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 4.244121E-08 0.000000E+00 9.00000E+100\n", + " 177 traj.phases.rotation->final_boundary_constraint->normal_force e 0.000000E+00 -4.997400E-02 0.000000E+00 E 9.00000E+100\n", + " 178 traj.rotation.collocation_constraint.defects:time e 0.000000E+00 -9.267154E-06 0.000000E+00 E 9.00000E+100\n", + " 179 traj.rotation.collocation_constraint.defects:time e 0.000000E+00 -6.200230E-06 0.000000E+00 E 9.00000E+100\n", + " 180 traj.rotation.collocation_constraint.defects:time e 0.000000E+00 -3.421241E-06 0.000000E+00 E 9.00000E+100\n", + " 181 traj.rotation.collocation_constraint.defects:time e 0.000000E+00 -2.775903E-06 0.000000E+00 E 9.00000E+100\n", + " 182 traj.rotation.collocation_constraint.defects:time e 0.000000E+00 -1.690882E-06 0.000000E+00 E 9.00000E+100\n", + " 183 traj.rotation.collocation_constraint.defects:time e 0.000000E+00 -6.704024E-07 0.000000E+00 9.00000E+100\n", + " 184 traj.rotation.collocation_constraint.defects:mass e 0.000000E+00 4.061554E-08 0.000000E+00 9.00000E+100\n", + " 185 traj.rotation.collocation_constraint.defects:mass e 0.000000E+00 9.950411E-08 0.000000E+00 9.00000E+100\n", + " 186 traj.rotation.collocation_constraint.defects:mass e 0.000000E+00 7.041146E-08 0.000000E+00 9.00000E+100\n", + " 187 traj.rotation.collocation_constraint.defects:mass e 0.000000E+00 2.500647E-08 0.000000E+00 9.00000E+100\n", + " 188 traj.rotation.collocation_constraint.defects:mass e 0.000000E+00 8.886661E-08 0.000000E+00 9.00000E+100\n", + " 189 traj.rotation.collocation_constraint.defects:mass e 0.000000E+00 6.393324E-08 0.000000E+00 9.00000E+100\n", + " 190 traj.phases.ascent->path_constraint->EAS i -1.000000E+30 7.966136E-01 1.000000E+00 9.00000E+100\n", + " 191 traj.phases.ascent->path_constraint->EAS i -1.000000E+30 8.138790E-01 1.000000E+00 9.00000E+100\n", + " 192 traj.phases.ascent->path_constraint->EAS i -1.000000E+30 8.376868E-01 1.000000E+00 9.00000E+100\n", + " 193 traj.phases.ascent->path_constraint->EAS i -1.000000E+30 8.452183E-01 1.000000E+00 9.00000E+100\n", + " 194 traj.phases.ascent->path_constraint->EAS i -1.000000E+30 8.452183E-01 1.000000E+00 9.00000E+100\n", + " 195 traj.phases.ascent->path_constraint->EAS i -1.000000E+30 8.624581E-01 1.000000E+00 9.00000E+100\n", + " 196 traj.phases.ascent->path_constraint->EAS i -1.000000E+30 8.862307E-01 1.000000E+00 9.00000E+100\n", + " 197 traj.phases.ascent->path_constraint->EAS i -1.000000E+30 8.937510E-01 1.000000E+00 9.00000E+100\n", + " 198 traj.phases.ascent_to_flap_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 199 traj.phases.ascent_to_flap_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 200 traj.phases.ascent_to_flap_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 201 traj.phases.ascent_to_flap_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 202 traj.phases.ascent_to_flap_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 203 traj.phases.ascent_to_flap_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 204 traj.phases.ascent_to_flap_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 205 traj.phases.ascent_to_flap_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 206 traj.phases.ascent_to_gear_retract->path_constraint->fuselage_pitch i -1.000000E+30 3.855732E-01 1.000000E+00 9.00000E+100\n", + " 207 traj.phases.ascent_to_gear_retract->path_constraint->fuselage_pitch i -1.000000E+30 3.907166E-01 1.000000E+00 9.00000E+100\n", + " 208 traj.phases.ascent_to_gear_retract->path_constraint->fuselage_pitch i -1.000000E+30 3.902838E-01 1.000000E+00 9.00000E+100\n", + " 209 traj.phases.ascent_to_gear_retract->path_constraint->fuselage_pitch i -1.000000E+30 3.895349E-01 1.000000E+00 9.00000E+100\n", + " 210 traj.phases.ascent_to_gear_retract->path_constraint->fuselage_pitch i -1.000000E+30 3.895349E-01 1.000000E+00 9.00000E+100\n", + " 211 traj.phases.ascent_to_gear_retract->path_constraint->fuselage_pitch i -1.000000E+30 3.870513E-01 1.000000E+00 9.00000E+100\n", + " 212 traj.phases.ascent_to_gear_retract->path_constraint->fuselage_pitch i -1.000000E+30 3.823625E-01 1.000000E+00 9.00000E+100\n", + " 213 traj.phases.ascent_to_gear_retract->path_constraint->fuselage_pitch i -1.000000E+30 3.806637E-01 1.000000E+00 9.00000E+100\n", + " 214 traj.phases.ascent_to_gear_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 215 traj.phases.ascent_to_gear_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 216 traj.phases.ascent_to_gear_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 217 traj.phases.ascent_to_gear_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 218 traj.phases.ascent_to_gear_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 219 traj.phases.ascent_to_gear_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 220 traj.phases.ascent_to_gear_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 221 traj.phases.ascent_to_gear_retract->path_constraint->load_factor i 0.000000E+00 1.000000E+00 1.100000E+00 9.00000E+100\n", + " 222 traj.phases.rotation->final_boundary_constraint->TAS i -1.000000E+30 9.824412E-01 1.000000E+00 9.00000E+100\n", + " 223 traj.phases.rotation->path_constraint->fuselage_pitch i -1.000000E+30 6.747216E-03 1.000000E+00 9.00000E+100\n", + " 224 traj.phases.rotation->path_constraint->fuselage_pitch i -1.000000E+30 5.444421E-02 1.000000E+00 9.00000E+100\n", + " 225 traj.phases.rotation->path_constraint->fuselage_pitch i -1.000000E+30 1.202563E-01 1.000000E+00 9.00000E+100\n", + " 226 traj.phases.rotation->path_constraint->fuselage_pitch i -1.000000E+30 1.410856E-01 1.000000E+00 9.00000E+100\n", + " 227 traj.phases.rotation->path_constraint->fuselage_pitch i -1.000000E+30 1.410856E-01 1.000000E+00 9.00000E+100\n", + " 228 traj.phases.rotation->path_constraint->fuselage_pitch i -1.000000E+30 1.887826E-01 1.000000E+00 9.00000E+100\n", + " 229 traj.phases.rotation->path_constraint->fuselage_pitch i -1.000000E+30 2.545947E-01 1.000000E+00 9.00000E+100\n", + " 230 traj.phases.rotation->path_constraint->fuselage_pitch i -1.000000E+30 2.754241E-01 1.000000E+00 9.00000E+100\n", + "\n", + "\n", + " Exit Status\n", + " Inform Description\n", + " -1 Maximum Iterations Exceeded\n", + "--------------------------------------------------------------------------------\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# Have checks for clashing user inputs\n", "# Raise warnings or errors depending on how clashing the issues are\n", @@ -939,7 +3280,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.18" + "version": "3.8.17" } }, "nbformat": 4, diff --git a/aviary/docs/getting_started/onboarding_level3.ipynb b/aviary/docs/getting_started/onboarding_level3.ipynb index 0f4bb0fbe..d0309aabe 100644 --- a/aviary/docs/getting_started/onboarding_level3.ipynb +++ b/aviary/docs/getting_started/onboarding_level3.ipynb @@ -57,10 +57,374 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "42c6704a", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/subsystems/propulsion/engine_deck.py:198: UserWarning: is a required option for EngineDecks, but has not been specified for EngineDeck . The default value will be used.\n", + " warnings.warn(\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'mach' in phase 'climb': lower, upper, ref\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'climb': lower, upper, ref\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'mach' in phase 'descent': lower, upper, ref\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'descent': lower, upper, ref\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:area', promoted using 'aircraft:canard:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:thickness_to_chord', promoted using 'aircraft:canard:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:wetted_area_scaler', promoted using 'aircraft:canard:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:area', promoted using 'aircraft:canard:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:aspect_ratio', promoted using 'aircraft:canard:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:thickness_to_chord', promoted using 'aircraft:canard:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:fuselage:avg_diameter', promoted using 'aircraft:fuselage:avg_diameter', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:fuselage:length', promoted using 'aircraft:fuselage:length', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:area', promoted using 'aircraft:horizontal_tail:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:aspect_ratio', promoted using 'aircraft:horizontal_tail:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:thickness_to_chord', promoted using 'aircraft:horizontal_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:nacelle:avg_diameter', promoted using 'aircraft:nacelle:avg_diameter', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:nacelle:avg_length', promoted using 'aircraft:nacelle:avg_length', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:area', promoted using 'aircraft:vertical_tail:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:aspect_ratio', promoted using 'aircraft:vertical_tail:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:thickness_to_chord', promoted using 'aircraft:vertical_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:aspect_ratio', promoted using 'aircraft:wing:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:glove_and_bat', promoted using 'aircraft:wing:glove_and_bat', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:taper_ratio', promoted using 'aircraft:wing:taper_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:thickness_to_chord', promoted using 'aircraft:wing:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:avg_diameter', promoted using 'aircraft:fuselage:avg_diameter', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:length', promoted using 'aircraft:fuselage:length', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:wetted_area_scaler', promoted using 'aircraft:fuselage:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:horizontal_tail:thickness_to_chord', promoted using 'aircraft:horizontal_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:horizontal_tail:vertical_tail_fraction', promoted using 'aircraft:horizontal_tail:vertical_tail_fraction', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:vertical_tail:thickness_to_chord', promoted using 'aircraft:vertical_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:aspect_ratio', promoted using 'aircraft:wing:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:glove_and_bat', promoted using 'aircraft:wing:glove_and_bat', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:thickness_to_chord', promoted using 'aircraft:wing:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:avg_diameter', promoted using 'aircraft:nacelle:avg_diameter', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:avg_length', promoted using 'aircraft:nacelle:avg_length', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:wetted_area_scaler', promoted using 'aircraft:nacelle:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:area', promoted using 'aircraft:horizontal_tail:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:vertical_tail_fraction', promoted using 'aircraft:horizontal_tail:vertical_tail_fraction', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:wetted_area_scaler', promoted using 'aircraft:horizontal_tail:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:vertical_tail:area', promoted using 'aircraft:vertical_tail:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:vertical_tail:wetted_area_scaler', promoted using 'aircraft:vertical_tail:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.wing' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.wing' : input variable 'aircraft:wing:wetted_area_scaler', promoted using 'aircraft:wing:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.climb' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.climb.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.climb.nonlinear_solver to override.\n", + " Setting `traj.phases.climb.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.climb.linear_solver to override.\n", + " Set `traj.phases.climb.options[\"auto_solvers\"] = False` to disable this behavior.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "The following variables have been overridden:\n", + " 'aircraft:design:landing_to_takeoff_mass_ratio\n", + " 'aircraft:engine:mass\n", + " 'aircraft:fuel:auxiliary_fuel_capacity\n", + " 'aircraft:fuel:fuselage_fuel_capacity\n", + " 'aircraft:fuselage:planform_area\n", + " 'aircraft:fuselage:wetted_area\n", + " 'aircraft:horizontal_tail:wetted_area\n", + " 'aircraft:nacelle:total_wetted_area\n", + " 'aircraft:nacelle:wetted_area\n", + " 'aircraft:propulsion:total_engine_controls_mass\n", + " 'aircraft:propulsion:total_starter_mass\n", + " 'aircraft:vertical_tail:wetted_area\n", + " 'aircraft:wing:aspect_ratio\n", + " 'aircraft:wing:wetted_area\n", + "\n", + "--- Constraint Report [traj] ---\n", + " --- climb ---\n", + " None\n", + " --- cruise ---\n", + " [path] 3.0000e+02 <= altitude_rate_max [ft/min]\n", + " --- descent ---\n", + " None\n", + "\n", + "Model viewer data has already been recorded for Driver.\n", + "\n", + "List of user-set options:\n", + "\n", + " Name Value used\n", + " file_print_level = 5 yes\n", + " hessian_approximation = limited-memory yes\n", + " linear_solver = mumps yes\n", + " max_iter = 100 yes\n", + " nlp_scaling_method = user-scaling yes\n", + " output_file = reports/problem/IPOPT.out yes\n", + " print_level = 4 yes\n", + " print_user_options = yes yes\n", + " sb = yes yes\n", + " tol = 0.001 yes\n", + "Total number of variables............................: 82\n", + " variables with only lower bounds: 0\n", + " variables with lower and upper bounds: 82\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 79\n", + "Total number of inequality constraints...............: 4\n", + " inequality constraints with only lower bounds: 4\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "\n", + "Number of Iterations....: 25\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 9.4146770609913695e+00 9.4146770609913695e+00\n", + "Dual infeasibility......: 1.0999629934911812e-08 1.0999629934911812e-08\n", + "Constraint violation....: 3.2276147976517677e-08 3.2276147976517677e-08\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 1.2325706634551805e-06 1.2325706634551805e-06\n", + "Overall NLP error.......: 1.2325706634551805e-06 1.2325706634551805e-06\n", + "\n", + "\n", + "Number of objective function evaluations = 28\n", + "Number of objective gradient evaluations = 26\n", + "Number of equality constraint evaluations = 28\n", + "Number of inequality constraint evaluations = 28\n", + "Number of equality constraint Jacobian evaluations = 26\n", + "Number of inequality constraint Jacobian evaluations = 26\n", + "Number of Lagrangian Hessian evaluations = 0\n", + "Total seconds in IPOPT = 13.391\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "\n", + "\n", + "Optimization Problem -- Optimization using pyOpt_sparse\n", + "================================================================================\n", + " Objective Function: _objfunc\n", + "\n", + " Solution: \n", + "--------------------------------------------------------------------------------\n", + " Total Time: 13.3939\n", + " User Objective Time : 9.6485\n", + " User Sensitivity Time : 3.6103\n", + " Interface Time : 0.0666\n", + " Opt Solver Time: 0.0686\n", + " Calls to Objective Function : 28\n", + " Calls to Sens Function : 26\n", + "\n", + "\n", + " Objectives\n", + " Index Name Value\n", + " 0 reg_objective 9.414677E+00\n", + "\n", + " Variables (c - continuous, i - integer, d - discrete)\n", + " Index Name Type Lower Bound Value Upper Bound Status\n", + " 0 mission:design:gross_mass_0 c 7.407407E-01 8.607091E-01 1.481481E+00 \n", + " 1 traj.climb.t_duration_0 c 5.000000E-01 5.000003E-01 2.000000E+00 l\n", + " 2 traj.climb.states:mass_0 c 0.000000E+00 5.241266E+00 1.000000E+17 \n", + " 3 traj.climb.states:mass_1 c 0.000000E+00 5.237291E+00 1.000000E+17 \n", + " 4 traj.climb.states:mass_2 c 0.000000E+00 5.236091E+00 1.000000E+17 \n", + " 5 traj.climb.states:mass_3 c 0.000000E+00 5.230548E+00 1.000000E+17 \n", + " 6 traj.climb.states:mass_4 c 0.000000E+00 5.223489E+00 1.000000E+17 \n", + " 7 traj.climb.states:mass_5 c 0.000000E+00 5.221338E+00 1.000000E+17 \n", + " 8 traj.climb.states:mass_6 c 0.000000E+00 5.215137E+00 1.000000E+17 \n", + " 9 traj.climb.states:mass_7 c 0.000000E+00 5.206956E+00 1.000000E+17 \n", + " 10 traj.climb.states:mass_8 c 0.000000E+00 5.204440E+00 1.000000E+17 \n", + " 11 traj.climb.states:mass_9 c 0.000000E+00 5.198692E+00 1.000000E+17 \n", + " 12 traj.climb.states:mass_10 c 0.000000E+00 5.190826E+00 1.000000E+17 \n", + " 13 traj.climb.states:mass_11 c 0.000000E+00 5.188345E+00 1.000000E+17 \n", + " 14 traj.climb.states:mass_12 c 0.000000E+00 5.183981E+00 1.000000E+17 \n", + " 15 traj.climb.states:mass_13 c 0.000000E+00 5.177987E+00 1.000000E+17 \n", + " 16 traj.climb.states:mass_14 c 0.000000E+00 5.176097E+00 1.000000E+17 \n", + " 17 traj.climb.states:mass_15 c 0.000000E+00 5.174062E+00 1.000000E+17 \n", + " 18 traj.climb.states:mass_16 c 0.000000E+00 5.171248E+00 1.000000E+17 \n", + " 19 traj.climb.states:mass_17 c 0.000000E+00 5.170354E+00 1.000000E+17 \n", + " 20 traj.climb.states:range_0 c 0.000000E+00 2.764851E-03 1.000000E+15 \n", + " 21 traj.climb.states:range_1 c 0.000000E+00 5.071419E-03 1.000000E+15 \n", + " 22 traj.climb.states:range_2 c 0.000000E+00 5.851859E-03 1.000000E+15 \n", + " 23 traj.climb.states:range_3 c 0.000000E+00 9.998326E-03 1.000000E+15 \n", + " 24 traj.climb.states:range_4 c 0.000000E+00 1.663641E-02 1.000000E+15 \n", + " 25 traj.climb.states:range_5 c 0.000000E+00 1.895456E-02 1.000000E+15 \n", + " 26 traj.climb.states:range_6 c 0.000000E+00 2.644512E-02 1.000000E+15 \n", + " 27 traj.climb.states:range_7 c 0.000000E+00 3.822814E-02 1.000000E+15 \n", + " 28 traj.climb.states:range_8 c 0.000000E+00 4.229839E-02 1.000000E+15 \n", + " 29 traj.climb.states:range_9 c 0.000000E+00 5.222057E-02 1.000000E+15 \n", + " 30 traj.climb.states:range_10 c 0.000000E+00 6.724973E-02 1.000000E+15 \n", + " 31 traj.climb.states:range_11 c 0.000000E+00 7.232091E-02 1.000000E+15 \n", + " 32 traj.climb.states:range_12 c 0.000000E+00 8.163066E-02 1.000000E+15 \n", + " 33 traj.climb.states:range_13 c 0.000000E+00 9.521093E-02 1.000000E+15 \n", + " 34 traj.climb.states:range_14 c 0.000000E+00 9.968231E-02 1.000000E+15 \n", + " 35 traj.climb.states:range_15 c 0.000000E+00 1.045838E-01 1.000000E+15 \n", + " 36 traj.climb.states:range_16 c 0.000000E+00 1.114998E-01 1.000000E+15 \n", + " 37 traj.climb.states:range_17 c 0.000000E+00 1.137251E-01 1.000000E+15 \n", + " 38 traj.cruise.t_initial_0 c 7.260000E+02 8.460004E+02 2.904000E+03 \n", + " 39 traj.cruise.t_duration_0 c 5.000000E-01 5.000000E-01 2.000000E+00 l\n", + " 40 traj.cruise.states:mass_0 c 0.000000E+00 5.170354E+00 1.000000E+17 \n", + " 41 traj.cruise.states:mass_1 c 0.000000E+00 5.005025E+00 1.000000E+17 \n", + " 42 traj.cruise.states:mass_2 c 0.000000E+00 4.780360E+00 1.000000E+17 \n", + " 43 traj.cruise.states:mass_3 c 0.000000E+00 4.710045E+00 1.000000E+17 \n", + " 44 traj.cruise.states:range_0 c 0.000000E+00 1.137251E-01 1.000000E+15 \n", + " 45 traj.cruise.states:range_1 c 0.000000E+00 1.127228E+00 1.000000E+15 \n", + " 46 traj.cruise.states:range_2 c 0.000000E+00 2.525655E+00 1.000000E+15 \n", + " 47 traj.cruise.states:range_3 c 0.000000E+00 2.968252E+00 1.000000E+15 \n", + " 48 traj.descent.t_initial_0 c 1.291140E+04 1.303140E+04 5.164560E+04 \n", + " 49 traj.descent.t_duration_0 c 5.000000E-01 5.000011E-01 2.000000E+00 \n", + " 50 traj.descent.states:mass_0 c 0.000000E+00 4.710045E+00 1.000000E+17 \n", + " 51 traj.descent.states:mass_1 c 0.000000E+00 4.710502E+00 1.000000E+17 \n", + " 52 traj.descent.states:mass_2 c 0.000000E+00 4.711242E+00 1.000000E+17 \n", + " 53 traj.descent.states:mass_3 c 0.000000E+00 4.711494E+00 1.000000E+17 \n", + " 54 traj.descent.states:mass_4 c 0.000000E+00 4.712779E+00 1.000000E+17 \n", + " 55 traj.descent.states:mass_5 c 0.000000E+00 4.714841E+00 1.000000E+17 \n", + " 56 traj.descent.states:mass_6 c 0.000000E+00 4.715567E+00 1.000000E+17 \n", + " 57 traj.descent.states:mass_7 c 0.000000E+00 4.717767E+00 1.000000E+17 \n", + " 58 traj.descent.states:mass_8 c 0.000000E+00 4.721139E+00 1.000000E+17 \n", + " 59 traj.descent.states:mass_9 c 0.000000E+00 4.722228E+00 1.000000E+17 \n", + " 60 traj.descent.states:mass_10 c 0.000000E+00 4.723686E+00 1.000000E+17 \n", + " 61 traj.descent.states:mass_11 c 0.000000E+00 4.725431E+00 1.000000E+17 \n", + " 62 traj.descent.states:mass_12 c 0.000000E+00 4.726157E+00 1.000000E+17 \n", + " 63 traj.descent.states:mass_13 c 0.000000E+00 4.726963E+00 1.000000E+17 \n", + " 64 traj.descent.states:mass_14 c 0.000000E+00 4.728154E+00 1.000000E+17 \n", + " 65 traj.descent.states:mass_15 c 0.000000E+00 4.728551E+00 1.000000E+17 \n", + " 66 traj.descent.states:range_0 c 0.000000E+00 2.968252E+00 1.000000E+15 \n", + " 67 traj.descent.states:range_1 c 0.000000E+00 2.976728E+00 1.000000E+15 \n", + " 68 traj.descent.states:range_2 c 0.000000E+00 2.988146E+00 1.000000E+15 \n", + " 69 traj.descent.states:range_3 c 0.000000E+00 2.991691E+00 1.000000E+15 \n", + " 70 traj.descent.states:range_4 c 0.000000E+00 3.007825E+00 1.000000E+15 \n", + " 71 traj.descent.states:range_5 c 0.000000E+00 3.028841E+00 1.000000E+15 \n", + " 72 traj.descent.states:range_6 c 0.000000E+00 3.035182E+00 1.000000E+15 \n", + " 73 traj.descent.states:range_7 c 0.000000E+00 3.051662E+00 1.000000E+15 \n", + " 74 traj.descent.states:range_8 c 0.000000E+00 3.072458E+00 1.000000E+15 \n", + " 75 traj.descent.states:range_9 c 0.000000E+00 3.078555E+00 1.000000E+15 \n", + " 76 traj.descent.states:range_10 c 0.000000E+00 3.089619E+00 1.000000E+15 \n", + " 77 traj.descent.states:range_11 c 0.000000E+00 3.103383E+00 1.000000E+15 \n", + " 78 traj.descent.states:range_12 c 0.000000E+00 3.107367E+00 1.000000E+15 \n", + " 79 traj.descent.states:range_13 c 0.000000E+00 3.111617E+00 1.000000E+15 \n", + " 80 traj.descent.states:range_14 c 0.000000E+00 3.117100E+00 1.000000E+15 \n", + " 81 traj.descent.states:range_15 c 0.000000E+00 3.118742E+00 1.000000E+15 \n", + "\n", + " Constraints (i - inequality, e - equality)\n", + " Index Name Type Lower Value Upper Status Lagrange Multiplier (N/A)\n", + " 0 mass_resid e 0.000000E+00 -3.227615E-08 0.000000E+00 9.00000E+100\n", + " 1 traj.linkages.climb:time_final|cruise:time_initial e 0.000000E+00 1.136868E-13 0.000000E+00 9.00000E+100\n", + " 2 traj.linkages.climb:mass_final|cruise:mass_initial e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", + " 3 traj.linkages.climb:range_final|cruise:range_initial e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", + " 4 traj.linkages.cruise:time_final|descent:time_initial e 0.000000E+00 -1.818989E-12 0.000000E+00 9.00000E+100\n", + " 5 traj.linkages.cruise:mass_final|descent:mass_initial e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", + " 6 traj.linkages.cruise:range_final|descent:range_initial e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", + " 7 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.025097E-14 0.000000E+00 9.00000E+100\n", + " 8 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.860766E-14 0.000000E+00 9.00000E+100\n", + " 9 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.699134E-14 0.000000E+00 9.00000E+100\n", + " 10 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 3.485284E-14 0.000000E+00 9.00000E+100\n", + " 11 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 3.003003E-14 0.000000E+00 9.00000E+100\n", + " 12 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.531926E-14 0.000000E+00 9.00000E+100\n", + " 13 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 3.113611E-14 0.000000E+00 9.00000E+100\n", + " 14 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.886567E-14 0.000000E+00 9.00000E+100\n", + " 15 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.598810E-14 0.000000E+00 9.00000E+100\n", + " 16 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.408043E-14 0.000000E+00 9.00000E+100\n", + " 17 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.173824E-14 0.000000E+00 9.00000E+100\n", + " 18 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.099713E-14 0.000000E+00 9.00000E+100\n", + " 19 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.608025E-14 0.000000E+00 9.00000E+100\n", + " 20 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.587637E-14 0.000000E+00 9.00000E+100\n", + " 21 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.558807E-14 0.000000E+00 9.00000E+100\n", + " 22 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 7.279583E-15 0.000000E+00 9.00000E+100\n", + " 23 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 7.206002E-15 0.000000E+00 9.00000E+100\n", + " 24 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 7.240740E-15 0.000000E+00 9.00000E+100\n", + " 25 traj.climb.collocation_constraint.defects:range e 0.000000E+00 1.162790E-14 0.000000E+00 9.00000E+100\n", + " 26 traj.climb.collocation_constraint.defects:range e 0.000000E+00 1.105201E-14 0.000000E+00 9.00000E+100\n", + " 27 traj.climb.collocation_constraint.defects:range e 0.000000E+00 1.002517E-14 0.000000E+00 9.00000E+100\n", + " 28 traj.climb.collocation_constraint.defects:range e 0.000000E+00 2.058287E-14 0.000000E+00 9.00000E+100\n", + " 29 traj.climb.collocation_constraint.defects:range e 0.000000E+00 1.782458E-14 0.000000E+00 9.00000E+100\n", + " 30 traj.climb.collocation_constraint.defects:range e 0.000000E+00 1.511325E-14 0.000000E+00 9.00000E+100\n", + " 31 traj.climb.collocation_constraint.defects:range e 0.000000E+00 1.872588E-14 0.000000E+00 9.00000E+100\n", + " 32 traj.climb.collocation_constraint.defects:range e 0.000000E+00 1.655588E-14 0.000000E+00 9.00000E+100\n", + " 33 traj.climb.collocation_constraint.defects:range e 0.000000E+00 1.434107E-14 0.000000E+00 9.00000E+100\n", + " 34 traj.climb.collocation_constraint.defects:range e 0.000000E+00 1.377297E-14 0.000000E+00 9.00000E+100\n", + " 35 traj.climb.collocation_constraint.defects:range e 0.000000E+00 1.265000E-14 0.000000E+00 9.00000E+100\n", + " 36 traj.climb.collocation_constraint.defects:range e 0.000000E+00 1.141126E-14 0.000000E+00 9.00000E+100\n", + " 37 traj.climb.collocation_constraint.defects:range e 0.000000E+00 8.538640E-15 0.000000E+00 9.00000E+100\n", + " 38 traj.climb.collocation_constraint.defects:range e 0.000000E+00 8.126975E-15 0.000000E+00 9.00000E+100\n", + " 39 traj.climb.collocation_constraint.defects:range e 0.000000E+00 7.635711E-15 0.000000E+00 9.00000E+100\n", + " 40 traj.climb.collocation_constraint.defects:range e 0.000000E+00 3.521029E-15 0.000000E+00 9.00000E+100\n", + " 41 traj.climb.collocation_constraint.defects:range e 0.000000E+00 3.453567E-15 0.000000E+00 9.00000E+100\n", + " 42 traj.climb.collocation_constraint.defects:range e 0.000000E+00 3.366714E-15 0.000000E+00 9.00000E+100\n", + " 43 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 5.312109E-13 0.000000E+00 9.00000E+100\n", + " 44 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 4.063769E-13 0.000000E+00 9.00000E+100\n", + " 45 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 2.575362E-13 0.000000E+00 9.00000E+100\n", + " 46 traj.cruise.collocation_constraint.defects:range e 0.000000E+00 -6.926598E-18 0.000000E+00 9.00000E+100\n", + " 47 traj.cruise.collocation_constraint.defects:range e 0.000000E+00 3.463299E-18 0.000000E+00 9.00000E+100\n", + " 48 traj.cruise.collocation_constraint.defects:range e 0.000000E+00 -6.926598E-18 0.000000E+00 9.00000E+100\n", + " 49 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.910022E-14 0.000000E+00 9.00000E+100\n", + " 50 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.529124E-14 0.000000E+00 9.00000E+100\n", + " 51 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.342543E-14 0.000000E+00 9.00000E+100\n", + " 52 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 6.585307E-14 0.000000E+00 9.00000E+100\n", + " 53 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 5.552915E-14 0.000000E+00 9.00000E+100\n", + " 54 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 4.341976E-14 0.000000E+00 9.00000E+100\n", + " 55 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 4.791654E-14 0.000000E+00 9.00000E+100\n", + " 56 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.929329E-14 0.000000E+00 9.00000E+100\n", + " 57 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.075605E-14 0.000000E+00 9.00000E+100\n", + " 58 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 2.145444E-14 0.000000E+00 9.00000E+100\n", + " 59 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 1.435837E-14 0.000000E+00 9.00000E+100\n", + " 60 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 9.991150E-15 0.000000E+00 9.00000E+100\n", + " 61 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 5.078937E-15 0.000000E+00 9.00000E+100\n", + " 62 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 5.142482E-15 0.000000E+00 9.00000E+100\n", + " 63 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 4.257099E-15 0.000000E+00 9.00000E+100\n", + " 64 traj.descent.collocation_constraint.defects:range e 0.000000E+00 6.438287E-14 0.000000E+00 9.00000E+100\n", + " 65 traj.descent.collocation_constraint.defects:range e 0.000000E+00 6.567239E-14 0.000000E+00 9.00000E+100\n", + " 66 traj.descent.collocation_constraint.defects:range e 0.000000E+00 6.757017E-14 0.000000E+00 9.00000E+100\n", + " 67 traj.descent.collocation_constraint.defects:range e 0.000000E+00 1.393325E-13 0.000000E+00 9.00000E+100\n", + " 68 traj.descent.collocation_constraint.defects:range e 0.000000E+00 1.459218E-13 0.000000E+00 9.00000E+100\n", + " 69 traj.descent.collocation_constraint.defects:range e 0.000000E+00 1.566014E-13 0.000000E+00 9.00000E+100\n", + " 70 traj.descent.collocation_constraint.defects:range e 0.000000E+00 1.907169E-13 0.000000E+00 9.00000E+100\n", + " 71 traj.descent.collocation_constraint.defects:range e 0.000000E+00 2.047396E-13 0.000000E+00 9.00000E+100\n", + " 72 traj.descent.collocation_constraint.defects:range e 0.000000E+00 2.289513E-13 0.000000E+00 9.00000E+100\n", + " 73 traj.descent.collocation_constraint.defects:range e 0.000000E+00 2.003578E-13 0.000000E+00 9.00000E+100\n", + " 74 traj.descent.collocation_constraint.defects:range e 0.000000E+00 2.175539E-13 0.000000E+00 9.00000E+100\n", + " 75 traj.descent.collocation_constraint.defects:range e 0.000000E+00 2.479632E-13 0.000000E+00 9.00000E+100\n", + " 76 traj.descent.collocation_constraint.defects:range e 0.000000E+00 1.271784E-13 0.000000E+00 9.00000E+100\n", + " 77 traj.descent.collocation_constraint.defects:range e 0.000000E+00 1.344334E-13 0.000000E+00 9.00000E+100\n", + " 78 traj.descent.collocation_constraint.defects:range e 0.000000E+00 1.461002E-13 0.000000E+00 9.00000E+100\n", + " 79 traj.phases.cruise->path_constraint->altitude_rate_max i 3.000000E+02 7.127272E+02 1.000000E+30 9.00000E+100\n", + " 80 traj.phases.cruise->path_constraint->altitude_rate_max i 3.000000E+02 7.752630E+02 1.000000E+30 9.00000E+100\n", + " 81 traj.phases.cruise->path_constraint->altitude_rate_max i 3.000000E+02 8.643321E+02 1.000000E+30 9.00000E+100\n", + " 82 traj.phases.cruise->path_constraint->altitude_rate_max i 3.000000E+02 8.932716E+02 1.000000E+30 9.00000E+100\n", + "\n", + "\n", + " Exit Status\n", + " Inform Description\n", + " 0 Solve Succeeded\n", + "--------------------------------------------------------------------------------\n", + "\n", + "-------------------------------\n", + "times_climb: [846.00038137] (s)\n", + "altitudes_climb: [10668.] (m)\n", + "masses_climb: [51703.54384226] (kg)\n", + "ranges_climb: [113725.11889636] (m)\n", + "velocities_climb: [234.25795132] (m/s)\n", + "thrusts_climb: [71713.80312354] (N)\n", + "times_cruise: [13031.40073487] (s)\n", + "altitudes_cruise: [10668.] (m)\n", + "masses_cruise: [47100.44512976] (kg)\n", + "ranges_cruise: [2968252.0417268] (m)\n", + "velocities_cruise: [234.25795132] (m/s)\n", + "thrusts_cruise: [26338.70498784] (N)\n", + "times_descent: [13908.60273889] (s)\n", + "altitudes_descent: [10.668] (m)\n", + "masses_descent: [47285.51458051] (kg)\n", + "ranges_descent: [3118741.8185247] (m)\n", + "velocities_descent: [102.07377559] (m/s)\n", + "thrusts_descent: [-43173.10618655] (N)\n", + "-------------------------------\n" + ] + } + ], "source": [ "'''\n", "NOTES:\n", @@ -69,28 +433,18 @@ "Computed Aero\n", "N3CC data\n", "'''\n", - "import warnings\n", "\n", "import dymos as dm\n", "import openmdao.api as om\n", "import scipy.constants as _units\n", - "from packaging import version\n", "\n", - "from aviary.api import Aircraft, Mission, Dynamic\n", "import aviary.api as av\n", "\n", - "use_new_dymos_syntax = version.parse(dm.__version__) > version.parse(\"1.8.0\")\n", - "\n", - "# benchmark based on N3CC (fixed cruise alt) FLOPS model\n", "\n", - "\n", - "##########################################\n", - "# init problem #\n", - "##########################################\n", "prob = om.Problem(model=om.Group())\n", - "\n", - "prob.driver = driver = om.pyOptSparseDriver(optimizer='IPOPT')\n", - "driver.opt_settings[\"max_iter\"] = 0\n", + "driver = prob.driver = om.pyOptSparseDriver()\n", + "driver.options[\"optimizer\"] = \"IPOPT\"\n", + "driver.opt_settings[\"max_iter\"] = 100\n", "driver.opt_settings[\"tol\"] = 1e-3\n", "driver.opt_settings['print_level'] = 4\n", "\n", @@ -100,42 +454,35 @@ "\n", "aviary_inputs = av.get_flops_inputs('N3CC')\n", "\n", + "aviary_inputs.set_val(av.Mission.Landing.LIFT_COEFFICIENT_MAX,\n", + " 2.4, units=\"unitless\")\n", + "aviary_inputs.set_val(av.Mission.Takeoff.LIFT_COEFFICIENT_MAX,\n", + " 2.0, units=\"unitless\")\n", "aviary_inputs.set_val(\n", - " Mission.Landing.LIFT_COEFFICIENT_MAX, 2.4, units='unitless')\n", - "aviary_inputs.set_val(\n", - " Mission.Takeoff.LIFT_COEFFICIENT_MAX, 2.0, units='unitless')\n", - "aviary_inputs.set_val(\n", - " Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT, val=.0175,\n", - " units='unitless')\n", - "\n", - "takeoff_fuel_burned = 577 # lbm\n", - "takeoff_thrust_per_eng = 24555.5 # lbf\n", - "takeoff_L_over_D = 17.35\n", + " av.Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT,\n", + " val=.0175, units=\"unitless\")\n", "\n", - "aviary_inputs.set_val(\n", - " Mission.Takeoff.FUEL_SIMPLE, takeoff_fuel_burned, units='lbm')\n", - "aviary_inputs.set_val(\n", - " Mission.Takeoff.LIFT_OVER_DRAG, takeoff_L_over_D, units='unitless')\n", - "aviary_inputs.set_val(\n", - " Mission.Design.THRUST_TAKEOFF_PER_ENG, takeoff_thrust_per_eng, units='lbf')\n", + "takeoff_fuel_burned = 577 # lbm TODO: where should this get connected from?\n", + "takeoff_thrust_per_eng = 24555.5 # lbf TODO: where should this get connected from?\n", + "takeoff_L_over_D = 17.35 # TODO: should this come from aero?\n", "\n", - "##########################################\n", - "# Phase Info #\n", - "##########################################\n", + "aviary_inputs.set_val(av.Mission.Takeoff.FUEL_SIMPLE,\n", + " takeoff_fuel_burned, units='lbm')\n", + "aviary_inputs.set_val(av.Mission.Takeoff.LIFT_OVER_DRAG,\n", + " takeoff_L_over_D, units=\"unitless\")\n", + "aviary_inputs.set_val(av.Mission.Design.THRUST_TAKEOFF_PER_ENG,\n", + " takeoff_thrust_per_eng, units='lbf')\n", "\n", "alt_airport = 0 # ft\n", - "cruise_mach = .785\n", "\n", "alt_i_climb = 0*_units.foot # m\n", "alt_f_climb = 35000.0*_units.foot # m\n", "mass_i_climb = 131000*_units.lb # kg\n", "mass_f_climb = 126000*_units.lb # kg\n", - "v_i_climb = 198.44*_units.knot # m/s\n", - "v_f_climb = 455.49*_units.knot # m/s\n", "# initial mach set to lower value so it can intersect with takeoff end mach\n", "# mach_i_climb = 0.3\n", "mach_i_climb = 0.2\n", - "mach_f_climb = cruise_mach\n", + "mach_f_climb = 0.79\n", "range_i_climb = 0*_units.nautical_mile # m\n", "range_f_climb = 160.3*_units.nautical_mile # m\n", "t_i_climb = 2 * _units.minute # sec\n", @@ -148,10 +495,7 @@ "alt_max_cruise = 35000*_units.foot # m\n", "mass_i_cruise = 126000*_units.lb # kg\n", "mass_f_cruise = 102000*_units.lb # kg\n", - "v_i_cruise = 455.49*_units.knot # m/s\n", - "v_f_cruise = 455.49*_units.knot # m/s\n", - "mach_min_cruise = cruise_mach\n", - "mach_max_cruise = cruise_mach\n", + "cruise_mach = 0.79\n", "range_i_cruise = 160.3*_units.nautical_mile # m\n", "range_f_cruise = 3243.9*_units.nautical_mile # m\n", "t_i_cruise = 26.20*_units.minute # sec\n", @@ -162,9 +506,7 @@ "# final altitude set to 35 to ensure landing is feasible point\n", "# alt_f_descent = 0*_units.foot\n", "alt_f_descent = 35*_units.foot\n", - "v_i_descent = 455.49*_units.knot\n", - "v_f_descent = 198.44*_units.knot\n", - "mach_i_descent = cruise_mach\n", + "mach_i_descent = 0.79\n", "mach_f_descent = 0.3\n", "mass_i_descent = 102000*_units.pound\n", "mass_f_descent = 101000*_units.pound\n", @@ -174,10 +516,25 @@ "t_f_descent = 461.62*_units.minute\n", "t_duration_descent = t_f_descent - t_i_descent\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", + "\n", + "prob.model.add_design_var(av.Mission.Design.GROSS_MASS, units='lbm',\n", + " lower=100000.0, upper=200000.0, ref=135000)\n", + "\n", + "takeoff_options = av.HeightEnergyTakeoffPhaseBuilder(\n", + " airport_altitude=alt_airport, # ft\n", + " # no units\n", + " num_engines=aviary_inputs.get_val(av.Aircraft.Engine.NUM_ENGINES)\n", + ")\n", + "\n", "##################\n", "# Define Phases #\n", "##################\n", - "\n", "num_segments_climb = 6\n", "num_segments_cruise = 1\n", "num_segments_descent = 5\n", @@ -194,12 +551,7 @@ " num_segments=num_segments_descent, order=3, compressed=True,\n", " segment_ends=descent_seg_ends)\n", "\n", - "takeoff_options = av.HeightEnergyTakeoffPhaseBuilder(\n", - " airport_altitude=alt_airport, # ft\n", - " num_engines=aviary_inputs.get_val(Aircraft.Engine.NUM_ENGINES)\n", - ")\n", - "\n", - "climb_options = av.HeightEnergyClimbPhaseBuilder(\n", + "climb_options = av.HeightEnergyPhaseBuilder(\n", " 'test_climb',\n", " user_options=av.AviaryValues({\n", " 'initial_altitude': (alt_i_climb, 'm'),\n", @@ -207,31 +559,30 @@ " 'initial_mach': (mach_i_climb, 'unitless'),\n", " 'final_mach': (mach_f_climb, 'unitless'),\n", " 'fix_initial': (False, 'unitless'),\n", - " 'fix_range': (False, 'unitless'),\n", " 'input_initial': (True, 'unitless'),\n", + " 'use_polynomial_control': (False, 'unitless'),\n", " }),\n", " core_subsystems=av.default_mission_subsystems,\n", " subsystem_options={'core_aerodynamics': {'method': 'computed'}},\n", " transcription=transcription_climb,\n", ")\n", "\n", - "cruise_options = av.HeightEnergyCruisePhaseBuilder(\n", + "cruise_options = av.HeightEnergyPhaseBuilder(\n", " 'test_cruise',\n", " user_options=av.AviaryValues({\n", - " 'min_altitude': (alt_min_cruise, 'm'),\n", - " 'max_altitude': (alt_max_cruise, 'm'),\n", - " 'min_mach': (mach_min_cruise, 'unitless'),\n", - " 'max_mach': (mach_max_cruise, 'unitless'),\n", + " 'initial_altitude': (alt_min_cruise, 'm'),\n", + " 'final_altitude': (alt_max_cruise, 'm'),\n", + " 'initial_mach': (cruise_mach, 'unitless'),\n", + " 'final_mach': (cruise_mach, 'unitless'),\n", " 'required_available_climb_rate': (300, 'ft/min'),\n", " 'fix_initial': (False, 'unitless'),\n", - " 'fix_final': (False, 'unitless'),\n", " }),\n", " core_subsystems=av.default_mission_subsystems,\n", " subsystem_options={'core_aerodynamics': {'method': 'computed'}},\n", " transcription=transcription_cruise,\n", ")\n", "\n", - "descent_options = av.HeightEnergyDescentPhaseBuilder(\n", + "descent_options = av.HeightEnergyPhaseBuilder(\n", " 'test_descent',\n", " user_options=av.AviaryValues({\n", " 'final_altitude': (alt_f_descent, 'm'),\n", @@ -239,7 +590,7 @@ " 'initial_mach': (mach_i_descent, 'unitless'),\n", " 'final_mach': (mach_f_descent, 'unitless'),\n", " 'fix_initial': (False, 'unitless'),\n", - " 'fix_range': (True, 'unitless'),\n", + " 'use_polynomial_control': (False, 'unitless'),\n", " }),\n", " core_subsystems=av.default_mission_subsystems,\n", " subsystem_options={'core_aerodynamics': {'method': 'computed'}},\n", @@ -247,16 +598,13 @@ ")\n", "\n", "landing_options = av.HeightEnergyLandingPhaseBuilder(\n", - " ref_wing_area=aviary_inputs.get_val(Aircraft.Wing.AREA, 'ft**2'),\n", - " Cl_max_ldg=aviary_inputs.get_val(Mission.Landing.LIFT_COEFFICIENT_MAX)\n", + " ref_wing_area=aviary_inputs.get_val(av.Aircraft.Wing.AREA, units='ft**2'),\n", + " Cl_max_ldg=aviary_inputs.get_val(\n", + " av.Mission.Landing.LIFT_COEFFICIENT_MAX) # no units\n", ")\n", "\n", "av.preprocess_crewpayload(aviary_inputs)\n", "\n", - "##########################################\n", - "# add pre mission systems #\n", - "##########################################\n", - "\n", "# Upstream static analysis for aero\n", "prob.model.add_subsystem(\n", " 'pre_mission',\n", @@ -265,10 +613,6 @@ " promotes_inputs=['aircraft:*', 'mission:*'],\n", " promotes_outputs=['aircraft:*', 'mission:*'])\n", "\n", - "##########################################\n", - "# add phases #\n", - "##########################################\n", - "\n", "# directly connect phases (strong_couple = True), or use linkage constraints (weak\n", "# coupling / strong_couple=False)\n", "strong_couple = False\n", @@ -291,15 +635,20 @@ "\n", "# if fix_initial is false, can we always set input_initial to be true for\n", "# necessary states, and then ignore if we use a linkage?\n", - "climb.set_time_options(\n", - " fix_initial=True, fix_duration=False, units='s',\n", - " duration_bounds=(1, t_duration_climb*2), duration_ref=t_duration_climb)\n", - "cruise.set_time_options(\n", - " fix_initial=False, fix_duration=False, units='s',\n", - " duration_bounds=(1, t_duration_cruise*2), duration_ref=t_duration_cruise)\n", + "climb.set_time_options(fix_initial=True, fix_duration=False, units='s',\n", + " duration_bounds=(t_duration_climb*0.5, t_duration_climb*2),\n", + " duration_ref=t_duration_climb)\n", + "cruise.set_time_options(fix_initial=False, fix_duration=False, units='s',\n", + " duration_bounds=(t_duration_cruise*0.5, t_duration_cruise*2),\n", + " duration_ref=t_duration_cruise,\n", + " initial_bounds=(t_duration_climb*0.5, t_duration_climb*2))\n", "descent.set_time_options(\n", " fix_initial=False, fix_duration=False, units='s',\n", - " duration_bounds=(1, t_duration_descent*2), duration_ref=t_duration_descent)\n", + " duration_bounds=(t_duration_descent*0.5, t_duration_descent*2),\n", + " duration_ref=t_duration_descent,\n", + " initial_bounds=(\n", + " (t_duration_cruise + t_duration_climb)*0.5,\n", + " (t_duration_cruise + t_duration_climb)*2))\n", "\n", "traj.add_phase('climb', climb)\n", "\n", @@ -307,108 +656,105 @@ "\n", "traj.add_phase('descent', descent)\n", "\n", - "if use_new_dymos_syntax:\n", - " climb.timeseries_options['use_prefix'] = True\n", - " cruise.timeseries_options['use_prefix'] = True\n", - " descent.timeseries_options['use_prefix'] = True\n", - "\n", - "##########################################\n", - "# add post mission system #\n", - "##########################################\n", - "\n", "prob.model.add_subsystem(\n", " 'landing', landing, promotes_inputs=['aircraft:*', 'mission:*'],\n", " promotes_outputs=['mission:*'])\n", "\n", - "##########################################\n", - "# link phases #\n", - "##########################################\n", - "\n", - "traj.link_phases([\"climb\", \"cruise\"], [\"time\", Dynamic.Mission.ALTITUDE,\n", - " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple)\n", - "traj.link_phases([\"cruise\", \"descent\"], [\"time\", Dynamic.Mission.ALTITUDE,\n", - " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple)\n", + "traj.link_phases([\"climb\", \"cruise\", \"descent\"], [\n", + " \"time\", \"mass\", \"range\"], connected=strong_couple)\n", "\n", "traj = av.setup_trajectory_params(prob.model, traj, aviary_inputs)\n", "\n", "##################################\n", "# Connect in Takeoff and Landing #\n", "##################################\n", - "\n", - "prob.model.add_subsystem(\n", - " \"takeoff_constraints\",\n", - " om.ExecComp(\n", - " [\n", - " \"takeoff_mass_con=takeoff_mass-climb_start_mass\",\n", - " \"takeoff_range_con=takeoff_range-climb_start_range\",\n", - " \"takeoff_vel_con=takeoff_vel-climb_start_vel\",\n", - " \"takeoff_alt_con=takeoff_alt-climb_start_alt\"\n", - " ],\n", - " takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'},\n", - " climb_start_mass={'units': 'lbm'},\n", - " takeoff_range_con={'units': 'ft'}, takeoff_range={'units': 'ft'},\n", - " climb_start_range={'units': 'ft'},\n", - " takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'},\n", - " climb_start_vel={'units': 'm/s'},\n", - " takeoff_alt_con={'units': 'ft'}, takeoff_alt={'units': 'ft'},\n", - " climb_start_alt={'units': 'ft'}\n", - " ),\n", - " promotes_inputs=[\n", - " (\"takeoff_mass\", Mission.Takeoff.FINAL_MASS),\n", - " (\"takeoff_range\", Mission.Takeoff.GROUND_DISTANCE),\n", - " (\"takeoff_vel\", Mission.Takeoff.FINAL_VELOCITY),\n", - " (\"takeoff_alt\", Mission.Takeoff.FINAL_ALTITUDE),\n", - " ],\n", - " promotes_outputs=[\"takeoff_mass_con\", \"takeoff_range_con\",\n", - " \"takeoff_vel_con\", \"takeoff_alt_con\"],\n", - ")\n", - "\n", - "prob.model.connect('traj.climb.states:mass',\n", - " 'takeoff_constraints.climb_start_mass', src_indices=[0])\n", - "prob.model.connect('traj.climb.states:range',\n", - " 'takeoff_constraints.climb_start_range', src_indices=[0])\n", - "prob.model.connect('traj.climb.states:velocity',\n", - " 'takeoff_constraints.climb_start_vel', src_indices=[0])\n", - "prob.model.connect('traj.climb.states:altitude',\n", - " 'takeoff_constraints.climb_start_alt', src_indices=[0])\n", - "\n", - "prob.model.connect(Mission.Takeoff.FINAL_MASS,\n", + "prob.model.connect(av.Mission.Takeoff.FINAL_MASS,\n", " 'traj.climb.initial_states:mass')\n", - "prob.model.connect(Mission.Takeoff.GROUND_DISTANCE,\n", + "prob.model.connect(av.Mission.Takeoff.GROUND_DISTANCE,\n", " 'traj.climb.initial_states:range')\n", - "prob.model.connect(Mission.Takeoff.FINAL_VELOCITY,\n", - " 'traj.climb.initial_states:velocity')\n", - "prob.model.connect(Mission.Takeoff.FINAL_ALTITUDE,\n", - " 'traj.climb.initial_states:altitude')\n", "\n", "prob.model.connect('traj.descent.states:mass',\n", - " Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1])\n", - "prob.model.connect('traj.descent.states:altitude', Mission.Landing.INITIAL_ALTITUDE,\n", + " av.Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1])\n", + "# TODO: approach velocity should likely be connected\n", + "prob.model.connect('traj.descent.control_values:altitude', av.Mission.Landing.INITIAL_ALTITUDE,\n", " src_indices=[-1])\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", + " descent_mass_final={'units': 'lbm', 'shape': 1},\n", + " fuel_burned={'units': 'lbm', 'shape': 1})\n", + "\n", + "prob.model.add_subsystem('fuel_burn', ecomp,\n", + " promotes_inputs=[\n", + " ('initial_mass', av.Mission.Design.GROSS_MASS)],\n", + " promotes_outputs=['fuel_burned'])\n", + "\n", + "prob.model.connect(\"traj.descent.states:mass\",\n", + " \"fuel_burn.descent_mass_final\", src_indices=[-1])\n", + "\n", + "# TODO: need to add some sort of check that this value is less than the fuel capacity\n", + "# TODO: need to update this with actual FLOPS value, this gives unrealistic\n", + "# appearance of accuracy\n", + "# TODO: the overall_fuel variable is the burned fuel plus the reserve, but should\n", + "# also include the unused fuel, and the hierarchy variable name should be more clear\n", + "ecomp = om.ExecComp('overall_fuel = fuel_burned + fuel_reserve',\n", + " fuel_burned={'units': 'lbm', 'shape': 1},\n", + " fuel_reserve={'units': 'lbm', 'val': 2173.},\n", + " overall_fuel={'units': 'lbm'})\n", + "prob.model.add_subsystem('fuel_calc', ecomp,\n", + " promotes_inputs=['fuel_burned'],\n", + " promotes_outputs=['overall_fuel'])\n", + "\n", + "ecomp = om.ExecComp(\n", + " 'mass_resid = operating_empty_mass + overall_fuel + payload_mass '\n", + " '- initial_mass',\n", + " operating_empty_mass={'units': 'lbm'},\n", + " overall_fuel={'units': 'lbm'},\n", + " payload_mass={'units': 'lbm'},\n", + " initial_mass={'units': 'lbm'},\n", + " mass_resid={'units': 'lbm'})\n", + "\n", + "prob.model.add_subsystem(\n", + " 'mass_constraint', ecomp,\n", + " promotes_inputs=[\n", + " ('operating_empty_mass', av.Aircraft.Design.OPERATING_MASS),\n", + " 'overall_fuel',\n", + " ('payload_mass', av.Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS),\n", + " ('initial_mass', av.Mission.Design.GROSS_MASS)],\n", + " promotes_outputs=['mass_resid'])\n", + "\n", + "prob.model.add_constraint('mass_resid', equals=0.0, ref=1.0)\n", + "\n", + "##########################\n", "# Add Objective Function #\n", "##########################\n", "\n", "# This is an example of a overall mission objective\n", "# create a compound objective that minimizes climb time and maximizes final mass\n", "# we are maxing final mass b/c we don't have an independent value for fuel_mass yet\n", - "# we are going to normalize these (makign each of the sub-objectives approx = 1 )\n", + "# we are going to normalize these (making each of the sub-objectives approx = 1 )\n", + "# TODO: change the scaling on climb_duration\n", "prob.model.add_subsystem(\n", " \"regularization\",\n", " om.ExecComp(\n", - " \"reg_objective = - descent_mass_final/60000\",\n", + " \"reg_objective = fuel_mass/1500\",\n", " reg_objective=0.0,\n", - " descent_mass_final={\"units\": \"kg\", \"shape\": 1},\n", + " fuel_mass={\"units\": \"lbm\", \"shape\": 1},\n", " ),\n", " promotes_outputs=['reg_objective']\n", ")\n", "# connect the final mass from cruise into the objective\n", - "prob.model.connect(\"traj.descent.states:mass\",\n", - " \"regularization.descent_mass_final\", src_indices=[-1])\n", + "prob.model.connect(av.Mission.Design.FUEL_MASS, \"regularization.fuel_mass\")\n", "\n", "prob.model.add_objective('reg_objective', ref=1)\n", "\n", + "# Set initial default values for all LEAPS aircraft variables.\n", + "av.set_aviary_initial_values(prob.model, aviary_inputs)\n", + "\n", "prob.model.add_subsystem(\n", " 'input_sink',\n", " av.VariablesIn(aviary_options=aviary_inputs),\n", @@ -416,16 +762,7 @@ " promotes_outputs=['*']\n", ")\n", "\n", - "# suppress warnings:\n", - "# \"input variable '...' promoted using '*' was already promoted using 'aircraft:*'\n", - "with warnings.catch_warnings():\n", - "\n", - " # Set initial default values for all LEAPS aircraft variables.\n", - " warnings.simplefilter(\"ignore\", om.PromotionWarning)\n", - " av.set_aviary_initial_values(prob.model, aviary_inputs)\n", - "\n", - " warnings.simplefilter(\"ignore\", om.PromotionWarning)\n", - " prob.setup()\n", + "prob.setup(force_alloc_complex=True)\n", "\n", "###########################################\n", "# Intial Settings for States and Controls #\n", @@ -434,97 +771,79 @@ "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", "\n", - "prob.set_val('traj.climb.states:altitude', climb.interp(\n", - " Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m')\n", - "# prob.set_val(\n", - "# 'traj.climb.states:velocity', climb.interp(Dynamic.Mission.VELOCITY, ys=[170, v_f_climb]),\n", - "# units='m/s')\n", - "prob.set_val('traj.climb.states:velocity', climb.interp(\n", - " Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s')\n", + "prob.set_val('traj.climb.controls:altitude', climb.interp(\n", + " av.Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m')\n", + "prob.set_val(\n", + " 'traj.climb.controls:mach', climb.interp(\n", + " av.Dynamic.Mission.MACH, ys=[mach_i_climb, mach_f_climb]), units='unitless')\n", "prob.set_val('traj.climb.states:mass', climb.interp(\n", - " Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", + " av.Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", "prob.set_val('traj.climb.states:range', climb.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') # nmi\n", - "\n", - "prob.set_val('traj.climb.controls:velocity_rate',\n", - " climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.0]),\n", - " units='m/s**2')\n", - "prob.set_val('traj.climb.controls:throttle',\n", - " climb.interp(Dynamic.Mission.THROTTLE, ys=[1.0, 1.0]),\n", - " units='unitless')\n", + " av.Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m')\n", "\n", "prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s')\n", "prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s')\n", "\n", - "prob.set_val('traj.cruise.states:altitude', cruise.interp(\n", - " Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m')\n", - "prob.set_val('traj.cruise.states:velocity', cruise.interp(\n", - " Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s')\n", + "prob.set_val('traj.cruise.polynomial_controls:altitude', cruise.interp(\n", + " av.Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m')\n", + "prob.set_val(\n", + " 'traj.cruise.polynomial_controls:mach', cruise.interp(\n", + " av.Dynamic.Mission.MACH, ys=[cruise_mach, cruise_mach]), units='unitless')\n", "prob.set_val('traj.cruise.states:mass', cruise.interp(\n", - " Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", + " av.Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", "prob.set_val('traj.cruise.states:range', cruise.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi\n", - "\n", - "prob.set_val('traj.cruise.controls:velocity_rate',\n", - " cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]),\n", - " units='m/s**2')\n", - "prob.set_val('traj.cruise.controls:throttle',\n", - " cruise.interp(Dynamic.Mission.THROTTLE, ys=[0.8, 0.75]),\n", - " units='unitless')\n", + " av.Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m')\n", "\n", "prob.set_val('traj.descent.t_initial', t_i_descent, units='s')\n", "prob.set_val('traj.descent.t_duration', t_duration_descent, units='s')\n", "\n", - "prob.set_val('traj.descent.states:altitude', descent.interp(\n", - " Dynamic.Mission.ALTITUDE, ys=[alt_i_descent, alt_f_descent]), units='m')\n", - "prob.set_val('traj.descent.states:velocity', descent.interp(\n", - " Dynamic.Mission.VELOCITY, ys=[v_i_descent, v_f_descent]), units='m/s')\n", + "prob.set_val('traj.descent.controls:altitude', descent.interp(\n", + " av.Dynamic.Mission.ALTITUDE, ys=[alt_i_descent, alt_f_descent]), units='m')\n", + "prob.set_val(\n", + " 'traj.descent.controls:mach', descent.interp(\n", + " av.Dynamic.Mission.MACH, ys=[mach_i_descent, mach_f_descent]), units='unitless')\n", "prob.set_val('traj.descent.states:mass', descent.interp(\n", - " Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", + " av.Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", "prob.set_val('traj.descent.states:range', descent.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m')\n", - "\n", - "prob.set_val('traj.descent.controls:velocity_rate',\n", - " descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.0]),\n", - " units='m/s**2')\n", - "prob.set_val('traj.descent.controls:throttle',\n", - " descent.interp(Dynamic.Mission.THROTTLE, ys=[0.0, 0.0]),\n", - " units='unitless')\n", + " av.Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m')\n", "\n", "# Turn off solver printing so that the SNOPT output is readable.\n", "prob.set_solver_print(level=0)\n", "\n", - "dm.run_problem(prob, make_plots=False, solution_record_file='N3CC_full_mission.db')\n", + "dm.run_problem(prob, simulate=False, make_plots=False, simulate_kwargs={\n", + " 'times_per_seg': 100, 'atol': 1e-9, 'rtol': 1e-9},\n", + " solution_record_file='N3CC_sizing.db')\n", "prob.record(\"final\")\n", "prob.cleanup()\n", "\n", "times_climb = prob.get_val('traj.climb.timeseries.time', units='s')\n", "altitudes_climb = prob.get_val(\n", - " 'traj.climb.timeseries.states:altitude', units='m')\n", - "masses_climb = prob.get_val('traj.climb.timeseries.states:mass', units='kg')\n", - "ranges_climb = prob.get_val('traj.climb.timeseries.states:range', units='m')\n", + " 'traj.climb.timeseries.altitude', units='m')\n", + "masses_climb = prob.get_val('traj.climb.timeseries.mass', units='kg')\n", + "ranges_climb = prob.get_val('traj.climb.timeseries.range', units='m')\n", "velocities_climb = prob.get_val(\n", - " 'traj.climb.timeseries.states:velocity', units='m/s')\n", + " 'traj.climb.timeseries.velocity', units='m/s')\n", "thrusts_climb = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N')\n", "times_cruise = prob.get_val('traj.cruise.timeseries.time', units='s')\n", "altitudes_cruise = prob.get_val(\n", - " 'traj.cruise.timeseries.states:altitude', units='m')\n", - "masses_cruise = prob.get_val('traj.cruise.timeseries.states:mass', units='kg')\n", - "ranges_cruise = prob.get_val('traj.cruise.timeseries.states:range', units='m')\n", + " 'traj.cruise.timeseries.altitude', units='m')\n", + "masses_cruise = prob.get_val('traj.cruise.timeseries.mass', units='kg')\n", + "ranges_cruise = prob.get_val('traj.cruise.timeseries.range', units='m')\n", "velocities_cruise = prob.get_val(\n", - " 'traj.cruise.timeseries.states:velocity', units='m/s')\n", + " 'traj.cruise.timeseries.velocity', units='m/s')\n", "thrusts_cruise = prob.get_val(\n", " 'traj.cruise.timeseries.thrust_net_total', units='N')\n", "times_descent = prob.get_val('traj.descent.timeseries.time', units='s')\n", "altitudes_descent = prob.get_val(\n", - " 'traj.descent.timeseries.states:altitude', units='m')\n", - "masses_descent = prob.get_val('traj.descent.timeseries.states:mass', units='kg')\n", - "ranges_descent = prob.get_val('traj.descent.timeseries.states:range', units='m')\n", + " 'traj.descent.timeseries.altitude', units='m')\n", + "masses_descent = prob.get_val('traj.descent.timeseries.mass', units='kg')\n", + "ranges_descent = prob.get_val('traj.descent.timeseries.range', units='m')\n", "velocities_descent = prob.get_val(\n", - " 'traj.descent.timeseries.states:velocity', units='m/s')\n", + " 'traj.descent.timeseries.velocity', units='m/s')\n", "thrusts_descent = prob.get_val(\n", " 'traj.descent.timeseries.thrust_net_total', units='N')\n", "\n", + "\n", "print(\"-------------------------------\")\n", "print(f\"times_climb: {times_climb[-1]} (s)\")\n", "print(f\"altitudes_climb: {altitudes_climb[-1]} (m)\")\n", @@ -547,597 +866,12 @@ "print(\"-------------------------------\")\n" ] }, - { - "cell_type": "markdown", - "id": "4c0f7de8", - "metadata": {}, - "source": [ - "### Move each code block to a function\n", - "\n", - "This code is quite verbose!\n", - "\n", - "To make it easier to follow the steps mentioned above, we split this script into several functions each representing a step at the beginning of this section (except `check_inputs()` and `add_design_variables()`).\n", - "These methods also closely mirror those from `aviary/interface/methods_for_level2.py`, so you can draw parallels between Level 2 and 3.\n", - "\n", - "Here's what the new run script looks like:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e1b0432f", - "metadata": {}, - "outputs": [], - "source": [ - "'''\n", - "NOTES:\n", - "Includes:\n", - "Takeoff, Climb, Cruise, Descent, Landing\n", - "Computed Aero\n", - "N3CC data\n", - "'''\n", - "import warnings\n", - "\n", - "import dymos as dm\n", - "import openmdao.api as om\n", - "import scipy.constants as _units\n", - "from packaging import version\n", - "\n", - "import aviary.api as av\n", - "\n", - "use_new_dymos_syntax = version.parse(dm.__version__) > version.parse(\"1.8.0\")\n", - "\n", - "\n", - "##########################################\n", - "# Phase Info\n", - "##########################################\n", - "\n", - "alt_airport = 0 # ft\n", - "cruise_mach = .785\n", - "\n", - "alt_i_climb = 0*_units.foot # m\n", - "alt_f_climb = 35000.0*_units.foot # m\n", - "mass_i_climb = 131000*_units.lb # kg\n", - "mass_f_climb = 126000*_units.lb # kg\n", - "v_i_climb = 198.44*_units.knot # m/s\n", - "v_f_climb = 455.49*_units.knot # m/s\n", - "# initial mach set to lower value so it can intersect with takeoff end mach\n", - "# mach_i_climb = 0.3\n", - "mach_i_climb = 0.2\n", - "mach_f_climb = cruise_mach\n", - "range_i_climb = 0*_units.nautical_mile # m\n", - "range_f_climb = 160.3*_units.nautical_mile # m\n", - "t_i_climb = 2 * _units.minute # sec\n", - "t_f_climb = 26.20*_units.minute # sec\n", - "t_duration_climb = t_f_climb - t_i_climb\n", - "\n", - "alt_i_cruise = 35000*_units.foot # m\n", - "alt_f_cruise = 35000*_units.foot # m\n", - "alt_min_cruise = 35000*_units.foot # m\n", - "alt_max_cruise = 35000*_units.foot # m\n", - "mass_i_cruise = 126000*_units.lb # kg\n", - "mass_f_cruise = 102000*_units.lb # kg\n", - "v_i_cruise = 455.49*_units.knot # m/s\n", - "v_f_cruise = 455.49*_units.knot # m/s\n", - "mach_min_cruise = cruise_mach\n", - "mach_max_cruise = cruise_mach\n", - "range_i_cruise = 160.3*_units.nautical_mile # m\n", - "range_f_cruise = 3243.9*_units.nautical_mile # m\n", - "t_i_cruise = 26.20*_units.minute # sec\n", - "t_f_cruise = 432.38*_units.minute # sec\n", - "t_duration_cruise = t_f_cruise - t_i_cruise\n", - "\n", - "alt_i_descent = 35000*_units.foot\n", - "# final altitude set to 35 to ensure landing is feasible point\n", - "# alt_f_descent = 0*_units.foot\n", - "alt_f_descent = 35*_units.foot\n", - "v_i_descent = 455.49*_units.knot\n", - "v_f_descent = 198.44*_units.knot\n", - "mach_i_descent = cruise_mach\n", - "mach_f_descent = 0.3\n", - "mass_i_descent = 102000*_units.pound\n", - "mass_f_descent = 101000*_units.pound\n", - "range_i_descent = 3243.9*_units.nautical_mile\n", - "range_f_descent = 3378.7*_units.nautical_mile\n", - "t_i_descent = 432.38*_units.minute\n", - "t_f_descent = 461.62*_units.minute\n", - "t_duration_descent = t_f_descent - t_i_descent\n", - "\n", - "def load_inputs():\n", - " aviary_inputs = av.get_flops_inputs('N3CC')\n", - "\n", - " aviary_inputs.set_val(\n", - " Mission.Landing.LIFT_COEFFICIENT_MAX, 2.4, units='unitless')\n", - " aviary_inputs.set_val(\n", - " Mission.Takeoff.LIFT_COEFFICIENT_MAX, 2.0, units='unitless')\n", - " aviary_inputs.set_val(\n", - " Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT, val=.0175,\n", - " units='unitless')\n", - "\n", - " takeoff_fuel_burned = 577 # lbm\n", - " takeoff_thrust_per_eng = 24555.5 # lbf\n", - " takeoff_L_over_D = 17.35\n", - "\n", - " aviary_inputs.set_val(\n", - " Mission.Takeoff.FUEL_SIMPLE, takeoff_fuel_burned, units='lbm')\n", - " aviary_inputs.set_val(\n", - " Mission.Takeoff.LIFT_OVER_DRAG, takeoff_L_over_D, units='unitless')\n", - " aviary_inputs.set_val(\n", - " Mission.Design.THRUST_TAKEOFF_PER_ENG, takeoff_thrust_per_eng, units='lbf')\n", - "\n", - " return aviary_inputs\n", - "\n", - "\n", - "def add_pre_mission_system(aviary_inputs, prob):\n", - " takeoff_options = av.HeightEnergyTakeoffPhaseBuilder(\n", - " airport_altitude=alt_airport, # ft\n", - " num_engines=aviary_inputs.get_val(Aircraft.Engine.NUM_ENGINES)\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", - " promotes_inputs=['aircraft:*', 'mission:*'],\n", - " promotes_outputs=['aircraft:*', 'mission:*'])\n", - "\n", - " takeoff = takeoff_options.build_phase(False)\n", - "\n", - " prob.model.add_subsystem(\n", - " 'takeoff', takeoff, promotes_inputs=['aircraft:*', 'mission:*'],\n", - " promotes_outputs=['mission:*'])\n", - "\n", - " prob.model.add_subsystem(\n", - " \"takeoff_constraints\",\n", - " om.ExecComp(\n", - " [\n", - " \"takeoff_mass_con=takeoff_mass-climb_start_mass\",\n", - " \"takeoff_range_con=takeoff_range-climb_start_range\",\n", - " \"takeoff_vel_con=takeoff_vel-climb_start_vel\",\n", - " \"takeoff_alt_con=takeoff_alt-climb_start_alt\"\n", - " ],\n", - " takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'},\n", - " climb_start_mass={'units': 'lbm'},\n", - " takeoff_range_con={'units': 'ft'}, takeoff_range={'units': 'ft'},\n", - " climb_start_range={'units': 'ft'},\n", - " takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'},\n", - " climb_start_vel={'units': 'm/s'},\n", - " takeoff_alt_con={'units': 'ft'}, takeoff_alt={'units': 'ft'},\n", - " climb_start_alt={'units': 'ft'}\n", - " ),\n", - " promotes_inputs=[\n", - " (\"takeoff_mass\", Mission.Takeoff.FINAL_MASS),\n", - " (\"takeoff_range\", Mission.Takeoff.GROUND_DISTANCE),\n", - " (\"takeoff_vel\", Mission.Takeoff.FINAL_VELOCITY),\n", - " (\"takeoff_alt\", Mission.Takeoff.FINAL_ALTITUDE),\n", - " ],\n", - " promotes_outputs=[\"takeoff_mass_con\", \"takeoff_range_con\",\n", - " \"takeoff_vel_con\", \"takeoff_alt_con\"],\n", - " )\n", - "\n", - " prob.model.connect(Mission.Takeoff.FINAL_MASS,\n", - " 'traj.climb.initial_states:mass')\n", - " prob.model.connect(Mission.Takeoff.GROUND_DISTANCE,\n", - " 'traj.climb.initial_states:range')\n", - " prob.model.connect(Mission.Takeoff.FINAL_VELOCITY,\n", - " 'traj.climb.initial_states:velocity')\n", - " prob.model.connect(Mission.Takeoff.FINAL_ALTITUDE,\n", - " 'traj.climb.initial_states:altitude')\n", - "\n", - "\n", - "def add_post_mission_systems(aviary_inputs, prob):\n", - " landing_options = av.HeightEnergyLandingPhaseBuilder(\n", - " ref_wing_area=aviary_inputs.get_val(Aircraft.Wing.AREA, 'ft**2'),\n", - " Cl_max_ldg=aviary_inputs.get_val(Mission.Landing.LIFT_COEFFICIENT_MAX)\n", - " )\n", - "\n", - " landing = landing_options.build_phase(\n", - " False,\n", - " )\n", - "\n", - " prob.model.add_subsystem(\n", - " 'landing', landing, promotes_inputs=['aircraft:*', 'mission:*'],\n", - " promotes_outputs=['mission:*'])\n", - "\n", - " prob.model.connect('traj.descent.states:mass',\n", - " Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1])\n", - " prob.model.connect('traj.descent.states:altitude', Mission.Landing.INITIAL_ALTITUDE,\n", - " src_indices=[-1])\n", - "\n", - "\n", - "def set_initial_guesses(prob, traj):\n", - " # have to add this block to recover climb, cruise, and descent phases first\n", - " phase_items = traj._phases.items()\n", - " for idx, (_, phase) in enumerate(phase_items):\n", - " if idx == 0: climb = phase\n", - " elif idx == 1: cruise = phase\n", - " else: descent = phase\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", - "\n", - " prob.set_val('traj.climb.states:altitude', climb.interp(\n", - " Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m')\n", - " # prob.set_val(\n", - " # 'traj.climb.states:velocity', climb.interp(Dynamic.Mission.VELOCITY, ys=[170, v_f_climb]),\n", - " # units='m/s')\n", - " prob.set_val('traj.climb.states:velocity', climb.interp(\n", - " Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s')\n", - " prob.set_val('traj.climb.states:mass', climb.interp(\n", - " Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", - " prob.set_val('traj.climb.states:range', climb.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') # nmi\n", - "\n", - " prob.set_val('traj.climb.controls:velocity_rate',\n", - " climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.0]),\n", - " units='m/s**2')\n", - " prob.set_val('traj.climb.controls:throttle',\n", - " climb.interp(Dynamic.Mission.THROTTLE, ys=[1.0, 1.0]),\n", - " units='unitless')\n", - "\n", - " prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s')\n", - " prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s')\n", - "\n", - " prob.set_val('traj.cruise.states:altitude', cruise.interp(\n", - " Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m')\n", - " prob.set_val('traj.cruise.states:velocity', cruise.interp(\n", - " Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s')\n", - " prob.set_val('traj.cruise.states:mass', cruise.interp(\n", - " Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", - " prob.set_val('traj.cruise.states:range', cruise.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi\n", - "\n", - " prob.set_val('traj.cruise.controls:velocity_rate',\n", - " cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]),\n", - " units='m/s**2')\n", - " prob.set_val('traj.cruise.controls:throttle',\n", - " cruise.interp(Dynamic.Mission.THROTTLE, ys=[0.8, 0.75]),\n", - " units='unitless')\n", - "\n", - " prob.set_val('traj.descent.t_initial', t_i_descent, units='s')\n", - " prob.set_val('traj.descent.t_duration', t_duration_descent, units='s')\n", - "\n", - " prob.set_val('traj.descent.states:altitude', descent.interp(\n", - " Dynamic.Mission.ALTITUDE, ys=[alt_i_descent, alt_f_descent]), units='m')\n", - " prob.set_val('traj.descent.states:velocity', descent.interp(\n", - " Dynamic.Mission.VELOCITY, ys=[v_i_descent, v_f_descent]), units='m/s')\n", - " prob.set_val('traj.descent.states:mass', descent.interp(\n", - " Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", - " prob.set_val('traj.descent.states:range', descent.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m')\n", - "\n", - " prob.set_val('traj.descent.controls:velocity_rate',\n", - " descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.0]),\n", - " units='m/s**2')\n", - " prob.set_val('traj.descent.controls:throttle',\n", - " descent.interp(Dynamic.Mission.THROTTLE, ys=[0.0, 0.0]),\n", - " units='unitless')\n", - "\n", - "\n", - "def setup(aviary_inputs, prob):\n", - " prob.model.add_subsystem(\n", - " 'input_sink',\n", - " av.VariablesIn(aviary_options=aviary_inputs),\n", - " promotes_inputs=['*'],\n", - " promotes_outputs=['*']\n", - " )\n", - "\n", - " # suppress warnings:\n", - " # \"input variable '...' promoted using '*' was already promoted using 'aircraft:*'\n", - " with warnings.catch_warnings():\n", - "\n", - " # Set initial default values for all LEAPS aircraft variables.\n", - " warnings.simplefilter(\"ignore\", om.PromotionWarning)\n", - " av.set_aviary_initial_values(prob.model, aviary_inputs)\n", - "\n", - " warnings.simplefilter(\"ignore\", om.PromotionWarning)\n", - " prob.setup()\n", - "\n", - "\n", - "def add_objective(prob):\n", - " # This is an example of a overall mission objective\n", - " # create a compound objective that minimizes climb time and maximizes final mass\n", - " # we are maxing final mass b/c we don't have an independent value for fuel_mass yet\n", - " # we are going to normalize these (makign each of the sub-objectives approx = 1 )\n", - " prob.model.add_subsystem(\n", - " \"regularization\",\n", - " om.ExecComp(\n", - " \"reg_objective = - descent_mass_final/60000\",\n", - " reg_objective=0.0,\n", - " descent_mass_final={\"units\": \"kg\", \"shape\": 1},\n", - " ),\n", - " promotes_outputs=['reg_objective']\n", - " )\n", - " # connect the final mass from descent into the objective\n", - " prob.model.connect(\"traj.descent.states:mass\",\n", - " \"regularization.descent_mass_final\", src_indices=[-1])\n", - "\n", - " prob.model.add_objective('reg_objective', ref=1)\n", - "\n", - "\n", - "def add_phases(aviary_inputs, prob):\n", - " ##################\n", - " # Define Phases #\n", - " ##################\n", - "\n", - " num_segments_climb = 6\n", - " num_segments_cruise = 1\n", - " num_segments_descent = 5\n", - "\n", - " climb_seg_ends, _ = dm.utils.lgl.lgl(num_segments_climb + 1)\n", - " descent_seg_ends, _ = dm.utils.lgl.lgl(num_segments_descent + 1)\n", - "\n", - " transcription_climb = dm.Radau(\n", - " num_segments=num_segments_climb, order=3, compressed=True,\n", - " segment_ends=climb_seg_ends)\n", - " transcription_cruise = dm.Radau(\n", - " num_segments=num_segments_cruise, order=3, compressed=True)\n", - " transcription_descent = dm.Radau(\n", - " num_segments=num_segments_descent, order=3, compressed=True,\n", - " segment_ends=descent_seg_ends)\n", - "\n", - " climb_options = av.HeightEnergyClimbPhaseBuilder(\n", - " 'test_climb',\n", - " user_options=av.AviaryValues({\n", - " 'initial_altitude': (alt_i_climb, 'm'),\n", - " 'final_altitude': (alt_f_climb, 'm'),\n", - " 'initial_mach': (mach_i_climb, 'unitless'),\n", - " 'final_mach': (mach_f_climb, 'unitless'),\n", - " 'fix_initial': (False, 'unitless'),\n", - " 'fix_range': (False, 'unitless'),\n", - " 'input_initial': (True, 'unitless'),\n", - " }),\n", - " core_subsystems=av.default_mission_subsystems,\n", - " subsystem_options={'core_aerodynamics': {'method': 'computed'}},\n", - " transcription=transcription_climb,\n", - " )\n", - "\n", - " cruise_options = av.HeightEnergyCruisePhaseBuilder(\n", - " 'test_cruise',\n", - " user_options=av.AviaryValues({\n", - " 'min_altitude': (alt_min_cruise, 'm'),\n", - " 'max_altitude': (alt_max_cruise, 'm'),\n", - " 'min_mach': (mach_min_cruise, 'unitless'),\n", - " 'max_mach': (mach_max_cruise, 'unitless'),\n", - " 'required_available_climb_rate': (300, 'ft/min'),\n", - " 'fix_initial': (False, 'unitless'),\n", - " 'fix_final': (False, 'unitless'),\n", - " }),\n", - " core_subsystems=av.default_mission_subsystems,\n", - " subsystem_options={'core_aerodynamics': {'method': 'computed'}},\n", - " transcription=transcription_cruise,\n", - " )\n", - "\n", - " descent_options = av.HeightEnergyDescentPhaseBuilder(\n", - " 'test_descent',\n", - " user_options=av.AviaryValues({\n", - " 'final_altitude': (alt_f_descent, 'm'),\n", - " 'initial_altitude': (alt_i_descent, 'm'),\n", - " 'initial_mach': (mach_i_descent, 'unitless'),\n", - " 'final_mach': (mach_f_descent, 'unitless'),\n", - " 'fix_initial': (False, 'unitless'),\n", - " 'fix_range': (True, 'unitless'),\n", - " }),\n", - " core_subsystems=av.default_mission_subsystems,\n", - " subsystem_options={'core_aerodynamics': {'method': 'computed'}},\n", - " transcription=transcription_descent,\n", - " )\n", - "\n", - " climb = climb_options.build_phase(aviary_options=aviary_inputs)\n", - "\n", - " cruise = cruise_options.build_phase(aviary_options=aviary_inputs)\n", - "\n", - " descent = descent_options.build_phase(aviary_options=aviary_inputs)\n", - "\n", - " traj = prob.model.add_subsystem('traj', dm.Trajectory())\n", - "\n", - " climb.set_time_options(\n", - " fix_initial=True, fix_duration=False, units='s',\n", - " duration_bounds=(1, t_duration_climb*2), duration_ref=t_duration_climb)\n", - " cruise.set_time_options(\n", - " fix_initial=False, fix_duration=False, units='s',\n", - " duration_bounds=(1, t_duration_cruise*2), duration_ref=t_duration_cruise)\n", - " descent.set_time_options(\n", - " fix_initial=False, fix_duration=False, units='s',\n", - " duration_bounds=(1, t_duration_descent*2), duration_ref=t_duration_descent)\n", - "\n", - " traj.add_phase('climb', climb)\n", - "\n", - " traj.add_phase('cruise', cruise)\n", - "\n", - " traj.add_phase('descent', descent)\n", - "\n", - " if use_new_dymos_syntax: # needed for print_outputs()\n", - " climb.timeseries_options['use_prefix'] = True\n", - " cruise.timeseries_options['use_prefix'] = True\n", - " descent.timeseries_options['use_prefix'] = True\n", - "\n", - " return traj\n", - "\n", - "\n", - "def link_phases(aviary_inputs, prob, traj):\n", - " # directly connect phases (strong_couple = True), or use linkage constraints (weak\n", - " # coupling / strong_couple=False)\n", - " strong_couple = False\n", - "\n", - " traj.link_phases([\"climb\", \"cruise\"], [\"time\", Dynamic.Mission.ALTITUDE,\n", - " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple)\n", - " traj.link_phases([\"cruise\", \"descent\"], [\"time\", Dynamic.Mission.ALTITUDE,\n", - " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple)\n", - "\n", - " traj = av.setup_trajectory_params(prob.model, traj, aviary_inputs)\n", - "\n", - " ##################################\n", - " # Connect in Takeoff #\n", - " ##################################\n", - "\n", - " prob.model.connect('traj.climb.states:mass',\n", - " 'takeoff_constraints.climb_start_mass', src_indices=[0])\n", - " prob.model.connect('traj.climb.states:range',\n", - " 'takeoff_constraints.climb_start_range', src_indices=[0])\n", - " prob.model.connect('traj.climb.states:velocity',\n", - " 'takeoff_constraints.climb_start_vel', src_indices=[0])\n", - " prob.model.connect('traj.climb.states:altitude',\n", - " 'takeoff_constraints.climb_start_alt', src_indices=[0])\n", - "\n", - "\n", - "def run_aviary_problem(prob, sim):\n", - " # Turn off solver printing so that the SNOPT output is readable.\n", - " prob.set_solver_print(level=0)\n", - "\n", - " dm.run_problem(prob, simulate=sim, make_plots=True, simulate_kwargs={\n", - " 'times_per_seg': 100, 'atol': 1e-9, 'rtol': 1e-9}, \n", - " solution_record_file='N3CC_full_mission.db')\n", - " prob.record(\"final\")\n", - " prob.cleanup()\n", - "\n", - "\n", - "def run_N3CC_full_mission(sim=True):\n", - " ##########################################\n", - " # Build problem #\n", - " ##########################################\n", - " prob = om.Problem(model=om.Group())\n", - " #prob.driver = driver\n", - "\n", - " traj = None\n", - "\n", - " ##########################################\n", - " # Aircraft Input Variables and Options #\n", - " ##########################################\n", - "\n", - " aviary_inputs = load_inputs()\n", - "\n", - " ##########################################\n", - " # add pre-mission systems #\n", - " ##########################################\n", - "\n", - " add_pre_mission_system(aviary_inputs, prob)\n", - "\n", - " ##########################################\n", - " # add phases #\n", - " ##########################################\n", - "\n", - " traj = add_phases(aviary_inputs, prob)\n", - "\n", - " ##########################################\n", - " # add post mission system #\n", - " ##########################################\n", - "\n", - " add_post_mission_systems(aviary_inputs, prob)\n", - "\n", - " ##########################################\n", - " # add driver #\n", - " ##########################################\n", - "\n", - " prob.driver = add_driver()\n", - "\n", - " ##########################################\n", - " # link phases #\n", - " ##########################################\n", - "\n", - " link_phases(aviary_inputs, prob, traj)\n", - "\n", - " ##########################\n", - " # Add Objective Function #\n", - " ##########################\n", - "\n", - " add_objective(prob)\n", - "\n", - " #######\n", - " # setup\n", - " #######\n", - "\n", - " setup(aviary_inputs, prob)\n", - "\n", - " ###########################################\n", - " # Intial Settings for States and Controls #\n", - " ###########################################\n", - "\n", - " set_initial_guesses(prob, traj)\n", - "\n", - " #####################\n", - " # run aviary problem\n", - " #####################\n", - "\n", - " run_aviary_problem(prob, sim)\n", - "\n", - " print_outputs(prob)\n", - "\n", - "\n", - "def add_driver():\n", - " driver = om.ScipyOptimizeDriver()\n", - " driver.options['optimizer'] = 'SLSQP'\n", - " driver.opt_settings['maxiter'] = 0\n", - " driver.opt_settings['ftol'] = 5.0e-3\n", - " driver.opt_settings['eps'] = 1e-2\n", - "\n", - " return driver\n", - "\n", - "\n", - "def print_outputs(prob):\n", - " times_climb = prob.get_val('traj.climb.timeseries.time', units='s')\n", - " altitudes_climb = prob.get_val(\n", - " 'traj.climb.timeseries.states:altitude', units='m')\n", - " masses_climb = prob.get_val('traj.climb.timeseries.states:mass', units='kg')\n", - " ranges_climb = prob.get_val('traj.climb.timeseries.states:range', units='m')\n", - " velocities_climb = prob.get_val(\n", - " 'traj.climb.timeseries.states:velocity', units='m/s')\n", - " thrusts_climb = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N')\n", - " times_cruise = prob.get_val('traj.cruise.timeseries.time', units='s')\n", - " altitudes_cruise = prob.get_val(\n", - " 'traj.cruise.timeseries.states:altitude', units='m')\n", - " masses_cruise = prob.get_val('traj.cruise.timeseries.states:mass', units='kg')\n", - " ranges_cruise = prob.get_val('traj.cruise.timeseries.states:range', units='m')\n", - " velocities_cruise = prob.get_val(\n", - " 'traj.cruise.timeseries.states:velocity', units='m/s')\n", - " thrusts_cruise = prob.get_val(\n", - " 'traj.cruise.timeseries.thrust_net_total', units='N')\n", - " times_descent = prob.get_val('traj.descent.timeseries.time', units='s')\n", - " altitudes_descent = prob.get_val(\n", - " 'traj.descent.timeseries.states:altitude', units='m')\n", - " masses_descent = prob.get_val('traj.descent.timeseries.states:mass', units='kg')\n", - " ranges_descent = prob.get_val('traj.descent.timeseries.states:range', units='m')\n", - " velocities_descent = prob.get_val(\n", - " 'traj.descent.timeseries.states:velocity', units='m/s')\n", - " thrusts_descent = prob.get_val(\n", - " 'traj.descent.timeseries.thrust_net_total', units='N')\n", - "\n", - " print(\"-------------------------------\")\n", - " print(f\"times_climb: {times_climb[-1]} (s)\")\n", - " print(f\"altitudes_climb: {altitudes_climb[-1]} (m)\")\n", - " print(f\"masses_climb: {masses_climb[-1]} (kg)\")\n", - " print(f\"ranges_climb: {ranges_climb[-1]} (m)\")\n", - " print(f\"velocities_climb: {velocities_climb[-1]} (m/s)\")\n", - " print(f\"thrusts_climb: {thrusts_climb[-1]} (N)\")\n", - " print(f\"times_cruise: {times_cruise[-1]} (s)\")\n", - " print(f\"altitudes_cruise: {altitudes_cruise[-1]} (m)\")\n", - " print(f\"masses_cruise: {masses_cruise[-1]} (kg)\")\n", - " print(f\"ranges_cruise: {ranges_cruise[-1]} (m)\")\n", - " print(f\"velocities_cruise: {velocities_cruise[-1]} (m/s)\")\n", - " print(f\"thrusts_cruise: {thrusts_cruise[-1]} (N)\")\n", - " print(f\"times_descent: {times_descent[-1]} (s)\")\n", - " print(f\"altitudes_descent: {altitudes_descent[-1]} (m)\")\n", - " print(f\"masses_descent: {masses_descent[-1]} (kg)\")\n", - " print(f\"ranges_descent: {ranges_descent[-1]} (m)\")\n", - " print(f\"velocities_descent: {velocities_descent[-1]} (m/s)\")\n", - " print(f\"thrusts_descent: {thrusts_descent[-1]} (N)\")\n", - " print(\"-------------------------------\")\n", - "\n", - "\n", - "run_N3CC_full_mission(sim=False)" - ] - }, { "cell_type": "markdown", "id": "2b43d293", "metadata": {}, "source": [ - "You see the same outputs.\n", - "\n", - "This model demonstrates the flexibility of level 3. For example, the `load_inputs` function does not load the aircraft model from a `.csv` file but from a Python file using the `get_flops_inputs()` method.\n", + "This model demonstrates the flexibility of level 3. For example, we do not load the aircraft model from a `.csv` file but from a Python file using the `get_flops_inputs()` method.\n", "\n", "This function not only reads Aviary and mission variables but also builds the engine. More information can be found in `aviary/models/N3CC/N3CC_data.py`.\n", "\n", From feebdeac7ec66e48b087ba49e70a96137cd6b559 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Tue, 9 Jan 2024 12:52:55 -0500 Subject: [PATCH 022/188] write description of initial guess of reserves in input_csv_phase_info.md --- aviary/docs/getting_started/input_csv_phase_info.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aviary/docs/getting_started/input_csv_phase_info.md b/aviary/docs/getting_started/input_csv_phase_info.md index 6f3781fd3..01f0a59db 100644 --- a/aviary/docs/getting_started/input_csv_phase_info.md +++ b/aviary/docs/getting_started/input_csv_phase_info.md @@ -18,13 +18,13 @@ This section is under development. - climb_range: 0, - reserves: 0 -The initial guess of `reserves` is used to define the reserve fuel. Initially, its value can be anything larger than or equal to 0. There are two variables to control the reserve fuel in the model file (`.csv`): +The initial guess of `reserves` is used to define the reserve fuel. Initially, its value can be anything larger than or equal to 0. There are two Aviary variables to control the reserve fuel in the model file (`.csv`): - `Aircraft.Design.FIXED_RESERVES_FUEL`: the required fuel reserves: directly in lbm, -- `Aircraft.Design.RESERVES_FRACTION`: the required fuel reserves: given as a proportion of mission fuel, +- `Aircraft.Design.RESERVES_FRACTION`: the required fuel reserves: given as a proportion of mission fuel. -If the value of initial guess of `reserves` is not 0 and is within the allowed range, the initial guess of reserve fuel is determined by the parameter `reserves`: -- if `reserves > 1.0`, we set `Aircraft.Design.FIXED_RESERVES_FUEL = reserves`, -- if `0.0 <= reserves <= 1.0`, we set `Aircraft.Design.RESERVES_FRACTION = reserves`. +Users should set one of them to zero. If the value of initial guess of `reserves` (also in the model file if any) is 0, the initial guess of reserve fuel comes from the above two Aviary variables. Otherwise, it is determined by the parameter `reserves`: +- if `reserves > 10`, we assume it is the actual fuel reserves. +- if `0.0 <= reserves <= 10`, we assume it is the fraction of the mission fuel. The case when `reserves` is between 1 and 10 is non-sensical but technically valid. The initial guess of `reserves` is always converted to the actual design reserves (instead of reserve factor) and is used to update the initial guesses of `fuel_burn_per_passenger_mile` and `cruise_mass_final`. From eb1944121406c0019b51286c71879d52569d77de Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Tue, 9 Jan 2024 12:54:46 -0500 Subject: [PATCH 023/188] allow reserves fraction to be greater than 1 in methods_for_level2.py --- aviary/interface/methods_for_level2.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 3667ae4e9..57680022d 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -2438,7 +2438,7 @@ def _add_gasp_landing_systems(self): def _add_fuel_reserve_component(self, reserves_name=Mission.Design.RESERVE_FUEL): reserves_val = self.aviary_inputs.get_val( Aircraft.Design.FIXED_RESERVES_FUEL, units='lbm') - reserves_fac = self.aviary_inputs.get_val( + reserves_frac = self.aviary_inputs.get_val( Aircraft.Design.RESERVES_FRACTION, units='unitless') if reserves_val > 0.0: self.model.add_subsystem( @@ -2449,11 +2449,11 @@ def _add_fuel_reserve_component(self, reserves_name=Mission.Design.RESERVE_FUEL) ), promotes_outputs=[("reserve_fuel", reserves_name)], ) - elif reserves_fac >= 0 and reserves_fac <= 1: + elif reserves_frac >= 0: self.model.add_subsystem( "reserves_calc", om.ExecComp( - f"reserve_fuel = {reserves_fac}*(takeoff_mass - final_mass)", + f"reserve_fuel = {reserves_frac}*(takeoff_mass - final_mass)", takeoff_mass={"units": "lbm"}, final_mass={"units": "lbm"}, reserve_fuel={"units": "lbm"} From 4867a4386e78cc8e7096e3d9acdb0d758b5c3af5 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Tue, 9 Jan 2024 12:56:20 -0500 Subject: [PATCH 024/188] describe RESERVES_FRACTION in more detail. --- aviary/variable_info/variable_meta_data.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index 0c949e1c2..966c4aa18 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -1206,7 +1206,10 @@ }, option=True, units="unitless", - desc='required fuel reserves: given as a proportion of mission fuel', + desc='required fuel reserves: given as a proportion of mission fuel. This value must be nonnegative.\ + If it is 0.5, the reserve fuel is half of the mission fuel (one third of the total fuel). Note\ + it can be greater than 1. If it is 2, there would be twice as much reserve fuel as mission fuel\ + (the total fuel carried would be 1/3 for the mission and 2/3 for the reserve)', default_value=0, ) From 88f37979220986a4dae9cb19177fc90544bc96d7 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Tue, 9 Jan 2024 12:58:18 -0500 Subject: [PATCH 025/188] allow initial guess of reserves fuel in model file to have a fraction greater than 1. --- aviary/utils/process_input_decks.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/aviary/utils/process_input_decks.py b/aviary/utils/process_input_decks.py index 7f2698895..924d79214 100644 --- a/aviary/utils/process_input_decks.py +++ b/aviary/utils/process_input_decks.py @@ -168,29 +168,25 @@ def initial_guessing(aircraft_values: AviaryValues()): if initial_guesses['reserves'] == 0: reserves = aircraft_values.get_val( Aircraft.Design.FIXED_RESERVES_FUEL, units='lbm') + reserves_option = "direct_val" if reserves == 0: reserves = aircraft_values.get_val( Aircraft.Design.RESERVES_FRACTION, units='unitless') + reserves_option = "fraction_val" else: reserves = initial_guesses['reserves'] if reserves < 0.0: raise ValueError('initial_guesses["reserves"] must be greater than 0.') - elif reserves <= 1.0: - aircraft_values.set_val( - Aircraft.Design.FIXED_RESERVES_FUEL, 0.0, units='lbm') - aircraft_values.set_val( - Aircraft.Design.RESERVES_FRACTION, reserves, units='unitless') + elif reserves > 10: + reserves_option = "direct_val" else: - aircraft_values.set_val( - Aircraft.Design.FIXED_RESERVES_FUEL, reserves, units='lbm') - aircraft_values.set_val( - Aircraft.Design.RESERVES_FRACTION, 0.0, units='unitless') + reserves_option = "fraction_val" num_pax = aircraft_values.get_val(Aircraft.CrewPayload.NUM_PASSENGERS) - if reserves <= 0: - reserves *= -(num_pax * initial_guesses['fuel_burn_per_passenger_mile'] * - aircraft_values.get_val(Mission.Design.RANGE, units='NM')) + if reserves_option == "fraction_val": + reserves *= (num_pax * initial_guesses['fuel_burn_per_passenger_mile'] * + aircraft_values.get_val(Mission.Design.RANGE, units='NM')) initial_guesses['reserves'] = reserves if Mission.Summary.GROSS_MASS in aircraft_values: From 821d047c3a2a86b4f2a7116e72b8630d97a6810d Mon Sep 17 00:00:00 2001 From: "Kenneth T. Moore" Date: Tue, 9 Jan 2024 13:36:32 -0500 Subject: [PATCH 026/188] Restore support for structured abscissa for aero tables. --- .../test/test_solved_aero_group.py | 74 +++++++++++++++++++ .../aerodynamics/gasp_based/table_based.py | 11 +-- 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py index 59c5dc0b7..d70bb9418 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py @@ -115,6 +115,80 @@ def test_solved_aero_pass_polar(self): assert_near_equal(CL_pass, CL_base, 1e-6) assert_near_equal(CD_pass, CD_base, 1e-6) + def test_solved_aero_pass_polar_unique_abscissa(self): + # Solved Aero with shortened lists of table abscissa. + prob = AviaryProblem( + phase_info, mission_method="FLOPS", mass_method="FLOPS") + + csv_path = pkg_resources.resource_filename( + "aviary", "subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv") + + prob.load_inputs(csv_path) + prob.add_pre_mission_systems() + prob.add_phases() + prob.add_post_mission_systems() + + prob.link_phases() + + prob.setup() + + prob.set_initial_guesses() + + prob.run_model() + + CL_base = prob.get_val("traj.cruise.rhs_all.core_aerodynamics.tabular_aero.CL") + CD_base = prob.get_val("traj.cruise.rhs_all.core_aerodynamics.tabular_aero.CD") + + # Lift and Drag polars passed from external component in static. + + ph_in = deepcopy(phase_info) + + alt = np.array([0., 3000., 6000., 9000., 12000., 15000., 18000., 21000., + 24000., 27000., 30000., 33000., 36000., 38000., 42000.]) + mach = np.array([0. , 0.2 , 0.4 , 0.5 , 0.6 , 0.7 , 0.75, 0.8 , 0.85, 0.9 ]) + alpha = np.array([-2., 0., 2., 4., 6., 8., 10.]) + + polar_builder = FakeDragPolarBuilder(name="aero", altitude=alt, mach=mach, + alpha=alpha) + aero_data = NamedValues() + aero_data.set_val('altitude', alt, 'ft') + aero_data.set_val('mach', mach, 'unitless') + aero_data.set_val('angle_of_attack', alpha, 'deg') + + subsystem_options = {'method': 'solved_alpha', + 'aero_data': aero_data, + 'training_data': True} + ph_in['pre_mission']['external_subsystems'] = [polar_builder] + + ph_in['cruise']['subsystem_options'] = {'core_aerodynamics': subsystem_options} + + prob = AviaryProblem(ph_in, mission_method="FLOPS", mass_method="FLOPS") + + prob.load_inputs(csv_path) + + prob.aviary_inputs.set_val(Aircraft.Design.LIFT_POLAR, + np.zeros_like(CL), units='unitless') + prob.aviary_inputs.set_val(Aircraft.Design.DRAG_POLAR, + np.zeros_like(CD), units='unitless') + + prob.add_pre_mission_systems() + prob.add_phases() + prob.add_post_mission_systems() + + prob.link_phases() + + prob.setup() + + prob.set_initial_guesses() + + prob.run_model() + + CL_pass = prob.get_val("traj.cruise.rhs_all.core_aerodynamics.tabular_aero.CL") + CD_pass = prob.get_val("traj.cruise.rhs_all.core_aerodynamics.tabular_aero.CD") + + assert_near_equal(CL_pass, CL_base, 1e-6) + assert_near_equal(CD_pass, CD_base, 1e-6) + class FakeCalcDragPolar(om.ExplicitComponent): """ diff --git a/aviary/subsystems/aerodynamics/gasp_based/table_based.py b/aviary/subsystems/aerodynamics/gasp_based/table_based.py index c9fc4d397..d333fe16f 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/table_based.py +++ b/aviary/subsystems/aerodynamics/gasp_based/table_based.py @@ -588,11 +588,12 @@ def _structure_special_grid(aero_data): # units don't matter, not using values aoa = aero_data.get_val('angle_of_attack', 'deg') - # special case alpha - this format saturates alpha at its max - # get unique alphas at zero alt mach 0, should cover the full range - # TODO this does not work with data that is already in structured grid format - mask = (data[0] == x0[0]) & (data[1] == x1[0]) - aoa = np.unique(aoa[mask]) + if data[0].shape[0] > x0.shape[0]: + # special case alpha - this format saturates alpha at its max + # get unique alphas at zero alt mach 0, should cover the full range + mask = (data[0] == x0[0]) & (data[1] == x1[0]) + aoa = np.unique(aoa[mask]) + _, _, aoa = np.meshgrid(x0, x1, aoa) # put the aoa data back in the NamedValues object From e005203ad430f541413814d06d7a6550fb5829f8 Mon Sep 17 00:00:00 2001 From: "Kenneth T. Moore" Date: Tue, 9 Jan 2024 14:29:50 -0500 Subject: [PATCH 027/188] PEP --- .../aerodynamics/flops_based/test/test_solved_aero_group.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py index d70bb9418..89064de19 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py @@ -143,10 +143,10 @@ def test_solved_aero_pass_polar_unique_abscissa(self): ph_in = deepcopy(phase_info) - alt = np.array([0., 3000., 6000., 9000., 12000., 15000., 18000., 21000., + alt = np.array([0., 3000., 6000., 9000., 12000., 15000., 18000., 21000., 24000., 27000., 30000., 33000., 36000., 38000., 42000.]) - mach = np.array([0. , 0.2 , 0.4 , 0.5 , 0.6 , 0.7 , 0.75, 0.8 , 0.85, 0.9 ]) - alpha = np.array([-2., 0., 2., 4., 6., 8., 10.]) + mach = np.array([0., 0.2, 0.4, 0.5, 0.6, 0.7, 0.75, 0.8, 0.85, 0.9]) + alpha = np.array([-2., 0., 2., 4., 6., 8., 10.]) polar_builder = FakeDragPolarBuilder(name="aero", altitude=alt, mach=mach, alpha=alpha) From da3029e45c3e1b1d140643d0ce4d61a3a2c32a67 Mon Sep 17 00:00:00 2001 From: "Kenneth T. Moore" Date: Tue, 9 Jan 2024 14:53:41 -0500 Subject: [PATCH 028/188] This PR uses a feature that is only working correctly on the dev branch of OpenMDAO --- .github/workflows/test_workflow.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 3edbe2f3e..f1d6cc706 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -42,7 +42,7 @@ jobs: SCIPY: '1.6' PYOPTSPARSE: 'v2.9.1' SNOPT: '7.7' - OPENMDAO: '3.27' + OPENMDAO: 'dev' DYMOS: '1.8.0' MAKE_DOCS: 0 @@ -64,7 +64,7 @@ jobs: SCIPY: 1 PYOPTSPARSE: 'v2.9.1' SNOPT: '7.7' - OPENMDAO: 'latest' + OPENMDAO: 'dev' DYMOS: 'latest' MAKE_DOCS: 0 @@ -75,7 +75,7 @@ jobs: SCIPY: 1 PYOPTSPARSE: 'v2.9.1' SNOPT: '7.7' - OPENMDAO: 'latest' + OPENMDAO: 'dev' DYMOS: 'latest' MAKE_DOCS: 1 From a7c5d16178a986ce61ab23b788f8a4205907a25b Mon Sep 17 00:00:00 2001 From: "Kenneth T. Moore" Date: Tue, 9 Jan 2024 15:00:44 -0500 Subject: [PATCH 029/188] This PR uses a feature that is only working correctly on the dev branch of OpenMDAO --- .github/workflows/test_workflow_no_dev_install.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_workflow_no_dev_install.yml b/.github/workflows/test_workflow_no_dev_install.yml index 14d2d2002..76c30870e 100644 --- a/.github/workflows/test_workflow_no_dev_install.yml +++ b/.github/workflows/test_workflow_no_dev_install.yml @@ -24,7 +24,7 @@ jobs: matrix: include: # latest versions of openmdao/dymos - - NAME: latest + - NAME: dev PY: 3 steps: @@ -87,4 +87,4 @@ jobs: echo "=============================================================" echo "Run Tests" echo "=============================================================" - testflo . -n 1 --show_skipped \ No newline at end of file + testflo . -n 1 --show_skipped From c55a7d451dce1802e43b0db80cc36ce6d5a180a9 Mon Sep 17 00:00:00 2001 From: "Kenneth T. Moore" Date: Tue, 9 Jan 2024 15:49:42 -0500 Subject: [PATCH 030/188] resolve conflict --- .github/workflows/test_workflow_no_dev_install.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test_workflow_no_dev_install.yml b/.github/workflows/test_workflow_no_dev_install.yml index bc916c255..fa78fb1db 100644 --- a/.github/workflows/test_workflow_no_dev_install.yml +++ b/.github/workflows/test_workflow_no_dev_install.yml @@ -24,8 +24,9 @@ jobs: matrix: include: # latest versions of openmdao/dymos - - NAME: dev + - NAME: latest PY: 3 + OPENMDAO: 'dev' steps: - name: Display run details From ae3daeb2eb6298749beb66bc01343ec7759964fd Mon Sep 17 00:00:00 2001 From: "Kenneth T. Moore" Date: Tue, 9 Jan 2024 15:57:42 -0500 Subject: [PATCH 031/188] This PR uses a feature that is only working correctly on the dev branch of OpenMDAO --- .github/workflows/test_workflow_no_dev_install.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test_workflow_no_dev_install.yml b/.github/workflows/test_workflow_no_dev_install.yml index fa78fb1db..fdc417d36 100644 --- a/.github/workflows/test_workflow_no_dev_install.yml +++ b/.github/workflows/test_workflow_no_dev_install.yml @@ -26,7 +26,6 @@ jobs: # latest versions of openmdao/dymos - NAME: latest PY: 3 - OPENMDAO: 'dev' steps: - name: Display run details @@ -56,6 +55,16 @@ jobs: auto-update-conda: true python-version: ${{ matrix.PY }} + - name: Install OpenMDAO Dev + shell: bash -l {0} + run: | + echo "=============================================================" + echo "THIS STEP IS TEMPORARY" + echo "Please remove after the release of OpenMDAO 3.31." + echo "Install OpenMDAO" + echo "=============================================================" + pip install git+https://github.com/OpenMDAO/OpenMDAO + - name: Checkout Aviary uses: actions/checkout@v2 From 19dcacc188693750e14c49557d7612594577d0fa Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 10 Jan 2024 14:01:21 -0600 Subject: [PATCH 032/188] updates based on PR --- README.md | 2 +- aviary/validation_cases/benchmark_tests/test_bench_GwFm.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e42db2f66..d5a010004 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ The user can select which type of mission analysis to use, as well as whether to ## Installation The simplest installation method for users is to install via pip. -From within the base folder of Aviary, perform this command in your terminal: +Once you have cloned the Aviary repo, change directories into the top-level Aviary folder (not within the `aviary` folder) and run the following command: pip install . diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py index 2dd22d79b..3366ebfc4 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py @@ -368,6 +368,6 @@ def bench_test_swap_1_GwFm_simple(self): if __name__ == '__main__': - z = ProblemPhaseTestCase() - z.setUp() - z.bench_test_swap_1_GwFm_simple() + test = ProblemPhaseTestCase() + test.setUp() + test.bench_test_swap_1_GwFm_simple() From a99c3ebcda416d97a99c7afa7dcaee97d0b4e574 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 10 Jan 2024 14:35:11 -0600 Subject: [PATCH 033/188] Added two examples and ensured they're tested --- aviary/examples/run_aviary_example.py | 127 ++++++++++++++++++++ aviary/examples/run_basic_aviary_example.py | 16 +++ aviary/examples/test/test_all_examples.py | 2 +- 3 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 aviary/examples/run_aviary_example.py create mode 100644 aviary/examples/run_basic_aviary_example.py diff --git a/aviary/examples/run_aviary_example.py b/aviary/examples/run_aviary_example.py new file mode 100644 index 000000000..3b7a9db8e --- /dev/null +++ b/aviary/examples/run_aviary_example.py @@ -0,0 +1,127 @@ +""" +This is a slightly more complex Aviary example of running a coupled aircraft design-mission optimization. +It runs the same mission as the `run_basic_aviary_example.py` script, but it uses the AviaryProblem class to set up the problem. +This exposes more options and flexibility to the user and uses the "Level 2" API within Aviary. + +We define a `phase_info` object, which tells Aviary how to model the mission. +Here we have climb, cruise, a descent phases. +We then call the correct methods in order to set up and run an Aviary optimization problem. +This performs a coupled design-mission optimization and outputs the results from Aviary into the `reports` folder. +""" +import aviary.api as av + + +phase_info = { + "pre_mission": {"include_takeoff": False, "optimize_mass": True}, + "climb": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + "optimize_mach": False, + "optimize_altitude": False, + "polynomial_control_order": 1, + "num_segments": 5, + "order": 3, + "solve_for_range": False, + "initial_mach": (0.2, "unitless"), + "final_mach": (0.72, "unitless"), + "mach_bounds": ((0.18, 0.74), "unitless"), + "initial_altitude": (0.0, "ft"), + "final_altitude": (32000.0, "ft"), + "altitude_bounds": ((0.0, 34000.0), "ft"), + "throttle_enforcement": "path_constraint", + "fix_initial": True, + "constrain_final": False, + "fix_duration": False, + "initial_bounds": ((0.0, 0.0), "min"), + "duration_bounds": ((64.0, 192.0), "min"), + }, + "initial_guesses": {"times": ([0, 128], "min")}, + }, + "cruise": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + "optimize_mach": False, + "optimize_altitude": False, + "polynomial_control_order": 1, + "num_segments": 5, + "order": 3, + "solve_for_range": False, + "initial_mach": (0.72, "unitless"), + "final_mach": (0.72, "unitless"), + "mach_bounds": ((0.7, 0.74), "unitless"), + "initial_altitude": (32000.0, "ft"), + "final_altitude": (34000.0, "ft"), + "altitude_bounds": ((23000.0, 38000.0), "ft"), + "throttle_enforcement": "boundary_constraint", + "fix_initial": False, + "constrain_final": False, + "fix_duration": False, + "initial_bounds": ((64.0, 192.0), "min"), + "duration_bounds": ((56.5, 169.5), "min"), + }, + "initial_guesses": {"times": ([128, 113], "min")}, + }, + "descent": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + "optimize_mach": False, + "optimize_altitude": False, + "polynomial_control_order": 1, + "num_segments": 5, + "order": 3, + "solve_for_range": False, + "initial_mach": (0.72, "unitless"), + "final_mach": (0.36, "unitless"), + "mach_bounds": ((0.34, 0.74), "unitless"), + "initial_altitude": (34000.0, "ft"), + "final_altitude": (500.0, "ft"), + "altitude_bounds": ((0.0, 38000.0), "ft"), + "throttle_enforcement": "path_constraint", + "fix_initial": False, + "constrain_final": True, + "fix_duration": False, + "initial_bounds": ((120.5, 361.5), "min"), + "duration_bounds": ((29.0, 87.0), "min"), + }, + "initial_guesses": {"times": ([241, 58], "min")}, + }, + "post_mission": { + "include_landing": False, + "constrain_range": True, + "target_range": (1906, "nmi"), + }, +} + + +prob = av.AviaryProblem(phase_info, "simple", "FLOPS", av.AnalysisScheme.COLLOCATION) + +# Load aircraft and options data from user +# Allow for user overrides here +prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm.csv') + +# Have checks for clashing user inputs +# Raise warnings or errors depending on how clashing the issues are +prob.check_inputs() + +prob.add_pre_mission_systems() + +prob.add_phases() + +prob.add_post_mission_systems() + +# Link phases and variables +prob.link_phases() + +prob.add_driver("SLSQP", max_iter=100) + +prob.add_design_variables() + +# Load optimization problem formulation +# Detail which variables the optimizer can control +prob.add_objective() + +prob.setup() + +prob.set_initial_guesses() + +prob.run_aviary_problem() diff --git a/aviary/examples/run_basic_aviary_example.py b/aviary/examples/run_basic_aviary_example.py new file mode 100644 index 000000000..85492efc1 --- /dev/null +++ b/aviary/examples/run_basic_aviary_example.py @@ -0,0 +1,16 @@ +""" +This is a straightforward and basic example of running a coupled aircraft design-mission optimization in Aviary. +This uses the "level 1" API within Aviary. + +We use the pre-defined single aisle commercial transport aircraft definition and use a pre-defined phase_info object +to describe the mission optimization problem to Aviary. +This mission consists of climb, cruise, and descent phases. +We then call the `run_aviary` function, which takes in the path to the aircraft model, the phase info, and some other options. +This performs a coupled design-mission optimization and outputs the results from Aviary into the `reports` folder. +""" +import aviary.api as av + + +prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv', av.default_simple_phase_info, + mission_method="simple", mass_method="FLOPS", + optimizer="SLSQP", make_plots=True) diff --git a/aviary/examples/test/test_all_examples.py b/aviary/examples/test/test_all_examples.py index 387654108..f4f347d47 100644 --- a/aviary/examples/test/test_all_examples.py +++ b/aviary/examples/test/test_all_examples.py @@ -45,7 +45,7 @@ def setUpClass(cls): This method is called once before starting the tests and is used to populate the 'run_files' attribute with a list of run scripts. """ - cls.base_directory = "../external_subsystems" # Adjust the path as necessary + cls.base_directory = "../" # Adjust the path as necessary cls.run_files = cls.find_run_files(cls.base_directory) @staticmethod From da864e2a7fe160899dda53424f748c9939b4442e Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Wed, 10 Jan 2024 15:55:13 -0500 Subject: [PATCH 034/188] Adjusting iframe for N2 for better visibility --- aviary/visualization/dashboard.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index 342efc704..abccd94f2 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -22,7 +22,6 @@ # Constants # Can't get using CSS to work with frames and the raw_css for the template so going with # this for now -iframe_css = "width=100% height=4000vh overflow=hidden margin=0px padding=0px border=none" aviary_variables_json_file_name = 'aviary_vars.json' @@ -87,8 +86,14 @@ def create_report_frame(format, text_filepath): """ if os.path.exists(text_filepath): if format == 'html': + # iframe_css = "width=100% height=4000vh overflow=hidden margin=0px padding=0px border=none" + # report_pane = pn.pane.HTML( + # f'') + # iframe_css = "width=1200px height=1200px overflow=scroll margin=0px padding=0px border=20px frameBorder=20px scrolling=yes" + iframe_css = 'max-width=1200px max-height=1200px overflow="scroll" margin=0px padding=0px border=20px frameBorder=20px scrolling="yes"' + iframe_css = 'width=1200px height=1200px overflow-x="scroll" overflow="scroll" margin=0px padding=0px border=20px frameBorder=20px scrolling="yes"' report_pane = pn.pane.HTML( - f'') + f'' ) elif format in ['markdown', 'text']: with open(text_filepath, "rb") as f: file_text = f.read() From fff1453bbe168be07caf15d63a12025699f692fa Mon Sep 17 00:00:00 2001 From: John Jasa Date: Wed, 10 Jan 2024 15:03:35 -0600 Subject: [PATCH 035/188] Update test_bench_FwFm.py --- aviary/validation_cases/benchmark_tests/test_bench_FwFm.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index 200f43058..3b9217ddf 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -265,9 +265,6 @@ def setUp(self): def bench_test_swap_4_FwFm(self): local_phase_info = deepcopy(phase_info) - prob = run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv', - local_phase_info, - mission_method="FLOPS", mass_method="FLOPS") prob = run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv', local_phase_info, mission_method="FLOPS", mass_method="FLOPS") From 76ec6c05a8db96d0fd9a7e4cdeddf0eaea7d3775 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 10 Jan 2024 15:22:33 -0600 Subject: [PATCH 036/188] Fixed path for examples script --- aviary/examples/test/test_all_examples.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/aviary/examples/test/test_all_examples.py b/aviary/examples/test/test_all_examples.py index f4f347d47..8393a27c7 100644 --- a/aviary/examples/test/test_all_examples.py +++ b/aviary/examples/test/test_all_examples.py @@ -45,8 +45,9 @@ def setUpClass(cls): This method is called once before starting the tests and is used to populate the 'run_files' attribute with a list of run scripts. """ - cls.base_directory = "../" # Adjust the path as necessary - cls.run_files = cls.find_run_files(cls.base_directory) + base_directory = os.path.join(os.path.dirname( + os.path.dirname(os.path.abspath(__file__))), ".") + cls.run_files = cls.find_run_files(base_directory) @staticmethod def find_run_files(base_dir): From be054fa00d261b11ac49ddbaa0b2d0679fb8d4f9 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 10 Jan 2024 15:36:22 -0600 Subject: [PATCH 037/188] Need to pip install all if we're doing examples --- .github/workflows/test_workflow_no_dev_install.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_workflow_no_dev_install.yml b/.github/workflows/test_workflow_no_dev_install.yml index 98f0eefe1..74c498830 100644 --- a/.github/workflows/test_workflow_no_dev_install.yml +++ b/.github/workflows/test_workflow_no_dev_install.yml @@ -65,7 +65,7 @@ jobs: echo "Install Aviary" echo "=============================================================" pip install packaging - pip install .[test] + pip install .[all] - name: Display conda environment info shell: bash -l {0} From 3eaad5142fc62252f78990f5b401ef308a4151e2 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 10 Jan 2024 15:56:13 -0600 Subject: [PATCH 038/188] Merging --- .../OAS_weight/run_simple_OAS_mission.py | 15 +++------------ .../battery/run_multiphase_mission.py | 2 +- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py b/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py index 656ca18ed..60437a486 100644 --- a/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py +++ b/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py @@ -112,9 +112,8 @@ mission_method = 'simple' mass_method = 'FLOPS' make_plots = False -max_iter = 100 -optimizer = 'SNOPT' - +max_iter = 1 # set this to a higher number to fully run the optimization +optimizer = 'SLSQP' prob = av.AviaryProblem(phase_info, mission_method=mission_method, mass_method='FLOPS') @@ -124,15 +123,7 @@ prob.add_phases() prob.add_post_mission_systems() prob.link_phases() - -driver = prob.driver = om.pyOptSparseDriver() -driver.options["optimizer"] = optimizer -driver.declare_coloring() -driver.opt_settings["Major iterations limit"] = max_iter -driver.opt_settings["Major optimality tolerance"] = 1e-4 -driver.opt_settings["Major feasibility tolerance"] = 1e-5 -driver.opt_settings["iSumm"] = 6 - +prob.add_driver(optimizer=optimizer, max_iter=max_iter) prob.add_design_variables() prob.add_objective() prob.setup() diff --git a/aviary/examples/external_subsystems/battery/run_multiphase_mission.py b/aviary/examples/external_subsystems/battery/run_multiphase_mission.py index 584f75238..e0c9590b4 100644 --- a/aviary/examples/external_subsystems/battery/run_multiphase_mission.py +++ b/aviary/examples/external_subsystems/battery/run_multiphase_mission.py @@ -37,7 +37,7 @@ # Link phases and variables prob.link_phases() -prob.add_driver("SNOPT") +prob.add_driver("SLSQP") prob.add_design_variables() From 3781c7eef0dffa97954c502c5b38159a45a5bfc7 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Thu, 11 Jan 2024 09:49:36 -0500 Subject: [PATCH 039/188] Removed comment no longer needed --- aviary/visualization/dashboard.py | 1 - 1 file changed, 1 deletion(-) diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index 330f01fc1..aa1ebf8e2 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -556,7 +556,6 @@ def dashboard(script_name, problem_recorder, driver_recorder, port): if __name__ == "__main__": - # so we can get the files written to the repo top directory parser = argparse.ArgumentParser() _dashboard_setup_parser(parser) args = parser.parse_args() From 3f49ee0560d1c1a5b3360fceddf0671da615976b Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Thu, 11 Jan 2024 09:55:50 -0500 Subject: [PATCH 040/188] PEP8 fix --- aviary/interface/test/test_simple_mission.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aviary/interface/test/test_simple_mission.py b/aviary/interface/test/test_simple_mission.py index 327843fcd..78ec4902c 100644 --- a/aviary/interface/test/test_simple_mission.py +++ b/aviary/interface/test/test_simple_mission.py @@ -4,6 +4,7 @@ from openmdao.utils.testing_utils import require_pyoptsparse, use_tempdirs import subprocess + @use_tempdirs class AircraftMissionTestSuite(unittest.TestCase): From b123b94d54f86001b0b9efcb7a5f775f985acb0b Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 11 Jan 2024 11:38:23 -0600 Subject: [PATCH 041/188] Updated docs based on main --- aviary/docs/examples/OAS_subsystem.ipynb | 60 ++++++++++++++++++++---- aviary/interface/methods_for_level2.py | 17 ++++--- 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/aviary/docs/examples/OAS_subsystem.ipynb b/aviary/docs/examples/OAS_subsystem.ipynb index d0c2fe73e..20826a0e8 100644 --- a/aviary/docs/examples/OAS_subsystem.ipynb +++ b/aviary/docs/examples/OAS_subsystem.ipynb @@ -34,7 +34,7 @@ "Other Aviary variables can also be added as additional inputs based on user needs.\n", "\n", "```{note}\n", - "Some modifications of the [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) code may be necessary to add new inputs not already defined.\n", + "Some modifications of the [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) code will be necessary to add new inputs not already defined.\n", "```\n", "\n", "Here is the builder object for the OAS wing weight analysis example:" @@ -42,9 +42,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/subsystems/propulsion/engine_deck.py:198: UserWarning: is a required option for EngineDecks, but has not been specified for EngineDeck . The default value will be used.\n", + " warnings.warn(\n" + ] + } + ], "source": [ "# %load ../../examples/external_subsystems/OAS_weight/OAS_wing_weight_builder.py\n", "\"\"\"\n", @@ -214,9 +223,37 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'climb_1': {'subsystem_options': {'core_aerodynamics': {'method': 'computed'}}, 'user_options': {'optimize_mach': False, 'optimize_altitude': False, 'polynomial_control_order': 1, 'num_segments': 5, 'order': 3, 'solve_for_range': False, 'initial_mach': (0.2, 'unitless'), 'final_mach': (0.72, 'unitless'), 'mach_bounds': ((0.18, 0.74), 'unitless'), 'initial_altitude': (0.0, 'ft'), 'final_altitude': (32000.0, 'ft'), 'altitude_bounds': ((0.0, 34000.0), 'ft'), 'throttle_enforcement': 'path_constraint', 'fix_initial': True, 'constrain_final': False, 'fix_duration': False, 'initial_bounds': ((0.0, 0.0), 'min'), 'duration_bounds': ((64.0, 192.0), 'min')}, 'initial_guesses': {'times': ([0, 128], 'min')}}, 'climb_2': {'subsystem_options': {'core_aerodynamics': {'method': 'computed'}}, 'user_options': {'optimize_mach': False, 'optimize_altitude': False, 'polynomial_control_order': 1, 'num_segments': 5, 'order': 3, 'solve_for_range': False, 'initial_mach': (0.72, 'unitless'), 'final_mach': (0.72, 'unitless'), 'mach_bounds': ((0.7, 0.74), 'unitless'), 'initial_altitude': (32000.0, 'ft'), 'final_altitude': (34000.0, 'ft'), 'altitude_bounds': ((23000.0, 38000.0), 'ft'), 'throttle_enforcement': 'boundary_constraint', 'fix_initial': False, 'constrain_final': False, 'fix_duration': False, 'initial_bounds': ((64.0, 192.0), 'min'), 'duration_bounds': ((56.5, 169.5), 'min')}, 'initial_guesses': {'times': ([128, 113], 'min')}}, 'descent_1': {'subsystem_options': {'core_aerodynamics': {'method': 'computed'}}, 'user_options': {'optimize_mach': False, 'optimize_altitude': False, 'polynomial_control_order': 1, 'num_segments': 5, 'order': 3, 'solve_for_range': False, 'initial_mach': (0.72, 'unitless'), 'final_mach': (0.36, 'unitless'), 'mach_bounds': ((0.34, 0.74), 'unitless'), 'initial_altitude': (34000.0, 'ft'), 'final_altitude': (500.0, 'ft'), 'altitude_bounds': ((0.0, 38000.0), 'ft'), 'throttle_enforcement': 'path_constraint', 'fix_initial': False, 'constrain_final': True, 'fix_duration': False, 'initial_bounds': ((120.5, 361.5), 'min'), 'duration_bounds': ((29.0, 87.0), 'min')}, 'initial_guesses': {'times': ([241, 58], 'min')}}, 'post_mission': {'include_landing': False, 'constrain_range': True, 'target_range': (1800.0, 'nmi')}, 'pre_mission': {'include_takeoff': False, 'optimize_mass': True, 'external_subsystems': []}}\n" + ] + }, + { + "ename": "UnboundLocalError", + "evalue": "local variable 'traj' referenced before assignment", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mUnboundLocalError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[2], line 124\u001b[0m\n\u001b[1;32m 122\u001b[0m prob\u001b[38;5;241m.\u001b[39mcheck_inputs()\n\u001b[1;32m 123\u001b[0m prob\u001b[38;5;241m.\u001b[39madd_pre_mission_systems()\n\u001b[0;32m--> 124\u001b[0m \u001b[43mprob\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_phases\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 125\u001b[0m prob\u001b[38;5;241m.\u001b[39madd_post_mission_systems()\n\u001b[1;32m 126\u001b[0m prob\u001b[38;5;241m.\u001b[39mlink_phases()\n", + "File \u001b[0;32m/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/interface/methods_for_level2.py:1082\u001b[0m, in \u001b[0;36mAviaryProblem.add_phases\u001b[0;34m(self, phase_info_parameterization)\u001b[0m\n\u001b[1;32m 1080\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmission_method \u001b[38;5;129;01mis\u001b[39;00m HEIGHT_ENERGY \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmission_method \u001b[38;5;129;01mis\u001b[39;00m SIMPLE:\n\u001b[1;32m 1081\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m phase_idx, phase_name \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(phases):\n\u001b[0;32m-> 1082\u001b[0m phase \u001b[38;5;241m=\u001b[39m \u001b[43mtraj\u001b[49m\u001b[38;5;241m.\u001b[39madd_phase(\n\u001b[1;32m 1083\u001b[0m phase_name, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_get_height_energy_phase(phase_name, phase_idx))\n\u001b[1;32m 1084\u001b[0m add_subsystem_timeseries_outputs(phase, phase_name)\n\u001b[1;32m 1086\u001b[0m \u001b[38;5;66;03m# loop through phase_info and external subsystems\u001b[39;00m\n", + "\u001b[0;31mUnboundLocalError\u001b[0m: local variable 'traj' referenced before assignment" + ] + } + ], "source": [ "# %load ../../examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py\n", "'''\n", @@ -329,16 +366,16 @@ "if use_OAS:\n", " phase_info['pre_mission']['external_subsystems'] = [wing_weight_builder]\n", "\n", - "aircraft_definition_file = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'\n", + "aircraft_definition_file = 'models/test_aircraft/aircraft_for_bench_FwFm_simple.csv'\n", "mission_method = 'simple'\n", "mass_method = 'FLOPS'\n", "make_plots = False\n", "max_iter = 100\n", "optimizer = 'IPOPT'\n", "\n", - "prob = av.AviaryProblem(phase_info, mission_method=mission_method, mass_method='FLOPS')\n", + "prob = av.AviaryProblem()\n", "\n", - "prob.load_inputs(aircraft_definition_file)\n", + "prob.load_inputs(aircraft_definition_file, phase_info)\n", "prob.check_inputs()\n", "prob.add_pre_mission_systems()\n", "prob.add_phases()\n", @@ -381,6 +418,13 @@ "# prob.run_aviary_problem('dymos_solution.db', make_plots=False)\n", "# print('wing mass = ', prob.model.get_val(av.Aircraft.Wing.MASS, units='lbm'))\n" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 9285db939..c72be22a2 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -208,15 +208,14 @@ def load_inputs(self, input_filename, phase_info=None, engine_builder=None): print('Loaded outputted_phase_info.py generated with GUI') else: - # 2dof -> two_dof - method = self.mission_method.value.replace('2DOF', 'two_dof') - - module = importlib.import_module( - self.mission_method.value, 'aviary.interface.default_phase_info') - phase_info = getattr(module, 'phase_info') - - print('Loaded default phase_info for' - f'{self.mission_method.value.lower()} equations of motion') + if self.mission_method is TWO_DEGREES_OF_FREEDOM: + from aviary.interface.default_phase_info.two_dof import phase_info + elif self.mission_method is HEIGHT_ENERGY: + from aviary.interface.default_phase_info.height_energy import phase_info + elif self.mission_method is SIMPLE: + from aviary.interface.default_phase_info.simple import phase_info + elif self.mission_method is SOLVED: + from aviary.interface.default_phase_info.solved import phase_info # create a new dictionary that only contains the phases from phase_info self.phase_info = {} From 98858d19468f92ca5e61c7abdd88c009c52e95e3 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 11 Jan 2024 11:39:59 -0600 Subject: [PATCH 042/188] Cleared notebook --- aviary/docs/examples/OAS_subsystem.ipynb | 52 ++---------------------- 1 file changed, 4 insertions(+), 48 deletions(-) diff --git a/aviary/docs/examples/OAS_subsystem.ipynb b/aviary/docs/examples/OAS_subsystem.ipynb index 20826a0e8..491b119ad 100644 --- a/aviary/docs/examples/OAS_subsystem.ipynb +++ b/aviary/docs/examples/OAS_subsystem.ipynb @@ -42,18 +42,9 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/subsystems/propulsion/engine_deck.py:198: UserWarning: is a required option for EngineDecks, but has not been specified for EngineDeck . The default value will be used.\n", - " warnings.warn(\n" - ] - } - ], + "outputs": [], "source": [ "# %load ../../examples/external_subsystems/OAS_weight/OAS_wing_weight_builder.py\n", "\"\"\"\n", @@ -223,37 +214,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", - " warnings.warn(\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'climb_1': {'subsystem_options': {'core_aerodynamics': {'method': 'computed'}}, 'user_options': {'optimize_mach': False, 'optimize_altitude': False, 'polynomial_control_order': 1, 'num_segments': 5, 'order': 3, 'solve_for_range': False, 'initial_mach': (0.2, 'unitless'), 'final_mach': (0.72, 'unitless'), 'mach_bounds': ((0.18, 0.74), 'unitless'), 'initial_altitude': (0.0, 'ft'), 'final_altitude': (32000.0, 'ft'), 'altitude_bounds': ((0.0, 34000.0), 'ft'), 'throttle_enforcement': 'path_constraint', 'fix_initial': True, 'constrain_final': False, 'fix_duration': False, 'initial_bounds': ((0.0, 0.0), 'min'), 'duration_bounds': ((64.0, 192.0), 'min')}, 'initial_guesses': {'times': ([0, 128], 'min')}}, 'climb_2': {'subsystem_options': {'core_aerodynamics': {'method': 'computed'}}, 'user_options': {'optimize_mach': False, 'optimize_altitude': False, 'polynomial_control_order': 1, 'num_segments': 5, 'order': 3, 'solve_for_range': False, 'initial_mach': (0.72, 'unitless'), 'final_mach': (0.72, 'unitless'), 'mach_bounds': ((0.7, 0.74), 'unitless'), 'initial_altitude': (32000.0, 'ft'), 'final_altitude': (34000.0, 'ft'), 'altitude_bounds': ((23000.0, 38000.0), 'ft'), 'throttle_enforcement': 'boundary_constraint', 'fix_initial': False, 'constrain_final': False, 'fix_duration': False, 'initial_bounds': ((64.0, 192.0), 'min'), 'duration_bounds': ((56.5, 169.5), 'min')}, 'initial_guesses': {'times': ([128, 113], 'min')}}, 'descent_1': {'subsystem_options': {'core_aerodynamics': {'method': 'computed'}}, 'user_options': {'optimize_mach': False, 'optimize_altitude': False, 'polynomial_control_order': 1, 'num_segments': 5, 'order': 3, 'solve_for_range': False, 'initial_mach': (0.72, 'unitless'), 'final_mach': (0.36, 'unitless'), 'mach_bounds': ((0.34, 0.74), 'unitless'), 'initial_altitude': (34000.0, 'ft'), 'final_altitude': (500.0, 'ft'), 'altitude_bounds': ((0.0, 38000.0), 'ft'), 'throttle_enforcement': 'path_constraint', 'fix_initial': False, 'constrain_final': True, 'fix_duration': False, 'initial_bounds': ((120.5, 361.5), 'min'), 'duration_bounds': ((29.0, 87.0), 'min')}, 'initial_guesses': {'times': ([241, 58], 'min')}}, 'post_mission': {'include_landing': False, 'constrain_range': True, 'target_range': (1800.0, 'nmi')}, 'pre_mission': {'include_takeoff': False, 'optimize_mass': True, 'external_subsystems': []}}\n" - ] - }, - { - "ename": "UnboundLocalError", - "evalue": "local variable 'traj' referenced before assignment", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mUnboundLocalError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[2], line 124\u001b[0m\n\u001b[1;32m 122\u001b[0m prob\u001b[38;5;241m.\u001b[39mcheck_inputs()\n\u001b[1;32m 123\u001b[0m prob\u001b[38;5;241m.\u001b[39madd_pre_mission_systems()\n\u001b[0;32m--> 124\u001b[0m \u001b[43mprob\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_phases\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 125\u001b[0m prob\u001b[38;5;241m.\u001b[39madd_post_mission_systems()\n\u001b[1;32m 126\u001b[0m prob\u001b[38;5;241m.\u001b[39mlink_phases()\n", - "File \u001b[0;32m/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/interface/methods_for_level2.py:1082\u001b[0m, in \u001b[0;36mAviaryProblem.add_phases\u001b[0;34m(self, phase_info_parameterization)\u001b[0m\n\u001b[1;32m 1080\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmission_method \u001b[38;5;129;01mis\u001b[39;00m HEIGHT_ENERGY \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmission_method \u001b[38;5;129;01mis\u001b[39;00m SIMPLE:\n\u001b[1;32m 1081\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m phase_idx, phase_name \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(phases):\n\u001b[0;32m-> 1082\u001b[0m phase \u001b[38;5;241m=\u001b[39m \u001b[43mtraj\u001b[49m\u001b[38;5;241m.\u001b[39madd_phase(\n\u001b[1;32m 1083\u001b[0m phase_name, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_get_height_energy_phase(phase_name, phase_idx))\n\u001b[1;32m 1084\u001b[0m add_subsystem_timeseries_outputs(phase, phase_name)\n\u001b[1;32m 1086\u001b[0m \u001b[38;5;66;03m# loop through phase_info and external subsystems\u001b[39;00m\n", - "\u001b[0;31mUnboundLocalError\u001b[0m: local variable 'traj' referenced before assignment" - ] - } - ], + "outputs": [], "source": [ "# %load ../../examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py\n", "'''\n", @@ -418,13 +381,6 @@ "# prob.run_aviary_problem('dymos_solution.db', make_plots=False)\n", "# print('wing mass = ', prob.model.get_val(av.Aircraft.Wing.MASS, units='lbm'))\n" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { From 2113a7d9123975bb9ffc0a754f7028b99da3f8d4 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 11 Jan 2024 11:43:52 -0600 Subject: [PATCH 043/188] Added Carl's error message logic --- aviary/interface/test/test_check_phase_info.py | 6 ++++++ aviary/interface/utils/check_phase_info.py | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/aviary/interface/test/test_check_phase_info.py b/aviary/interface/test/test_check_phase_info.py index cf455372b..1c0cf7fde 100644 --- a/aviary/interface/test/test_check_phase_info.py +++ b/aviary/interface/test/test_check_phase_info.py @@ -36,6 +36,12 @@ def test_correct_input_gasp(self): self.assertTrue(check_phase_info(phase_info_gasp, mission_method=TWO_DEGREES_OF_FREEDOM)) + def test_incorrect_mission_method(self): + # Let's pass an incorrect mission_method name + incorrect_mission_method = 'INVALID_METHOD' + with self.assertRaises(ValueError): + check_phase_info(phase_info_flops, mission_method=incorrect_mission_method) + if __name__ == '__main__': unittest.main() diff --git a/aviary/interface/utils/check_phase_info.py b/aviary/interface/utils/check_phase_info.py index 9e2f9d771..cc40add8b 100644 --- a/aviary/interface/utils/check_phase_info.py +++ b/aviary/interface/utils/check_phase_info.py @@ -226,8 +226,10 @@ def check_phase_info(phase_info, mission_method): elif mission_method is SIMPLE: return else: - raise ValueError( - "Invalid mission_method. Please choose from 'HEIGHT_ENERGY', 'TWO_DEGREES_OF_FREEDOM', 'SIMPLE', or 'SOLVED'.") + possible_values = ["'"+e.value+"'" for e in EquationsOfMotion] + possible_values[-1] = "or " + possible_values[-1] + raise ValueError("Invalid mission_method. Please choose from " + + ", ".join(possible_values) + ".") # Check if all phases exist in phase_info for phase in phase_info: From 64e3881e07495f53f387fddbcecbfcd3e4c03bd2 Mon Sep 17 00:00:00 2001 From: "Kenneth T. Moore" Date: Thu, 11 Jan 2024 13:20:20 -0500 Subject: [PATCH 044/188] Merge out latest from main and update test. --- .../flops_based/test/test_solved_aero_group.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py index b24722b7a..378645081 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py @@ -118,13 +118,14 @@ def test_solved_aero_pass_polar(self): def test_solved_aero_pass_polar_unique_abscissa(self): # Solved Aero with shortened lists of table abscissa. - prob = AviaryProblem( - phase_info, mission_method="FLOPS", mass_method="FLOPS") + local_phase_info = deepcopy(phase_info) + + prob = AviaryProblem() csv_path = pkg_resources.resource_filename( "aviary", "subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv") - prob.load_inputs(csv_path) + prob.load_inputs(csv_path, local_phase_info) prob.add_pre_mission_systems() prob.add_phases() prob.add_post_mission_systems() @@ -163,9 +164,9 @@ def test_solved_aero_pass_polar_unique_abscissa(self): ph_in['cruise']['subsystem_options'] = {'core_aerodynamics': subsystem_options} - prob = AviaryProblem(ph_in, mission_method="FLOPS", mass_method="FLOPS") + prob = AviaryProblem() - prob.load_inputs(csv_path) + prob.load_inputs(csv_path, ph_in) prob.aviary_inputs.set_val(Aircraft.Design.LIFT_POLAR, np.zeros_like(CL), units='unitless') @@ -280,4 +281,4 @@ def build_pre_mission(self, aviary_inputs): if __name__ == "__main__": # unittest.main() test = TestSolvedAero() - test.test_solved_aero_pass_polar() + test.test_solved_aero_pass_polar_unique_abscissa() From db531411fd87295c9887810604ee2f5326da385f Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 11 Jan 2024 12:25:03 -0600 Subject: [PATCH 045/188] Fixed example --- aviary/examples/external_subsystems/battery/run_cruise.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/examples/external_subsystems/battery/run_cruise.py b/aviary/examples/external_subsystems/battery/run_cruise.py index 528493120..33e348fb8 100644 --- a/aviary/examples/external_subsystems/battery/run_cruise.py +++ b/aviary/examples/external_subsystems/battery/run_cruise.py @@ -16,7 +16,7 @@ # 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) +prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv', phase_info) prob.add_pre_mission_systems() From c9f956a978fb4e254024ba12b7d8933f2b1f9e92 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 11 Jan 2024 13:58:43 -0600 Subject: [PATCH 046/188] All tests, docs, and benches pass --- aviary/api.py | 4 +- ...oupled_aircraft_mission_optimization.ipynb | 7 - .../getting_started/onboarding_level1.ipynb | 2 +- .../getting_started/onboarding_level2.ipynb | 14 +- ..._same_mission_at_different_UI_levels.ipynb | 2 +- .../docs/user_guide/features/overriding.ipynb | 2 +- .../battery/run_multiphase_mission.py | 2 +- aviary/interface/methods_for_level2.py | 7 +- aviary/interface/test/test_basic_report.py | 2 +- .../interface/test/test_check_phase_info.py | 12 +- aviary/interface/test/test_phase_info.py | 4 +- aviary/interface/test/test_reserve_support.py | 2 +- aviary/interface/utils/check_phase_info.py | 66 +--- .../flops_based/ode/test/test_landing_ode.py | 2 +- .../flops_based/ode/test/test_takeoff_ode.py | 2 +- .../test_bench_climb_large_single_aisle_1.py | 260 ------------- .../test_bench_climb_large_single_aisle_2.py | 366 ------------------ ...bench_cruise_climb_large_single_aisle_1.py | 316 --------------- .../test_bench_cruise_large_single_aisle_1.py | 253 ------------ .../test_bench_cruise_large_single_aisle_2.py | 247 ------------ ...test_bench_descent_large_single_aisle_1.py | 255 ------------ ...test_bench_descent_large_single_aisle_2.py | 256 ------------ .../phases/run_phases/run_ascent.py | 2 +- aviary/models/N3CC/N3CC_data.py | 4 +- ...N3CC_generic_low_speed_polars_FLOPSinp.csv | 2 +- .../large_single_aisle_1_FLOPS_data.py | 2 +- .../large_single_aisle_2_FLOPS_data.py | 2 +- .../large_single_aisle_2_altwt_FLOPS_data.py | 2 +- ...ge_single_aisle_2_detailwing_FLOPS_data.py | 2 +- .../test_aircraft/aircraft_for_bench_FwFm.csv | 2 +- .../test_aircraft/aircraft_for_bench_GwFm.csv | 2 +- .../test/test_computed_aero_group.py | 2 +- .../test/test_solved_aero_group.py | 3 +- .../test/test_tabular_aero_group.py | 2 +- .../test/test_flops_based_premission.py | 2 +- aviary/utils/Fortran_to_Aviary.py | 2 +- .../benchmark_tests/test_0_iters.py | 6 +- .../test_FLOPS_balanced_field_length.py | 2 +- .../test_FLOPS_based_sizing_N3CC.py | 2 +- .../test_FLOPS_detailed_landing.py | 2 +- .../test_FLOPS_detailed_takeoff.py | 2 +- .../benchmark_tests/test_bench_FwFm.py | 3 - aviary/variable_info/enums.py | 1 - 43 files changed, 68 insertions(+), 2064 deletions(-) delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py delete mode 100644 aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py diff --git a/aviary/api.py b/aviary/api.py index 0f86edfb9..d86b1158f 100644 --- a/aviary/api.py +++ b/aviary/api.py @@ -32,7 +32,7 @@ from aviary.utils.data_interpolator_builder import build_data_interpolator from aviary.variable_info.enums import AlphaModes, AnalysisScheme, ProblemType, SpeedType, GASPEngineType, FlapType, EquationsOfMotion, LegacyCode, Verbosity from aviary.interface.default_phase_info.two_dof import phase_info as default_2DOF_phase_info -from aviary.interface.default_phase_info.height_energy import phase_info as default_height_energy_phase_info +from aviary.interface.default_phase_info.simple import phase_info as default_simple_phase_info from aviary.interface.default_phase_info.two_dof_fiti import create_2dof_based_ascent_phases, create_2dof_based_descent_phases from aviary.interface.default_phase_info.solved import phase_info as default_solved_phase_info from aviary.interface.default_phase_info.simple import phase_info as default_simple_phase_info @@ -46,7 +46,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.interface.default_phase_info.simple import default_premission_subsystems, default_mission_subsystems ################### # Level 3 Imports # diff --git a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb index 631f5fe37..68344b92a 100644 --- a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb +++ b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb @@ -126,13 +126,6 @@ "}" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, { "cell_type": "markdown", "metadata": {}, diff --git a/aviary/docs/getting_started/onboarding_level1.ipynb b/aviary/docs/getting_started/onboarding_level1.ipynb index 62fff50a8..853ed37e9 100644 --- a/aviary/docs/getting_started/onboarding_level1.ipynb +++ b/aviary/docs/getting_started/onboarding_level1.ipynb @@ -253,7 +253,7 @@ " - `mission:objectives:fuel` if `mission_method` is `GASP` \n", " - `fuel_burned` if `mission_method` is `FLOPS`.\n", "\n", - "- `--phase_info`: Path to phase info file. If not provided, it is `default_phase_info/gasp.py` if Mission origin is `2DOF` and `default_phase_info/flops.py` for `height_energy`.\n", + "- `--phase_info`: Path to phase info file. If not provided, it is `default_phase_info/gasp.py` if Mission origin is `2DOF` and `default_phase_info/flops.py` for `simple`.\n", "\n", "- `--n2`: Generate an n2 diagram after the analysis. “[N2](https://openmdao.org/newdocs/versions/latest/features/model_visualization/n2_basics/n2_basics.html)” diagram is an OpenMDAO helper to visualize the model (see [details](https://openmdao.org/newdocs/versions/latest/features/model_visualization/n2_details/n2_details.html) too and [tutorial](https://www.youtube.com/watch?v=42VtbX6CX3A)). It is highly recommended that this option is turned on for new users.\n", "\n", diff --git a/aviary/docs/getting_started/onboarding_level2.ipynb b/aviary/docs/getting_started/onboarding_level2.ipynb index a4ab72b3a..30d1e1c7c 100644 --- a/aviary/docs/getting_started/onboarding_level2.ipynb +++ b/aviary/docs/getting_started/onboarding_level2.ipynb @@ -271,7 +271,7 @@ "source": [ "This call adds a pre-mission group (also called static analysis group) which includes pre-mission propulsion, geometry, pre-mission aerodynamics, and mass subsystems. \n", "\n", - "For `height_energy` missions, aviary currently models FLOPS' \"simplified\" takeoff as defined in [mission/flops_based/phases/simplified_takeoff.py](https://github.com/OpenMDAO/Aviary/blob/main/aviary/mission/flops_based/phases/simplified_takeoff.py).\n", + "For `simple` missions, aviary currently models FLOPS' \"simplified\" takeoff as defined in [mission/flops_based/phases/simplified_takeoff.py](https://github.com/OpenMDAO/Aviary/blob/main/aviary/mission/flops_based/phases/simplified_takeoff.py).\n", "\n", "Next is the line" ] @@ -295,7 +295,7 @@ "id": "f9f50477", "metadata": {}, "source": [ - "which adds a sequence of core mission phases. In addition, if `mission_method` is `2dof` and `ascent` is a phase, it adds an equality constraint to the problem to ensure that the TAS at the end of the groundroll phase is equal to the rotation velocity at the start of the rotation phase (`_add_groundroll_eq_constraint(phase)`). If `mission_method` is `height_energy`, it sets up trajectory parameters by calling `setup_trajectory_params()`. If `mission_method` is `solved`, it has a block of code to make sure that the trajectory is smooth by applying boundary constraints between phases (e.g. fuselage pitch angle or true airspeed).\n", + "which adds a sequence of core mission phases. In addition, if `mission_method` is `2dof` and `ascent` is a phase, it adds an equality constraint to the problem to ensure that the TAS at the end of the groundroll phase is equal to the rotation velocity at the start of the rotation phase (`_add_groundroll_eq_constraint(phase)`). If `mission_method` is `simple`, it sets up trajectory parameters by calling `setup_trajectory_params()`. If `mission_method` is `solved`, it has a block of code to make sure that the trajectory is smooth by applying boundary constraints between phases (e.g. fuselage pitch angle or true airspeed).\n", "\n", "It follows by adding post-mission subsystems:" ] @@ -315,7 +315,7 @@ "id": "0c8038df", "metadata": {}, "source": [ - "Similar to pre-mission, it adds a landing phase if `include_landing` key of `post_mission` has value of `True`. If user chooses to define a `post_mission`, it will override the default. For `2dof` missions, landing is defined in [mission/gasp_based/phases/landing_group.py](https://github.com/OpenMDAO/Aviary/blob/main/aviary/mission/gasp_based/phases/landing_group.py). For `height_energy` mission, landing means a [simplified landing](https://github.com/OpenMDAO/Aviary/blob/main/aviary/mission/flops_based/phases/simplified_landing.py). Note that the `solved` method currently doesn't have any post mission systems.\n", + "Similar to pre-mission, it adds a landing phase if `include_landing` key of `post_mission` has value of `True`. If user chooses to define a `post_mission`, it will override the default. For `2dof` missions, landing is defined in [mission/gasp_based/phases/landing_group.py](https://github.com/OpenMDAO/Aviary/blob/main/aviary/mission/gasp_based/phases/landing_group.py). For `simple` mission, landing means a [simplified landing](https://github.com/OpenMDAO/Aviary/blob/main/aviary/mission/flops_based/phases/simplified_landing.py). Note that the `solved` method currently doesn't have any post mission systems.\n", "\n", "The next line is" ] @@ -337,7 +337,7 @@ "source": [ "This is important for allowing each phase of flight to pass to the next without discontinuities in the parameters. Consider Dymos' [Aircraft Balanced Field Length Calculation](https://openmdao.github.io/dymos/examples/balanced_field/balanced_field.html) example. In that example, we see separate nonlinear boundary constraints, nonlinear path constraints, and phase continuity constraints between phases. We don't want to go deeper in this function call, but just point out that each individual link can be set via dymos function `link_phases`. See [dymos API](https://openmdao.github.io/dymos/api/trajectory_api.html) for more details.\n", "\n", - "The code blocks in this function (namely, `link_phases()`) are for `2DOF`, `height_energy`, and `solved` missions. The links are set up based on physical principals (e.g. you can’t have instantaneous changes in mass, velocity, position etc.). Special care is required if the user selects a different or unusual set of phases. \n", + "The code blocks in this function (namely, `link_phases()`) are for `2DOF`, `simple`, and `solved` missions. The links are set up based on physical principals (e.g. you can’t have instantaneous changes in mass, velocity, position etc.). Special care is required if the user selects a different or unusual set of phases. \n", "\n", "Now, our aircraft and the mission are fully defined. We are ready to define an optimization problem. This is achieved by adding an optimization driver, adding design variables, and an objective. \n", "\n", @@ -513,7 +513,7 @@ "id": "57986647", "metadata": {}, "source": [ - "For `height_energy` and `2DOF` missions, this method performs several calls to `set_val` on the trajectory for states and controls to seed the problem with reasonable initial guesses using `initial_guesses` within corresponding phases (e.g. `default_flops_phases.py` and `default_gasp_phases.py`). For `solved` missions, it performs similar tasks but for hard-coded state parameters. This is reasonable because a `solved` mission is actually a level 3 Aviary approach. We will cover it in [level 3 onboarding doc](onboarding_level3.ipynb) in the next page. Note that initial guesses for all phases are especially important for collocation methods.\n", + "For `simple` and `2DOF` missions, this method performs several calls to `set_val` on the trajectory for states and controls to seed the problem with reasonable initial guesses using `initial_guesses` within corresponding phases (e.g. `default_flops_phases.py` and `default_gasp_phases.py`). For `solved` missions, it performs similar tasks but for hard-coded state parameters. This is reasonable because a `solved` mission is actually a level 3 Aviary approach. We will cover it in [level 3 onboarding doc](onboarding_level3.ipynb) in the next page. Note that initial guesses for all phases are especially important for collocation methods.\n", "\n", "The last line is to run the problem we just set up:" ] @@ -900,11 +900,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", -<<<<<<< HEAD - "version": "3.8.17" -======= "version": "3.10.8" ->>>>>>> 2113a7d9123975bb9ffc0a754f7028b99da3f8d4 } }, "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 9a20fd22f..ca898b0e2 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 @@ -32,7 +32,7 @@ "import aviary.api as av\n", "\n", "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',\n", - " av.default_height_energy_phase_info,\n", + " av.default_simple_phase_info,\n", " max_iter=0, optimizer=\"SLSQP\", make_plots=False)" ] }, diff --git a/aviary/docs/user_guide/features/overriding.ipynb b/aviary/docs/user_guide/features/overriding.ipynb index e7f81401d..1b0109ff7 100644 --- a/aviary/docs/user_guide/features/overriding.ipynb +++ b/aviary/docs/user_guide/features/overriding.ipynb @@ -117,7 +117,7 @@ " return wing_group\n", "\n", "\n", - "from aviary.api import default_height_energy_phase_info as phase_info \n", + "from aviary.api import default_simple_phase_info as phase_info \n", "phase_info['pre_mission']['external_subsystems'] = [HTailWeightBuilder(name=\"tail_external\")]\n" ] }, diff --git a/aviary/examples/external_subsystems/battery/run_multiphase_mission.py b/aviary/examples/external_subsystems/battery/run_multiphase_mission.py index 1cae165e9..37fd5936a 100644 --- a/aviary/examples/external_subsystems/battery/run_multiphase_mission.py +++ b/aviary/examples/external_subsystems/battery/run_multiphase_mission.py @@ -4,7 +4,7 @@ from aviary.examples.external_subsystems.battery.battery_builder import BatteryBuilder from aviary.examples.external_subsystems.battery.battery_variables import Aircraft -from aviary.api import default_height_energy_phase_info as phase_info +from aviary.api import default_simple_phase_info as phase_info battery_builder = BatteryBuilder(include_constraints=False) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 5781675b4..1c2084bc6 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -66,7 +66,6 @@ FLOPS = LegacyCode.FLOPS GASP = LegacyCode.GASP -HEIGHT_ENERGY = EquationsOfMotion.HEIGHT_ENERGY TWO_DEGREES_OF_FREEDOM = EquationsOfMotion.TWO_DEGREES_OF_FREEDOM SIMPLE = EquationsOfMotion.SIMPLE SOLVED = EquationsOfMotion.SOLVED @@ -207,8 +206,6 @@ def load_inputs(self, input_filename, phase_info=None, engine_builder=None): else: if self.mission_method is TWO_DEGREES_OF_FREEDOM: from aviary.interface.default_phase_info.two_dof import phase_info - elif self.mission_method is HEIGHT_ENERGY: - from aviary.interface.default_phase_info.height_energy import phase_info elif self.mission_method is SIMPLE: from aviary.interface.default_phase_info.simple import phase_info elif self.mission_method is SOLVED: @@ -695,7 +692,7 @@ def _add_groundroll_eq_constraint(self, phase): promotes_inputs=["t_init_gear", "t_init_flaps"], ) - def _get_height_energy_phase(self, phase_name, phase_idx): + def _get_simple_phase(self, phase_name, phase_idx): base_phase_options = self.phase_info[phase_name] fix_duration = base_phase_options['user_options']['fix_duration'] @@ -1057,7 +1054,7 @@ def add_subsystem_timeseries_outputs(phase, phase_name): elif self.mission_method is SIMPLE: for phase_idx, phase_name in enumerate(phases): phase = traj.add_phase( - phase_name, self._get_height_energy_phase(phase_name, phase_idx)) + phase_name, self._get_simple_phase(phase_name, phase_idx)) add_subsystem_timeseries_outputs(phase, phase_name) # loop through phase_info and external subsystems diff --git a/aviary/interface/test/test_basic_report.py b/aviary/interface/test/test_basic_report.py index 01b166d9f..02d2ddc25 100644 --- a/aviary/interface/test/test_basic_report.py +++ b/aviary/interface/test/test_basic_report.py @@ -5,7 +5,7 @@ from openmdao.utils.testing_utils import use_tempdirs -from aviary.interface.default_phase_info.height_energy import phase_info +from aviary.interface.default_phase_info.simple import phase_info from aviary.interface.methods_for_level1 import run_aviary from openmdao.utils.testing_utils import use_tempdirs diff --git a/aviary/interface/test/test_check_phase_info.py b/aviary/interface/test/test_check_phase_info.py index 1c0cf7fde..593d80cb5 100644 --- a/aviary/interface/test/test_check_phase_info.py +++ b/aviary/interface/test/test_check_phase_info.py @@ -2,25 +2,25 @@ import copy from aviary.interface.utils.check_phase_info import check_phase_info -from aviary.interface.default_phase_info.height_energy import phase_info as phase_info_flops +from aviary.interface.default_phase_info.simple import phase_info as phase_info_flops from aviary.interface.default_phase_info.two_dof import phase_info as phase_info_gasp from aviary.variable_info.enums import EquationsOfMotion -HEIGHT_ENERGY = EquationsOfMotion.HEIGHT_ENERGY +SIMPLE = EquationsOfMotion.SIMPLE TWO_DEGREES_OF_FREEDOM = EquationsOfMotion.TWO_DEGREES_OF_FREEDOM class TestCheckInputs(unittest.TestCase): - def test_correct_input_flops(self): + def test_correct_input_simple(self): # This should pass without any issue as it's the same valid dict as before - self.assertTrue(check_phase_info(phase_info_flops, mission_method=HEIGHT_ENERGY)) + self.assertTrue(check_phase_info(phase_info_flops, mission_method=SIMPLE)) def test_incorrect_tuple(self): # Let's replace a tuple with a float in the 'climb' phase incorrect_tuple_phase_info = copy.deepcopy(phase_info_flops) incorrect_tuple_phase_info['climb']['user_options']['initial_altitude'] = 10.668e3 with self.assertRaises(ValueError): - check_phase_info(incorrect_tuple_phase_info, mission_method=HEIGHT_ENERGY) + check_phase_info(incorrect_tuple_phase_info, mission_method=SIMPLE) def test_incorrect_unit(self): # Let's replace a valid unit with an invalid one in the 'climb' phase @@ -29,7 +29,7 @@ def test_incorrect_unit(self): 10.668e3, 'invalid_unit') with self.assertRaisesRegex(ValueError, "Key initial_altitude in phase climb has an invalid unit invalid_unit."): - check_phase_info(incorrect_unit_phase_info, mission_method=HEIGHT_ENERGY) + check_phase_info(incorrect_unit_phase_info, mission_method=SIMPLE) def test_correct_input_gasp(self): # This should pass without any issue as it's the same valid dict as before diff --git a/aviary/interface/test/test_phase_info.py b/aviary/interface/test/test_phase_info.py index 18cf60784..ffefec9ae 100644 --- a/aviary/interface/test/test_phase_info.py +++ b/aviary/interface/test/test_phase_info.py @@ -7,8 +7,8 @@ from openmdao.utils.assert_utils import assert_near_equal -from aviary.interface.default_phase_info.gasp import phase_info as ph_in_gasp -from aviary.interface.default_phase_info.gasp import phase_info_parameterization as phase_info_parameterization_gasp +from aviary.interface.default_phase_info.two_dof import phase_info as ph_in_gasp +from aviary.interface.default_phase_info.two_dof import phase_info_parameterization as phase_info_parameterization_gasp from aviary.interface.methods_for_level2 import AviaryProblem from aviary.mission.flops_based.phases.phase_builder_base import \ diff --git a/aviary/interface/test/test_reserve_support.py b/aviary/interface/test/test_reserve_support.py index 928f6217d..0b6e3e2cf 100644 --- a/aviary/interface/test/test_reserve_support.py +++ b/aviary/interface/test/test_reserve_support.py @@ -6,7 +6,7 @@ from aviary.interface.methods_for_level2 import AviaryProblem from aviary.interface.default_phase_info.simple import phase_info as ph_in_flops -from aviary.interface.default_phase_info.gasp import phase_info as ph_in_gasp +from aviary.interface.default_phase_info.two_dof import phase_info as ph_in_gasp from aviary.variable_info.variables import Aircraft, Mission diff --git a/aviary/interface/utils/check_phase_info.py b/aviary/interface/utils/check_phase_info.py index cc40add8b..ecd21875c 100644 --- a/aviary/interface/utils/check_phase_info.py +++ b/aviary/interface/utils/check_phase_info.py @@ -1,7 +1,6 @@ from openmdao.utils.units import valid_units from aviary.variable_info.enums import SpeedType, EquationsOfMotion -HEIGHT_ENERGY = EquationsOfMotion.HEIGHT_ENERGY TWO_DEGREES_OF_FREEDOM = EquationsOfMotion.TWO_DEGREES_OF_FREEDOM SIMPLE = EquationsOfMotion.SIMPLE SOLVED = EquationsOfMotion.SOLVED @@ -17,48 +16,25 @@ def check_phase_info(phase_info, mission_method): # Common key-values for climb, cruise, and descent common_entries = { - 'initial_ref': tuple, - 'initial_bounds': tuple, - 'duration_ref': tuple, - 'duration_bounds': tuple, - } - - # Phase-specific entries - climb_specific = { - 'input_initial': bool, - 'no_descent': bool, - 'initial_mach': float, - 'initial_altitude': tuple, - 'final_altitude': tuple, - 'final_mach': float, - 'fix_range': bool, - 'fix_initial_time': bool, - } - - cruise_specific = { - 'min_mach': float, - 'max_mach': float, - 'required_available_climb_rate': tuple, - 'mass_f_cruise': tuple, - 'range_f_cruise': tuple, - 'fix_final': bool, - } - - descent_specific = { + 'optimize_mach': bool, + 'optimize_altitude': bool, + 'solve_for_range': bool, + 'initial_mach': tuple, + 'final_mach': tuple, + 'mach_bounds': tuple, 'initial_altitude': tuple, 'final_altitude': tuple, - 'initial_mach': float, - 'final_mach': float, - 'no_climb': bool, - 'fix_range': bool, + 'altitude_bounds': tuple, + 'throttle_enforcement': str, + 'constrain_final': bool, + 'fix_duration': bool, + 'initial_bounds': tuple, + 'duration_bounds': tuple, } # Combine common and phase-specific entries - phase_keys_flops = { + phase_keys_simple = { 'pre_mission': {'include_takeoff': bool, 'optimize_mass': bool}, - 'climb': {**common_entries, **climb_specific}, - 'cruise': {**common_entries, **cruise_specific}, - 'descent': {**common_entries, **descent_specific}, 'post_mission': {'include_landing': bool} } @@ -94,7 +70,7 @@ def check_phase_info(phase_info, mission_method): 'alt_ref': tuple, } common_descent = { - 'input_initial': bool, + 'input_initial': (bool, dict), 'EAS_limit': tuple, 'mach_cruise': float, 'input_speed_type': SpeedType, @@ -209,13 +185,7 @@ def check_phase_info(phase_info, mission_method): } phase_keys = {} - if mission_method is HEIGHT_ENERGY: - for phase in phase_info: - if phase != 'pre_mission' and phase != 'post_mission': - phase_keys[phase] = {**common_keys, **phase_keys_flops[phase]} - else: - phase_keys[phase] = phase_keys_flops[phase] - elif mission_method is TWO_DEGREES_OF_FREEDOM: + if mission_method is TWO_DEGREES_OF_FREEDOM: for phase in phase_info: if phase != 'pre_mission' and phase != 'post_mission' and phase != 'cruise': phase_keys[phase] = {**common_keys, **phase_keys_gasp[phase]} @@ -224,7 +194,11 @@ def check_phase_info(phase_info, mission_method): elif mission_method is SOLVED: return elif mission_method is SIMPLE: - return + for phase in phase_info: + if phase != 'pre_mission' and phase != 'post_mission': + phase_keys[phase] = {**common_keys, **common_entries} + else: + phase_keys[phase] = phase_keys_simple[phase] else: possible_values = ["'"+e.value+"'" for e in EquationsOfMotion] possible_values[-1] = "or " + possible_values[-1] 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 16e34c0f2..e3faf4747 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,7 @@ import openmdao.api as om -from aviary.interface.default_phase_info.height_energy import default_mission_subsystems +from aviary.interface.default_phase_info.simple import 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) 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 fd39339e5..ebcf3a092 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,7 @@ import openmdao.api as om -from aviary.interface.default_phase_info.height_energy import default_mission_subsystems +from aviary.interface.default_phase_info.simple import 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) diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py deleted file mode 100644 index 002760085..000000000 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py +++ /dev/null @@ -1,260 +0,0 @@ -''' -NOTES: -Includes: -Climb -Computed Aero -Large Single Aisle 1 data -CURRENTLY REMOVED FROM BENCHMARK TEST SUITE -''' - -import unittest - -import dymos as dm -# Suppress the annoying warnings from matplotlib when running dymos. -import matplotlib as mpl -import numpy as np -import openmdao.api as om -import scipy.constants as _units -from dymos.utils.testing_utils import assert_timeseries_near_equal -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.flops_based.ode.mission_ODE import MissionODE -from aviary.mission.flops_based.phases.climb_phase import Climb -from aviary.interface.default_phase_info.height_energy import prop, aero, geom -from aviary.subsystems.premission import CorePreMission -from aviary.utils.functions import set_aviary_initial_values -from aviary.validation_cases.validation_tests import get_flops_inputs -from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Dynamic - -mpl.rc('figure', max_open_warning=0) - -try: - import pyoptsparse -except ImportError: - pyoptsparse = None - - -''' -NOTE benchmark currently hits iteration limit - problem only converges when velocity ref & ref0 in energyphase is changed to 1e3. - Changing velocity ref breaks some full-mission benchmarks, so is currently not - implemented -''' -# benchmark based on Large Single Aisle 1 (fixed cruise alt) FLOPS model - - -def run_trajectory(): - prob = om.Problem(model=om.Group()) - - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 50 - driver.opt_settings["Major optimality tolerance"] = 1e-5 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-3 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - # TODO enable coloring once issue has been resolved: - # https://github.com/OpenMDAO/OpenMDAO/issues/2507 - # driver.declare_coloring() - - ########################## - # Problem Settings # - ########################## - alt_i_climb = 0*_units.foot # m - alt_f_climb = 35000.0*_units.foot # m - mass_i_climb = 180623*_units.lb # kg - mass_f_climb = 176765*_units.lb # kg - v_i_climb = 198.44*_units.knot # m/s - v_f_climb = 455.49*_units.knot # m/s - mach_i_climb = 0.3 - mach_f_climb = 0.79 - range_i_climb = 0*_units.nautical_mile # m - range_f_climb = 160.3*_units.nautical_mile # m - t_i_climb = 2 * _units.minute # sec - t_f_climb = 26.20*_units.minute # sec - t_duration_climb = t_f_climb - t_i_climb - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle1FLOPS') - - climb_options = Climb( - 'test_climb', - initial_altitude=alt_i_climb, - final_altitude=alt_f_climb, - no_descent=False, - # note, Mach = 0.0 causes an error in aero, perhaps in other code - initial_mach=mach_i_climb, - final_mach=mach_f_climb, - fix_initial=True, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - aviary_options=aviary_inputs, - ) - - # replace debug_no_mass flag with list of subsystem builders without mass - core_subsystems = [prop, geom, aero] - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'core_premission', - CorePreMission(aviary_options=aviary_inputs, subsystems=core_subsystems), - promotes_inputs=['aircraft:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - transcription = dm.Radau(num_segments=6, order=3, compressed=False) - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - climb = climb_options.build_phase(MissionODE, transcription) - - traj.add_phase('climb', climb) - - climb.add_objective('time', loc='final', ref=1e3) - # climb.add_objective(Dynamic.Mission.MASS, loc='final', ref=-1e4) - - climb.set_time_options( - fix_initial=True, fix_duration=False, units='s', - duration_bounds=(1, t_duration_climb*2), duration_ref=t_duration_climb) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - - prob.setup() - - prob.set_val('traj.climb.t_initial', t_i_climb, units='s') - prob.set_val('traj.climb.t_duration', t_duration_climb, units='s') - - prob.set_val('traj.climb.states:altitude', climb.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m') - prob.set_val('traj.climb.states:velocity', climb.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s') - prob.set_val('traj.climb.states:mass', climb.interp( - Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') - prob.set_val('traj.climb.states:range', climb.interp( - Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') - - prob.set_val('traj.climb.controls:velocity_rate', - climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.05]), - units='m/s**2') - prob.set_val('traj.climb.controls:throttle', - climb.interp(Dynamic.Mission.THROTTLE, ys=[0.5, 0.5]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=False, make_plots=False, - solution_record_file='climb_max.db') - prob.record("final") - prob.cleanup() - - return prob - - -@unittest.skip('benchmark_climb_large_single_aisle_1 currently broken') -class ClimbPhaseTestCase(unittest.TestCase): - def bench_test_climb_large_single_aisle_1(self): - - prob = run_trajectory() - - times = prob.get_val('traj.climb.timeseries.time', units='s') - altitudes = prob.get_val('traj.climb.timeseries.states:altitude', units='m') - masses = prob.get_val('traj.climb.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.climb.timeseries.states:range', units='m') - velocities = prob.get_val('traj.climb.timeseries.states:velocity', units='m/s') - thrusts = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N') - - expected_times_s = [ - [120.], [194.07139282], [296.27479672], [328.62182461], - [328.62182461], [402.69321743], [504.89662133], [537.24364922], - [537.24364922], [611.31504204], [713.51844594], [745.86547383], - [745.86547383], [819.93686665], [922.14027055], [954.48729844], - [954.48729844], [1028.55869126], [1130.76209516], [1163.10912305], - [1163.10912305], [1237.18051587], [1339.38391977], [1371.73094766]] - expected_altitudes_m = [ - [0.], [682.4957554], [2476.9915886], [3148.23528025], - [3148.23528025], [4477.82410739], [5953.00480303], [6351.40548265], - [6351.40548265], [7144.57711953], [8022.01978103], [8258.96785373], - [8258.96785373], [8740.86702454], [9286.23944667], [9434.70712276], - [9434.70712276], [9740.61479402], [10091.17192047], [10187.1054111], - [10187.1054111], [10383.06677812], [10606.85289388], [10668.]] - expected_masses_kg = [ - [81929.21464651], [81734.3159625], [81482.28032417], [81409.67409534], - [81409.67409534], [81261.52268984], [81089.79910736], [81041.35712905], - [81041.35712905], [80939.57475401], [80815.51316484], [80779.24867668], - [80779.24867668], [80700.64682801], [80600.66210256], [80570.67210015], - [80570.67210015], [80504.18318007], [80416.95604372], [80390.28585848], - [80390.28585848], [80330.69704984], [80251.40682218], [80226.91650584]] - expected_ranges_m = [ - [0.], [11134.82482615], [33305.36225275], [40552.08037408], - [40552.08037408], [57694.75967874], [81567.92031544], [89129.68416299], - [89129.68416299], [106463.26453256], [130389.14274257], [137962.93786], - [137962.93786], [155308.03326502], [179243.7729914], [186819.85564691], - [186819.85564691], [204168.96379317], [228108.3526042], [235685.29047396], - [235685.29047396], [253035.99320713], [276976.90557005], [284554.20584747]] - expected_velocities_ms = [ - [102.08605905], [190.58935413], [228.38194188], [230.69562115], - [230.69562115], [233.30227629], [234.24467254], [234.25795132], - [234.25795132], [234.25795132], [234.25795132], [234.25795132], - [234.25795132], [234.25795132], [234.25795132], [234.25795132], - [234.25795132], [234.25795132], [234.25795132], [234.25795132], - [234.25795132], [234.25795132], [234.25795132], [234.25795132]] - expected_thrusts_N = [ - [218457.50162414], [171332.33326933], [141120.77188326], [131766.72736631], - [131766.72736631], [112828.24508393], [94178.64187388], [89529.25529378], - [89529.25529378], [80383.22196309], [71047.86501907], [68765.74648505], - [68765.74648505], [64112.90745184], [59068.27795964], [57877.0412593], - [57877.0412593], [55418.69760271], [52595.0053262], [51821.03735429], - [51821.03735429], [50238.39534494], [48428.26539664], [47933.1465328]] - expected_times_s = np.array(expected_times_s) - expected_altitudes_m = np.array(expected_altitudes_m) - expected_masses_kg = np.array(expected_masses_kg) - expected_ranges_m = np.array(expected_ranges_m) - expected_velocities_ms = np.array(expected_velocities_ms) - expected_thrusts_N = np.array(expected_thrusts_N) - - # NOTE rtol = 0.01 = 1% different from truth (first timeseries) - # atol = 1 = no more than +/-1 meter difference between values - atol = 1e-2 - rtol = 1e-3 - - # Objective - assert_near_equal(times[-1], expected_times_s[-1], tolerance=rtol) - - # Flight path - - assert_timeseries_near_equal( - expected_times_s, expected_masses_kg, times, masses, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_ranges_m, times, ranges, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_velocities_ms, times, velocities, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_thrusts_N, times, thrusts, - abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py deleted file mode 100644 index f03466f7f..000000000 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py +++ /dev/null @@ -1,366 +0,0 @@ -''' -NOTES: -Includes: -Climb -Computed Aero -Large Single Aisle 2 data -''' - -import unittest - -import dymos as dm -# Suppress the annoying warnings from matplotlib when running dymos. -import matplotlib as mpl -import numpy as np -import openmdao.api as om -import scipy.constants as _units - -from dymos.utils.testing_utils import assert_timeseries_near_equal -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import use_tempdirs -from packaging import version -from aviary.variable_info.variables_in import VariablesIn - -from aviary.utils.aviary_values import AviaryValues -from aviary.mission.flops_based.phases.climb_phase import Climb -from aviary.interface.default_phase_info.height_energy import prop, aero, geom -from aviary.subsystems.premission import CorePreMission -from aviary.utils.functions import set_aviary_initial_values -from aviary.validation_cases.validation_tests import get_flops_inputs -from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Dynamic - -mpl.rc('figure', max_open_warning=0) - -try: - import pyoptsparse -except ImportError: - pyoptsparse = None - - -def run_trajectory(): - prob = om.Problem(model=om.Group()) - - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 40 - driver.opt_settings["Major optimality tolerance"] = 1e-5 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-3 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - # TODO enable coloring once issue has been resolved: - # https://github.com/OpenMDAO/OpenMDAO/issues/2507 - # driver.declare_coloring() - - ########################## - # Problem Settings # - ########################## - alt_i_climb = 35 * _units.foot # m - alt_f_climb = 35000.0 * _units.foot # m - mass_i_climb = 169172 * _units.lb # kg - mass_f_climb = 164160 * _units.lb # kg - v_i_climb = 198.44 * _units.knot # m/s - v_f_climb = 452.61 * _units.knot # m/s - mach_i_climb = 0.3 - mach_f_climb = 0.775 - range_i_climb = 0 * _units.nautical_mile # m - range_f_climb = 124 * _units.nautical_mile # m - t_i_climb = 0 - t_f_climb = 20.14 * _units.minute # sec - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle2FLOPS') - transcription = dm.Radau(num_segments=6, order=3, compressed=False) - climb_options = Climb( - 'test_climb', - user_options=AviaryValues({ - 'initial_altitude': (alt_i_climb, 'm'), - 'final_altitude': (alt_f_climb, 'm'), - 'initial_mach': (mach_i_climb, 'unitless'), - 'final_mach': (mach_f_climb, 'unitless'), - 'fix_initial': (True, 'unitless'), - 'fix_range': (False, 'unitless'), - 'input_initial': (False, 'unitless'), - }), - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - core_subsystems=[aero, prop], - transcription=transcription, - ) - - # replace debug_no_mass flag with list of subsystem builders without mass - core_subsystems = [prop, geom, aero] - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'core_premission', - CorePreMission(aviary_options=aviary_inputs, subsystems=core_subsystems), - promotes_inputs=['aircraft:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - climb = climb_options.build_phase(aviary_options=aviary_inputs) - - traj.add_phase('climb', climb) - - climb.timeseries_options['use_prefix'] = True - - climb.add_objective('time', loc='final', ref=t_f_climb) - - climb.set_time_options( - fix_initial=True, fix_duration=False, units='s', - duration_bounds=(t_f_climb * 0.5, t_f_climb * 2), duration_ref=t_f_climb) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs, phases=['climb']) - - prob.model.add_subsystem( - 'input_sink', - VariablesIn(aviary_options=aviary_inputs), - promotes_inputs=['*'], - promotes_outputs=['*'] - ) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - - prob.setup() - - prob.set_val('traj.climb.t_initial', t_i_climb, units='s') - prob.set_val('traj.climb.t_duration', t_f_climb, units='s') - - prob.set_val('traj.climb.states:altitude', climb.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m') - prob.set_val('traj.climb.states:velocity', climb.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s') - prob.set_val('traj.climb.states:mass', climb.interp( - Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') - prob.set_val('traj.climb.states:range', climb.interp( - Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') # nmi - - prob.set_val('traj.climb.controls:velocity_rate', - climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.05]), - units='m/s**2') - prob.set_val('traj.climb.controls:throttle', - climb.interp(Dynamic.Mission.THROTTLE, ys=[0.5, 0.5]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=False, make_plots=False, - solution_record_file='climb_large_single_aisle_2.db') - prob.record("final") - prob.cleanup() - - return prob - - -@use_tempdirs -class ClimbPhaseTestCase(unittest.TestCase): - def bench_test_climb_large_single_aisle_2(self): - - prob = run_trajectory() - - times = prob.get_val('traj.climb.timeseries.time', units='s') - altitudes = prob.get_val('traj.climb.timeseries.states:altitude', units='m') - masses = prob.get_val('traj.climb.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.climb.timeseries.states:range', units='m') - velocities = prob.get_val('traj.climb.timeseries.states:velocity', units='m/s') - thrusts = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N') - - expected_times_s = [[0.], - [47.24020828], - [112.42205385], - [133.05188512], - [133.05188512], - [180.2920934], - [245.47393897], - [266.10377023], - [266.10377023], - [313.34397852], - [378.52582409], - [399.15565535], - [399.15565535], - [446.39586363], - [511.5777092], - [532.20754047], - [532.20754047], - [579.44774875], - [644.62959432], - [665.25942558], - [665.25942558], - [712.49963387], - [777.68147944], - [798.3113107]] - expected_altitudes_m = [[1.06680000e+01], - [1.64717443e+02], - [1.21077165e+03], - [1.65467452e+03], - [1.65467452e+03], - [2.63158548e+03], - [3.89195114e+03], - [4.26784031e+03], - [4.26784031e+03], - [5.08501440e+03], - [6.12319963e+03], - [6.43302565e+03], - [6.43302565e+03], - [7.11281142e+03], - [7.98114971e+03], - [8.23811059e+03], - [8.23811059e+03], - [8.78587957e+03], - [9.45185516e+03], - [9.64164118e+03], - [9.64164118e+03], - [1.00442465e+04], - [1.05301137e+04], - [1.06680000e+04]] - expected_masses_kg = [[76735.12841764], - [76606.6291851], - [76423.55875817], - [76369.21098493], - [76369.21098493], - [76249.27821197], - [76096.52180626], - [76051.03001076], - [76051.03001076], - [75951.61028918], - [75824.47689696], - [75786.47518169], - [75786.47518169], - [75703.26334226], - [75596.63038983], - [75564.65308165], - [75564.65308165], - [75493.66861479], - [75400.85356264], - [75372.67886333], - [75372.67886333], - [75310.24572772], - [75228.35359487], - [75203.34794937]] - expected_ranges_m = [[0.], - [6656.35106052], - [19411.34037117], - [23606.44276229], - [23606.44276229], - [33597.9222712], - [47757.51502804], - [52308.8364503], - [52308.8364503], - [62843.02681099], - [77579.88662088], - [82280.86896803], - [82280.86896803], - [93082.94529627], - [108032.30577631], - [112765.20449737], - [112765.20449737], - [123607.6358803], - [138572.23956024], - [143309.37828794], - [143309.37828794], - [154158.17439593], - [169129.72020176], - [173868.65393385]] - expected_velocities_ms = [[102.08635556], - [173.4078533], - [206.56979636], - [209.71234319], - [209.71234319], - [215.12096513], - [220.69657248], - [222.14669648], - [222.14669648], - [225.06833215], - [228.02045426], - [228.64470582], - [228.64470582], - [229.49739505], - [229.80567178], - [229.81001554], - [229.81001554], - [229.81001554], - [229.81001554], - [229.81001554], - [229.81001554], - [229.81001554], - [229.81001554], - [229.81001554]] - expected_thrusts_N = [[183100.97258682], - [163996.9938714], - [144753.36497874], - [140427.87965941], - [140427.87965941], - [131136.19372391], - [119398.47487166], - [115939.50935006], - [115939.50935006], - [108449.59352749], - [99269.67371293], - [96533.89180294], - [96533.89180294], - [90902.4892038], - [84031.52375462], - [81889.41102505], - [81889.41102505], - [77138.3352612], - [71330.53467419], - [69720.96587699], - [69720.96587699], - [66405.48655242], - [62587.8225939], - [61541.80174696]] - - expected_times_s = np.array(expected_times_s) - expected_altitudes_m = np.array(expected_altitudes_m) - expected_masses_kg = np.array(expected_masses_kg) - expected_ranges_m = np.array(expected_ranges_m) - expected_velocities_ms = np.array(expected_velocities_ms) - expected_thrusts_N = np.array(expected_thrusts_N) - - # NOTE rtol = 0.01 = 1% different from truth (first timeseries) - # atol = 1 = no more than +/-1 meter difference between values - atol = 1e-2 - rtol = 1e-3 - - # Objective - assert_near_equal(times[-1], expected_times_s[-1], tolerance=rtol) - - # Flight path - assert_timeseries_near_equal( - expected_times_s, expected_masses_kg, times, masses, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_ranges_m, times, ranges, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_velocities_ms, times, velocities, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_thrusts_N, times, thrusts, - abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == "__main__": - test = ClimbPhaseTestCase() - test.bench_test_climb_large_single_aisle_2() diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py deleted file mode 100644 index c88f5dd8e..000000000 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py +++ /dev/null @@ -1,316 +0,0 @@ -############################################################### -# NOTES: -# Includes: -# Cruise -# Computed Aero -# Large Single Aisle 1 data -############################################################### -import unittest - -import dymos as dm -# Suppress the annoying warnings from matplotlib when running dymos. -import matplotlib as mpl -import numpy as np -import openmdao.api as om -import scipy.constants as _units - -from dymos.utils.testing_utils import assert_timeseries_near_equal -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.flops_based.ode.mission_ODE import MissionODE -from aviary.mission.flops_based.phases.cruise_phase import Cruise -from aviary.interface.default_phase_info.height_energy import prop, aero, geom -from aviary.subsystems.premission import CorePreMission -from aviary.utils.functions import set_aviary_initial_values -from aviary.utils.functions import get_path -from aviary.validation_cases.validation_tests import get_flops_inputs -from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Dynamic - -mpl.rc('figure', max_open_warning=0) - - -try: - import pyoptsparse -except ImportError: - pyoptsparse = None - - -# benchmark based on Large Single Aisle 1 (fixed cruise alt) FLOPS model - -def run_trajectory(): - prob = om.Problem(model=om.Group()) - - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 30 - driver.opt_settings["Major optimality tolerance"] = 1e-5 - driver.opt_settings["Major feasibility tolerance"] = 1e-5 - driver.opt_settings["iSumm"] = 6 - driver.opt_settings["Verify level"] = 3 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-6 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - # TODO enable coloring once issue has been resolved: - # https://github.com/OpenMDAO/OpenMDAO/issues/2507 - # driver.declare_coloring() - - ########################## - # Problem Settings # - ########################## - alt_min_cruise = 30000*_units.foot # m - alt_max_cruise = 36000*_units.foot # m - alt_i_cruise = alt_min_cruise - alt_f_cruise = 36000*_units.foot # m - mass_i_cruise = 176765*_units.lb # kg - mass_f_cruise = 143521*_units.lb # kg - velocity_i_cruise = 465.55*_units.knot # m/s - velocity_f_cruise = 465.55*_units.knot # m/s - mach_i_cruise = 0.79 - mach_f_cruise = 0.79 - mach_min_cruise = 0.78999 - mach_max_cruise = 0.79001 - range_i_cruise = 160.3*_units.nautical_mile # m - range_f_cruise = 3243.9*_units.nautical_mile # m - t_i_cruise = 26.20*_units.minute # sec - t_f_cruise = 432.38*_units.minute # sec - t_duration_cruise = t_f_cruise - t_i_cruise - - prob.set_solver_print(level=0) - - transcription = dm.Radau(num_segments=8, order=3, compressed=True) - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle1FLOPS') - # engine_models = aviary_inputs['engine_models'] - - cruise_options = Cruise( - 'test_cruise', - min_altitude=alt_min_cruise, # m - max_altitude=alt_max_cruise, # m - # note, Mach = 0.0 causes an error in aero, perhaps in other code - min_mach=mach_min_cruise, - max_mach=mach_max_cruise, - required_available_climb_rate=300*_units.foot/_units.minute, # ft/min to m/s - fix_initial=True, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - aviary_options=aviary_inputs, - # engine_models=engine_models, - no_descent=True, - velocity_f_cruise=velocity_f_cruise, - mass_f_cruise=mass_f_cruise, - range_f_cruise=range_f_cruise, - - ) - - # replace debug_no_mass flag with list of subsystem builders without mass - core_subsystems = [prop, geom, aero] - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'core_premission', - CorePreMission(aviary_options=aviary_inputs, subsystems=core_subsystems), - promotes_inputs=['aircraft:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - cruise = cruise_options.build_phase(MissionODE, transcription) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - traj.add_phase('cruise', cruise) - - cruise.set_time_options( - fix_initial=True, fix_duration=False, units='s', - duration_bounds=(1, t_duration_cruise*2), duration_ref=t_duration_cruise) - - cruise.add_objective(Dynamic.Mission.MASS, loc='final', ref=-mass_f_cruise) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - - # IVC = prob.model.add_subsystem('IVC', om.IndepVarComp(), promotes_outputs=['*']) - # IVC.add_output('alt_i', val=32000, units='ft') - prob.model.add_constraint( - 'traj.cruise.states:altitude', - indices=[0], equals=alt_min_cruise, units='m', ref=alt_max_cruise) - - # Alternative implmentation of above - # holds the first node in altitude constant - # cruise.set_state_options(Dynamic.Mission.ALTITUDE, fix_initial=True) - - prob.setup() - - prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s') - prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s') - - prob.set_val( - 'traj.cruise.states:altitude', cruise.interp( - Dynamic.Mission.ALTITUDE, ys=[ - alt_i_cruise, (alt_f_cruise + alt_i_cruise) / 2]), units='m') - prob.set_val( - 'traj.cruise.states:velocity', cruise.interp( - Dynamic.Mission.VELOCITY, ys=[ - velocity_i_cruise, velocity_f_cruise]), units='m/s') - prob.set_val('traj.cruise.states:mass', cruise.interp( - Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi - - prob.set_val('traj.cruise.controls:velocity_rate', - cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), - units='m/s**2') - prob.set_val('traj.cruise.controls:throttle', - cruise.interp(Dynamic.Mission.THROTTLE, ys=[0.5, 0.5]), - units='unitless') - - dm.run_problem(prob, simulate=False, make_plots=False, - solution_record_file='cruise_climb_max.db') - # TODO Simulate=True is crashing here so turned it off - - prob.cleanup() - prob.record("final") - - return prob - - -@unittest.skip('benchmark cruise climb currently broken') -class CruisePhaseTestCase(unittest.TestCase): - def bench_test_cruise_climb_large_single_aisle_1(self): - - prob = run_trajectory() - - times = prob.get_val('traj.cruise.timeseries.time', units='s') - altitudes = prob.get_val('traj.cruise.timeseries.states:altitude', units='m') - masses = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.cruise.timeseries.states:range', units='m') - velocities = prob.get_val('traj.cruise.timeseries.states:velocity', units='m/s') - thrusts = prob.get_val('traj.cruise.timeseries.thrust_net_total', units='N') - - expected_times_s = [ - [1572.0], [2654.1067424751645], [4147.193185981006], - [4619.749940380141], [4619.749940380141], [5701.856682855307], - [7194.943126361148], [7667.499880760283], [7667.499880760283], - [8749.606623235448], [10242.693066741289], [10715.249821140425], - [10715.249821140425], [11797.356563615589], [13290.44300712143], - [13762.999761520567], [13762.999761520567], [14845.106503995732], - [16338.192947501573], [16810.749701900706], [16810.749701900706], - [17892.856444375873], [19385.942887881713], [19858.49964228085], - [19858.49964228085], [20940.606384756014], [22433.692828261857], - [22906.249582660992], [22906.249582660992], [23988.356325136156], - [25481.442768642], [25953.999523041133]] - expected_altitudes_m = [ - [9143.999999999998], [9708.208298692567], [10127.822388940609], - [10214.217379879337], [10214.217379879337], [10369.633608560018], - [10522.493213427248], [10561.102831034279], [10561.102831034279], - [10628.89921313077], [10700.84689461149], [10720.94842484514], - [10720.94842484514], [10759.7268947497], [10811.373374694173], - [10828.933975559758], [10828.933975559758], [10866.85055516194], - [10912.976573928156], [10924.787065056735], [10924.787065056735], - [10948.28098891448], [10967.163582971652], [10969.578328436102], - [10969.578328436102], [10971.188528219269], [10971.305320817934], - [10972.40306787028], [10972.40306787028], [10972.800000000001], - [10972.682828875833], [10972.8]] - expected_masses_kg = [ - [80179.25528304999], [79388.27899969438], [78357.5492916318], - [78038.12469387538], [78038.12469387538], [77318.48636094612], - [76344.12665022336], [76039.40895912607], [76039.40895912607], - [75347.90752400359], [74405.46275374181], [74109.60273338258], - [74109.60273338258], [73436.39272100825], [72516.3728326044], - [72227.22710472894], [72227.22710472894], [71569.02331279762], - [70669.56072490575], [70386.99122373879], [70386.99122373879], - [69743.47490624938], [68863.48019743375], [68586.78382987661], - [68586.78382987661], [67956.17424058718], [67092.43136900471], - [66820.49389265837], [66820.49389265837], [66200.47169407656], - [65350.50275054499], [65082.74154168183]] - expected_ranges_m = [ - [296875.60000000003], [554932.6549301515], [908399.8849826958], - [1019938.0213070473], [1019938.0213070473], [1274830.9442516388], - [1625714.5770829467], [1736624.0715069345], [1736624.0715069345], - [1990386.259724133], [2340154.5629672543], [2450786.080862452], - [2450786.080862452], [2704005.1890667905], [3053155.1477462808], - [3163604.8984363866], [3163604.8984363866], [3416419.8294669725], - [3765031.23567717], [3875315.9608939146], [3875315.9608939146], - [4127790.908533788], [4476045.826943081], [4586252.017090351], - [4586252.017090351], [4838601.188787049], [5186784.687764149], - [5296985.604312349], [5296985.604312349], [5549329.03066934], - [5897505.925045533], [6007702.8]] - expected_velocities_ms = [ - [239.49901683172416], [237.57721365239863], [236.1272332817375], - [235.83480578606836], [235.83480578606836], [235.29228140558052], - [234.76087668521515], [234.63268475430843], [234.63268475430843], - [234.3910317141664], [234.14254607637204], [234.07650600638797], - [234.07650600638797], [233.93612811601653], [233.75522209810927], - [233.69840302886462], [233.69840302886462], [233.56754384846963], - [233.4030426703855], [233.35949436934354], [233.35949436934354], - [233.28100688012185], [233.21763783283092], [233.20729273195352], - [233.20729273195352], [233.19770503012535], [233.1994910278998], - [233.19937577943125], [233.19937577943125], [233.19406389286172], - [233.19249705434646], [233.197992365194]] - expected_thrusts_N = [ - [46413.113617016286], [43959.216926887144], [42322.72191477366], - [42001.69876565644], [42001.698765656445], [41407.67462380937], - [40737.526959795134], [40531.856232353945], [40531.85623235394], - [40132.12747513132], [39640.66854140172], [39484.44541552107], - [39484.44541552107], [39159.04488467944], [38737.64967064259], - [38601.13281610918], [38601.13281610918], [38291.27389642972], - [37859.254019237305], [37729.15520426054], [37729.155204260525], - [37427.990254061384], [37028.69942780689], [36907.64255965252], - [36907.64255965253], [36649.2311134786], [36319.78199219473], - [36213.12929993469], [36213.12929994349], [35988.316744926444], - [35701.59647680185], [35614.98883340026]] - - expected_times_s = np.array(expected_times_s) - expected_altitudes_m = np.array(expected_altitudes_m) - expected_masses_kg = np.array(expected_masses_kg) - expected_ranges_m = np.array(expected_ranges_m) - expected_velocities_ms = np.array(expected_velocities_ms) - expected_thrusts_N = np.array(expected_thrusts_N) - - # Objective - - rtol = 1e-2 - - assert_near_equal(times[-1], expected_times_s[-1], tolerance=rtol) - - # Flight path - - # NOTE rtol = 0.01 = 1% different from truth (first timeseries) - # atol = 1 = no more than +/-1 meter difference between values - atol = 1e-2 - rtol = 1e-3 - - assert_timeseries_near_equal( - expected_times_s, expected_masses_kg, times, masses, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_ranges_m, times, ranges, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_velocities_ms, times, velocities, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_thrusts_N, times, thrusts, - abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py deleted file mode 100644 index b9925cf5b..000000000 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py +++ /dev/null @@ -1,253 +0,0 @@ -''' -NOTES: -Includes: -Cruise -Computed Aero -Large Single Aisle 1 data -''' - -import unittest - -import dymos as dm -# Suppress the annoying warnings from matplotlib when running dymos. -import matplotlib as mpl -import numpy as np -import openmdao.api as om -import scipy.constants as _units - -from dymos.utils.testing_utils import assert_timeseries_near_equal -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import use_tempdirs -from packaging import version -from aviary.variable_info.variables_in import VariablesIn - -from aviary.utils.aviary_values import AviaryValues -from aviary.mission.flops_based.phases.cruise_phase import Cruise -from aviary.interface.default_phase_info.height_energy import prop, aero, geom -from aviary.subsystems.premission import CorePreMission -from aviary.utils.functions import set_aviary_initial_values -from aviary.utils.functions import get_path -from aviary.validation_cases.validation_tests import (get_flops_inputs, - get_flops_outputs) -from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Aircraft, Dynamic - -mpl.rc('figure', max_open_warning=0) - -try: - import pyoptsparse - -except ImportError: - pyoptsparse = None - - -# benchmark based on Large Single Aisle 1 (fixed cruise alt) FLOPS model - -def run_trajectory(): - prob = om.Problem(model=om.Group()) - - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 50 - driver.opt_settings["Major optimality tolerance"] = 1e-5 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-6 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - # TODO enable coloring once issue has been resolved: - # https://github.com/OpenMDAO/OpenMDAO/issues/2507 - # driver.declare_coloring() - - ########################## - # Problem Settings # - ########################## - alt_i_cruise = 35000*_units.foot # m - alt_f_cruise = 35000*_units.foot # m - alt_min_cruise = 35000*_units.foot # m - alt_max_cruise = 35000*_units.foot # m - mass_i_cruise = 176765*_units.lb # kg - mass_f_cruise = 143521*_units.lb # kg - v_i_cruise = 455.49*_units.knot # m/s - v_f_cruise = 455.49*_units.knot # m/s - mach_i_cruise = 0.79 - mach_f_cruise = 0.79 - mach_min_cruise = 0.79 - mach_max_cruise = 0.79 - range_i_cruise = 160.3*_units.nautical_mile # m - range_f_cruise = 3243.9*_units.nautical_mile # m - t_i_cruise = 26.20*_units.minute # sec - t_f_cruise = 432.38*_units.minute # sec - t_duration_cruise = t_f_cruise - t_i_cruise - - prob.set_solver_print(level=2) - - transcription = dm.Radau(num_segments=1, order=3, compressed=True) - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle1FLOPS') - aviary_outputs = get_flops_outputs('LargeSingleAisle1FLOPS') - - # replace debug_no_mass flag with list of subsystem builders without mass - core_subsystems = [prop, geom, aero] - - cruise_options = Cruise( - 'test_cruise', - user_options=AviaryValues({ - 'min_altitude': (alt_min_cruise, 'm'), - 'max_altitude': (alt_max_cruise, 'm'), - 'min_mach': (mach_min_cruise, 'unitless'), - 'max_mach': (mach_max_cruise, 'unitless'), - 'required_available_climb_rate': (300, 'ft/min'), - 'fix_initial': (True, 'unitless'), - 'fix_final': (True, 'unitless'), - }), - core_subsystems=core_subsystems, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - transcription=transcription, - ) - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'core_premission', - CorePreMission(aviary_options=aviary_inputs, subsystems=core_subsystems), - promotes_inputs=['aircraft:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - cruise = cruise_options.build_phase(aviary_options=aviary_inputs) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - traj.add_phase('cruise', cruise) - - cruise.timeseries_options['use_prefix'] = True - - cruise.set_time_options( - fix_initial=True, fix_duration=False, units='s', - duration_bounds=(1, t_duration_cruise*2), duration_ref=t_duration_cruise) - - cruise.add_objective(Dynamic.Mission.MASS, loc='final', ref=-1e4) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs, phases=['cruise']) - - prob.model.add_subsystem( - 'input_sink', - VariablesIn(aviary_options=aviary_inputs), - promotes_inputs=['*'], - promotes_outputs=['*'] - ) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - key = Aircraft.Engine.THRUST_REVERSERS_MASS - val, units = aviary_outputs.get_item(key) - prob.model.set_input_defaults(key, val, units) - - prob.setup() - - prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s') - prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s') - - prob.set_val('traj.cruise.states:altitude', cruise.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m') - prob.set_val('traj.cruise.states:velocity', cruise.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s') - prob.set_val('traj.cruise.states:mass', cruise.interp( - Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi - - prob.set_val('traj.cruise.controls:velocity_rate', - cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), - units='m/s**2') - prob.set_val('traj.cruise.controls:throttle', - cruise.interp(Dynamic.Mission.THROTTLE, ys=[0.5, 0.5]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=False, make_plots=False, - solution_record_file='cruise_max.db') - # TODO Simulate=True is crashing here so turned it off - - prob.cleanup() - prob.record("final") - - return prob - - -@use_tempdirs -class CruisePhaseTestCase(unittest.TestCase): - def bench_test_cruise_large_single_aisle_1(self): - - prob = run_trajectory() - - times = prob.get_val('traj.cruise.timeseries.time', units='s') - altitudes = prob.get_val('traj.cruise.timeseries.states:altitude', units='m') - masses = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.cruise.timeseries.states:range', units='m') - velocities = prob.get_val('traj.cruise.timeseries.states:velocity', units='m/s') - thrusts = prob.get_val('traj.cruise.timeseries.thrust_net_total', units='N') - - expected_times_s = [[1572.], [10227.56555775], - [22170.47940152], [25950.37079939]] - expected_altitudes_m = [[10668.], [10668.], [10668.], [10668.]] - expected_masses_kg = [[80179.25528305], [ - 74612.30190345], [67357.05992796], [65154.3328912]] - expected_ranges_m = [[296875.6], [2324510.6550793], - [5122233.1849208], [6007702.8]] - expected_velocities_ms = [[234.25795132], [ - 234.25795132], [234.25795132], [234.25795132]] - expected_thrusts_N = [[41817.82877662], [ - 39634.49609004], [36930.60549609], [36149.38784885]] - - expected_times_s = np.array(expected_times_s) - expected_altitudes_m = np.array(expected_altitudes_m) - expected_masses_kg = np.array(expected_masses_kg) - expected_ranges_m = np.array(expected_ranges_m) - expected_velocities_ms = np.array(expected_velocities_ms) - expected_thrusts_N = np.array(expected_thrusts_N) - - # NOTE rtol = 0.01 = 1% different from truth (first timeseries) - # atol = 1 = no more than +/-1 meter difference between values - atol = 1e-2 - rtol = 1e-3 - - assert_near_equal(times[-1], expected_times_s[-1], tolerance=rtol) - - # Flight path - - assert_timeseries_near_equal( - expected_times_s, expected_masses_kg, times, masses, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_ranges_m, times, ranges, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_velocities_ms, times, velocities, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_thrusts_N, times, thrusts, - abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py deleted file mode 100644 index 8e1cfae23..000000000 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py +++ /dev/null @@ -1,247 +0,0 @@ -''' -NOTES: -Includes: -Cruise -Computed Aero -Large Single Aisle 2 data -CURRENTLY REMOVED FROM BENCHMARK TEST SUITE -''' - -import unittest - -import dymos as dm -# Suppress the annoying warnings from matplotlib when running dymos. -import matplotlib as mpl -import numpy as np -import openmdao.api as om -import scipy.constants as _units - -from dymos.utils.testing_utils import assert_timeseries_near_equal -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.flops_based.ode.mission_ODE import MissionODE -from aviary.mission.flops_based.phases.cruise_phase import Cruise -from aviary.interface.default_phase_info.height_energy import prop, aero, geom -from aviary.subsystems.premission import CorePreMission -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.functions import setup_trajectory_params -from aviary.variable_info.variables import Aircraft, Dynamic - -mpl.rc('figure', max_open_warning=0) - -try: - import pyoptsparse - -except ImportError: - pyoptsparse = None - - -''' -NOTE benchmark currently hits iteration limit - problem only converges when velocity ref & ref0 in energyphase is changed to 1e3. - Changing velocity ref breaks some full-mission benchmarks, so is currently not - implemented -''' - - -def run_trajectory(): - prob = om.Problem(model=om.Group()) - - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 50 - driver.opt_settings["Major optimality tolerance"] = 1e-5 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-6 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - # TODO enable coloring once issue has been resolved: - # https://github.com/OpenMDAO/OpenMDAO/issues/2507 - # driver.declare_coloring() - - ########################## - # Problem Settings # - ########################## - alt_i_cruise = 35000*_units.foot # m - alt_f_cruise = 35000*_units.foot # m - alt_min_cruise = 35000*_units.foot # m - alt_max_cruise = 35000*_units.foot # m - mass_i_cruise = 169730*_units.lb # kg - mass_f_cruise = 139810*_units.lb # kg - v_i_cruise = 452.61*_units.knot # m/s - v_f_cruise = 452.61*_units.knot # m/s - mach_i_cruise = 0.785 - mach_f_cruise = 0.785 - mach_min_cruise = 0.785 - mach_max_cruise = 0.785 - range_i_cruise = 116.6*_units.nautical_mile # m - range_f_cruise = 2558.3*_units.nautical_mile # m - t_i_cruise = 19.08*_units.minute # sec - t_f_cruise = 342.77*_units.minute # sec - t_duration_cruise = t_f_cruise - t_i_cruise # sec - - prob.set_solver_print(level=2) - - transcription = dm.Radau(num_segments=1, order=3, compressed=True) - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle2FLOPS') - aviary_outputs = get_flops_outputs('LargeSingleAisle2FLOPS') - - cruise_options = Cruise( - 'test_cruise', - min_altitude=alt_min_cruise, # m - max_altitude=alt_max_cruise, # m - # note, Mach = 0.0 causes an error in aero, perhaps in other code - min_mach=mach_min_cruise, - max_mach=mach_max_cruise, - required_available_climb_rate=300*_units.foot/_units.minute, # ft/min to m/s - fix_initial=True, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - aviary_options=aviary_inputs, - ) - - # replace debug_no_mass flag with list of subsystem builders without mass - core_subsystems = [prop, geom, aero] - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'core_premission', - CorePreMission(aviary_options=aviary_inputs, subsystems=core_subsystems), - promotes_inputs=['aircraft:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - cruise = cruise_options.build_phase(MissionODE, transcription) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - traj.add_phase('cruise', cruise) - - cruise.set_time_options( - fix_initial=True, fix_duration=False, units='s', - duration_bounds=(1, t_duration_cruise*2), duration_ref=t_duration_cruise) - - cruise.add_objective(Dynamic.Mission.MASS, loc='final', ref=-1e4) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - key = Aircraft.Engine.THRUST_REVERSERS_MASS - val, units = aviary_outputs.get_item(key) - prob.model.set_input_defaults(key, val, units) - - prob.setup() - - prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s') - prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s') - - prob.set_val('traj.cruise.states:altitude', cruise.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m') - prob.set_val('traj.cruise.states:velocity', cruise.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s') - prob.set_val('traj.cruise.states:mass', cruise.interp( - Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi - - prob.set_val('traj.cruise.controls:velocity_rate', - cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), - units='m/s**2') - prob.set_val('traj.cruise.controls:throttle', - cruise.interp(Dynamic.Mission.THROTTLE, ys=[0.5, 0.5]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=False, make_plots=False, - solution_record_file='cruise_large_single_aisle_2.db') - # TODO Simulate=True is crashing here so turned it off - - prob.cleanup() - prob.record("final") - - return prob - - -@unittest.skip('benchmark_cruise_large_single_aisle_2 currently broken') -class CruisePhaseTestCase(unittest.TestCase): - def bench_test_cruise_large_single_asile_2(self): - - prob = run_trajectory() - - times = prob.get_val('traj.cruise.timeseries.time', units='s') - altitudes = prob.get_val('traj.cruise.timeseries.states:altitude', units='m') - masses = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.cruise.timeseries.states:range', units='m') - velocities = prob.get_val('traj.cruise.timeseries.states:velocity', units='m/s') - thrusts = prob.get_val('traj.cruise.timeseries.thrust_net', units='N') - - expected_times_s = [[1144.8], [8042.22760495], - [17559.26991489], [20571.38126654]] - expected_altitudes_m = [[10668.], [10668.], [10668.], [10668.]] - expected_masses_kg = [[76988.2329601], [ - 72122.85057432], [65811.40723995], [63888.48266274]] - expected_ranges_m = [[215943.2], [1821494.02176252], - [4036826.45823737], [4737971.6]] - expected_velocities_ms = [[232.77530606], [ - 232.77530606], [232.77530606], [232.77530606]] - expected_thrusts_N = [[40492.90002165], [ - 38252.99661427], [35778.79636585], [35144.49009256]] - - expected_times_s = np.array(expected_times_s) - expected_altitudes_m = np.array(expected_altitudes_m) - expected_masses_kg = np.array(expected_masses_kg) - expected_ranges_m = np.array(expected_ranges_m) - expected_velocities_ms = np.array(expected_velocities_ms) - expected_thrusts_N = np.array(expected_thrusts_N) - - # NOTE rtol = 0.01 = 1% different from truth (first timeseries) - # atol = 1 = no more than +/-1 meter difference between values - atol = 1e-2 - rtol = 1e-3 - - # Objective - assert_near_equal(times[-1], expected_times_s[-1], tolerance=rtol) - - # Flight path - - assert_timeseries_near_equal( - expected_times_s, expected_masses_kg, times, masses, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_ranges_m, times, ranges, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_velocities_ms, times, velocities, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_thrusts_N, times, thrusts, - abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == "__main__": - # Changes to hardcoded tabular aero data changed this benchmark. Update benchmark - # test's expected values when aircraft-specific tabluar aero is avaliable - unittest.main() diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py deleted file mode 100644 index c1dba6168..000000000 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py +++ /dev/null @@ -1,255 +0,0 @@ -''' -NOTES: -Includes: -Descent -Computed Aero -Large Single Aisle 1 data -''' - -import unittest - -import dymos as dm -# Suppress the annoying warnings from matplotlib when running dymos. -import matplotlib as mpl -import numpy as np -import openmdao.api as om -import scipy.constants as _units - -from dymos.utils.testing_utils import assert_timeseries_near_equal -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.flops_based.ode.mission_ODE import MissionODE -from aviary.mission.flops_based.phases.descent_phase import Descent -from aviary.interface.default_phase_info.height_energy import prop, aero, geom -from aviary.subsystems.premission import CorePreMission -from aviary.utils.functions import set_aviary_initial_values -from aviary.utils.functions import get_path -from aviary.validation_cases.validation_tests import get_flops_inputs -from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Dynamic - -mpl.rc('figure', max_open_warning=0) - - -try: - import pyoptsparse - -except ImportError: - pyoptsparse = None - - -''' -NOTE descent profile is improved when velocity ref in EnergyPhase change to 1e3 - Implementing that velocity ref change breaks several mission benchmarks -''' -# benchmark based on Large Single Aisle 1 (fixed cruise alt) FLOPS model - - -def run_trajectory(): - prob = om.Problem(model=om.Group()) - - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 50 - driver.opt_settings["Major optimality tolerance"] = 5e-3 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-3 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - # TODO enable coloring once issue has been resolved: - # https://github.com/OpenMDAO/OpenMDAO/issues/2507 - # driver.declare_coloring() - - ########################## - # Problem Settings # - ########################## - alt_i_descent = 35000*_units.foot - alt_f_descent = 0*_units.foot - v_i_descent = 455.49*_units.knot - v_f_descent = 198.44*_units.knot - mach_i_descent = 0.79 - mach_f_descent = 0.3 - mass_i_descent = 143521*_units.pound - mass_f_descent = 143035*_units.pound - range_i_descent = 3243.9*_units.nautical_mile - range_f_descent = 3378.7*_units.nautical_mile - t_i_descent = 432.38*_units.minute - t_f_descent = 461.62*_units.minute - t_duration_descent = t_f_descent - t_i_descent - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle1FLOPS') - - descent_options = Descent( - 'test_descent', - final_altitude=alt_f_descent, - initial_altitude=alt_i_descent, - # note, Mach = 0.0 causes an error in aero, perhaps in other code - final_mach=mach_f_descent, - initial_mach=mach_i_descent, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - aviary_options=aviary_inputs, - ) - - # replace debug_no_mass flag with list of subsystem builders without mass - core_subsystems = [prop, geom, aero] - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'core_premission', - CorePreMission(aviary_options=aviary_inputs, subsystems=core_subsystems), - promotes_inputs=['aircraft:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - transcription = dm.Radau(num_segments=5, order=3, compressed=True) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - descent = descent_options.build_phase(MissionODE, transcription) - - # descent.add_objective(Dynamic.Mission.MASS, ref=-1e4, loc='final') - descent.add_objective(Dynamic.Mission.RANGE, ref=-1e5, loc='final') - - traj.add_phase('descent', descent) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - - prob.setup() - - # set initial conditions - prob.set_val('traj.descent.t_initial', t_i_descent, units='s') - prob.set_val('traj.descent.t_duration', t_duration_descent, units='s') - - prob.set_val('traj.descent.states:altitude', descent.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i_descent, alt_f_descent]), units='m') - prob.set_val('traj.descent.states:velocity', descent.interp( - Dynamic.Mission.VELOCITY, ys=[v_i_descent, v_f_descent]), units='m/s') - prob.set_val('traj.descent.states:mass', descent.interp( - Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') - prob.set_val('traj.descent.states:range', descent.interp( - Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m') - - prob.set_val('traj.descent.controls:velocity_rate', - descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), - units='m/s**2') - prob.set_val('traj.descent.controls:throttle', - descent.interp(Dynamic.Mission.THROTTLE, ys=[0.0, 0.0]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=False, make_plots=False, - solution_record_file='descent_max.db') - prob.record("final") - prob.cleanup() - - return prob - - -@unittest.skip('benchmark_descent_large_single_aisle_1 currently broken') -class DescentPhaseTestCase(unittest.TestCase): - def bench_test_descent_large_single_aisle_1(self): - - prob = run_trajectory() - - times = prob.get_val('traj.descent.timeseries.time', units='s') - altitudes = prob.get_val('traj.descent.timeseries.states:altitude', units='m') - masses = prob.get_val('traj.descent.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.descent.timeseries.states:range', units='m') - velocities = prob.get_val('traj.descent.timeseries.states:velocity', units='m/s') - thrusts = prob.get_val('traj.descent.timeseries.thrust_net', units='N') - - expected_times_s = [ - [25942.8], [26067.38110599], [26239.2776049], [26293.68225907], - [26293.68225907], [26418.26336507], [26590.15986397], [26644.56451815], - [26644.56451815], [26769.14562414], [26941.04212305], [26995.44677722], - [26995.44677722], [27120.02788321], [27291.92438212], [27346.3290363], - [27346.3290363], [27470.91014229], [27642.80664119], [27697.21129537]] - expected_altitudes_m = [ - [10668.], [9630.58727675], [8607.44716937], [8325.35146852], - [8325.35146852], [7618.26503578], [6519.12597312], [6144.16296733], - [6144.16296733], [5222.63590813], [3906.74184382], [3501.58245681], - [3501.58245681], [2693.56449806], [1613.14062128], [1227.34540813], - [1227.34540813], [472.05630168], [0.], [0.]] - expected_masses_kg = [ - [65100.03053477], [65068.4860871], [65009.01063053], [64988.47429787], - [64988.47429787], [64942.20142996], [64875.19680192], [64851.91888669], - [64851.91888669], [64793.85853886], [64706.58329093], [64678.30905669], - [64678.30905669], [64614.11135757], [64531.47572247], [64507.94243863], - [64507.94243863], [64464.03072407], [64420.28475648], [64408.7201039]] - expected_ranges_m = [ - [6007702.8], [6036868.3987895], [6077125.1955833], - [6089867.31136598], [6089867.31136598], [6119045.21397484], - [6159302.44709504], [6172042.94318126], [6172042.94318126], - [6201214.75820313], [6241466.48424821], [6254207.73380962], - [6254207.73380962], [6283402.65691348], [6322851.72600445], - [6334884.03220066], [6334884.03220066], [6360443.88994895], - [6388386.24507732], [6394712.53233535]] - expected_velocities_ms = [ - [234.25795132], [234.25795132], [234.25795132], [234.25795132], - [234.25795132], [234.25795132], [234.25795132], [234.25795132], - [234.25795132], [234.25795132], [234.25795132], [234.25795132], - [234.25795132], [233.47298378], [223.67831268], [216.71997882], - [216.71997882], [190.9857791], [129.0266439], [102.08605905]] - expected_thrusts_N = [ - [9516.07730964], [18867.54655988], [26134.27560127], [26569.54809341], - [26569.54809341], [26513.67959312], [27279.65638053], [27558.344662], - [27558.344662], [29558.29975054], [37141.0454636], [40960.56830135], - [40960.56830135], [46197.31464087], [36817.32495137], [29341.51748247], - [29341.51748247], [14369.16584473], [0.], [2.27381718e-11]] - - expected_times_s = np.array(expected_times_s) - expected_altitudes_m = np.array(expected_altitudes_m) - expected_masses_kg = np.array(expected_masses_kg) - expected_ranges_m = np.array(expected_ranges_m) - expected_velocities_ms = np.array(expected_velocities_ms) - expected_thrusts_N = np.array(expected_thrusts_N) - - # NOTE rtol = 0.01 = 1% different from truth (first timeseries) - # atol = 1 = no more than +/-1 meter difference between values - atol = 1e-2 - rtol = 1e-3 - - # Objective - assert_near_equal(times[-1], expected_times_s[-1], tolerance=rtol) - - # Flight path - - assert_timeseries_near_equal( - expected_times_s, expected_masses_kg, times, masses, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_ranges_m, times, ranges, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_velocities_ms, times, velocities, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_thrusts_N, times, thrusts, - abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py deleted file mode 100644 index e6378c4a2..000000000 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py +++ /dev/null @@ -1,256 +0,0 @@ -''' -NOTES: -Includes: -Descent -Computed Aero -Large Single Aisle 2 data -CURRENTLY REMOVED FROM BENCHMARK TEST SUITE -''' - -import unittest - -import dymos as dm -# Suppress the annoying warnings from matplotlib when running dymos. -import matplotlib as mpl -import numpy as np -import openmdao.api as om -import scipy.constants as _units - -from dymos.utils.testing_utils import assert_timeseries_near_equal -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.flops_based.ode.mission_ODE import MissionODE -from aviary.mission.flops_based.phases.descent_phase import Descent -from aviary.interface.default_phase_info.height_energy import prop, aero, geom -from aviary.subsystems.premission import CorePreMission -from aviary.utils.functions import set_aviary_initial_values -from aviary.utils.functions import get_path -from aviary.validation_cases.validation_tests import get_flops_inputs -from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Dynamic - -mpl.rc('figure', max_open_warning=0) - - -try: - import pyoptsparse - -except ImportError: - pyoptsparse = None - - -''' -NOTE benchmark only reaches 0-3 after 50 iterations with bad plots - problem easily converges with 0-1 when velocity ref & ref0 in energyphase is changed - to 1e3. - Changing velocity ref breaks some full-mission benchmarks, so is currently not - implemented -''' - - -def run_trajectory(): - prob = om.Problem(model=om.Group()) - - if pyoptsparse: - driver = prob.driver = om.pyOptSparseDriver() - driver.options["optimizer"] = "SNOPT" - - if driver.options["optimizer"] == "SNOPT": - driver.opt_settings["Major iterations limit"] = 50 - driver.opt_settings["Major optimality tolerance"] = 5e-3 - driver.opt_settings["Major feasibility tolerance"] = 1e-6 - driver.opt_settings["iSumm"] = 6 - elif driver.options["optimizer"] == "IPOPT": - driver.opt_settings["max_iter"] = 100 - driver.opt_settings["tol"] = 1e-3 - driver.opt_settings['print_level'] = 4 - - else: - driver = prob.driver = om.ScipyOptimizeDriver() - opt_settings = prob.driver.opt_settings - - driver.options['optimizer'] = 'SLSQP' - opt_settings['maxiter'] = 100 - opt_settings['ftol'] = 5.0e-3 - opt_settings['eps'] = 1e-2 - - # TODO enable coloring once issue has been resolved: - # https://github.com/OpenMDAO/OpenMDAO/issues/2507 - # driver.declare_coloring() - - ########################## - # Problem Settings # - ########################## - alt_i = 35000*_units.foot - alt_f = 35*_units.foot - v_i = 452.61*_units.knot - v_f = 198.44*_units.knot - mach_i = 0.785 - mach_f = 0.3 - mass_i = 140515*_units.pound - mass_f = 140002*_units.pound - range_i = 2830.8*_units.nautical_mile - range_f = 2960.0*_units.nautical_mile - t_i_descent = 0.0 - t_f_descent = 2000.0 - - ########################################## - # Aircraft Input Variables and Options # - ########################################## - - aviary_inputs = get_flops_inputs('LargeSingleAisle2FLOPS') - - descent_options = Descent( - 'test_descent', - final_altitude=alt_f, - initial_altitude=alt_i, - # note, Mach = 0.0 causes an error in aero, perhaps in other code - final_mach=mach_f, - initial_mach=mach_i, - subsystem_options={'core_aerodynamics': {'method': 'computed'}}, - aviary_options=aviary_inputs, - ) - - # replace debug_no_mass flag with list of subsystem builders without mass - core_subsystems = [prop, geom, aero] - - # Upstream static analysis for aero - prob.model.add_subsystem( - 'core_premission', - CorePreMission(aviary_options=aviary_inputs, subsystems=core_subsystems), - promotes_inputs=['aircraft:*'], - promotes_outputs=['aircraft:*', 'mission:*']) - - transcription = dm.Radau(num_segments=5, order=3, compressed=True) - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - - descent = descent_options.build_phase(MissionODE, transcription) - - descent.add_objective(Dynamic.Mission.RANGE, ref=-1e5, loc='final') - traj.add_phase('descent', descent) - - traj = setup_trajectory_params(prob.model, traj, aviary_inputs) - - # Set initial default values for all aircraft variables. - set_aviary_initial_values(prob.model, aviary_inputs) - - prob.setup() - - # set initial conditions - prob.set_val('traj.descent.t_initial', t_i_descent, units='s') - prob.set_val('traj.descent.t_duration', t_f_descent, units='s') - - prob.set_val('traj.descent.states:altitude', descent.interp( - Dynamic.Mission.ALTITUDE, ys=[alt_i, alt_f]), units='m') - prob.set_val('traj.descent.states:velocity', descent.interp( - Dynamic.Mission.VELOCITY, ys=[v_i, v_f]), units='m/s') - prob.set_val('traj.descent.states:mass', descent.interp( - Dynamic.Mission.MASS, ys=[mass_i, mass_f]), units='kg') - prob.set_val('traj.descent.states:range', descent.interp( - Dynamic.Mission.RANGE, ys=[range_i, range_f]), units='m') - - prob.set_val('traj.descent.controls:velocity_rate', - descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), - units='m/s**2') - prob.set_val('traj.descent.controls:throttle', - descent.interp(Dynamic.Mission.THROTTLE, ys=[0.0, 0.0]), - units='unitless') - - # Turn off solver printing so that the SNOPT output is readable. - prob.set_solver_print(level=0) - - dm.run_problem(prob, simulate=False, make_plots=False, - solution_record_file='descent_large_single_aisle_2.db') - prob.record("final") - prob.cleanup() - - return prob - - -@unittest.skip('benchmark_descent_large_single_aisle_2 currently broken') -class DescentPhaseTestCase(unittest.TestCase): - def bench_test_descent_large_single_aisle_2(self): - - prob = run_trajectory() - - times = prob.get_val('traj.descent.timeseries.time', units='s') - altitudes = prob.get_val('traj.descent.timeseries.states:altitude', units='m') - masses = prob.get_val('traj.descent.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.descent.timeseries.states:range', units='m') - velocities = prob.get_val('traj.descent.timeseries.states:velocity', units='m/s') - thrusts = prob.get_val('traj.descent.timeseries.thrust_net', units='N') - - expected_times_s = [ - [0.], [142.02539503], [337.99145239], [400.01403952], - [400.01403952], [542.03943455], [738.0054919], [800.02807903], - [800.02807903], [942.05347406], [1138.01953142], [1200.04211855], - [1200.04211855], [1342.06751358], [1538.03357093], [1600.05615806], - [1600.05615806], [1742.08155309], [1938.04761045], [2000.07019758]] - expected_altitudes_m = [ - [10668.], [9548.97609287], [8538.42241675], [8275.01276129], - [8275.01276129], [7601.31902636], [6519.47805911], [6141.13701298], - [6141.13701298], [5205.26802003], [3963.90368243], [3634.87695679], - [3634.87695679], [3055.62551952], [2221.91470683], [1840.14771729], - [1840.14771729], [870.95857222], [10.668], [10.668]] - expected_masses_kg = [ - [63736.53187055], [63688.55056043], [63592.93766122], [63558.62366657], - [63558.62366657], [63480.12720033], [63368.68894184], [63331.87300229], - [63331.87300229], [63243.53017169], [63103.08546544], [63051.9162013], - [63051.9162013], [62922.36463692], [62748.94842397], [62704.12656931], - [62704.12656931], [62627.76510694], [62566.74093186], [62554.55364275]] - expected_ranges_m = [ - [5242641.6], [5275682.08024547], [5321287.43849558], - [5335722.05453227], [5335722.05453227], [5368775.18998604], - [5414378.40648958], [5428810.78044196], [5428810.78044196], - [5461857.5756481], [5507456.7101919], [5521890.39254914], - [5521890.39254914], [5554951.82532665], [5599686.46586361], - [5613370.90489204], [5613370.90489204], [5642618.8601419], - [5674799.0551216], [5682083.57281856]] - expected_velocities_ms = [ - [232.77530606], [232.77530606], [232.77530606], [232.77530606], - [232.77530606], [232.77530606], [232.77530606], [232.77530606], - [232.77530606], [232.77530606], [232.77530606], [232.77530606], - [232.77530606], [232.05265856], [223.03560479], [216.62970611], - [216.62970611], [192.53473927], [130.45545087], [102.07377559]] - expected_thrusts_N = [ - [10348.85799036], [20322.69938272], [27901.58834456], - [28262.62341568], [28262.62341568], [28062.43245824], - [28590.47833586], [28815.02361611], [28815.02361611], - [30869.45928917], [38383.90751338], [41973.2222718], - [41973.2222718], [46287.80542225], [36032.4169276], - [28755.10323868], [28755.10323868], [13691.34754408], [0.], [0.]] - - expected_times_s = np.array(expected_times_s) - expected_altitudes_m = np.array(expected_altitudes_m) - expected_masses_kg = np.array(expected_masses_kg) - expected_ranges_m = np.array(expected_ranges_m) - expected_velocities_ms = np.array(expected_velocities_ms) - expected_thrusts_N = np.array(expected_thrusts_N) - - # NOTE rtol = 0.01 = 1% different from truth (first timeseries) - # atol = 1 = no more than +/-1 meter difference between values - atol = 1e-2 - rtol = 1e-3 - - # Objective - assert_near_equal(times[-1], expected_times_s[-1], tolerance=rtol) - - # Flight path - - assert_timeseries_near_equal( - expected_times_s, expected_masses_kg, times, masses, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_ranges_m, times, ranges, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_velocities_ms, times, velocities, - abs_tolerance=atol, rel_tolerance=rtol) - assert_timeseries_near_equal( - expected_times_s, expected_thrusts_N, times, thrusts, - abs_tolerance=atol, rel_tolerance=rtol) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/gasp_based/phases/run_phases/run_ascent.py b/aviary/mission/gasp_based/phases/run_phases/run_ascent.py index fdd3c0384..598e1ba8b 100644 --- a/aviary/mission/gasp_based/phases/run_phases/run_ascent.py +++ b/aviary/mission/gasp_based/phases/run_phases/run_ascent.py @@ -5,7 +5,7 @@ from aviary.mission.gasp_based.polynomial_fit import PolynomialFit from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Dynamic, Mission -from aviary.interface.default_phase_info.height_energy import default_mission_subsystems +from aviary.interface.default_phase_info.simple import default_mission_subsystems def run_ascent(make_plots=False): diff --git a/aviary/models/N3CC/N3CC_data.py b/aviary/models/N3CC/N3CC_data.py index a163553ea..13219ce56 100644 --- a/aviary/models/N3CC/N3CC_data.py +++ b/aviary/models/N3CC/N3CC_data.py @@ -26,7 +26,7 @@ from aviary.variable_info.variables import Mission from aviary.variable_info.variables import Settings from aviary.variable_info.enums import EquationsOfMotion, LegacyCode -from aviary.interface.default_phase_info.height_energy import default_mission_subsystems +from aviary.interface.default_phase_info.simple import default_mission_subsystems Dynamic = _Dynamic.Mission @@ -315,7 +315,7 @@ # Settings # --------------------------- -inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.HEIGHT_ENERGY) +inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.SIMPLE) inputs.set_val(Settings.MASS_METHOD, LegacyCode.FLOPS) # --------------------------- diff --git a/aviary/models/N3CC/N3CC_generic_low_speed_polars_FLOPSinp.csv b/aviary/models/N3CC/N3CC_generic_low_speed_polars_FLOPSinp.csv index 81ac1ee35..2ceb7088d 100644 --- a/aviary/models/N3CC/N3CC_generic_low_speed_polars_FLOPSinp.csv +++ b/aviary/models/N3CC/N3CC_generic_low_speed_polars_FLOPSinp.csv @@ -169,7 +169,7 @@ mission:takeoff:rolling_friction_coefficient,0.0175,unitless mission:takeoff:spoiler_drag_coefficient,0.085,unitless mission:takeoff:spoiler_lift_coefficient,-0.81,unitless mission:takeoff:thrust_incidence,0,deg -settings:equations_of_motion,height_energy +settings:equations_of_motion,simple settings:mass_method,FLOPS # Unconverted Values 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 feeca95a1..8b3f48616 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 @@ -263,7 +263,7 @@ # Settings # --------------------------- -inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.HEIGHT_ENERGY) +inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.SIMPLE) inputs.set_val(Settings.MASS_METHOD, LegacyCode.FLOPS) # --------------------------- 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 37ef21ff0..3f36a12f2 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 @@ -263,7 +263,7 @@ # Settings # --------------------------- -inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.HEIGHT_ENERGY) +inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.SIMPLE) inputs.set_val(Settings.MASS_METHOD, LegacyCode.FLOPS) # --------------------------- 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 667b0d72a..2c1328bc7 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 @@ -262,7 +262,7 @@ # Settings # --------------------------- -inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.HEIGHT_ENERGY) +inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.SIMPLE) inputs.set_val(Settings.MASS_METHOD, LegacyCode.FLOPS) # --------------------------- 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 ca02d5832..f8fe5041a 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 @@ -263,7 +263,7 @@ # Settings # --------------------------- -inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.HEIGHT_ENERGY) +inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.SIMPLE) inputs.set_val(Settings.MASS_METHOD, LegacyCode.FLOPS) # --------------------------- diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv index 2d4ea4703..abdddb634 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv @@ -155,5 +155,5 @@ mission:takeoff:fuel_simple,577,lbm mission:takeoff:lift_coefficient_max,3.0,unitless mission:takeoff:lift_over_drag,17.354,unitless mission:takeoff:rolling_friction_coefficient,0.0175,unitless -settings:equations_of_motion,height_energy +settings:equations_of_motion,simple settings:mass_method,FLOPS \ No newline at end of file diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv index 5c0d0b8a0..b0c9ace8d 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv @@ -269,5 +269,5 @@ mission:takeoff:lift_coefficient_flap_increment,0.4182,unitless mission:takeoff:lift_coefficient_max,3.0,unitless mission:takeoff:lift_over_drag,17.354,unitless mission:takeoff:rolling_friction_coefficient,0.0175,unitless -settings:equations_of_motion,height_energy +settings:equations_of_motion,simple settings:mass_method,GASP \ No newline at end of file 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 3788620b8..c6a26a221 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,7 +5,7 @@ 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.interface.default_phase_info.simple 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 diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py index edd31adfa..a09db92f1 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py @@ -88,7 +88,8 @@ def test_solved_aero_pass_polar(self): prob = AviaryProblem() - prob.load_inputs(csv_path, ph_in) + prob.load_inputs( + "subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv", ph_in) prob.aviary_inputs.set_val(Aircraft.Design.LIFT_POLAR, np.zeros_like(CL), units='unitless') 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 897caf9a5..216f17fc5 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,7 @@ 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.interface.default_phase_info.simple import aero, prop, geom 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 diff --git a/aviary/subsystems/test/test_flops_based_premission.py b/aviary/subsystems/test/test_flops_based_premission.py index 87a2251e1..07ebbf478 100644 --- a/aviary/subsystems/test/test_flops_based_premission.py +++ b/aviary/subsystems/test/test_flops_based_premission.py @@ -13,7 +13,7 @@ from aviary.variable_info.variables import Aircraft, Mission 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.interface.default_phase_info.simple import default_premission_subsystems from aviary.utils.preprocessors import preprocess_crewpayload diff --git a/aviary/utils/Fortran_to_Aviary.py b/aviary/utils/Fortran_to_Aviary.py index 3273f0ee5..82aad72c3 100644 --- a/aviary/utils/Fortran_to_Aviary.py +++ b/aviary/utils/Fortran_to_Aviary.py @@ -108,7 +108,7 @@ def create_aviary_deck(fortran_deck: str, legacy_code=None, defaults_deck=None, for var, (val, units) in sorted(vehicle_data['input_values']): writer.writerow([var] + val + [units]) if legacy_code is FLOPS: - EOM = 'height_energy' + EOM = 'simple' mass = 'FLOPS' if legacy_code is GASP: EOM = '2DOF' diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index 0b1dd82f6..5ddf69121 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -5,7 +5,7 @@ from aviary.interface.methods_for_level2 import AviaryProblem from aviary.interface.default_phase_info.two_dof import phase_info as two_dof_phase_info -from aviary.interface.default_phase_info.simple import phase_info as height_energy_phase_info +from aviary.interface.default_phase_info.simple import phase_info as simple_phase_info from aviary.interface.default_phase_info.solved import phase_info as solved_phase_info from aviary.variable_info.enums import EquationsOfMotion @@ -45,8 +45,8 @@ def test_gasp_zero_iters(self): class HEZeroItersTestCase(BaseProblemPhaseTestCase): @require_pyoptsparse(optimizer="IPOPT") - def test_height_energy_zero_iters(self): - local_phase_info = deepcopy(height_energy_phase_info) + def test_simple_zero_iters(self): + local_phase_info = deepcopy(simple_phase_info) self.build_and_run_problem('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv', local_phase_info) 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 aff3bb72c..98b67bb04 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 @@ -20,7 +20,7 @@ inputs as _inputs from aviary.variable_info.variables import Dynamic as _Dynamic from aviary.variable_info.variables_in import VariablesIn -from aviary.interface.default_phase_info.height_energy import default_premission_subsystems +from aviary.interface.default_phase_info.simple import default_premission_subsystems from aviary.subsystems.premission import CorePreMission Dynamic = _Dynamic.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 160819283..3de522d6f 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 @@ -26,7 +26,7 @@ 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.interface.default_phase_info.simple import default_premission_subsystems, default_mission_subsystems from aviary.utils.preprocessors import preprocess_crewpayload try: 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 512b710d8..99b4c3c31 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py @@ -18,7 +18,7 @@ landing_fullstop_user_options as _landing_fullstop_user_options) from aviary.variable_info.variables import Dynamic as _Dynamic -from aviary.interface.default_phase_info.height_energy import default_premission_subsystems +from aviary.interface.default_phase_info.simple import default_premission_subsystems from aviary.utils.preprocessors import preprocess_crewpayload from aviary.variable_info.variables_in import VariablesIn 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 bc403ccbf..abe145537 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py @@ -18,7 +18,7 @@ takeoff_liftoff_user_options as _takeoff_liftoff_user_options) from aviary.variable_info.variables import Aircraft, Dynamic as _Dynamic -from aviary.interface.default_phase_info.height_energy import default_premission_subsystems +from aviary.interface.default_phase_info.simple import default_premission_subsystems from aviary.utils.preprocessors import preprocess_crewpayload from aviary.variable_info.variables_in import VariablesIn diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index 81efcaf14..22aa5a384 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -8,7 +8,6 @@ from aviary.validation_cases.benchmark_utils import \ compare_against_expected_values from aviary.variable_info.variables import Dynamic -from aviary.interface.default_phase_info.simple import phase_info @use_tempdirs @@ -273,7 +272,6 @@ def bench_test_swap_4_FwFm(self): 'input_initial': True, "optimize_mach": True, "optimize_altitude": True, - "polynomial_control_order": None, "use_polynomial_control": False, "num_segments": 6, "order": 3, @@ -324,7 +322,6 @@ def bench_test_swap_4_FwFm(self): "user_options": { "optimize_mach": True, "optimize_altitude": True, - "polynomial_control_order": None, "use_polynomial_control": False, "num_segments": 5, "order": 3, diff --git a/aviary/variable_info/enums.py b/aviary/variable_info/enums.py index 949253944..802232eb2 100644 --- a/aviary/variable_info/enums.py +++ b/aviary/variable_info/enums.py @@ -57,7 +57,6 @@ class EquationsOfMotion(Enum): """ Available equations of motion for use during mission analysis """ - HEIGHT_ENERGY = 'height_energy' TWO_DEGREES_OF_FREEDOM = '2DOF' # TODO these are a little out of place atm SIMPLE = 'simple' From 68fba1b4d2f6a94fd2c01c7e1916fa854ace32a8 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 11 Jan 2024 14:34:44 -0600 Subject: [PATCH 047/188] Moving to height_energy --- aviary/api.py | 7 +- .../default_phase_info/height_energy.py | 251 +++------- aviary/interface/default_phase_info/simple.py | 99 ---- aviary/interface/methods_for_level2.py | 32 +- aviary/interface/test/test_basic_report.py | 2 +- .../interface/test/test_check_phase_info.py | 10 +- aviary/interface/test/test_interface_bugs.py | 2 +- aviary/interface/test/test_phase_info.py | 2 +- aviary/interface/test/test_reserve_support.py | 2 +- aviary/interface/utils/check_phase_info.py | 4 +- .../flops_based/ode/test/test_landing_ode.py | 2 +- .../flops_based/ode/test/test_takeoff_ode.py | 2 +- .../flops_based/phases/simple_energy_phase.py | 440 ------------------ .../phases/run_phases/run_ascent.py | 2 +- aviary/models/N3CC/N3CC_data.py | 4 +- ...N3CC_generic_low_speed_polars_FLOPSinp.csv | 2 +- .../large_single_aisle_1_FLOPS_data.py | 2 +- .../large_single_aisle_2_FLOPS_data.py | 2 +- .../large_single_aisle_2_altwt_FLOPS_data.py | 2 +- ...ge_single_aisle_2_detailwing_FLOPS_data.py | 2 +- .../test_aircraft/aircraft_for_bench_FwFm.csv | 2 +- .../aircraft_for_bench_FwFm_simple.csv | 2 +- .../test_aircraft/aircraft_for_bench_GwFm.csv | 2 +- .../aircraft_for_bench_GwFm_simple.csv | 2 +- .../test/data/high_wing_single_aisle.csv | 2 +- .../test/test_computed_aero_group.py | 2 +- .../test/test_solved_aero_group.py | 2 +- .../test/test_tabular_aero_group.py | 2 +- .../test/test_external_subsystem_bus.py | 2 +- .../test/test_flops_based_premission.py | 2 +- aviary/utils/Fortran_to_Aviary.py | 2 +- .../benchmark_tests/test_0_iters.py | 2 +- .../test_FLOPS_balanced_field_length.py | 2 +- .../test_FLOPS_based_sizing_N3CC.py | 4 +- .../test_FLOPS_detailed_landing.py | 2 +- .../test_FLOPS_detailed_takeoff.py | 2 +- .../benchmark_tests/test_bench_GwFm.py | 2 +- aviary/variable_info/enums.py | 2 +- 38 files changed, 132 insertions(+), 777 deletions(-) delete mode 100644 aviary/interface/default_phase_info/simple.py delete mode 100644 aviary/mission/flops_based/phases/simple_energy_phase.py diff --git a/aviary/api.py b/aviary/api.py index d86b1158f..412e843fe 100644 --- a/aviary/api.py +++ b/aviary/api.py @@ -32,10 +32,9 @@ from aviary.utils.data_interpolator_builder import build_data_interpolator from aviary.variable_info.enums import AlphaModes, AnalysisScheme, ProblemType, SpeedType, GASPEngineType, FlapType, EquationsOfMotion, LegacyCode, Verbosity from aviary.interface.default_phase_info.two_dof import phase_info as default_2DOF_phase_info -from aviary.interface.default_phase_info.simple import phase_info as default_simple_phase_info from aviary.interface.default_phase_info.two_dof_fiti import create_2dof_based_ascent_phases, create_2dof_based_descent_phases from aviary.interface.default_phase_info.solved import phase_info as default_solved_phase_info -from aviary.interface.default_phase_info.simple import phase_info as default_simple_phase_info +from aviary.interface.default_phase_info.height_energy import phase_info as default_height_energy_phase_info from aviary.interface.methods_for_level1 import run_level_1 from aviary.interface.methods_for_level1 import run_aviary from aviary.interface.methods_for_level2 import AviaryProblem @@ -46,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.simple import default_premission_subsystems, default_mission_subsystems +from aviary.interface.default_phase_info.height_energy import default_premission_subsystems, default_mission_subsystems ################### # Level 3 Imports # @@ -86,7 +85,7 @@ # Phase builders from aviary.mission.flops_based.phases.phase_builder_base import PhaseBuilderBase # note that this is only for simplified right now -from aviary.mission.flops_based.phases.simple_energy_phase import EnergyPhase as HeightEnergyPhaseBuilder +from aviary.mission.flops_based.phases.energy_phase import EnergyPhase as HeightEnergyPhaseBuilder from aviary.mission.flops_based.phases.build_landing import Landing as HeightEnergyLandingPhaseBuilder # note that this is only for simplified right now from aviary.mission.flops_based.phases.build_takeoff import Takeoff as HeightEnergyTakeoffPhaseBuilder diff --git a/aviary/interface/default_phase_info/height_energy.py b/aviary/interface/default_phase_info/height_energy.py index 66d584192..29dcd56ea 100644 --- a/aviary/interface/default_phase_info/height_energy.py +++ b/aviary/interface/default_phase_info/height_energy.py @@ -3,12 +3,10 @@ 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) @@ -17,188 +15,85 @@ default_premission_subsystems = [prop, geom, mass, aero] default_mission_subsystems = [aero, prop] + phase_info = { - 'pre_mission': { - 'include_takeoff': True, - 'optimize_mass': True, - }, - 'climb': { - 'subsystem_options': { - 'core_aerodynamics': {'method': 'computed'} - }, - 'user_options': { - 'fix_initial': {Dynamic.Mission.MASS: False, Dynamic.Mission.RANGE: False}, - 'fix_initial_time': True, - 'fix_duration': False, - 'num_segments': 6, - 'order': 3, - 'initial_altitude': (0., 'ft'), - 'initial_ref': (1., 's'), - 'initial_bounds': ((0., 500.), 's'), - 'duration_ref': (1452., 's'), - 'duration_bounds': ((726., 2904.), 's'), - 'final_altitude': (10668, 'm'), - 'input_initial': True, - 'no_descent': False, - 'initial_mach': 0.1, - 'final_mach': 0.79, - 'fix_range': False, - 'add_initial_mass_constraint': False, + "pre_mission": {"include_takeoff": False, "optimize_mass": True}, + "climb": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + "optimize_mach": False, + "optimize_altitude": False, + "polynomial_control_order": 1, + "num_segments": 5, + "order": 3, + "solve_for_range": False, + "initial_mach": (0.2, "unitless"), + "final_mach": (0.72, "unitless"), + "mach_bounds": ((0.18, 0.74), "unitless"), + "initial_altitude": (0.0, "ft"), + "final_altitude": (32000.0, "ft"), + "altitude_bounds": ((0.0, 34000.0), "ft"), + "throttle_enforcement": "path_constraint", + "fix_initial": True, + "constrain_final": False, + "fix_duration": False, + "initial_bounds": ((0.0, 0.0), "min"), + "duration_bounds": ((64.0, 192.0), "min"), + "add_initial_mass_constraint": False, }, - 'initial_guesses': { - 'times': ([2., 24.2], 'min'), - 'altitude': ([0., 35.e3], 'ft'), - 'velocity': ([220., 455.49], 'kn'), - 'mass': ([170.e3, 165.e3], 'lbm'), - 'range': ([0., 160.3], 'nmi'), - 'velocity_rate': ([0.25, 0.05], 'm/s**2'), - 'throttle': ([0.5, 0.5], 'unitless'), - } + "initial_guesses": {"times": ([0, 128], "min")}, }, - 'cruise': { - 'subsystem_options': { - 'core_aerodynamics': {'method': 'computed'} + "cruise": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + "optimize_mach": False, + "optimize_altitude": False, + "polynomial_control_order": 1, + "num_segments": 5, + "order": 3, + "solve_for_range": False, + "initial_mach": (0.72, "unitless"), + "final_mach": (0.72, "unitless"), + "mach_bounds": ((0.7, 0.74), "unitless"), + "initial_altitude": (32000.0, "ft"), + "final_altitude": (34000.0, "ft"), + "altitude_bounds": ((23000.0, 38000.0), "ft"), + "throttle_enforcement": "boundary_constraint", + "fix_initial": False, + "constrain_final": False, + "fix_duration": False, + "initial_bounds": ((64.0, 192.0), "min"), + "duration_bounds": ((56.5, 169.5), "min"), }, - 'user_options': { - 'fix_initial': False, - 'fix_final': False, - 'fix_duration': False, - 'num_segments': 1, - 'order': 3, - 'initial_ref': (1., 's'), - 'initial_bounds': ((500., 4000.), 's'), - 'duration_ref': (24370.8, 's'), - 'duration_bounds': ((726., 48741.6), 's'), - 'min_altitude': (10.668e3, 'm'), - 'max_altitude': (10.668e3, 'm'), - 'min_mach': 0.79, - 'max_mach': 0.79, - 'required_available_climb_rate': (1.524, 'm/s'), - 'mass_f_cruise': (1.e4, 'kg'), - 'range_f_cruise': (1.e6, 'm'), - }, - 'initial_guesses': { - 'times': ([26.2, 406.18], 'min'), - 'altitude': ([35.e3, 35.e3], 'ft'), - 'velocity': ([455.49, 455.49], 'kn'), - 'mass': ([165.e3, 140.e3], 'lbm'), - 'range': ([160.3, 3243.9], 'nmi'), - 'velocity_rate': ([0., 0.], 'm/s**2'), - 'throttle': ([0.95, 0.9], 'unitless'), - } + "initial_guesses": {"times": ([128, 113], "min")}, }, - 'descent': { - 'subsystem_options': { - 'core_aerodynamics': {'method': 'computed'} - }, - 'user_options': { - 'fix_initial': False, - 'fix_range': True, - 'fix_duration': False, - 'num_segments': 5, - 'order': 3, - 'initial_ref': (1., 's'), - 'initial_bounds': ((10.e3, 30.e3), 's'), - 'duration_ref': (1754.4, 's'), - 'duration_bounds': ((726., 3508.8), 's'), - 'initial_altitude': (10.668e3, 'm'), - 'final_altitude': (10.668, 'm'), - 'initial_mach': 0.79, - 'final_mach': 0.3, - 'no_climb': False, + "descent": { + "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, + "user_options": { + "optimize_mach": False, + "optimize_altitude": False, + "polynomial_control_order": 1, + "num_segments": 5, + "order": 3, + "solve_for_range": False, + "initial_mach": (0.72, "unitless"), + "final_mach": (0.36, "unitless"), + "mach_bounds": ((0.34, 0.74), "unitless"), + "initial_altitude": (34000.0, "ft"), + "final_altitude": (500.0, "ft"), + "altitude_bounds": ((0.0, 38000.0), "ft"), + "throttle_enforcement": "path_constraint", + "fix_initial": False, + "constrain_final": True, + "fix_duration": False, + "initial_bounds": ((120.5, 361.5), "min"), + "duration_bounds": ((29.0, 87.0), "min"), }, - 'initial_guesses': { - 'times': ([432.38, 29.24], 'min'), - 'altitude': ([35.e3, 35.], 'ft'), - 'velocity': ([455.49, 198.44], 'kn'), - 'mass': ([120.e3, 115.e3], 'lbm'), - 'range': ([3243.9, 3378.7], 'nmi'), - 'velocity_rate': ([-0.25, 0.0], 'm/s**2'), - 'throttle': ([0., 0.], 'unitless'), - } + "initial_guesses": {"times": ([241, 58], "min")}, }, - 'post_mission': { - 'include_landing': True, + "post_mission": { + "include_landing": False, + "constrain_range": True, + "target_range": (1906, "nmi"), }, } - - -def phase_info_parameterization(phase_info, aviary_inputs): - """ - Modify the values in the phase_info dictionary to accomodate different values - for the following mission design inputs: cruise altitude, cruise Mach number, - cruise range, design gross mass. - - Parameters - ---------- - phase_info : dict - Dictionary of phase settings for a mission profile - aviary_inputs : - Object containing values and units for all aviary inputs and options - - Returns - ------- - dict - Modified phase_info that has been changed to match the new mission - parameters - """ - - range_cruise = aviary_inputs.get_val(Mission.Design.RANGE, units='NM') - alt_cruise = aviary_inputs.get_val(Mission.Design.CRUISE_ALTITUDE, units='ft') - gross_mass = aviary_inputs.get_val(Mission.Design.GROSS_MASS, units='lbm') - mach_cruise = aviary_inputs.get_val(Mission.Summary.CRUISE_MACH) - - # Range - range_scale = 1.0 - old_range_cruise = 3500.0 - if range_cruise != old_range_cruise: - range_scale = range_cruise / old_range_cruise - - vals = phase_info['descent']['initial_guesses']['range'][0] - new_vals = [vals[0] * range_scale, vals[1] * range_scale] - phase_info['descent']['initial_guesses']['range'] = (new_vals, 'NM') - - vals = phase_info['cruise']['initial_guesses']['range'][0] - new_val = vals[1] * range_scale - phase_info['cruise']['initial_guesses']['range'] = ([vals[0], new_val], 'NM') - - # Altitude - - # This doesn't seem to be stored regularly in some of the files. - old_alt_cruise = 35000 - if alt_cruise != old_alt_cruise: - - phase_info['climb']['initial_guesses']['altitude'] = ([0.0, alt_cruise], 'ft') - phase_info['climb']['user_options']['final_altitude'] = (alt_cruise, 'ft') - phase_info['cruise']['initial_guesses']['altitude'] = \ - ([alt_cruise, alt_cruise], 'ft') - phase_info['cruise']['user_options']['min_altitude'] = (alt_cruise, 'ft') - phase_info['cruise']['user_options']['max_altitude'] = (alt_cruise, 'ft') - phase_info['descent']['initial_guesses']['altitude'] = ([alt_cruise, 0.0], 'ft') - - # TODO - Could adjust time guesses/bounds in climb2 and desc2. - - # Mass - old_gross_mass = 175400.0 - if gross_mass != old_gross_mass: - - # Note, this requires that the guess for gross mass is pretty close to the - # compute mass. - - mass_scale = gross_mass / old_gross_mass - - for phase in ['climb', 'cruise', 'descent']: - vals = phase_info[phase]['initial_guesses']['mass'][0] - new_vals = [vals[0] * mass_scale, vals[1] * mass_scale] - phase_info[phase]['initial_guesses']['mass'] = (new_vals, 'lbm') - - # Mach - old_mach_cruise = 0.79 - if mach_cruise != old_mach_cruise: - - phase_info['climb']['user_options']['final_mach'] = mach_cruise - phase_info['cruise']['user_options']['min_mach'] = mach_cruise - phase_info['cruise']['user_options']['max_mach'] = mach_cruise - phase_info['descent']['user_options']['initial_mach'] = mach_cruise - - return phase_info diff --git a/aviary/interface/default_phase_info/simple.py b/aviary/interface/default_phase_info/simple.py deleted file mode 100644 index 29dcd56ea..000000000 --- a/aviary/interface/default_phase_info/simple.py +++ /dev/null @@ -1,99 +0,0 @@ -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 - -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] - - -phase_info = { - "pre_mission": {"include_takeoff": False, "optimize_mass": True}, - "climb": { - "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, - "user_options": { - "optimize_mach": False, - "optimize_altitude": False, - "polynomial_control_order": 1, - "num_segments": 5, - "order": 3, - "solve_for_range": False, - "initial_mach": (0.2, "unitless"), - "final_mach": (0.72, "unitless"), - "mach_bounds": ((0.18, 0.74), "unitless"), - "initial_altitude": (0.0, "ft"), - "final_altitude": (32000.0, "ft"), - "altitude_bounds": ((0.0, 34000.0), "ft"), - "throttle_enforcement": "path_constraint", - "fix_initial": True, - "constrain_final": False, - "fix_duration": False, - "initial_bounds": ((0.0, 0.0), "min"), - "duration_bounds": ((64.0, 192.0), "min"), - "add_initial_mass_constraint": False, - }, - "initial_guesses": {"times": ([0, 128], "min")}, - }, - "cruise": { - "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, - "user_options": { - "optimize_mach": False, - "optimize_altitude": False, - "polynomial_control_order": 1, - "num_segments": 5, - "order": 3, - "solve_for_range": False, - "initial_mach": (0.72, "unitless"), - "final_mach": (0.72, "unitless"), - "mach_bounds": ((0.7, 0.74), "unitless"), - "initial_altitude": (32000.0, "ft"), - "final_altitude": (34000.0, "ft"), - "altitude_bounds": ((23000.0, 38000.0), "ft"), - "throttle_enforcement": "boundary_constraint", - "fix_initial": False, - "constrain_final": False, - "fix_duration": False, - "initial_bounds": ((64.0, 192.0), "min"), - "duration_bounds": ((56.5, 169.5), "min"), - }, - "initial_guesses": {"times": ([128, 113], "min")}, - }, - "descent": { - "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, - "user_options": { - "optimize_mach": False, - "optimize_altitude": False, - "polynomial_control_order": 1, - "num_segments": 5, - "order": 3, - "solve_for_range": False, - "initial_mach": (0.72, "unitless"), - "final_mach": (0.36, "unitless"), - "mach_bounds": ((0.34, 0.74), "unitless"), - "initial_altitude": (34000.0, "ft"), - "final_altitude": (500.0, "ft"), - "altitude_bounds": ((0.0, 38000.0), "ft"), - "throttle_enforcement": "path_constraint", - "fix_initial": False, - "constrain_final": True, - "fix_duration": False, - "initial_bounds": ((120.5, 361.5), "min"), - "duration_bounds": ((29.0, 87.0), "min"), - }, - "initial_guesses": {"times": ([241, 58], "min")}, - }, - "post_mission": { - "include_landing": False, - "constrain_range": True, - "target_range": (1906, "nmi"), - }, -} diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 1c2084bc6..5227a27ed 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -19,7 +19,7 @@ from aviary.constants import GRAV_ENGLISH_LBM, RHO_SEA_LEVEL_ENGLISH from aviary.mission.flops_based.phases.build_landing import Landing from aviary.mission.flops_based.phases.build_takeoff import Takeoff -from aviary.mission.flops_based.phases.simple_energy_phase import EnergyPhase +from aviary.mission.flops_based.phases.energy_phase import EnergyPhase from aviary.mission.gasp_based.ode.groundroll_ode import GroundrollODE from aviary.mission.gasp_based.ode.params import ParamPort from aviary.mission.gasp_based.ode.unsteady_solved.unsteady_solved_ode import \ @@ -67,7 +67,7 @@ GASP = LegacyCode.GASP TWO_DEGREES_OF_FREEDOM = EquationsOfMotion.TWO_DEGREES_OF_FREEDOM -SIMPLE = EquationsOfMotion.SIMPLE +HEIGHT_ENERGY = EquationsOfMotion.HEIGHT_ENERGY SOLVED = EquationsOfMotion.SOLVED @@ -206,8 +206,8 @@ def load_inputs(self, input_filename, phase_info=None, engine_builder=None): else: if self.mission_method is TWO_DEGREES_OF_FREEDOM: from aviary.interface.default_phase_info.two_dof import phase_info - elif self.mission_method is SIMPLE: - from aviary.interface.default_phase_info.simple import phase_info + elif self.mission_method is HEIGHT_ENERGY: + from aviary.interface.default_phase_info.height_energy import phase_info elif self.mission_method is SOLVED: from aviary.interface.default_phase_info.solved import phase_info @@ -240,7 +240,7 @@ def load_inputs(self, input_filename, phase_info=None, engine_builder=None): ## PROCESSING ## # set up core subsystems - if mission_method is SIMPLE: + if mission_method is HEIGHT_ENERGY: everything_else_origin = FLOPS elif mission_method in (TWO_DEGREES_OF_FREEDOM, SOLVED): everything_else_origin = GASP @@ -412,7 +412,7 @@ def add_pre_mission_systems(self): self._add_gasp_takeoff_systems() # Check for HE mission method - elif self.mission_method is SIMPLE: + elif self.mission_method is HEIGHT_ENERGY: self._add_flops_takeoff_systems() def _add_flops_takeoff_systems(self): @@ -714,7 +714,7 @@ def _get_simple_phase(self, phase_name, phase_idx): default_mission_subsystems = [ subsystems['aerodynamics'], subsystems['propulsion']] - if self.mission_method is SIMPLE: + if self.mission_method is HEIGHT_ENERGY: phase_object = EnergyPhase.from_phase_info( phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data) @@ -747,7 +747,7 @@ def _get_simple_phase(self, phase_name, phase_idx): fix_initial_time = get_initial(fix_initial, "time", True) input_initial = False - if self.mission_method is SIMPLE: + if self.mission_method is HEIGHT_ENERGY: user_options.set_val('initial_ref', 10., 'min') duration_bounds = user_options.get_val("duration_bounds", 'min') user_options.set_val( @@ -1051,7 +1051,7 @@ def add_subsystem_timeseries_outputs(phase, phase_name): if phase_name == 'ascent': self._add_groundroll_eq_constraint(phase) - elif self.mission_method is SIMPLE: + elif self.mission_method is HEIGHT_ENERGY: for phase_idx, phase_name in enumerate(phases): phase = traj.add_phase( phase_name, self._get_simple_phase(phase_name, phase_idx)) @@ -1173,7 +1173,7 @@ def add_post_mission_systems(self, include_landing=True): """ if include_landing and self.post_mission_info['include_landing']: - if self.mission_method is SIMPLE: + if self.mission_method is HEIGHT_ENERGY: self._add_flops_landing_systems() elif self.mission_method is TWO_DEGREES_OF_FREEDOM: self._add_gasp_landing_systems() @@ -1192,7 +1192,7 @@ def add_post_mission_systems(self, include_landing=True): self.post_mission.add_subsystem(external_subsystem.name, subsystem_postmission) - if self.mission_method is SIMPLE: + if self.mission_method is HEIGHT_ENERGY: phases = list(self.phase_info.keys()) ecomp = om.ExecComp('fuel_burned = initial_mass - mass_final', initial_mass={'units': 'lbm'}, @@ -1358,7 +1358,7 @@ def add_linkage_constraint(self, phase_a, phase_b, var_b): phases, vars=[Dynamic.Mission.RANGE], units='m', ref=10.e3) self.traj.link_phases(phases[:7], vars=['TAS'], units='kn', ref=200.) - elif self.mission_method is SIMPLE: + elif self.mission_method is HEIGHT_ENERGY: self.traj.link_phases( phases, ["time", Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=True) @@ -1619,7 +1619,7 @@ def add_design_variables(self): for dv_name, dv_dict in dv_dict.items(): self.model.add_design_var(dv_name, **dv_dict) - if self.mission_method is SIMPLE: + if self.mission_method is HEIGHT_ENERGY: optimize_mass = self.pre_mission_info.get('optimize_mass') if optimize_mass: self.model.add_design_var(Mission.Design.GROSS_MASS, units='lbm', @@ -1742,7 +1742,7 @@ def add_objective(self, objective_type=None, ref=None): self.model.add_objective(Mission.Objectives.FUEL, ref=ref) # If 'mission_method' is 'FLOPS', add a 'fuel_burned' objective - elif self.mission_method is SIMPLE: + elif self.mission_method is HEIGHT_ENERGY: ref = ref if ref is not None else default_ref_values.get("fuel_burned", 1) self.model.add_objective("fuel_burned", ref=ref) @@ -2031,7 +2031,7 @@ def _add_guesses(self, phase_name, phase, guesses): rotation_mass = self.initial_guesses['rotation_mass'] flight_duration = self.initial_guesses['flight_duration'] - if self.mission_method is SIMPLE: + if self.mission_method is HEIGHT_ENERGY: control_keys = ["mach", "altitude"] state_keys = ["mass", "range"] else: @@ -2045,7 +2045,7 @@ def _add_guesses(self, phase_name, phase, guesses): prob_keys = ["tau_gear", "tau_flaps"] # for the simple mission method, use the provided initial and final mach and altitude values from phase_info - if self.mission_method is SIMPLE: + if self.mission_method is HEIGHT_ENERGY: initial_altitude = self.phase_info[phase_name]['user_options']['initial_altitude'] final_altitude = self.phase_info[phase_name]['user_options']['final_altitude'] initial_mach = self.phase_info[phase_name]['user_options']['initial_mach'] diff --git a/aviary/interface/test/test_basic_report.py b/aviary/interface/test/test_basic_report.py index 02d2ddc25..01b166d9f 100644 --- a/aviary/interface/test/test_basic_report.py +++ b/aviary/interface/test/test_basic_report.py @@ -5,7 +5,7 @@ from openmdao.utils.testing_utils import use_tempdirs -from aviary.interface.default_phase_info.simple import phase_info +from aviary.interface.default_phase_info.height_energy import phase_info from aviary.interface.methods_for_level1 import run_aviary from openmdao.utils.testing_utils import use_tempdirs diff --git a/aviary/interface/test/test_check_phase_info.py b/aviary/interface/test/test_check_phase_info.py index 593d80cb5..f30b697d5 100644 --- a/aviary/interface/test/test_check_phase_info.py +++ b/aviary/interface/test/test_check_phase_info.py @@ -2,25 +2,25 @@ import copy from aviary.interface.utils.check_phase_info import check_phase_info -from aviary.interface.default_phase_info.simple import phase_info as phase_info_flops +from aviary.interface.default_phase_info.height_energy import phase_info as phase_info_flops from aviary.interface.default_phase_info.two_dof import phase_info as phase_info_gasp from aviary.variable_info.enums import EquationsOfMotion -SIMPLE = EquationsOfMotion.SIMPLE +HEIGHT_ENERGY = EquationsOfMotion.HEIGHT_ENERGY TWO_DEGREES_OF_FREEDOM = EquationsOfMotion.TWO_DEGREES_OF_FREEDOM class TestCheckInputs(unittest.TestCase): def test_correct_input_simple(self): # This should pass without any issue as it's the same valid dict as before - self.assertTrue(check_phase_info(phase_info_flops, mission_method=SIMPLE)) + self.assertTrue(check_phase_info(phase_info_flops, mission_method=HEIGHT_ENERGY)) def test_incorrect_tuple(self): # Let's replace a tuple with a float in the 'climb' phase incorrect_tuple_phase_info = copy.deepcopy(phase_info_flops) incorrect_tuple_phase_info['climb']['user_options']['initial_altitude'] = 10.668e3 with self.assertRaises(ValueError): - check_phase_info(incorrect_tuple_phase_info, mission_method=SIMPLE) + check_phase_info(incorrect_tuple_phase_info, mission_method=HEIGHT_ENERGY) def test_incorrect_unit(self): # Let's replace a valid unit with an invalid one in the 'climb' phase @@ -29,7 +29,7 @@ def test_incorrect_unit(self): 10.668e3, 'invalid_unit') with self.assertRaisesRegex(ValueError, "Key initial_altitude in phase climb has an invalid unit invalid_unit."): - check_phase_info(incorrect_unit_phase_info, mission_method=SIMPLE) + check_phase_info(incorrect_unit_phase_info, mission_method=HEIGHT_ENERGY) def test_correct_input_gasp(self): # This should pass without any issue as it's the same valid dict as before diff --git a/aviary/interface/test/test_interface_bugs.py b/aviary/interface/test/test_interface_bugs.py index ed811bc2c..59f614e3d 100644 --- a/aviary/interface/test/test_interface_bugs.py +++ b/aviary/interface/test/test_interface_bugs.py @@ -6,7 +6,7 @@ from aviary.interface.methods_for_level2 import AviaryProblem from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase -from aviary.interface.default_phase_info.simple import phase_info as ph_in +from aviary.interface.default_phase_info.height_energy import phase_info as ph_in from aviary.variable_info.variables import Aircraft from openmdao.utils.testing_utils import use_tempdirs diff --git a/aviary/interface/test/test_phase_info.py b/aviary/interface/test/test_phase_info.py index ffefec9ae..812410958 100644 --- a/aviary/interface/test/test_phase_info.py +++ b/aviary/interface/test/test_phase_info.py @@ -78,7 +78,7 @@ def _test_phase_info_dict(self, phase_info_dict, name): def test_default_phase_simple(self): """Tests the roundtrip conversion for default_phase_info.simple""" - from aviary.interface.default_phase_info.simple import phase_info + from aviary.interface.default_phase_info.height_energy import phase_info local_phase_info = deepcopy(phase_info) self._test_phase_info_dict(local_phase_info, 'cruise') diff --git a/aviary/interface/test/test_reserve_support.py b/aviary/interface/test/test_reserve_support.py index 0b6e3e2cf..0f0fce3b5 100644 --- a/aviary/interface/test/test_reserve_support.py +++ b/aviary/interface/test/test_reserve_support.py @@ -5,7 +5,7 @@ from openmdao.utils.testing_utils import use_tempdirs from aviary.interface.methods_for_level2 import AviaryProblem -from aviary.interface.default_phase_info.simple import phase_info as ph_in_flops +from aviary.interface.default_phase_info.height_energy import phase_info as ph_in_flops from aviary.interface.default_phase_info.two_dof import phase_info as ph_in_gasp from aviary.variable_info.variables import Aircraft, Mission diff --git a/aviary/interface/utils/check_phase_info.py b/aviary/interface/utils/check_phase_info.py index ecd21875c..48dc43a1b 100644 --- a/aviary/interface/utils/check_phase_info.py +++ b/aviary/interface/utils/check_phase_info.py @@ -2,7 +2,7 @@ from aviary.variable_info.enums import SpeedType, EquationsOfMotion TWO_DEGREES_OF_FREEDOM = EquationsOfMotion.TWO_DEGREES_OF_FREEDOM -SIMPLE = EquationsOfMotion.SIMPLE +HEIGHT_ENERGY = EquationsOfMotion.HEIGHT_ENERGY SOLVED = EquationsOfMotion.SOLVED @@ -193,7 +193,7 @@ def check_phase_info(phase_info, mission_method): phase_keys[phase] = phase_keys_gasp[phase] elif mission_method is SOLVED: return - elif mission_method is SIMPLE: + elif mission_method is HEIGHT_ENERGY: for phase in phase_info: if phase != 'pre_mission' and phase != 'post_mission': phase_keys[phase] = {**common_keys, **common_entries} 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 e3faf4747..16e34c0f2 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,7 @@ import openmdao.api as om -from aviary.interface.default_phase_info.simple import default_mission_subsystems +from aviary.interface.default_phase_info.height_energy import 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) 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 ebcf3a092..fd39339e5 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,7 @@ import openmdao.api as om -from aviary.interface.default_phase_info.simple import default_mission_subsystems +from aviary.interface.default_phase_info.height_energy import 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) diff --git a/aviary/mission/flops_based/phases/simple_energy_phase.py b/aviary/mission/flops_based/phases/simple_energy_phase.py deleted file mode 100644 index 6da23cbdb..000000000 --- a/aviary/mission/flops_based/phases/simple_energy_phase.py +++ /dev/null @@ -1,440 +0,0 @@ -import dymos as dm - -from aviary.mission.flops_based.phases.phase_builder_base import ( - register, PhaseBuilderBase, InitialGuessControl, InitialGuessParameter, - InitialGuessPolynomialControl, InitialGuessState, InitialGuessTime) - -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.variable_meta_data import _MetaData -from aviary.mission.flops_based.phases.phase_utils import add_subsystem_variables_to_phase, get_initial -from aviary.variable_info.variables import Dynamic -from aviary.mission.flops_based.ode.simple_mission_ODE import MissionODE - - -# TODO: support/handle the following in the base class -# - phase.set_time_options() -# - currently handled in level 3 interface implementation -# - self.external_subsystems -# - self.meta_data, with cls.default_meta_data customization point -@register -class EnergyPhase(PhaseBuilderBase): - ''' - A phase builder for a simple energy phase. - - Attributes - ---------- - name : str ('energy_phase') - object label - - subsystem_options (None) - dictionary of parameters to be passed to the subsystem builders - - user_options : AviaryValues () - state/path constraint values and flags - - supported options: - - num_segments : int (5) - transcription: number of segments - - order : int (3) - transcription: order of the state transcription; the order of the control - transcription is `order - 1` - - fix_initial : bool (True) - - initial_ref : float (1.0, 's') - - initial_bounds : pair ((0.0, 100.0) 's') - - duration_ref : float (1.0, 's') - - duration_bounds : pair ((0.0, 100.0) 's') - - required_available_climb_rate : float (None) - minimum avaliable climb rate - - constrain_final : bool (False) - - input_initial : bool (False) - - initial_guesses : AviaryValues () - state/path beginning values to be set on the problem - - supported options: - - times - - range - - altitude - - velocity - - velocity_rate - - mass - - throttle - - ode_class : type (None) - advanced: the type of system defining the ODE - - transcription : "Dymos transcription object" (None) - advanced: an object providing the transcription technique of the - optimal control problem - - external_subsystems : Sequence["subsystem builder"] () - advanced - - meta_data : dict (<"builtin" meta data>) - advanced: meta data associated with variables in the Aviary data hierarchy - - default_name : str - class attribute: derived type customization point; the default value - for name - - default_ode_class : type - class attribute: derived type customization point; the default value - for ode_class used by build_phase - - default_meta_data : dict - class attribute: derived type customization point; the default value for - meta_data - - Methods - ------- - build_phase - make_default_transcription - validate_options - assign_default_options - ''' - __slots__ = ('external_subsystems', 'meta_data') - - # region : derived type customization points - _meta_data_ = {} - - _initial_guesses_meta_data_ = {} - - default_name = 'cruise' - - default_ode_class = MissionODE - - default_meta_data = _MetaData - # endregion : derived type customization points - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, core_subsystems=core_subsystems, subsystem_options=subsystem_options, user_options=user_options, initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription) - - # TODO: support external_subsystems and meta_data in the base class - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - - def build_phase(self, aviary_options: AviaryValues = None): - ''' - Return a new energy phase for analysis using these constraints. - - If ode_class is None, default_ode_class is used. - - If transcription is None, the return value from calling - make_default_transcription is used. - - Parameters - ---------- - aviary_options : AviaryValues () - collection of Aircraft/Mission specific options - - Returns - ------- - dymos.Phase - ''' - phase: dm.Phase = super().build_phase(aviary_options) - - user_options: AviaryValues = self.user_options - - fix_initial = user_options.get_val('fix_initial') - constrain_final = user_options.get_val('constrain_final') - optimize_mach = user_options.get_val('optimize_mach') - optimize_altitude = user_options.get_val('optimize_altitude') - input_initial = user_options.get_val('input_initial') - polynomial_control_order = user_options.get_item('polynomial_control_order')[0] - use_polynomial_control = user_options.get_val('use_polynomial_control') - throttle_enforcement = user_options.get_val('throttle_enforcement') - mach_bounds = user_options.get_item('mach_bounds') - altitude_bounds = user_options.get_item('altitude_bounds') - initial_mach = user_options.get_item('initial_mach')[0] - final_mach = user_options.get_item('final_mach')[0] - initial_altitude = user_options.get_item('initial_altitude')[0] - final_altitude = user_options.get_item('final_altitude')[0] - solve_for_range = user_options.get_val('solve_for_range') - no_descent = user_options.get_val('no_descent') - no_climb = user_options.get_val('no_climb') - - ############## - # Add States # - ############## - # TODO: critically think about how we should handle fix_initial and input_initial defaults. - # In keeping with Dymos standards, the default should be False instead of True. - input_initial_mass = get_initial(input_initial, Dynamic.Mission.MASS) - fix_initial_mass = get_initial(fix_initial, Dynamic.Mission.MASS, True) - - # Experiment: use a constraint for mass instead of connected initial. - # This is due to some problems in mpi. - # This is needed for the cutting edge full subsystem integration. - # TODO: when a Dymos fix is in and we've verified that full case works with the fix, - # remove this argument. - if user_options.get_val('add_initial_mass_constraint'): - phase.add_constraint('rhs_all.initial_mass_residual', equals=0.0, ref=1e4) - input_initial_mass = False - - phase.add_state( - Dynamic.Mission.MASS, fix_initial=fix_initial_mass, fix_final=False, - lower=0.0, ref=1e4, defect_ref=1e6, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - input_initial=input_initial_mass, - # solve_segments='forward', - ) - - input_initial_range = get_initial(input_initial, Dynamic.Mission.RANGE) - fix_initial_range = get_initial(fix_initial, Dynamic.Mission.RANGE, True) - phase.add_state( - Dynamic.Mission.RANGE, fix_initial=fix_initial_range, fix_final=False, - lower=0.0, ref=1e6, defect_ref=1e8, units='m', - rate_source=Dynamic.Mission.RANGE_RATE, - input_initial=input_initial_range, - solve_segments='forward' if solve_for_range else None, - ) - - phase = add_subsystem_variables_to_phase( - phase, self.name, self.external_subsystems) - - ################ - # Add Controls # - ################ - if use_polynomial_control: - phase.add_polynomial_control( - Dynamic.Mission.MACH, - targets=Dynamic.Mission.MACH, units=mach_bounds[1], - opt=optimize_mach, lower=mach_bounds[0][0], upper=mach_bounds[0][1], - rate_targets=[Dynamic.Mission.MACH_RATE], - order=polynomial_control_order, ref=0.5, - ) - else: - phase.add_control( - Dynamic.Mission.MACH, - targets=Dynamic.Mission.MACH, units=mach_bounds[1], - opt=optimize_mach, lower=mach_bounds[0][0], upper=mach_bounds[0][1], - rate_targets=[Dynamic.Mission.MACH_RATE], - ref=0.5, - ) - - if optimize_mach and fix_initial: - phase.add_boundary_constraint( - Dynamic.Mission.MACH, loc='initial', equals=initial_mach, - ) - - if optimize_mach and constrain_final: - phase.add_boundary_constraint( - Dynamic.Mission.MACH, loc='final', equals=final_mach, - ) - - # Add altitude rate as a control - if use_polynomial_control: - phase.add_polynomial_control( - Dynamic.Mission.ALTITUDE, - targets=Dynamic.Mission.ALTITUDE, units=altitude_bounds[1], - opt=optimize_altitude, lower=altitude_bounds[0][0], upper=altitude_bounds[0][1], - rate_targets=[Dynamic.Mission.ALTITUDE_RATE], - order=polynomial_control_order, ref=altitude_bounds[0][1], - ) - else: - phase.add_control( - Dynamic.Mission.ALTITUDE, - targets=Dynamic.Mission.ALTITUDE, units=altitude_bounds[1], - opt=optimize_altitude, lower=altitude_bounds[0][0], upper=altitude_bounds[0][1], - rate_targets=[Dynamic.Mission.ALTITUDE_RATE], - ref=altitude_bounds[0][1], - ) - - if optimize_altitude and fix_initial: - phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc='initial', equals=initial_altitude, units=altitude_bounds[1], ref=1.e4, - ) - - if optimize_altitude and constrain_final: - phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc='final', equals=final_altitude, units=altitude_bounds[1], ref=1.e4, - ) - - ################## - # Add Timeseries # - ################## - phase.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units='unitless' - ) - - phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' - ) - - phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' - ) - - phase.add_timeseries_output( - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, - output_name=Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, units='m/s' - ) - - phase.add_timeseries_output( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - output_name=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units='lbm/h' - ) - - phase.add_timeseries_output( - Dynamic.Mission.ALTITUDE_RATE, - output_name=Dynamic.Mission.ALTITUDE_RATE, units='ft/s' - ) - - phase.add_timeseries_output( - Dynamic.Mission.THROTTLE, - output_name=Dynamic.Mission.THROTTLE, units='unitless' - ) - - phase.add_timeseries_output( - Dynamic.Mission.VELOCITY, - output_name=Dynamic.Mission.VELOCITY, units='m/s' - ) - - ################### - # Add Constraints # - ################### - if no_descent: - phase.add_path_constraint(Dynamic.Mission.ALTITUDE_RATE, lower=0.0) - - if no_climb: - phase.add_path_constraint(Dynamic.Mission.ALTITUDE_RATE, upper=0.0) - - required_available_climb_rate, units = user_options.get_item( - 'required_available_climb_rate') - - if required_available_climb_rate is not None: - phase.add_path_constraint( - Dynamic.Mission.ALTITUDE_RATE_MAX, - lower=required_available_climb_rate, units=units - ) - - if throttle_enforcement == 'boundary_constraint': - phase.add_boundary_constraint( - Dynamic.Mission.THROTTLE, loc='initial', lower=0.0, upper=1.0, units='unitless', - ) - phase.add_boundary_constraint( - Dynamic.Mission.THROTTLE, loc='final', lower=0.0, upper=1.0, units='unitless', - ) - elif throttle_enforcement == 'path_constraint': - phase.add_path_constraint( - Dynamic.Mission.THROTTLE, lower=0.0, upper=1.0, units='unitless', - ) - - return phase - - def make_default_transcription(self): - ''' - Return a transcription object to be used by default in build_phase. - ''' - user_options = self.user_options - - num_segments, _ = user_options.get_item('num_segments') - order, _ = user_options.get_item('order') - - seg_ends, _ = dm.utils.lgl.lgl(num_segments + 1) - - transcription = dm.Radau( - num_segments=num_segments, order=order, compressed=True, - segment_ends=seg_ends) - - return transcription - - def _extra_ode_init_kwargs(self): - """ - Return extra kwargs required for initializing the ODE. - """ - # TODO: support external_subsystems and meta_data in the base class - return { - 'external_subsystems': self.external_subsystems, - 'meta_data': self.meta_data, - 'subsystem_options': self.subsystem_options, - 'throttle_enforcement': self.user_options.get_val('throttle_enforcement'), - } - - -EnergyPhase._add_meta_data( - 'num_segments', val=5, desc='transcription: number of segments') - -EnergyPhase._add_meta_data( - 'order', val=3, - desc='transcription: order of the state transcription; the order of the control' - ' transcription is `order - 1`') - -EnergyPhase._add_meta_data('polynomial_control_order', val=3) - -EnergyPhase._add_meta_data('use_polynomial_control', val=True) - -EnergyPhase._add_meta_data('add_initial_mass_constraint', val=False) - -EnergyPhase._add_meta_data('fix_initial', val=True) - -EnergyPhase._add_meta_data('optimize_mach', val=False) - -EnergyPhase._add_meta_data('optimize_altitude', val=False) - -EnergyPhase._add_meta_data('initial_bounds', val=(0., 100.), units='s') - -EnergyPhase._add_meta_data('duration_bounds', val=(0., 100.), units='s') - -EnergyPhase._add_meta_data( - 'required_available_climb_rate', val=None, units='m/s', - desc='minimum avaliable climb rate') - -EnergyPhase._add_meta_data( - 'no_climb', val=False, desc='aircraft is not allowed to climb during phase') - -EnergyPhase._add_meta_data( - 'no_descent', val=False, desc='aircraft is not allowed to descend during phase') - -EnergyPhase._add_meta_data('constrain_final', val=False) - -EnergyPhase._add_meta_data('input_initial', val=False) - -EnergyPhase._add_meta_data('initial_mach', val=None, units='unitless') - -EnergyPhase._add_meta_data('final_mach', val=None, units='unitless') - -EnergyPhase._add_meta_data('initial_altitude', val=None, units='ft') - -EnergyPhase._add_meta_data('final_altitude', val=None, units='ft') - -EnergyPhase._add_meta_data('throttle_enforcement', val=None) - -EnergyPhase._add_meta_data('mach_bounds', val=(0., 2.), units='unitless') - -EnergyPhase._add_meta_data('altitude_bounds', val=(0., 60.e3), units='ft') - -EnergyPhase._add_meta_data('solve_for_range', val=False) - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessTime(), - desc='initial guess for initial time and duration specified as a tuple') - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('range'), - desc='initial guess for horizontal distance traveled') - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('altitude'), - desc='initial guess for vertical distances') - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('mach'), - desc='initial guess for speed') - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('mass'), - desc='initial guess for mass') diff --git a/aviary/mission/gasp_based/phases/run_phases/run_ascent.py b/aviary/mission/gasp_based/phases/run_phases/run_ascent.py index 598e1ba8b..fdd3c0384 100644 --- a/aviary/mission/gasp_based/phases/run_phases/run_ascent.py +++ b/aviary/mission/gasp_based/phases/run_phases/run_ascent.py @@ -5,7 +5,7 @@ from aviary.mission.gasp_based.polynomial_fit import PolynomialFit from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Dynamic, Mission -from aviary.interface.default_phase_info.simple import default_mission_subsystems +from aviary.interface.default_phase_info.height_energy import default_mission_subsystems def run_ascent(make_plots=False): diff --git a/aviary/models/N3CC/N3CC_data.py b/aviary/models/N3CC/N3CC_data.py index 13219ce56..a163553ea 100644 --- a/aviary/models/N3CC/N3CC_data.py +++ b/aviary/models/N3CC/N3CC_data.py @@ -26,7 +26,7 @@ from aviary.variable_info.variables import Mission from aviary.variable_info.variables import Settings from aviary.variable_info.enums import EquationsOfMotion, LegacyCode -from aviary.interface.default_phase_info.simple import default_mission_subsystems +from aviary.interface.default_phase_info.height_energy import default_mission_subsystems Dynamic = _Dynamic.Mission @@ -315,7 +315,7 @@ # Settings # --------------------------- -inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.SIMPLE) +inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.HEIGHT_ENERGY) inputs.set_val(Settings.MASS_METHOD, LegacyCode.FLOPS) # --------------------------- diff --git a/aviary/models/N3CC/N3CC_generic_low_speed_polars_FLOPSinp.csv b/aviary/models/N3CC/N3CC_generic_low_speed_polars_FLOPSinp.csv index 2ceb7088d..81ac1ee35 100644 --- a/aviary/models/N3CC/N3CC_generic_low_speed_polars_FLOPSinp.csv +++ b/aviary/models/N3CC/N3CC_generic_low_speed_polars_FLOPSinp.csv @@ -169,7 +169,7 @@ mission:takeoff:rolling_friction_coefficient,0.0175,unitless mission:takeoff:spoiler_drag_coefficient,0.085,unitless mission:takeoff:spoiler_lift_coefficient,-0.81,unitless mission:takeoff:thrust_incidence,0,deg -settings:equations_of_motion,simple +settings:equations_of_motion,height_energy settings:mass_method,FLOPS # Unconverted Values 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 8b3f48616..feeca95a1 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 @@ -263,7 +263,7 @@ # Settings # --------------------------- -inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.SIMPLE) +inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.HEIGHT_ENERGY) inputs.set_val(Settings.MASS_METHOD, LegacyCode.FLOPS) # --------------------------- 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 3f36a12f2..37ef21ff0 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 @@ -263,7 +263,7 @@ # Settings # --------------------------- -inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.SIMPLE) +inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.HEIGHT_ENERGY) inputs.set_val(Settings.MASS_METHOD, LegacyCode.FLOPS) # --------------------------- 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 2c1328bc7..667b0d72a 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 @@ -262,7 +262,7 @@ # Settings # --------------------------- -inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.SIMPLE) +inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.HEIGHT_ENERGY) inputs.set_val(Settings.MASS_METHOD, LegacyCode.FLOPS) # --------------------------- 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 f8fe5041a..ca02d5832 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 @@ -263,7 +263,7 @@ # Settings # --------------------------- -inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.SIMPLE) +inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.HEIGHT_ENERGY) inputs.set_val(Settings.MASS_METHOD, LegacyCode.FLOPS) # --------------------------- diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv index abdddb634..2d4ea4703 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv @@ -155,5 +155,5 @@ mission:takeoff:fuel_simple,577,lbm mission:takeoff:lift_coefficient_max,3.0,unitless mission:takeoff:lift_over_drag,17.354,unitless mission:takeoff:rolling_friction_coefficient,0.0175,unitless -settings:equations_of_motion,simple +settings:equations_of_motion,height_energy settings:mass_method,FLOPS \ No newline at end of file diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwFm_simple.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwFm_simple.csv index abdddb634..2d4ea4703 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwFm_simple.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwFm_simple.csv @@ -155,5 +155,5 @@ mission:takeoff:fuel_simple,577,lbm mission:takeoff:lift_coefficient_max,3.0,unitless mission:takeoff:lift_over_drag,17.354,unitless mission:takeoff:rolling_friction_coefficient,0.0175,unitless -settings:equations_of_motion,simple +settings:equations_of_motion,height_energy settings:mass_method,FLOPS \ No newline at end of file diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv index b0c9ace8d..5c0d0b8a0 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv @@ -269,5 +269,5 @@ mission:takeoff:lift_coefficient_flap_increment,0.4182,unitless mission:takeoff:lift_coefficient_max,3.0,unitless mission:takeoff:lift_over_drag,17.354,unitless mission:takeoff:rolling_friction_coefficient,0.0175,unitless -settings:equations_of_motion,simple +settings:equations_of_motion,height_energy settings:mass_method,GASP \ No newline at end of file diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm_simple.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm_simple.csv index b0c9ace8d..5c0d0b8a0 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm_simple.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm_simple.csv @@ -269,5 +269,5 @@ mission:takeoff:lift_coefficient_flap_increment,0.4182,unitless mission:takeoff:lift_coefficient_max,3.0,unitless mission:takeoff:lift_over_drag,17.354,unitless mission:takeoff:rolling_friction_coefficient,0.0175,unitless -settings:equations_of_motion,simple +settings:equations_of_motion,height_energy settings:mass_method,GASP \ No newline at end of file diff --git a/aviary/subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv b/aviary/subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv index df17fad98..356ddc757 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv +++ b/aviary/subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv @@ -137,5 +137,5 @@ mission:takeoff:fuel_simple,400,lbm mission:takeoff:lift_coefficient_max,2.55,unitless mission:takeoff:lift_over_drag,25,unitless mission:takeoff:rolling_friction_coefficient,0.0175,unitless -settings:equations_of_motion,simple +settings:equations_of_motion,height_energy settings:mass_method,FLOPS \ No newline at end of file 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 c6a26a221..3788620b8 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,7 +5,7 @@ from openmdao.utils.assert_utils import assert_near_equal from aviary.subsystems.premission import CorePreMission -from aviary.interface.default_phase_info.simple import aero, prop, geom +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 diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py index a09db92f1..ac78f16d8 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py @@ -13,7 +13,7 @@ from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase from aviary.utils.csv_data_file import read_data_file from aviary.utils.named_values import NamedValues -from aviary.interface.default_phase_info.simple import phase_info +from aviary.interface.default_phase_info.height_energy import phase_info from aviary.variable_info.variables import Aircraft from copy import deepcopy 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 216f17fc5..897caf9a5 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,7 @@ from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder from aviary.subsystems.premission import CorePreMission -from aviary.interface.default_phase_info.simple import aero, prop, geom +from aviary.interface.default_phase_info.height_energy import aero, prop, geom 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 diff --git a/aviary/subsystems/test/test_external_subsystem_bus.py b/aviary/subsystems/test/test_external_subsystem_bus.py index 97b3c5e69..24f9dd4ba 100644 --- a/aviary/subsystems/test/test_external_subsystem_bus.py +++ b/aviary/subsystems/test/test_external_subsystem_bus.py @@ -9,7 +9,7 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal -from aviary.interface.default_phase_info.simple import phase_info as ph_in +from aviary.interface.default_phase_info.height_energy import phase_info as ph_in from aviary.interface.methods_for_level2 import AviaryProblem from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase diff --git a/aviary/subsystems/test/test_flops_based_premission.py b/aviary/subsystems/test/test_flops_based_premission.py index 07ebbf478..87a2251e1 100644 --- a/aviary/subsystems/test/test_flops_based_premission.py +++ b/aviary/subsystems/test/test_flops_based_premission.py @@ -13,7 +13,7 @@ from aviary.variable_info.variables import Aircraft, Mission from aviary.variable_info.variables_in import VariablesIn from aviary.utils.functions import set_aviary_initial_values -from aviary.interface.default_phase_info.simple import default_premission_subsystems +from aviary.interface.default_phase_info.height_energy import default_premission_subsystems from aviary.utils.preprocessors import preprocess_crewpayload diff --git a/aviary/utils/Fortran_to_Aviary.py b/aviary/utils/Fortran_to_Aviary.py index 82aad72c3..3273f0ee5 100644 --- a/aviary/utils/Fortran_to_Aviary.py +++ b/aviary/utils/Fortran_to_Aviary.py @@ -108,7 +108,7 @@ def create_aviary_deck(fortran_deck: str, legacy_code=None, defaults_deck=None, for var, (val, units) in sorted(vehicle_data['input_values']): writer.writerow([var] + val + [units]) if legacy_code is FLOPS: - EOM = 'simple' + EOM = 'height_energy' mass = 'FLOPS' if legacy_code is GASP: EOM = '2DOF' diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index 5ddf69121..0423ac7de 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -5,7 +5,7 @@ from aviary.interface.methods_for_level2 import AviaryProblem from aviary.interface.default_phase_info.two_dof import phase_info as two_dof_phase_info -from aviary.interface.default_phase_info.simple import phase_info as simple_phase_info +from aviary.interface.default_phase_info.height_energy import phase_info as simple_phase_info from aviary.interface.default_phase_info.solved import phase_info as solved_phase_info from aviary.variable_info.enums import EquationsOfMotion 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 98b67bb04..aff3bb72c 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 @@ -20,7 +20,7 @@ inputs as _inputs from aviary.variable_info.variables import Dynamic as _Dynamic from aviary.variable_info.variables_in import VariablesIn -from aviary.interface.default_phase_info.simple import default_premission_subsystems +from aviary.interface.default_phase_info.height_energy import default_premission_subsystems from aviary.subsystems.premission import CorePreMission Dynamic = _Dynamic.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 3de522d6f..cd7129be8 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 @@ -22,11 +22,11 @@ from aviary.variable_info.functions import setup_trajectory_params from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables_in import VariablesIn -from aviary.mission.flops_based.phases.simple_energy_phase import EnergyPhase +from aviary.mission.flops_based.phases.energy_phase import EnergyPhase from aviary.variable_info.variables import Aircraft, Dynamic, Mission from aviary.subsystems.premission import CorePreMission -from aviary.interface.default_phase_info.simple import default_premission_subsystems, default_mission_subsystems +from aviary.interface.default_phase_info.height_energy import default_premission_subsystems, default_mission_subsystems from aviary.utils.preprocessors import preprocess_crewpayload try: 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 99b4c3c31..512b710d8 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py @@ -18,7 +18,7 @@ landing_fullstop_user_options as _landing_fullstop_user_options) from aviary.variable_info.variables import Dynamic as _Dynamic -from aviary.interface.default_phase_info.simple import default_premission_subsystems +from aviary.interface.default_phase_info.height_energy import default_premission_subsystems from aviary.utils.preprocessors import preprocess_crewpayload from aviary.variable_info.variables_in import VariablesIn 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 abe145537..bc403ccbf 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py @@ -18,7 +18,7 @@ takeoff_liftoff_user_options as _takeoff_liftoff_user_options) from aviary.variable_info.variables import Aircraft, Dynamic as _Dynamic -from aviary.interface.default_phase_info.simple import default_premission_subsystems +from aviary.interface.default_phase_info.height_energy import default_premission_subsystems from aviary.utils.preprocessors import preprocess_crewpayload from aviary.variable_info.variables_in import VariablesIn diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py index b5e9600aa..ad785f4d8 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py @@ -15,7 +15,7 @@ from aviary.validation_cases.benchmark_utils import \ compare_against_expected_values from aviary.variable_info.variables import Dynamic -from aviary.interface.default_phase_info.simple import phase_info +from aviary.interface.default_phase_info.height_energy import phase_info @use_tempdirs diff --git a/aviary/variable_info/enums.py b/aviary/variable_info/enums.py index 802232eb2..17e8f102c 100644 --- a/aviary/variable_info/enums.py +++ b/aviary/variable_info/enums.py @@ -59,7 +59,7 @@ class EquationsOfMotion(Enum): """ TWO_DEGREES_OF_FREEDOM = '2DOF' # TODO these are a little out of place atm - SIMPLE = 'simple' + HEIGHT_ENERGY = 'height_energy' SOLVED = 'solved' From 2fa1bc384ec41c386eb5067937528b6c2d6cdedb Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 11 Jan 2024 14:42:29 -0600 Subject: [PATCH 048/188] Added missing file --- .../flops_based/phases/energy_phase.py | 440 ++++++++++++++++++ 1 file changed, 440 insertions(+) create mode 100644 aviary/mission/flops_based/phases/energy_phase.py diff --git a/aviary/mission/flops_based/phases/energy_phase.py b/aviary/mission/flops_based/phases/energy_phase.py new file mode 100644 index 000000000..6da23cbdb --- /dev/null +++ b/aviary/mission/flops_based/phases/energy_phase.py @@ -0,0 +1,440 @@ +import dymos as dm + +from aviary.mission.flops_based.phases.phase_builder_base import ( + register, PhaseBuilderBase, InitialGuessControl, InitialGuessParameter, + InitialGuessPolynomialControl, InitialGuessState, InitialGuessTime) + +from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.variable_meta_data import _MetaData +from aviary.mission.flops_based.phases.phase_utils import add_subsystem_variables_to_phase, get_initial +from aviary.variable_info.variables import Dynamic +from aviary.mission.flops_based.ode.simple_mission_ODE import MissionODE + + +# TODO: support/handle the following in the base class +# - phase.set_time_options() +# - currently handled in level 3 interface implementation +# - self.external_subsystems +# - self.meta_data, with cls.default_meta_data customization point +@register +class EnergyPhase(PhaseBuilderBase): + ''' + A phase builder for a simple energy phase. + + Attributes + ---------- + name : str ('energy_phase') + object label + + subsystem_options (None) + dictionary of parameters to be passed to the subsystem builders + + user_options : AviaryValues () + state/path constraint values and flags + + supported options: + - num_segments : int (5) + transcription: number of segments + - order : int (3) + transcription: order of the state transcription; the order of the control + transcription is `order - 1` + - fix_initial : bool (True) + - initial_ref : float (1.0, 's') + - initial_bounds : pair ((0.0, 100.0) 's') + - duration_ref : float (1.0, 's') + - duration_bounds : pair ((0.0, 100.0) 's') + - required_available_climb_rate : float (None) + minimum avaliable climb rate + - constrain_final : bool (False) + - input_initial : bool (False) + + initial_guesses : AviaryValues () + state/path beginning values to be set on the problem + + supported options: + - times + - range + - altitude + - velocity + - velocity_rate + - mass + - throttle + + ode_class : type (None) + advanced: the type of system defining the ODE + + transcription : "Dymos transcription object" (None) + advanced: an object providing the transcription technique of the + optimal control problem + + external_subsystems : Sequence["subsystem builder"] () + advanced + + meta_data : dict (<"builtin" meta data>) + advanced: meta data associated with variables in the Aviary data hierarchy + + default_name : str + class attribute: derived type customization point; the default value + for name + + default_ode_class : type + class attribute: derived type customization point; the default value + for ode_class used by build_phase + + default_meta_data : dict + class attribute: derived type customization point; the default value for + meta_data + + Methods + ------- + build_phase + make_default_transcription + validate_options + assign_default_options + ''' + __slots__ = ('external_subsystems', 'meta_data') + + # region : derived type customization points + _meta_data_ = {} + + _initial_guesses_meta_data_ = {} + + default_name = 'cruise' + + default_ode_class = MissionODE + + default_meta_data = _MetaData + # endregion : derived type customization points + + def __init__( + self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, core_subsystems=None, + external_subsystems=None, meta_data=None + ): + super().__init__( + name=name, core_subsystems=core_subsystems, subsystem_options=subsystem_options, user_options=user_options, initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription) + + # TODO: support external_subsystems and meta_data in the base class + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + + self.meta_data = meta_data + + def build_phase(self, aviary_options: AviaryValues = None): + ''' + Return a new energy phase for analysis using these constraints. + + If ode_class is None, default_ode_class is used. + + If transcription is None, the return value from calling + make_default_transcription is used. + + Parameters + ---------- + aviary_options : AviaryValues () + collection of Aircraft/Mission specific options + + Returns + ------- + dymos.Phase + ''' + phase: dm.Phase = super().build_phase(aviary_options) + + user_options: AviaryValues = self.user_options + + fix_initial = user_options.get_val('fix_initial') + constrain_final = user_options.get_val('constrain_final') + optimize_mach = user_options.get_val('optimize_mach') + optimize_altitude = user_options.get_val('optimize_altitude') + input_initial = user_options.get_val('input_initial') + polynomial_control_order = user_options.get_item('polynomial_control_order')[0] + use_polynomial_control = user_options.get_val('use_polynomial_control') + throttle_enforcement = user_options.get_val('throttle_enforcement') + mach_bounds = user_options.get_item('mach_bounds') + altitude_bounds = user_options.get_item('altitude_bounds') + initial_mach = user_options.get_item('initial_mach')[0] + final_mach = user_options.get_item('final_mach')[0] + initial_altitude = user_options.get_item('initial_altitude')[0] + final_altitude = user_options.get_item('final_altitude')[0] + solve_for_range = user_options.get_val('solve_for_range') + no_descent = user_options.get_val('no_descent') + no_climb = user_options.get_val('no_climb') + + ############## + # Add States # + ############## + # TODO: critically think about how we should handle fix_initial and input_initial defaults. + # In keeping with Dymos standards, the default should be False instead of True. + input_initial_mass = get_initial(input_initial, Dynamic.Mission.MASS) + fix_initial_mass = get_initial(fix_initial, Dynamic.Mission.MASS, True) + + # Experiment: use a constraint for mass instead of connected initial. + # This is due to some problems in mpi. + # This is needed for the cutting edge full subsystem integration. + # TODO: when a Dymos fix is in and we've verified that full case works with the fix, + # remove this argument. + if user_options.get_val('add_initial_mass_constraint'): + phase.add_constraint('rhs_all.initial_mass_residual', equals=0.0, ref=1e4) + input_initial_mass = False + + phase.add_state( + Dynamic.Mission.MASS, fix_initial=fix_initial_mass, fix_final=False, + lower=0.0, ref=1e4, defect_ref=1e6, units='kg', + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, + input_initial=input_initial_mass, + # solve_segments='forward', + ) + + input_initial_range = get_initial(input_initial, Dynamic.Mission.RANGE) + fix_initial_range = get_initial(fix_initial, Dynamic.Mission.RANGE, True) + phase.add_state( + Dynamic.Mission.RANGE, fix_initial=fix_initial_range, fix_final=False, + lower=0.0, ref=1e6, defect_ref=1e8, units='m', + rate_source=Dynamic.Mission.RANGE_RATE, + input_initial=input_initial_range, + solve_segments='forward' if solve_for_range else None, + ) + + phase = add_subsystem_variables_to_phase( + phase, self.name, self.external_subsystems) + + ################ + # Add Controls # + ################ + if use_polynomial_control: + phase.add_polynomial_control( + Dynamic.Mission.MACH, + targets=Dynamic.Mission.MACH, units=mach_bounds[1], + opt=optimize_mach, lower=mach_bounds[0][0], upper=mach_bounds[0][1], + rate_targets=[Dynamic.Mission.MACH_RATE], + order=polynomial_control_order, ref=0.5, + ) + else: + phase.add_control( + Dynamic.Mission.MACH, + targets=Dynamic.Mission.MACH, units=mach_bounds[1], + opt=optimize_mach, lower=mach_bounds[0][0], upper=mach_bounds[0][1], + rate_targets=[Dynamic.Mission.MACH_RATE], + ref=0.5, + ) + + if optimize_mach and fix_initial: + phase.add_boundary_constraint( + Dynamic.Mission.MACH, loc='initial', equals=initial_mach, + ) + + if optimize_mach and constrain_final: + phase.add_boundary_constraint( + Dynamic.Mission.MACH, loc='final', equals=final_mach, + ) + + # Add altitude rate as a control + if use_polynomial_control: + phase.add_polynomial_control( + Dynamic.Mission.ALTITUDE, + targets=Dynamic.Mission.ALTITUDE, units=altitude_bounds[1], + opt=optimize_altitude, lower=altitude_bounds[0][0], upper=altitude_bounds[0][1], + rate_targets=[Dynamic.Mission.ALTITUDE_RATE], + order=polynomial_control_order, ref=altitude_bounds[0][1], + ) + else: + phase.add_control( + Dynamic.Mission.ALTITUDE, + targets=Dynamic.Mission.ALTITUDE, units=altitude_bounds[1], + opt=optimize_altitude, lower=altitude_bounds[0][0], upper=altitude_bounds[0][1], + rate_targets=[Dynamic.Mission.ALTITUDE_RATE], + ref=altitude_bounds[0][1], + ) + + if optimize_altitude and fix_initial: + phase.add_boundary_constraint( + Dynamic.Mission.ALTITUDE, loc='initial', equals=initial_altitude, units=altitude_bounds[1], ref=1.e4, + ) + + if optimize_altitude and constrain_final: + phase.add_boundary_constraint( + Dynamic.Mission.ALTITUDE, loc='final', equals=final_altitude, units=altitude_bounds[1], ref=1.e4, + ) + + ################## + # Add Timeseries # + ################## + phase.add_timeseries_output( + Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units='unitless' + ) + + phase.add_timeseries_output( + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' + ) + + phase.add_timeseries_output( + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' + ) + + phase.add_timeseries_output( + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, + output_name=Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, units='m/s' + ) + + phase.add_timeseries_output( + Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + output_name=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units='lbm/h' + ) + + phase.add_timeseries_output( + Dynamic.Mission.ALTITUDE_RATE, + output_name=Dynamic.Mission.ALTITUDE_RATE, units='ft/s' + ) + + phase.add_timeseries_output( + Dynamic.Mission.THROTTLE, + output_name=Dynamic.Mission.THROTTLE, units='unitless' + ) + + phase.add_timeseries_output( + Dynamic.Mission.VELOCITY, + output_name=Dynamic.Mission.VELOCITY, units='m/s' + ) + + ################### + # Add Constraints # + ################### + if no_descent: + phase.add_path_constraint(Dynamic.Mission.ALTITUDE_RATE, lower=0.0) + + if no_climb: + phase.add_path_constraint(Dynamic.Mission.ALTITUDE_RATE, upper=0.0) + + required_available_climb_rate, units = user_options.get_item( + 'required_available_climb_rate') + + if required_available_climb_rate is not None: + phase.add_path_constraint( + Dynamic.Mission.ALTITUDE_RATE_MAX, + lower=required_available_climb_rate, units=units + ) + + if throttle_enforcement == 'boundary_constraint': + phase.add_boundary_constraint( + Dynamic.Mission.THROTTLE, loc='initial', lower=0.0, upper=1.0, units='unitless', + ) + phase.add_boundary_constraint( + Dynamic.Mission.THROTTLE, loc='final', lower=0.0, upper=1.0, units='unitless', + ) + elif throttle_enforcement == 'path_constraint': + phase.add_path_constraint( + Dynamic.Mission.THROTTLE, lower=0.0, upper=1.0, units='unitless', + ) + + return phase + + def make_default_transcription(self): + ''' + Return a transcription object to be used by default in build_phase. + ''' + user_options = self.user_options + + num_segments, _ = user_options.get_item('num_segments') + order, _ = user_options.get_item('order') + + seg_ends, _ = dm.utils.lgl.lgl(num_segments + 1) + + transcription = dm.Radau( + num_segments=num_segments, order=order, compressed=True, + segment_ends=seg_ends) + + return transcription + + def _extra_ode_init_kwargs(self): + """ + Return extra kwargs required for initializing the ODE. + """ + # TODO: support external_subsystems and meta_data in the base class + return { + 'external_subsystems': self.external_subsystems, + 'meta_data': self.meta_data, + 'subsystem_options': self.subsystem_options, + 'throttle_enforcement': self.user_options.get_val('throttle_enforcement'), + } + + +EnergyPhase._add_meta_data( + 'num_segments', val=5, desc='transcription: number of segments') + +EnergyPhase._add_meta_data( + 'order', val=3, + desc='transcription: order of the state transcription; the order of the control' + ' transcription is `order - 1`') + +EnergyPhase._add_meta_data('polynomial_control_order', val=3) + +EnergyPhase._add_meta_data('use_polynomial_control', val=True) + +EnergyPhase._add_meta_data('add_initial_mass_constraint', val=False) + +EnergyPhase._add_meta_data('fix_initial', val=True) + +EnergyPhase._add_meta_data('optimize_mach', val=False) + +EnergyPhase._add_meta_data('optimize_altitude', val=False) + +EnergyPhase._add_meta_data('initial_bounds', val=(0., 100.), units='s') + +EnergyPhase._add_meta_data('duration_bounds', val=(0., 100.), units='s') + +EnergyPhase._add_meta_data( + 'required_available_climb_rate', val=None, units='m/s', + desc='minimum avaliable climb rate') + +EnergyPhase._add_meta_data( + 'no_climb', val=False, desc='aircraft is not allowed to climb during phase') + +EnergyPhase._add_meta_data( + 'no_descent', val=False, desc='aircraft is not allowed to descend during phase') + +EnergyPhase._add_meta_data('constrain_final', val=False) + +EnergyPhase._add_meta_data('input_initial', val=False) + +EnergyPhase._add_meta_data('initial_mach', val=None, units='unitless') + +EnergyPhase._add_meta_data('final_mach', val=None, units='unitless') + +EnergyPhase._add_meta_data('initial_altitude', val=None, units='ft') + +EnergyPhase._add_meta_data('final_altitude', val=None, units='ft') + +EnergyPhase._add_meta_data('throttle_enforcement', val=None) + +EnergyPhase._add_meta_data('mach_bounds', val=(0., 2.), units='unitless') + +EnergyPhase._add_meta_data('altitude_bounds', val=(0., 60.e3), units='ft') + +EnergyPhase._add_meta_data('solve_for_range', val=False) + +EnergyPhase._add_initial_guess_meta_data( + InitialGuessTime(), + desc='initial guess for initial time and duration specified as a tuple') + +EnergyPhase._add_initial_guess_meta_data( + InitialGuessState('range'), + desc='initial guess for horizontal distance traveled') + +EnergyPhase._add_initial_guess_meta_data( + InitialGuessState('altitude'), + desc='initial guess for vertical distances') + +EnergyPhase._add_initial_guess_meta_data( + InitialGuessState('mach'), + desc='initial guess for speed') + +EnergyPhase._add_initial_guess_meta_data( + InitialGuessState('mass'), + desc='initial guess for mass') From 0c9be9b2de2af51990b7eef19cd4f70714155734 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 11 Jan 2024 14:44:33 -0600 Subject: [PATCH 049/188] Moved simple to mission --- .../flops_based/ode/{simple_mission_EOM.py => mission_EOM.py} | 0 .../flops_based/ode/{simple_mission_ODE.py => mission_ODE.py} | 2 +- aviary/mission/flops_based/phases/energy_phase.py | 2 +- aviary/mission/flops_based/phases/phase_builder_base.py | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename aviary/mission/flops_based/ode/{simple_mission_EOM.py => mission_EOM.py} (100%) rename aviary/mission/flops_based/ode/{simple_mission_ODE.py => mission_ODE.py} (99%) diff --git a/aviary/mission/flops_based/ode/simple_mission_EOM.py b/aviary/mission/flops_based/ode/mission_EOM.py similarity index 100% rename from aviary/mission/flops_based/ode/simple_mission_EOM.py rename to aviary/mission/flops_based/ode/mission_EOM.py diff --git a/aviary/mission/flops_based/ode/simple_mission_ODE.py b/aviary/mission/flops_based/ode/mission_ODE.py similarity index 99% rename from aviary/mission/flops_based/ode/simple_mission_ODE.py rename to aviary/mission/flops_based/ode/mission_ODE.py index 58554956b..ef4c1a23f 100644 --- a/aviary/mission/flops_based/ode/simple_mission_ODE.py +++ b/aviary/mission/flops_based/ode/mission_ODE.py @@ -2,7 +2,7 @@ import openmdao.api as om from dymos.models.atmosphere import USatm1976Comp -from aviary.mission.flops_based.ode.simple_mission_EOM import MissionEOM +from aviary.mission.flops_based.ode.mission_EOM import MissionEOM from aviary.utils.aviary_values import AviaryValues from aviary.utils.functions import promote_aircraft_and_mission_vars from aviary.variable_info.variable_meta_data import _MetaData diff --git a/aviary/mission/flops_based/phases/energy_phase.py b/aviary/mission/flops_based/phases/energy_phase.py index 6da23cbdb..a1452a3f3 100644 --- a/aviary/mission/flops_based/phases/energy_phase.py +++ b/aviary/mission/flops_based/phases/energy_phase.py @@ -8,7 +8,7 @@ from aviary.variable_info.variable_meta_data import _MetaData from aviary.mission.flops_based.phases.phase_utils import add_subsystem_variables_to_phase, get_initial from aviary.variable_info.variables import Dynamic -from aviary.mission.flops_based.ode.simple_mission_ODE import MissionODE +from aviary.mission.flops_based.ode.mission_ODE import MissionODE # TODO: support/handle the following in the base class diff --git a/aviary/mission/flops_based/phases/phase_builder_base.py b/aviary/mission/flops_based/phases/phase_builder_base.py index 0ff2b77f4..b299689c5 100644 --- a/aviary/mission/flops_based/phases/phase_builder_base.py +++ b/aviary/mission/flops_based/phases/phase_builder_base.py @@ -28,7 +28,7 @@ import numpy as np import openmdao.api as om -from aviary.mission.flops_based.ode.simple_mission_ODE import MissionODE +from aviary.mission.flops_based.ode.mission_ODE import MissionODE from aviary.utils.aviary_values import AviaryValues, get_keys _require_new_meta_data_class_attr_ = \ From c1c705f9797e6c8e8ed00c6986ad74242b2d795b Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 11 Jan 2024 16:05:21 -0600 Subject: [PATCH 050/188] Updated OAS example call --- aviary/docs/examples/OAS_subsystem.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/docs/examples/OAS_subsystem.ipynb b/aviary/docs/examples/OAS_subsystem.ipynb index 491b119ad..3e7db68f6 100644 --- a/aviary/docs/examples/OAS_subsystem.ipynb +++ b/aviary/docs/examples/OAS_subsystem.ipynb @@ -339,7 +339,7 @@ "prob = av.AviaryProblem()\n", "\n", "prob.load_inputs(aircraft_definition_file, phase_info)\n", - "prob.check_inputs()\n", + "prob.check_and_preprocess_inputs()\n", "prob.add_pre_mission_systems()\n", "prob.add_phases()\n", "prob.add_post_mission_systems()\n", From a085bac645ac3b494403a384faa940c9a3ae28b5 Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Thu, 11 Jan 2024 17:21:40 -0800 Subject: [PATCH 051/188] Fixes for setting and using reserve values Removed unused Enum Allow user to set both the fraction and the additional reserve Fixed backwards incompatibility with GASP decks Updated docs --- .../getting_started/input_csv_phase_info.md | 8 +-- aviary/interface/methods_for_level2.py | 56 ++++++++++--------- aviary/interface/test/test_reserve_support.py | 4 +- .../large_single_aisle_1_GwGm.csv | 4 +- .../small_single_aisle_GwGm.csv | 4 +- .../small_single_aisle_GwGm.dat | 2 +- .../test_aircraft/aircraft_for_bench_FwFm.csv | 2 +- .../test_aircraft/aircraft_for_bench_FwGm.csv | 2 +- .../test_aircraft/aircraft_for_bench_GwFm.csv | 2 +- .../test_aircraft/aircraft_for_bench_GwGm.csv | 2 +- ...converter_configuration_test_data_GwGm.csv | 4 +- ...converter_configuration_test_data_GwGm.dat | 2 +- aviary/utils/Fortran_to_Aviary.py | 14 +++-- aviary/utils/process_input_decks.py | 38 ++++++------- aviary/variable_info/enums.py | 24 -------- aviary/variable_info/variable_meta_data.py | 34 +++++++---- aviary/variable_info/variables.py | 5 +- 17 files changed, 100 insertions(+), 107 deletions(-) diff --git a/aviary/docs/getting_started/input_csv_phase_info.md b/aviary/docs/getting_started/input_csv_phase_info.md index 01f0a59db..4863a70a0 100644 --- a/aviary/docs/getting_started/input_csv_phase_info.md +++ b/aviary/docs/getting_started/input_csv_phase_info.md @@ -19,12 +19,12 @@ This section is under development. - reserves: 0 The initial guess of `reserves` is used to define the reserve fuel. Initially, its value can be anything larger than or equal to 0. There are two Aviary variables to control the reserve fuel in the model file (`.csv`): -- `Aircraft.Design.FIXED_RESERVES_FUEL`: the required fuel reserves: directly in lbm, -- `Aircraft.Design.RESERVES_FRACTION`: the required fuel reserves: given as a proportion of mission fuel. +- `Aircraft.Design.RESERVE_FUEL_ADDITIONAL`: the required fuel reserves: directly in lbm, +- `Aircraft.Design.RESERVE_FUEL_FRACTION`: the required fuel reserves: given as a proportion of mission fuel. -Users should set one of them to zero. If the value of initial guess of `reserves` (also in the model file if any) is 0, the initial guess of reserve fuel comes from the above two Aviary variables. Otherwise, it is determined by the parameter `reserves`: +If the value of initial guess of `reserves` (also in the model file if any) is 0, the initial guess of reserve fuel comes from the above two Aviary variables. Otherwise, it is determined by the parameter `reserves`: - if `reserves > 10`, we assume it is the actual fuel reserves. -- if `0.0 <= reserves <= 10`, we assume it is the fraction of the mission fuel. The case when `reserves` is between 1 and 10 is non-sensical but technically valid. +- if `0.0 <= reserves <= 10`, we assume it is the fraction of the mission fuel. The initial guess of `reserves` is always converted to the actual design reserves (instead of reserve factor) and is used to update the initial guesses of `fuel_burn_per_passenger_mile` and `cruise_mass_final`. diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 9feb8f85e..2eb0d3e01 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -2451,30 +2451,34 @@ def _add_gasp_landing_systems(self): def _add_fuel_reserve_component(self, reserves_name=Mission.Design.RESERVE_FUEL): reserves_val = self.aviary_inputs.get_val( - Aircraft.Design.FIXED_RESERVES_FUEL, units='lbm') + Aircraft.Design.RESERVE_FUEL_ADDITIONAL, units='lbm') reserves_frac = self.aviary_inputs.get_val( - Aircraft.Design.RESERVES_FRACTION, units='unitless') - if reserves_val > 0.0: - self.model.add_subsystem( - "reserves_calc", - om.ExecComp( - f"reserve_fuel = {reserves_val}", - reserve_fuel={"val": reserves_val, "units": "lbm"} - ), - promotes_outputs=[("reserve_fuel", reserves_name)], - ) - elif reserves_frac >= 0: - self.model.add_subsystem( - "reserves_calc", - om.ExecComp( - f"reserve_fuel = {reserves_frac}*(takeoff_mass - final_mass)", - takeoff_mass={"units": "lbm"}, - final_mass={"units": "lbm"}, - reserve_fuel={"units": "lbm"} - ), - promotes_inputs=[ - ("takeoff_mass", Mission.Summary.GROSS_MASS), - ("final_mass", Mission.Landing.TOUCHDOWN_MASS), - ], - promotes_outputs=[("reserve_fuel", reserves_name)], - ) + Aircraft.Design.RESERVE_FUEL_FRACTION, units='unitless') + + if reserves_frac == 0 and reserves_val == 0: + return + + input_data = {} + input_promotions = {} + equation_string = f"reserve_fuel = " + if reserves_frac != 0: + input_data = {'takeoff_mass': {"units": "lbm"}, + 'final_mass': {"units": "lbm"}} + input_promotions = {'promotes_inputs': [ + ("takeoff_mass", Mission.Summary.GROSS_MASS), + ("final_mass", Mission.Landing.TOUCHDOWN_MASS) + ]} + equation_string += f"{reserves_frac}*(takeoff_mass - final_mass)" + if reserves_val != 0: + equation_string += f" + {reserves_val}" + + self.model.add_subsystem( + "reserves_calc", + om.ExecComp( + equation_string, + reserve_fuel={"val": reserves_val, "units": "lbm"}, + **input_data + ), + promotes_outputs=[("reserve_fuel", reserves_name)], + **input_promotions + ) diff --git a/aviary/interface/test/test_reserve_support.py b/aviary/interface/test/test_reserve_support.py index 860ac397e..ef47fce98 100644 --- a/aviary/interface/test/test_reserve_support.py +++ b/aviary/interface/test/test_reserve_support.py @@ -26,7 +26,7 @@ def test_post_mission_promotion(self): prob.check_inputs() prob.aviary_inputs.set_val( - Aircraft.Design.FIXED_RESERVES_FUEL, 10000.0, units='lbm') + Aircraft.Design.RESERVE_FUEL_ADDITIONAL, 10000.0, units='lbm') prob.add_pre_mission_systems() prob.add_phases() @@ -74,7 +74,7 @@ def test_gasp_relative_reserve(self): prob.run_model() res_frac = prob.aviary_inputs.get_val( - Aircraft.Design.RESERVES_FRACTION, units='unitless') + Aircraft.Design.RESERVE_FUEL_FRACTION, units='unitless') td_mass = prob.model.get_val(Mission.Landing.TOUCHDOWN_MASS, units='lbm') reserve = prob.model.get_val(Mission.Design.RESERVE_FUEL, units='lbm') assert_near_equal(reserve, res_frac * (140000.0 - td_mass), 1e-3) diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv index b9b9912fe..64edaefb8 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv @@ -12,10 +12,10 @@ aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,16.5,unitless aircraft:design:drag_increment,0.00175,unitless aircraft:design:equipment_mass_coefficients,928,0.0736,0.112,0.14,1959,1.65,551,11192,5,3,50,7.6,12,unitless -aircraft:design:fixed_reserves_fuel,4998,lbm aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves_fraction,0,unitless +aircraft:design:reserve_fuel_additional,4998,lbm +aircraft:design:reserve_fuel_fraction,0,unitless aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless diff --git a/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv b/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv index f47ed1bfb..95fa07b07 100644 --- a/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv +++ b/aviary/models/small_single_aisle/small_single_aisle_GwGm.csv @@ -12,10 +12,10 @@ aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,16.5,unitless aircraft:design:drag_increment,0.0018,unitless aircraft:design:equipment_mass_coefficients,778,0.06,0.112,0.14,1349,1.65,397,9071,7.6,3,50,6,12,unitless -aircraft:design:fixed_reserves_fuel,0,lbm aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves_fraction,0.125,unitless +aircraft:design:reserve_fuel_additional,0,lbm +aircraft:design:reserve_fuel_fraction,0.125,unitless aircraft:design:static_margin,0.05,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.025,unitless diff --git a/aviary/models/small_single_aisle/small_single_aisle_GwGm.dat b/aviary/models/small_single_aisle/small_single_aisle_GwGm.dat index 9ad297777..622fbf4d1 100644 --- a/aviary/models/small_single_aisle/small_single_aisle_GwGm.dat +++ b/aviary/models/small_single_aisle/small_single_aisle_GwGm.dat @@ -205,7 +205,7 @@ OFEM=.78, ! off design specified mission Mach number ROSCAB=9999., ! cabin rate of sink during descent (500.) fpm RSMX=900., ! maximum allowable rate of sink during landing approach ft per min (1000) - FRESF=0.125, ! Reserve Fuel fraction of mission fuel (minus sign for code trigger) + FRESF=-0.125, ! Reserve Fuel fraction of mission fuel (minus sign for code trigger) RF(1)=2.0, ! Reserve Fuel Input: Time for Missed Approach (min) RF(2)=100., ! Reserve Fuel Input: Range to alternate RF(3)=25000., ! Reserve Fuel Input: Cruise altitude to alternate diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv index 01633dc49..de6223b33 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv @@ -25,7 +25,7 @@ aircraft:design:base_area,0.0,ft**2 aircraft:design:empty_mass_margin_scaler,0.0,unitless aircraft:design:lift_dependent_drag_coeff_factor,0.909839381134961,unitless aircraft:design:touchdown_mass,152800.0,lbm -aircraft:design:fixed_reserves_fuel,3000.,lbm +aircraft:design:reserve_fuel_additional,3000.,lbm aircraft:design:subsonic_drag_coeff_factor,1.0,unitless aircraft:design:supersonic_drag_coeff_factor,1.0,unitless aircraft:design:use_alt_mass,False,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv index 3a4f5348e..b4a10d6ff 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwGm.csv @@ -12,7 +12,7 @@ aircraft:design:drag_increment,0.00175,unitless aircraft:design:equipment_mass_coefficients,928,0.0736,0.112,0.14,1959,1.65,551,11192,5,3,50,7.6,12,unitless aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:fixed_reserves_fuel,3000.,lbm +aircraft:design:reserve_fuel_additional,3000.,lbm aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.025,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv index 01f9be0cc..b195ce6d1 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv @@ -39,7 +39,7 @@ aircraft:design:lift_dependent_drag_coeff_factor,0.909839381134961,unitless aircraft:design:touchdown_mass,152800.0,lbm aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:fixed_reserves_fuel,5000.,lbm +aircraft:design:reserve_fuel_additional,5000.,lbm aircraft:design:smooth_mass_discontinuities,False,unitless aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv index c6c89e6f3..ef970f38b 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv @@ -13,7 +13,7 @@ aircraft:design:drag_increment,0.00175,unitless aircraft:design:equipment_mass_coefficients,928,0.0736,0.112,0.14,1959,1.65,551,11192,5,3,50,7.6,12,unitless aircraft:design:max_structural_speed,402.5,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:fixed_reserves_fuel,4998,lbm +aircraft:design:reserve_fuel_additional,4998,lbm aircraft:design:static_margin,0.03,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless diff --git a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv index ee9f695ca..b11a4a4d6 100644 --- a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv +++ b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.csv @@ -12,10 +12,10 @@ aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,30,unitless aircraft:design:drag_increment,0.0014,unitless aircraft:design:equipment_mass_coefficients,1014,0.0736,0.085,0.105,1504,1.65,126,9114,5,3,0,10,12,unitless -aircraft:design:fixed_reserves_fuel,0,lbm aircraft:design:max_structural_speed,440,mi/h aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves_fraction,0.15,unitless +aircraft:design:reserve_fuel_additional,0,lbm +aircraft:design:reserve_fuel_fraction,0.15,unitless aircraft:design:static_margin,0.05,unitless aircraft:design:structural_mass_increment,0,lbm aircraft:design:supercritical_drag_shift,0.033,unitless diff --git a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.dat b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.dat index ce493357c..1ee358869 100644 --- a/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.dat +++ b/aviary/models/test_aircraft/converter_configuration_test_data_GwGm.dat @@ -209,7 +209,7 @@ aircraft:engine:data_file=models/engines/turbofan_23k_1.deck OFEM=.78, ! off design specified mission Mach number ROSCAB=9999., ! cabin rate of sink during descent (500.) fpm RSMX=900., ! maximum allowable rate of sink during landing approach ft per min (1000) - FRESF=0.15, ! Reserve fuel fraction of mission fuel (negative sign trigger) + FRESF=-0.15, ! Reserve fuel fraction of mission fuel (negative sign trigger) RF(1)=.05, ! Reserve Fuel Input: Time for Missed Approach RF(2)=125., ! Reserve Fuel Input: Range to alternate RF(3)=20000., ! Reserve Fuel Input: Cruise altitude to alternate diff --git a/aviary/utils/Fortran_to_Aviary.py b/aviary/utils/Fortran_to_Aviary.py index ce0f09aae..512b596cf 100644 --- a/aviary/utils/Fortran_to_Aviary.py +++ b/aviary/utils/Fortran_to_Aviary.py @@ -434,12 +434,16 @@ def update_gasp_options(vehicle_data): input_values.set_val(Aircraft.Wing.FLAP_DRAG_INCREMENT_OPTIMUM, [[.12, .23, .13, .23, .23, .1, .15][flap_ind]]) - res = input_values.get_val(Aircraft.Design.FIXED_RESERVES_FUEL, units='lbm')[0] - if res <= 1.0: - input_values.set_val(Aircraft.Design.FIXED_RESERVES_FUEL, [0], units='lbm') - input_values.set_val(Aircraft.Design.RESERVES_FRACTION, [res], units='unitless') + res = input_values.get_val(Aircraft.Design.RESERVE_FUEL_ADDITIONAL, units='lbm')[0] + if res <= 0: + input_values.set_val(Aircraft.Design.RESERVE_FUEL_ADDITIONAL, [0], units='lbm') + input_values.set_val(Aircraft.Design.RESERVE_FUEL_FRACTION, + [-res], units='unitless') + elif res >= 10: + input_values.set_val(Aircraft.Design.RESERVE_FUEL_FRACTION, + [0], units='unitless') else: - input_values.set_val(Aircraft.Design.RESERVES_FRACTION, [0], units='unitless') + ValueError('"FRESF" is not valid between 0 and 10.') vehicle_data['input_values'] = input_values return vehicle_data diff --git a/aviary/utils/process_input_decks.py b/aviary/utils/process_input_decks.py index 924d79214..4667a5a34 100644 --- a/aviary/utils/process_input_decks.py +++ b/aviary/utils/process_input_decks.py @@ -45,8 +45,8 @@ def create_vehicle(vehicle_deck=''): aircraft_values.set_val('mass_defect', val=10000, units='lbm') aircraft_values.set_val('problem_type', val=ProblemType.SIZING) aircraft_values.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False) - aircraft_values.set_val(Aircraft.Design.FIXED_RESERVES_FUEL, val=4998, units='lbm') - aircraft_values.set_val(Aircraft.Design.RESERVES_FRACTION, val=0, units='unitless') + # aircraft_values.set_val(Aircraft.Design.RESERVE_FUEL_ADDITIONAL, val=4998, units='lbm') + # aircraft_values.set_val(Aircraft.Design.RESERVE_FUEL_FRACTION, val=0, units='unitless') vehicle_deck = get_path(vehicle_deck) @@ -165,28 +165,24 @@ def update_dependent_options(aircraft_values: AviaryValues(), dependent_options) def initial_guessing(aircraft_values: AviaryValues()): problem_type = aircraft_values.get_val('problem_type') - if initial_guesses['reserves'] == 0: - reserves = aircraft_values.get_val( - Aircraft.Design.FIXED_RESERVES_FUEL, units='lbm') - reserves_option = "direct_val" - if reserves == 0: - reserves = aircraft_values.get_val( - Aircraft.Design.RESERVES_FRACTION, units='unitless') - reserves_option = "fraction_val" - else: - reserves = initial_guesses['reserves'] - if reserves < 0.0: - raise ValueError('initial_guesses["reserves"] must be greater than 0.') - elif reserves > 10: - reserves_option = "direct_val" - else: - reserves_option = "fraction_val" - num_pax = aircraft_values.get_val(Aircraft.CrewPayload.NUM_PASSENGERS) - - if reserves_option == "fraction_val": + reserve_val = aircraft_values.get_val( + Aircraft.Design.RESERVE_FUEL_ADDITIONAL, units='lbm') + reserve_frac = aircraft_values.get_val( + Aircraft.Design.RESERVE_FUEL_FRACTION, units='unitless') + + reserves = initial_guesses['reserves'] + if reserves < 0.0: + raise ValueError( + 'initial_guesses["reserves"] must be greater than or equal to 0.') + elif reserves == 0: + reserves += reserve_val + reserves += (reserve_frac * (num_pax * initial_guesses['fuel_burn_per_passenger_mile'] * + aircraft_values.get_val(Mission.Design.RANGE, units='NM'))) + elif reserves < 10: reserves *= (num_pax * initial_guesses['fuel_burn_per_passenger_mile'] * aircraft_values.get_val(Mission.Design.RANGE, units='NM')) + initial_guesses['reserves'] = reserves if Mission.Summary.GROSS_MASS in aircraft_values: diff --git a/aviary/variable_info/enums.py b/aviary/variable_info/enums.py index aabe458d1..912283e50 100644 --- a/aviary/variable_info/enums.py +++ b/aviary/variable_info/enums.py @@ -181,27 +181,3 @@ class Flap_Type(Enum): """ Double-slotted Fowler flaps """ - - -@unique -class Reserves_Type(Enum): - """ - Defines the type of reserves used. Currently, Set_by_Time is not implemented. - """ - - Set_None = 0 - """ - Do not set it and let initial_guess['reserves'] decide. - """ - Set_Direct = 1 - """ - Set required fuel reserves directly in lbm (must be larger than 10). - """ - Set_Fraction = 2 - """ - Set required fuel reserves as a proportion of mission fuel (must be btween -1 and 0). - """ - Set_by_Time = 3 - """ - Set required fuel reserves as a proportion of time (must be btween 0 and 1 which correspond to 0 and 45 minutes). - """ diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index 966c4aa18..e2601e0cc 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -1049,27 +1049,26 @@ ) add_meta_data( - Aircraft.Design.FIXED_RESERVES_FUEL, + Aircraft.Design.FIXED_USEFUL_LOAD, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.FRESF', + historical_name={"GASP": 'INGASP.WFUL', "FLOPS": None, "LEAPS1": None }, - option=True, - units="lbm", - desc='required fuel reserves: directly in lbm', - default_value=0, + units='lbm', + desc='total mass of fixed useful load: crew, service items, trapped oil, etc', ) add_meta_data( - Aircraft.Design.FIXED_USEFUL_LOAD, + Aircraft.Design.IJEFF, meta_data=_MetaData, - historical_name={"GASP": 'INGASP.WFUL', + historical_name={"GASP": 'INGASP.IJEFF', "FLOPS": None, "LEAPS1": None }, - units='lbm', - desc='total mass of fixed useful load: crew, service items, trapped oil, etc', + desc="A flag used by Jeff V. Bowles to debug GASP code during his 53 years supporting the development of GASP. \ + This flag is planted here to thank him for his hard work and dedication, Aviary wouldn't be what it is today \ + without his help.", ) add_meta_data( @@ -1198,7 +1197,20 @@ ) add_meta_data( - Aircraft.Design.RESERVES_FRACTION, + Aircraft.Design.RESERVE_FUEL_ADDITIONAL, + meta_data=_MetaData, + historical_name={"GASP": 'INGASP.FRESF', + "FLOPS": None, + "LEAPS1": None + }, + option=True, + units="lbm", + desc='required fuel reserves: directly in lbm', + default_value=0, +) + +add_meta_data( + Aircraft.Design.RESERVE_FUEL_FRACTION, meta_data=_MetaData, historical_name={"GASP": None, "FLOPS": None, diff --git a/aviary/variable_info/variables.py b/aviary/variable_info/variables.py index 84deaf290..64c623c93 100644 --- a/aviary/variable_info/variables.py +++ b/aviary/variable_info/variables.py @@ -131,8 +131,8 @@ class Design: EXTERNAL_SUBSYSTEMS_MASS = 'aircraft:design:external_subsystems_mass' FINENESS = 'aircraft:design:fineness' FIXED_EQUIPMENT_MASS = 'aircraft:design:fixed_equipment_mass' - FIXED_RESERVES_FUEL = 'aircraft:design:fixed_reserves_fuel' FIXED_USEFUL_LOAD = 'aircraft:design:fixed_useful_load' + IJEFF = 'ijeff' LAMINAR_FLOW_LOWER = 'aircraft:design:laminar_flow_lower' LAMINAR_FLOW_UPPER = 'aircraft:design:laminar_flow_upper' @@ -148,7 +148,8 @@ class Design: MAX_STRUCTURAL_SPEED = 'aircraft:design:max_structural_speed' OPERATING_MASS = 'aircraft:design:operating_mass' PART25_STRUCTURAL_CATEGORY = 'aircraft:design:part25_structural_category' - RESERVES_FRACTION = 'aircraft:design:reserves_fraction' + RESERVE_FUEL_ADDITIONAL = 'aircraft:design:reserve_fuel_additional' + RESERVE_FUEL_FRACTION = 'aircraft:design:reserve_fuel_fraction' SMOOTH_MASS_DISCONTINUITIES = 'aircraft:design:smooth_mass_discontinuities' STATIC_MARGIN = 'aircraft:design:static_margin' STRUCTURAL_MASS_INCREMENT = 'aircraft:design:structural_mass_increment' From 84a8d0e2398ffb282b405e9655fdee06eb321cb1 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Fri, 12 Jan 2024 11:22:16 -0500 Subject: [PATCH 052/188] Added some more outputs to help debug --- aviary/interface/test/test_simple_mission.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/aviary/interface/test/test_simple_mission.py b/aviary/interface/test/test_simple_mission.py index 78ec4902c..403c8542e 100644 --- a/aviary/interface/test/test_simple_mission.py +++ b/aviary/interface/test/test_simple_mission.py @@ -126,7 +126,11 @@ def test_mission_basic_and_dashboard(self): try: subprocess.check_output(cmd.split()) except subprocess.CalledProcessError as err: - self.fail("Command '{}' failed. Return code: {}".format(cmd, err.returncode)) + self.fail("Command '{}' failed. Return code: {} \n output: {} \n stderr: {} \n stdout: {}".format(cmd, + err.returncode, + err.output, + err.stderr, + err.stdout)) @require_pyoptsparse(optimizer="IPOPT") def test_mission_basic_pyopt(self): From 42dedb389070a90c448d048f80a9fb1b261cb0f4 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Fri, 12 Jan 2024 11:55:11 -0500 Subject: [PATCH 053/188] Handle the situation where the final case was never recorded --- aviary/visualization/dashboard.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index 39699abd2..79afbdf68 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -128,6 +128,9 @@ def create_aviary_variables_table_data_nested(script_name, recorder_file): """ cr = om.CaseReader(recorder_file) + if 'final' not in cr.list_cases(): + return None + case = cr.get_case('final') outputs = case.list_outputs(explicit=True, implicit=True, val=True, residuals=True, residuals_tol=None, @@ -412,12 +415,13 @@ def dashboard(script_name, problem_recorder, driver_recorder, port): # copy script.js file to reports/script_name/aviary_vars/index.html. # mod the script.js file to point at the json file # create the json file and put it in reports/script_name/aviary_vars/aviary_vars.json - create_aviary_variables_table_data_nested( + table_data_nested = create_aviary_variables_table_data_nested( script_name, problem_recorder) # create the json file - aviary_vars_pane = create_report_frame('html', - f'{reports_dir}/aviary_vars/index.html') + if table_data_nested: + aviary_vars_pane = create_report_frame('html', + f'{reports_dir}/aviary_vars/index.html') - results_tabs_list.append(('Aviary Variables', aviary_vars_pane)) + results_tabs_list.append(('Aviary Variables', aviary_vars_pane)) ####### Subsystems Tab ####### subsystem_tabs_list = [] From dd86b2461a4226c13bb85d44b4efddf1ab00efc9 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Fri, 12 Jan 2024 12:03:01 -0500 Subject: [PATCH 054/188] removed comment that was a dupe --- aviary/visualization/dashboard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index 79afbdf68..d567de469 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -416,10 +416,10 @@ def dashboard(script_name, problem_recorder, driver_recorder, port): # mod the script.js file to point at the json file # create the json file and put it in reports/script_name/aviary_vars/aviary_vars.json table_data_nested = create_aviary_variables_table_data_nested( - script_name, problem_recorder) # create the json file + script_name, problem_recorder) if table_data_nested: aviary_vars_pane = create_report_frame('html', - f'{reports_dir}/aviary_vars/index.html') + f'{reports_dir}/aviary_vars/index.html') results_tabs_list.append(('Aviary Variables', aviary_vars_pane)) From d1ba030a65bd787fe57a776ca056e5f2444fe3ca Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 12 Jan 2024 11:05:15 -0600 Subject: [PATCH 055/188] Merging --- .../test_workflow_no_dev_install.yml | 2 +- aviary/docs/examples/OAS_subsystem.ipynb | 2 +- ...oupled_aircraft_mission_optimization.ipynb | 10 +-- .../onboarding_ext_subsystem.ipynb | 10 +-- .../getting_started/onboarding_level2.ipynb | 19 ++--- .../getting_started/onboarding_level3.ipynb | 2 +- ..._same_mission_at_different_UI_levels.ipynb | 4 +- aviary/docs/user_guide/subsystems.md | 2 +- .../OAS_weight/run_simple_OAS_mission.py | 6 +- .../external_subsystems/battery/run_cruise.py | 2 +- .../battery/run_multiphase_mission.py | 8 +- aviary/examples/level2_shooting_traj.py | 6 +- aviary/examples/test/test_all_examples.py | 5 +- aviary/interface/methods_for_level1.py | 6 +- aviary/interface/methods_for_level2.py | 7 +- aviary/interface/test/test_interface_bugs.py | 6 +- aviary/interface/test/test_phase_info.py | 2 +- aviary/interface/test/test_reserve_support.py | 4 +- .../test/test_solved_aero_group.py | 73 +++++++++++++++++++ .../aerodynamics/gasp_based/table_based.py | 11 +-- .../test/test_custom_engine_model.py | 6 +- .../test/test_external_subsystem_bus.py | 5 +- .../benchmark_tests/test_0_iters.py | 2 +- .../test_full_mission_solved_level3.py | 6 +- .../test_subsystems_within_a_mission.py | 12 +-- 25 files changed, 142 insertions(+), 76 deletions(-) diff --git a/.github/workflows/test_workflow_no_dev_install.yml b/.github/workflows/test_workflow_no_dev_install.yml index 98f0eefe1..74c498830 100644 --- a/.github/workflows/test_workflow_no_dev_install.yml +++ b/.github/workflows/test_workflow_no_dev_install.yml @@ -65,7 +65,7 @@ jobs: echo "Install Aviary" echo "=============================================================" pip install packaging - pip install .[test] + pip install .[all] - name: Display conda environment info shell: bash -l {0} diff --git a/aviary/docs/examples/OAS_subsystem.ipynb b/aviary/docs/examples/OAS_subsystem.ipynb index 491b119ad..3e7db68f6 100644 --- a/aviary/docs/examples/OAS_subsystem.ipynb +++ b/aviary/docs/examples/OAS_subsystem.ipynb @@ -339,7 +339,7 @@ "prob = av.AviaryProblem()\n", "\n", "prob.load_inputs(aircraft_definition_file, phase_info)\n", - "prob.check_inputs()\n", + "prob.check_and_preprocess_inputs()\n", "prob.add_pre_mission_systems()\n", "prob.add_phases()\n", "prob.add_post_mission_systems()\n", diff --git a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb index 68344b92a..850f8a627 100644 --- a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb +++ b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb @@ -208,9 +208,7 @@ "# Allow for user overrides here\n", "prob.load_inputs(aircraft_filename, phase_info)\n", "\n", - "# Have checks for clashing user inputs\n", - "# Raise warnings or errors depending on how clashing the issues are\n", - "prob.check_inputs()\n", + "prob.check_and_preprocess_inputs()\n", "\n", "prob.add_pre_mission_systems()\n", "\n", @@ -328,10 +326,8 @@ "# Allow for user overrides here\n", "prob.load_inputs(aircraft_filename, phase_info)\n", "\n", - "# Have checks for clashing user inputs\n", - "# Raise warnings or errors depending on how clashing the issues are\n", - "prob.check_inputs()\n", - "\n", + "prob.check_and_preprocess_inputs()\n", + "# Preprocess inputs\n", "prob.add_pre_mission_systems()\n", "\n", "prob.add_phases()\n", diff --git a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb index bde8b897e..a8c11950b 100644 --- a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb +++ b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb @@ -64,7 +64,7 @@ "\n", "# Have checks for clashing user inputs\n", "# Raise warnings or errors depending on how clashing the issues are\n", - "# prob.check_inputs()\n", + "# prob.check_and_preprocess_inputs()\n", "\n", "prob.add_pre_mission_systems()\n", "\n", @@ -123,7 +123,7 @@ "\n", "# Have checks for clashing user inputs\n", "# Raise warnings or errors depending on how clashing the issues are\n", - "# prob.check_inputs()\n", + "# prob.check_and_preprocess_inputs()\n", "\n", "prob.add_pre_mission_systems()\n", "\n", @@ -170,7 +170,7 @@ "\n", "- **init**\n", "- **load_inputs**\n", - "- **check_inputs**\n", + "- **check_and_preprocess_inputs**\n", "- **add_pre_mission_systems**\n", "- **add_phases**\n", "- **add_post_mission_systems**\n", @@ -260,7 +260,7 @@ "source": [ "# Have checks for clashing user inputs\n", "# Raise warnings or errors depending on severity of the issues\n", - "prob.check_inputs()" + "prob.check_and_preprocess_inputs()" ] }, { @@ -630,7 +630,7 @@ "prob = av.AviaryProblem()\n", "\n", "prob.load_inputs(aircraft_definition_file, phase_info)\n", - "prob.check_inputs()\n", + "prob.check_and_preprocess_inputs()\n", "prob.add_pre_mission_systems()\n", "prob.add_phases()\n", "prob.add_post_mission_systems()\n", diff --git a/aviary/docs/getting_started/onboarding_level2.ipynb b/aviary/docs/getting_started/onboarding_level2.ipynb index 30d1e1c7c..e052fd842 100644 --- a/aviary/docs/getting_started/onboarding_level2.ipynb +++ b/aviary/docs/getting_started/onboarding_level2.ipynb @@ -42,7 +42,7 @@ "\n", "- `prob = AviaryProblem()`\n", "- `prob.load_inputs()`\n", - "- `prob.check_inputs()`\n", + "- `prob.check_and_preprocess_inputs()`\n", "- `prob.add_pre_mission_systems()`\n", "- `prob.add_phases()`\n", "- `prob.add_post_mission_systems()`\n", @@ -94,9 +94,8 @@ "# Allow for user overrides here\n", "prob.load_inputs(aircraft_filename, av.default_2DOF_phase_info)\n", "\n", - "# Have checks for clashing user inputs\n", - "# Raise warnings or errors depending on how clashing the issues are\n", - "prob.check_inputs()\n", + "# Preprocess inputs\n", + "prob.check_and_preprocess_inputs()\n", "\n", "# adds a pre-mission group (propulsion, geometry, static aerodynamics, and mass)\n", "prob.add_pre_mission_systems()\n", @@ -241,7 +240,7 @@ "metadata": {}, "outputs": [], "source": [ - "prob.check_inputs()" + "prob.check_and_preprocess_inputs()" ] }, { @@ -680,9 +679,8 @@ "# Allow for user overrides here\n", "prob.load_inputs(aircraft_filename, phase_info)\n", "\n", - "# Have checks for clashing user inputs\n", - "# Raise warnings or errors depending on how clashing the issues are\n", - "prob.check_inputs()\n", + "# Preprocess inputs\n", + "prob.check_and_preprocess_inputs()\n", "\n", "prob.add_pre_mission_systems()\n", "\n", @@ -835,9 +833,8 @@ "metadata": {}, "outputs": [], "source": [ - "# Have checks for clashing user inputs\n", - "# Raise warnings or errors depending on how clashing the issues are\n", - "prob.check_inputs()\n", + "# Preprocess inputs\n", + "prob.check_and_preprocess_inputs()\n", "\n", "prob.add_pre_mission_systems()\n", "\n", diff --git a/aviary/docs/getting_started/onboarding_level3.ipynb b/aviary/docs/getting_started/onboarding_level3.ipynb index 1f185bb80..bb4141353 100644 --- a/aviary/docs/getting_started/onboarding_level3.ipynb +++ b/aviary/docs/getting_started/onboarding_level3.ipynb @@ -34,7 +34,7 @@ "In `aviary/validation_cases/benchmark_tests` folder, there is an N3CC aircraft full mission benchmark test `test_FLOPS_based_full_mission_N3CC.py`. Now, we will show how to create an N3CC example in level3. The key is that we follow the same steps:\n", "- init\n", "- load_inputs\n", - "- check_inputs (optional)\n", + "- check_and_preprocess_inputs (optional)\n", "- add_pre_mission_systems\n", "- add_phases\n", "- add_post_mission_systems\n", 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 9a20fd22f..ed3a90000 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 @@ -146,8 +146,8 @@ "# Allow for user overrides here\n", "prob.load_inputs(csv_path, phase_info)\n", "\n", - "# Have checks for clashing user inputs\n", - "prob.check_inputs()\n", + + "prob.check_and_preprocess_inputs()\n", "\n", "prob.add_pre_mission_systems()\n", "\n", diff --git a/aviary/docs/user_guide/subsystems.md b/aviary/docs/user_guide/subsystems.md index 0b19295ed..d5441dbac 100644 --- a/aviary/docs/user_guide/subsystems.md +++ b/aviary/docs/user_guide/subsystems.md @@ -12,7 +12,7 @@ In the following outline, the methods listed at the top-level are defined in `me Any sub-listed method is one that you can provide with your subsystem builder, showing where within the level 3 method hierarchy that subsystem method gets used. - `load_inputs` - loads the aviary_values inputs and options that the user specifies. -- `check_inputs` - checks the user-supplied input values for any potential problems. +- `check_and_preprocess_inputs` - checks the user-supplied input values for any potential problems. - `preprocess_inputs` - `add_pre_mission_systems` - adds pre-mission Systems to the Aviary problem - `get_mass_names` diff --git a/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py b/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py index 8b8ac8949..064c86985 100644 --- a/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py +++ b/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py @@ -110,13 +110,13 @@ aircraft_definition_file = 'models/test_aircraft/aircraft_for_bench_FwFm_simple.csv' make_plots = False -max_iter = 100 -optimizer = 'IPOPT' +max_iter = 1 # set this to a higher number to fully run the optimization +optimizer = 'SLSQP' prob = av.AviaryProblem() prob.load_inputs(aircraft_definition_file, phase_info) -prob.check_inputs() +prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() prob.add_phases() prob.add_post_mission_systems() diff --git a/aviary/examples/external_subsystems/battery/run_cruise.py b/aviary/examples/external_subsystems/battery/run_cruise.py index a0463c89d..44882c487 100644 --- a/aviary/examples/external_subsystems/battery/run_cruise.py +++ b/aviary/examples/external_subsystems/battery/run_cruise.py @@ -16,7 +16,7 @@ # 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) +prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv', phase_info) prob.add_pre_mission_systems() diff --git a/aviary/examples/external_subsystems/battery/run_multiphase_mission.py b/aviary/examples/external_subsystems/battery/run_multiphase_mission.py index 1cae165e9..975dc7ef5 100644 --- a/aviary/examples/external_subsystems/battery/run_multiphase_mission.py +++ b/aviary/examples/external_subsystems/battery/run_multiphase_mission.py @@ -24,9 +24,9 @@ # Allow for user overrides here prob.load_inputs(input_file, phase_info) -# Have checks for clashing user inputs -# Raise warnings or errors depending on how clashing the issues are -prob.check_inputs() + +# Preprocess inputs +prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() @@ -37,7 +37,7 @@ # Link phases and variables prob.link_phases() -prob.add_driver("SNOPT") +prob.add_driver("SLSQP") prob.add_design_variables() diff --git a/aviary/examples/level2_shooting_traj.py b/aviary/examples/level2_shooting_traj.py index 983f42d6f..0bbd323b5 100644 --- a/aviary/examples/level2_shooting_traj.py +++ b/aviary/examples/level2_shooting_traj.py @@ -36,9 +36,9 @@ def run_aviary(aircraft_filename, phase_info, optimizer=None, analysis_scheme=An # Allow for user overrides here prob.load_inputs(aircraft_filename, phase_info) - # Have checks for clashing user inputs - # Raise warnings or errors depending on how clashing the issues are - prob.check_inputs() + +# Preprocess inputs + prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() diff --git a/aviary/examples/test/test_all_examples.py b/aviary/examples/test/test_all_examples.py index 387654108..8393a27c7 100644 --- a/aviary/examples/test/test_all_examples.py +++ b/aviary/examples/test/test_all_examples.py @@ -45,8 +45,9 @@ def setUpClass(cls): This method is called once before starting the tests and is used to populate the 'run_files' attribute with a list of run scripts. """ - cls.base_directory = "../external_subsystems" # Adjust the path as necessary - cls.run_files = cls.find_run_files(cls.base_directory) + base_directory = os.path.join(os.path.dirname( + os.path.dirname(os.path.abspath(__file__))), ".") + cls.run_files = cls.find_run_files(base_directory) @staticmethod def find_run_files(base_dir): diff --git a/aviary/interface/methods_for_level1.py b/aviary/interface/methods_for_level1.py index 0bb4d810c..d5c04a1e9 100644 --- a/aviary/interface/methods_for_level1.py +++ b/aviary/interface/methods_for_level1.py @@ -66,9 +66,9 @@ def run_aviary(aircraft_filename, phase_info, optimizer=None, # Allow for user overrides here prob.load_inputs(aircraft_filename, phase_info) - # Have checks for clashing user inputs - # Raise warnings or errors depending on how clashing the issues are - prob.check_inputs() + +# Preprocess inputs + prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 5227a27ed..8254984e0 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -342,11 +342,10 @@ def _update_metadata_from_subsystems(self): if variable in self.meta_data: self.meta_data.pop(variable) - def check_inputs(self): + def check_and_preprocess_inputs(self): """ - This method checks the user-supplied input values for any potential problems. - These problems include variable names that are not recognized in Aviary, - conflicting options or values, or units mismatching. + 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. """ check_phase_info(self.phase_info, self.mission_method) diff --git a/aviary/interface/test/test_interface_bugs.py b/aviary/interface/test/test_interface_bugs.py index 59f614e3d..4c5d1bed4 100644 --- a/aviary/interface/test/test_interface_bugs.py +++ b/aviary/interface/test/test_interface_bugs.py @@ -74,9 +74,9 @@ def test_post_mission_promotion(self): prob.load_inputs(csv_path, phase_info) - # Have checks for clashing user inputs - # Raise warnings or errors depending on how clashing the issues are - # prob.check_inputs() + +# Preprocess inputs + # prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() diff --git a/aviary/interface/test/test_phase_info.py b/aviary/interface/test/test_phase_info.py index 812410958..cc49d51f9 100644 --- a/aviary/interface/test/test_phase_info.py +++ b/aviary/interface/test/test_phase_info.py @@ -92,7 +92,7 @@ def test_phase_info_parameterization_gasp(self): prob.load_inputs( "models/small_single_aisle/small_single_aisle_GwGm.csv", phase_info) - prob.check_inputs() + prob.check_and_preprocess_inputs() # We can set some crazy vals, since we aren't going to optimize. prob.aviary_inputs.set_val(Mission.Design.RANGE, 5000, 'km') diff --git a/aviary/interface/test/test_reserve_support.py b/aviary/interface/test/test_reserve_support.py index 0f0fce3b5..d3e41caf2 100644 --- a/aviary/interface/test/test_reserve_support.py +++ b/aviary/interface/test/test_reserve_support.py @@ -19,7 +19,7 @@ def test_post_mission_promotion(self): prob = AviaryProblem() prob.load_inputs("models/test_aircraft/aircraft_for_bench_GwFm.csv", phase_info) - prob.check_inputs() + prob.check_and_preprocess_inputs() # TODO: This needs to be converted into a reserve and a scaler so that it can # be given proper units. @@ -52,7 +52,7 @@ def test_gasp_relative_reserve(self): prob.load_inputs( "models/small_single_aisle/small_single_aisle_GwGm.csv", phase_info) - prob.check_inputs() + prob.check_and_preprocess_inputs() prob.aviary_inputs.set_val(Mission.Summary.GROSS_MASS, 140000.0, units='lbm') diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py index ac78f16d8..40f7a9393 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py @@ -114,6 +114,79 @@ def test_solved_aero_pass_polar(self): assert_near_equal(CL_pass, CL_base, 1e-6) assert_near_equal(CD_pass, CD_base, 1e-6) + def test_solved_aero_pass_polar_unique_abscissa(self): + # Solved Aero with shortened lists of table abscissa. + local_phase_info = deepcopy(phase_info) + + prob = AviaryProblem() + + csv_path = "subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv" + prob.load_inputs(csv_path, local_phase_info) + prob.add_pre_mission_systems() + prob.add_phases() + prob.add_post_mission_systems() + + prob.link_phases() + + prob.setup() + + prob.set_initial_guesses() + + prob.run_model() + + CL_base = prob.get_val("traj.cruise.rhs_all.core_aerodynamics.tabular_aero.CL") + CD_base = prob.get_val("traj.cruise.rhs_all.core_aerodynamics.tabular_aero.CD") + + # Lift and Drag polars passed from external component in static. + + ph_in = deepcopy(phase_info) + + alt = np.array([0., 3000., 6000., 9000., 12000., 15000., 18000., 21000., + 24000., 27000., 30000., 33000., 36000., 38000., 42000.]) + mach = np.array([0., 0.2, 0.4, 0.5, 0.6, 0.7, 0.75, 0.8, 0.85, 0.9]) + alpha = np.array([-2., 0., 2., 4., 6., 8., 10.]) + + polar_builder = FakeDragPolarBuilder(name="aero", altitude=alt, mach=mach, + alpha=alpha) + aero_data = NamedValues() + aero_data.set_val('altitude', alt, 'ft') + aero_data.set_val('mach', mach, 'unitless') + aero_data.set_val('angle_of_attack', alpha, 'deg') + + subsystem_options = {'method': 'solved_alpha', + 'aero_data': aero_data, + 'training_data': True} + ph_in['pre_mission']['external_subsystems'] = [polar_builder] + + ph_in['cruise']['subsystem_options'] = {'core_aerodynamics': subsystem_options} + + prob = AviaryProblem() + + prob.load_inputs(csv_path, ph_in) + + prob.aviary_inputs.set_val(Aircraft.Design.LIFT_POLAR, + np.zeros_like(CL), units='unitless') + prob.aviary_inputs.set_val(Aircraft.Design.DRAG_POLAR, + np.zeros_like(CD), units='unitless') + + prob.add_pre_mission_systems() + prob.add_phases() + prob.add_post_mission_systems() + + prob.link_phases() + + prob.setup() + + prob.set_initial_guesses() + + prob.run_model() + + CL_pass = prob.get_val("traj.cruise.rhs_all.core_aerodynamics.tabular_aero.CL") + CD_pass = prob.get_val("traj.cruise.rhs_all.core_aerodynamics.tabular_aero.CD") + + assert_near_equal(CL_pass, CL_base, 1e-6) + assert_near_equal(CD_pass, CD_base, 1e-6) + class FakeCalcDragPolar(om.ExplicitComponent): """ diff --git a/aviary/subsystems/aerodynamics/gasp_based/table_based.py b/aviary/subsystems/aerodynamics/gasp_based/table_based.py index c9fc4d397..d333fe16f 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/table_based.py +++ b/aviary/subsystems/aerodynamics/gasp_based/table_based.py @@ -588,11 +588,12 @@ def _structure_special_grid(aero_data): # units don't matter, not using values aoa = aero_data.get_val('angle_of_attack', 'deg') - # special case alpha - this format saturates alpha at its max - # get unique alphas at zero alt mach 0, should cover the full range - # TODO this does not work with data that is already in structured grid format - mask = (data[0] == x0[0]) & (data[1] == x1[0]) - aoa = np.unique(aoa[mask]) + if data[0].shape[0] > x0.shape[0]: + # special case alpha - this format saturates alpha at its max + # get unique alphas at zero alt mach 0, should cover the full range + mask = (data[0] == x0[0]) & (data[1] == x1[0]) + aoa = np.unique(aoa[mask]) + _, _, aoa = np.meshgrid(x0, x1, aoa) # put the aoa data back in the NamedValues object diff --git a/aviary/subsystems/propulsion/test/test_custom_engine_model.py b/aviary/subsystems/propulsion/test/test_custom_engine_model.py index 93464c6f8..c1756d749 100644 --- a/aviary/subsystems/propulsion/test/test_custom_engine_model.py +++ b/aviary/subsystems/propulsion/test/test_custom_engine_model.py @@ -167,9 +167,9 @@ def test_custom_engine(self): prob.load_inputs("models/test_aircraft/aircraft_for_bench_GwFm.csv", phase_info, engine_builder=SimpleTestEngine()) - # Have checks for clashing user inputs - # Raise warnings or errors depending on how clashing the issues are - prob.check_inputs() + +# Preprocess inputs + prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() diff --git a/aviary/subsystems/test/test_external_subsystem_bus.py b/aviary/subsystems/test/test_external_subsystem_bus.py index 24f9dd4ba..68f3f82b0 100644 --- a/aviary/subsystems/test/test_external_subsystem_bus.py +++ b/aviary/subsystems/test/test_external_subsystem_bus.py @@ -90,9 +90,8 @@ def test_external_subsystem_bus(self): prob = AviaryProblem() - prob.load_inputs( - "models/test_aircraft/aircraft_for_bench_FwFm_simple.csv", phase_info) - prob.check_inputs() + prob.load_inputs("models/test_aircraft/aircraft_for_bench_FwFm.csv", phase_info) + prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() prob.add_phases() diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index 0423ac7de..d8fe2c56e 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -18,7 +18,7 @@ def build_and_run_problem(self, input_filename, phase_info, objective_type=None) prob.load_inputs(input_filename, phase_info) - prob.check_inputs() + prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() prob.add_phases() prob.add_post_mission_systems() diff --git a/aviary/validation_cases/benchmark_tests/test_full_mission_solved_level3.py b/aviary/validation_cases/benchmark_tests/test_full_mission_solved_level3.py index a479d8077..d194d8c5c 100644 --- a/aviary/validation_cases/benchmark_tests/test_full_mission_solved_level3.py +++ b/aviary/validation_cases/benchmark_tests/test_full_mission_solved_level3.py @@ -26,9 +26,9 @@ def bench_test_solved_full_mission(self): prob.load_inputs(input_file, local_phase_info) prob.aviary_inputs.set_val(Mission.Design.RANGE, 2000.0, units="NM") - # Have checks for clashing user inputs - # Raise warnings or errors depending on how clashing the issues are - prob.check_inputs() + +# Preprocess inputs + prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() diff --git a/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py b/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py index cd760af1f..2b9c8ab3a 100644 --- a/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py +++ b/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py @@ -58,9 +58,9 @@ def test_subsystems_in_a_mission(self): prob.load_inputs("models/test_aircraft/aircraft_for_bench_GwFm.csv", phase_info) - # Have checks for clashing user inputs - # Raise warnings or errors depending on how clashing the issues are - prob.check_inputs() + +# Preprocess inputs + prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() @@ -106,9 +106,9 @@ def test_bad_initial_guess_key(self): prob.load_inputs("models/test_aircraft/aircraft_for_bench_GwFm.csv", phase_info) - # Have checks for clashing user inputs - # Raise warnings or errors depending on how clashing the issues are - prob.check_inputs() + +# Preprocess inputs + prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() From 8b61a46bd4e60799c0b3d3094bd4817ab436a991 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 12 Jan 2024 11:19:04 -0600 Subject: [PATCH 056/188] Filter out Dymos solver warnings --- aviary/interface/methods_for_level2.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 8254984e0..8a710ea6e 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -1841,6 +1841,7 @@ def setup(self, **kwargs): set_aviary_initial_values( self.model, self.aviary_inputs, meta_data=self.meta_data) + warnings.simplefilter("ignore", om.OpenMDAOWarning) warnings.simplefilter("ignore", om.PromotionWarning) super().setup(**kwargs) From ffd4a6e5b19a3a1d882918b204c6dc771edc2b61 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Fri, 12 Jan 2024 12:58:06 -0500 Subject: [PATCH 057/188] More print statements to help debug --- aviary/visualization/dashboard.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index aa1ebf8e2..af53b6dd1 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -311,6 +311,12 @@ def dashboard(script_name, problem_recorder, driver_recorder, port): """ reports_dir = f"reports/{script_name}/" + print("reports contents") + reports_dir_contents = os.listdir("reports") + for item in reports_dir_contents: + print(item) + print("end reports contents") + if not Path(reports_dir).is_dir(): raise ValueError( f"The script name, '{script_name}', does not have a reports folder associated with it. " From ebbaea637f5d6b62a4b8c6d42a094a51cde83fa1 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Fri, 12 Jan 2024 13:20:14 -0500 Subject: [PATCH 058/188] More debug prints --- aviary/interface/test/test_simple_mission.py | 6 ++++++ aviary/visualization/dashboard.py | 3 +++ 2 files changed, 9 insertions(+) diff --git a/aviary/interface/test/test_simple_mission.py b/aviary/interface/test/test_simple_mission.py index 403c8542e..d78a8dfeb 100644 --- a/aviary/interface/test/test_simple_mission.py +++ b/aviary/interface/test/test_simple_mission.py @@ -116,6 +116,12 @@ def run_mission(self, phase_info, optimizer): def test_mission_basic_and_dashboard(self): prob = self.run_mission(self.phase_info, "SLSQP") + import os + print(f"pwd = {os.pwd()}") + files = os.listdir() + for file in files: + print(file) + self.assertIsNotNone(prob) self.assertFalse(prob.failed) diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index af53b6dd1..49ea7f207 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -311,6 +311,9 @@ def dashboard(script_name, problem_recorder, driver_recorder, port): """ reports_dir = f"reports/{script_name}/" + import os + print(f"pwd = {os.pwd()}") + print("reports contents") reports_dir_contents = os.listdir("reports") for item in reports_dir_contents: From f554b104b477b39ff91d799cd549c80260fdbc01 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Fri, 12 Jan 2024 13:29:57 -0500 Subject: [PATCH 059/188] used wrong os function --- aviary/interface/test/test_simple_mission.py | 2 +- aviary/visualization/dashboard.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/interface/test/test_simple_mission.py b/aviary/interface/test/test_simple_mission.py index d78a8dfeb..a011641de 100644 --- a/aviary/interface/test/test_simple_mission.py +++ b/aviary/interface/test/test_simple_mission.py @@ -117,7 +117,7 @@ def run_mission(self, phase_info, optimizer): def test_mission_basic_and_dashboard(self): prob = self.run_mission(self.phase_info, "SLSQP") import os - print(f"pwd = {os.pwd()}") + print(f"pwd = {os.cwd()}") files = os.listdir() for file in files: print(file) diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index 49ea7f207..a500b2992 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -312,7 +312,7 @@ def dashboard(script_name, problem_recorder, driver_recorder, port): reports_dir = f"reports/{script_name}/" import os - print(f"pwd = {os.pwd()}") + print(f"pwd = {os.cwd()}") print("reports contents") reports_dir_contents = os.listdir("reports") From 3ac6247ac28be3a41f22f7aff67f94414a47fe8b Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Fri, 12 Jan 2024 13:48:11 -0500 Subject: [PATCH 060/188] used wrong os function --- aviary/interface/test/test_simple_mission.py | 2 +- aviary/visualization/dashboard.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/interface/test/test_simple_mission.py b/aviary/interface/test/test_simple_mission.py index a011641de..fbe7e66ca 100644 --- a/aviary/interface/test/test_simple_mission.py +++ b/aviary/interface/test/test_simple_mission.py @@ -117,7 +117,7 @@ def run_mission(self, phase_info, optimizer): def test_mission_basic_and_dashboard(self): prob = self.run_mission(self.phase_info, "SLSQP") import os - print(f"pwd = {os.cwd()}") + print(f"pwd = {os.getcwd()}") files = os.listdir() for file in files: print(file) diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index a500b2992..27137ccfd 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -312,7 +312,7 @@ def dashboard(script_name, problem_recorder, driver_recorder, port): reports_dir = f"reports/{script_name}/" import os - print(f"pwd = {os.cwd()}") + print(f"pwd = {os.getcwd()}") print("reports contents") reports_dir_contents = os.listdir("reports") From 4dfbc2b14e671ddbff09b8c8fe5ed198880d2bf6 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 12 Jan 2024 12:56:36 -0600 Subject: [PATCH 061/188] Tests and benches pass --- aviary/interface/methods_for_level2.py | 32 ++++++++++++++----- .../flops_based/phases/simplified_landing.py | 4 +-- .../flops_based/phases/simplified_takeoff.py | 10 +++++- .../benchmark_tests/test_bench_FwFm.py | 8 ++--- .../benchmark_tests/test_bench_GwFm.py | 5 +-- aviary/variable_info/variable_meta_data.py | 12 +++++++ aviary/variable_info/variables.py | 1 + 7 files changed, 52 insertions(+), 20 deletions(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 8a710ea6e..70bbfb7d3 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -2382,17 +2382,33 @@ def _add_flops_landing_systems(self): 'traj.climb.initial_states:mass') self.model.connect(Mission.Takeoff.GROUND_DISTANCE, 'traj.climb.initial_states:range') - # TODO: connect this correctly - # mass is the most important to connect but these others should - # be connected as well - # self.model.connect(Mission.Takeoff.FINAL_VELOCITY, - # 'traj.climb.initial_states:mach') - # self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, - # 'traj.climb.controls:altitude') + + # Create an ExecComp to compute the difference in mach + mach_diff_comp = om.ExecComp('mach_difference = final_mach - initial_mach') + self.model.add_subsystem('mach_diff_comp', mach_diff_comp) + + # Connect the inputs to the mach difference component + self.model.connect(Mission.Takeoff.FINAL_MACH, 'mach_diff_comp.final_mach') + self.model.connect('traj.climb.control_values:mach', + 'mach_diff_comp.initial_mach', src_indices=[0]) + + # Add constraint for mach difference + self.model.add_constraint('mach_diff_comp.mach_difference', equals=0.0) + + # Similar steps for altitude difference + alt_diff_comp = om.ExecComp( + 'altitude_difference = final_altitude - initial_altitude', units='ft') + self.model.add_subsystem('alt_diff_comp', alt_diff_comp) + + self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, + 'alt_diff_comp.final_altitude') + self.model.connect('traj.climb.control_values:altitude', + 'alt_diff_comp.initial_altitude', src_indices=[0]) + + self.model.add_constraint('alt_diff_comp.altitude_difference', equals=0.0) self.model.connect('traj.descent.states:mass', Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1]) - # TODO: approach velocity should likely be connected self.model.connect('traj.descent.control_values:altitude', Mission.Landing.INITIAL_ALTITUDE, src_indices=[0]) diff --git a/aviary/mission/flops_based/phases/simplified_landing.py b/aviary/mission/flops_based/phases/simplified_landing.py index 07391f77a..5e893b693 100644 --- a/aviary/mission/flops_based/phases/simplified_landing.py +++ b/aviary/mission/flops_based/phases/simplified_landing.py @@ -117,10 +117,10 @@ def setup(self): self.add_subsystem( "calcs", LandingCalc(), + promotes_inputs=[Mission.Landing.TOUCHDOWN_MASS, "rho", + Aircraft.Wing.AREA, Mission.Landing.LIFT_COEFFICIENT_MAX], promotes_outputs=[ Mission.Landing.GROUND_DISTANCE, Mission.Landing.INITIAL_VELOCITY, ], - promotes_inputs=[Mission.Landing.TOUCHDOWN_MASS, "rho", - Aircraft.Wing.AREA, Mission.Landing.LIFT_COEFFICIENT_MAX], ) diff --git a/aviary/mission/flops_based/phases/simplified_takeoff.py b/aviary/mission/flops_based/phases/simplified_takeoff.py index 2f7848a8c..95d761a2d 100644 --- a/aviary/mission/flops_based/phases/simplified_takeoff.py +++ b/aviary/mission/flops_based/phases/simplified_takeoff.py @@ -379,7 +379,7 @@ def setup(self): "USatm", USatm1976Comp(num_nodes=1), promotes_inputs=[("h", Dynamic.Mission.ALTITUDE)], - promotes_outputs=["rho"], + promotes_outputs=["rho", ("sos", "speed_of_sound")], ) self.add_subsystem( @@ -417,3 +417,11 @@ def setup(self): Mission.Takeoff.FINAL_ALTITUDE, ], ) + + self.add_subsystem('compute_mach', om.ExecComp('final_mach = final_velocity / speed_of_sound', + final_mach={'units': 'unitless'}, + final_velocity={'units': 'm/s'}, + speed_of_sound={'units': 'm/s'}), + promotes_inputs=[('speed_of_sound', 'speed_of_sound'), + ('final_velocity', Mission.Takeoff.FINAL_VELOCITY)], + promotes_outputs=[('final_mach', Mission.Takeoff.FINAL_MACH)]) diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index 22aa5a384..803449af0 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -1,4 +1,3 @@ -from copy import deepcopy import unittest import numpy as np @@ -7,7 +6,6 @@ from aviary.interface.methods_for_level1 import run_aviary from aviary.validation_cases.benchmark_utils import \ compare_against_expected_values -from aviary.variable_info.variables import Dynamic @use_tempdirs @@ -268,7 +266,7 @@ def bench_test_swap_4_FwFm(self): "climb": { "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, "user_options": { - 'fix_initial': {Dynamic.Mission.MASS: False, Dynamic.Mission.RANGE: False}, + 'fix_initial': False, 'input_initial': True, "optimize_mach": True, "optimize_altitude": True, @@ -279,7 +277,7 @@ def bench_test_swap_4_FwFm(self): "initial_mach": (0.2, "unitless"), "final_mach": (0.79, "unitless"), "mach_bounds": ((0.1, 0.8), "unitless"), - "initial_altitude": (0.0, "ft"), + "initial_altitude": (35., "ft"), "final_altitude": (35000.0, "ft"), "altitude_bounds": ((0.0, 36000.0), "ft"), "throttle_enforcement": "path_constraint", @@ -350,7 +348,7 @@ def bench_test_swap_4_FwFm(self): } prob = run_aviary( - 'models/test_aircraft/aircraft_for_bench_FwFm_simple.csv', phase_info) + 'models/test_aircraft/aircraft_for_bench_FwFm_simple.csv', phase_info, max_iter=100) compare_against_expected_values(prob, self.expected_dict) diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py index ad785f4d8..166e19ca4 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py @@ -5,7 +5,6 @@ Computed Aero Large Single Aisle 1 data ''' -from copy import deepcopy import unittest import numpy as np @@ -14,8 +13,6 @@ from aviary.interface.methods_for_level1 import run_aviary from aviary.validation_cases.benchmark_utils import \ compare_against_expected_values -from aviary.variable_info.variables import Dynamic -from aviary.interface.default_phase_info.height_energy import phase_info @use_tempdirs @@ -275,7 +272,7 @@ def bench_test_swap_1_GwFm(self): "climb": { "subsystem_options": {"core_aerodynamics": {"method": "computed"}}, "user_options": { - 'fix_initial': {Dynamic.Mission.MASS: False, Dynamic.Mission.RANGE: False}, + 'fix_initial': False, 'input_initial': True, "optimize_mach": True, "optimize_altitude": True, diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index 94d66ccdc..12bd99eee 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -7067,6 +7067,18 @@ default_value=35.0, ) +add_meta_data( + Mission.Takeoff.FINAL_MACH, + meta_data=_MetaData, + historical_name={"GASP": None, + "FLOPS": None, + "LEAPS1": None, + }, + units='unitless', + desc='Mach number of aircraft after taking off and ' + 'clearing a 35 foot obstacle' +) + add_meta_data( Mission.Takeoff.FINAL_MASS, meta_data=_MetaData, diff --git a/aviary/variable_info/variables.py b/aviary/variable_info/variables.py index a64d774f4..35efb7501 100644 --- a/aviary/variable_info/variables.py +++ b/aviary/variable_info/variables.py @@ -709,6 +709,7 @@ class Takeoff: DRAG_COEFFICIENT_MIN = 'mission:takeoff:drag_coefficient_min' FIELD_LENGTH = 'mission:takeoff:field_length' FINAL_ALTITUDE = 'mission:takeoff:final_altitude' + FINAL_MACH = 'mission:takeoff:final_mach' FINAL_MASS = 'mission:takeoff:final_mass' FINAL_VELOCITY = 'mission:takeoff:final_velocity' FUEL_SIMPLE = 'mission:takeoff:fuel_simple' From bf53319aaf7152c28663781da59b60970473fb79 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 12 Jan 2024 12:59:55 -0600 Subject: [PATCH 062/188] Removed defunct variable in takeoff --- .../mission/flops_based/phases/simplified_takeoff.py | 12 ------------ .../phases/test/test_simplified_takeoff.py | 4 ---- .../models/test_aircraft/aircraft_for_bench_FwFm.csv | 1 - .../models/test_aircraft/aircraft_for_bench_GwFm.csv | 1 - 4 files changed, 18 deletions(-) diff --git a/aviary/mission/flops_based/phases/simplified_takeoff.py b/aviary/mission/flops_based/phases/simplified_takeoff.py index 95d761a2d..5060f0c04 100644 --- a/aviary/mission/flops_based/phases/simplified_takeoff.py +++ b/aviary/mission/flops_based/phases/simplified_takeoff.py @@ -103,12 +103,6 @@ def setup(self): add_aviary_input(self, Mission.Takeoff.LIFT_OVER_DRAG, val=2) - # we don't actually need this? It seems like we should from the equation in the - # paper, but we are using the equation from LEAPS1 because it doesn't require L - # or D - add_aviary_input(self, Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT, - val=0.00175) - add_aviary_output(self, Mission.Takeoff.GROUND_DISTANCE, val=0) add_aviary_output(self, Mission.Takeoff.FINAL_VELOCITY, @@ -133,7 +127,6 @@ def setup_partials(self): Aircraft.Wing.AREA, Mission.Takeoff.LIFT_COEFFICIENT_MAX, Mission.Design.THRUST_TAKEOFF_PER_ENG, - Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT, Mission.Takeoff.LIFT_OVER_DRAG, ], ) @@ -160,7 +153,6 @@ def compute(self, inputs, outputs): Cl_max = inputs[Mission.Takeoff.LIFT_COEFFICIENT_MAX] thrust = inputs[Mission.Design.THRUST_TAKEOFF_PER_ENG] L_over_D = inputs[Mission.Takeoff.LIFT_OVER_DRAG] - mu = inputs[Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT] num_engines = self.options['num_engines'] rho_ratio = rho / rho_SL @@ -205,17 +197,14 @@ def compute(self, inputs, outputs): outputs[Mission.Takeoff.FINAL_ALTITUDE] = 35 def compute_partials(self, inputs, J): - rho_SL = RHO_SEA_LEVEL_METRIC - v_stall = inputs["v_stall"] ramp_weight = inputs[Mission.Design.GROSS_MASS] * GRAV_ENGLISH_LBM rho = inputs["rho"] S = inputs[Aircraft.Wing.AREA] Cl_max = inputs[Mission.Takeoff.LIFT_COEFFICIENT_MAX] thrust = inputs[Mission.Design.THRUST_TAKEOFF_PER_ENG] L_over_D = inputs[Mission.Takeoff.LIFT_OVER_DRAG] - mu = inputs[Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT] num_engines = self.options['num_engines'] rho_ratio = rho / rho_SL @@ -408,7 +397,6 @@ def setup(self): Mission.Takeoff.LIFT_COEFFICIENT_MAX, Mission.Design.THRUST_TAKEOFF_PER_ENG, Mission.Takeoff.LIFT_OVER_DRAG, - Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT, ], promotes_outputs=[ Mission.Takeoff.GROUND_DISTANCE, diff --git a/aviary/mission/flops_based/phases/test/test_simplified_takeoff.py b/aviary/mission/flops_based/phases/test/test_simplified_takeoff.py index c011af727..472a5bcc0 100644 --- a/aviary/mission/flops_based/phases/test/test_simplified_takeoff.py +++ b/aviary/mission/flops_based/phases/test/test_simplified_takeoff.py @@ -91,8 +91,6 @@ def setUp(self): Mission.Design.THRUST_TAKEOFF_PER_ENG, val=28928.0, units="lbf") # check self.prob.model.set_input_defaults( Mission.Takeoff.LIFT_OVER_DRAG, val=17.354, units='unitless') # check - self.prob.model.set_input_defaults( - Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT, val=0.0175, units='unitless') # check self.prob.setup(check=False, force_alloc_complex=True) @@ -145,8 +143,6 @@ def setUp(self): Mission.Design.THRUST_TAKEOFF_PER_ENG, val=28928.0, units="lbf") # check self.prob.model.set_input_defaults( Mission.Takeoff.LIFT_OVER_DRAG, val=17.354, units='unitless') # check - self.prob.model.set_input_defaults( - Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT, val=0.0175, units='unitless') # check self.prob.model.set_input_defaults( Dynamic.Mission.ALTITUDE, val=0, units="ft") # check diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv index 2d4ea4703..925e6aed6 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv @@ -154,6 +154,5 @@ mission:summary:fuel_flow_scaler,1.0,unitless mission:takeoff:fuel_simple,577,lbm mission:takeoff:lift_coefficient_max,3.0,unitless mission:takeoff:lift_over_drag,17.354,unitless -mission:takeoff:rolling_friction_coefficient,0.0175,unitless settings:equations_of_motion,height_energy settings:mass_method,FLOPS \ No newline at end of file diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv index 5c0d0b8a0..c59731257 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv @@ -268,6 +268,5 @@ mission:takeoff:fuel_simple,577,lbm mission:takeoff:lift_coefficient_flap_increment,0.4182,unitless mission:takeoff:lift_coefficient_max,3.0,unitless mission:takeoff:lift_over_drag,17.354,unitless -mission:takeoff:rolling_friction_coefficient,0.0175,unitless settings:equations_of_motion,height_energy settings:mass_method,GASP \ No newline at end of file From bbbd79655c42d40c3a9ab91fb107c6e3c07d8bbb Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 12 Jan 2024 13:29:12 -0600 Subject: [PATCH 063/188] Fixed merge --- aviary/interface/test/test_phase_info.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/interface/test/test_phase_info.py b/aviary/interface/test/test_phase_info.py index 5736adbf2..1f960f088 100644 --- a/aviary/interface/test/test_phase_info.py +++ b/aviary/interface/test/test_phase_info.py @@ -94,7 +94,7 @@ def test_phase_info_parameterization_gasp(self): prob = AviaryProblem() - csv_path = "models/small_single_aisle/small_single_aisle_GwGm.csv") + csv_path = "models/small_single_aisle/small_single_aisle_GwGm.csv" prob.load_inputs(csv_path, phase_info) prob.check_and_preprocess_inputs() @@ -130,7 +130,7 @@ def test_phase_info_parameterization_flops(self): prob = AviaryProblem() - csv_path = "models/test_aircraft/aircraft_for_bench_FwFm.csv") + csv_path = "models/test_aircraft/aircraft_for_bench_FwFm.csv" prob.load_inputs(csv_path, phase_info) prob.check_and_preprocess_inputs() From 677cfce633f214831fb2924ada122bec8ae21d0d Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Fri, 12 Jan 2024 14:30:26 -0500 Subject: [PATCH 064/188] Added more prints --- aviary/interface/test/test_simple_mission.py | 6 +++++- aviary/visualization/dashboard.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/aviary/interface/test/test_simple_mission.py b/aviary/interface/test/test_simple_mission.py index fbe7e66ca..f1b3b6f81 100644 --- a/aviary/interface/test/test_simple_mission.py +++ b/aviary/interface/test/test_simple_mission.py @@ -117,10 +117,14 @@ def run_mission(self, phase_info, optimizer): def test_mission_basic_and_dashboard(self): prob = self.run_mission(self.phase_info, "SLSQP") import os - print(f"pwd = {os.getcwd()}") + import sys + print( + f"in test_mission_basic_and_dashboard pwd = {os.getcwd()}", file=sys.stderr) + print("in current directory these are the files") files = os.listdir() for file in files: print(file) + print("end of current directory files") self.assertIsNotNone(prob) self.assertFalse(prob.failed) diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index 27137ccfd..7b1a49b52 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -312,7 +312,7 @@ def dashboard(script_name, problem_recorder, driver_recorder, port): reports_dir = f"reports/{script_name}/" import os - print(f"pwd = {os.getcwd()}") + print(f"in dashboard pwd = {os.getcwd()}") print("reports contents") reports_dir_contents = os.listdir("reports") From e5cdf1a5b3b261424b3ccbb975ae2e5e58168241 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Fri, 12 Jan 2024 14:38:46 -0500 Subject: [PATCH 065/188] Added tmate session to workflow temporarily --- .github/workflows/test_workflow.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 3edbe2f3e..436b1947c 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -213,6 +213,10 @@ jobs: python run_all.py cd ../.. + - name: Setup tmate session + uses: mxschmitt/action-tmate@v3 + + - name: Run tests if: matrix.MAKE_DOCS == 0 shell: bash -l {0} From 3c80a2400084442612746e9c7f067923b0c06bb4 Mon Sep 17 00:00:00 2001 From: jkirk5 Date: Fri, 12 Jan 2024 15:54:14 -0500 Subject: [PATCH 066/188] allow L2 interface to accept AviaryValues objects --- aviary/api.py | 1 + aviary/interface/methods_for_level2.py | 17 +++++++--- aviary/utils/process_input_decks.py | 46 ++++++++++++++++---------- 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/aviary/api.py b/aviary/api.py index 9bd1e7104..81b1fafc0 100644 --- a/aviary/api.py +++ b/aviary/api.py @@ -149,5 +149,6 @@ from aviary.subsystems.propulsion.propulsion_builder import CorePropulsionBuilder # Testing +# NOTE these load every FLOPS validation test case, every Avairy run from aviary.validation_cases.validation_tests import get_flops_inputs, get_flops_outputs from aviary.validation_cases.validation_data.flops_data.FLOPS_Test_Data import FLOPS_Test_Data diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 9285db939..cf76e4326 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -42,7 +42,7 @@ from aviary.subsystems.premission import CorePreMission from aviary.mission.gasp_based.ode.breguet_cruise_ode import BreguetCruiseODESolution from aviary.utils.functions import set_aviary_initial_values, Null, create_opts2vals, add_opts2vals, promote_aircraft_and_mission_vars -from aviary.utils.process_input_decks import create_vehicle +from aviary.utils.process_input_decks import create_vehicle, update_GASP_options from aviary.utils.preprocessors import preprocess_crewpayload from aviary.interface.utils.check_phase_info import check_phase_info from aviary.utils.aviary_values import AviaryValues @@ -150,7 +150,7 @@ def __init__(self, analysis_scheme=AnalysisScheme.COLLOCATION, **kwargs): self.analysis_scheme = analysis_scheme - def load_inputs(self, input_filename, phase_info=None, engine_builder=None): + def load_inputs(self, aviary_inputs, phase_info=None, engine_builder=None): """ This method loads the aviary_values inputs and options that the user specifies. They could specify files to load and values to @@ -163,14 +163,23 @@ def load_inputs(self, input_filename, phase_info=None, engine_builder=None): """ ## LOAD INPUT FILE ### self.engine_builder = engine_builder - self.aviary_inputs, self.initial_guesses = create_vehicle(input_filename) - aviary_inputs = self.aviary_inputs + # 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) + # aviary_inputs = self.aviary_inputs + # pull which methods will be used for subsystems and mission self.mission_method = mission_method = aviary_inputs.get_val( Settings.EQUATIONS_OF_MOTION) self.mass_method = mass_method = aviary_inputs.get_val(Settings.MASS_METHOD) + if mission_method is TWO_DEGREES_OF_FREEDOM or mass_method is GASP: + aviary_inputs, initial_guesses = update_GASP_options(aviary_inputs, + initial_guesses) + self.aviary_inputs = aviary_inputs + self.initial_guesses = initial_guesses + if mission_method is TWO_DEGREES_OF_FREEDOM: aviary_inputs.set_val(Mission.Summary.CRUISE_MASS_FINAL, val=self.initial_guesses['cruise_mass_final'], units='lbm') diff --git a/aviary/utils/process_input_decks.py b/aviary/utils/process_input_decks.py index 3705f18c7..840d254f6 100644 --- a/aviary/utils/process_input_decks.py +++ b/aviary/utils/process_input_decks.py @@ -51,21 +51,14 @@ def create_vehicle(vehicle_deck=''): """ aircraft_values = get_option_defaults(engine=False) - # TODO remove all hardcoded GASP values here, find appropriate place for them + # TODO temporary, needed until debug_mode retired in favor of new verbosity flag aircraft_values.set_val('debug_mode', val=False) - 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') - aircraft_values.set_val('problem_type', val=ProblemType.SIZING) - aircraft_values.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False) - aircraft_values.set_val(Aircraft.Design.RESERVES, val=4998) - vehicle_deck = get_path(vehicle_deck) - - parse_inputs(vehicle_deck, aircraft_values) - # update the dependent options with the current values - update_options(aircraft_values, initial_guesses) + if isinstance(vehicle_deck, AviaryValues): + aircraft_values.update(vehicle_deck) + else: + vehicle_deck = get_path(vehicle_deck) + parse_inputs(vehicle_deck, aircraft_values) return aircraft_values, initial_guesses @@ -120,7 +113,7 @@ def parse_inputs(vehicle_deck, aircraft_values: AviaryValues(), meta_data=_MetaD aircraft_values = set_value(var_name, var_values, aircraft_values) continue - elif var_name in meta_data.keys(): + if var_name in meta_data.keys(): aircraft_values = set_value( var_name, var_values, aircraft_values, units=data_units, is_array=is_array, meta_data=meta_data) continue @@ -135,8 +128,11 @@ def parse_inputs(vehicle_deck, aircraft_values: AviaryValues(), meta_data=_MetaD return aircraft_values, initial_guesses +# TODO this should be a preprocessor, and tasks split to be specific to subsystem +# e.g. aero preprocessor, mass preprocessor, 2DOF preprocessor, etc. -def update_options(aircraft_values: AviaryValues(), initial_guesses): + +def update_GASP_options(aircraft_values: AviaryValues(), initial_guesses): """ Updates options based on the current values in aircraft_values. This function also handles special cases and prints debug information if the debug mode is active. @@ -150,11 +146,27 @@ def update_options(aircraft_values: AviaryValues(), initial_guesses): ------- tuple: Updated aircraft values and initial guesses. """ + GASP_defaults = AviaryValues() + GASP_defaults.set_val('INGASP.JENGSZ', val=4) + GASP_defaults.set_val('test_mode', val=False) + GASP_defaults.set_val('use_surrogates', val=True) + GASP_defaults.set_val('mass_defect', val=10000, units='lbm') + GASP_defaults.set_val('problem_type', val=ProblemType.SIZING) + GASP_defaults.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False) + GASP_defaults.set_val(Aircraft.Design.RESERVES, val=4998) + + # overwrite GASP_defaults with values from aircraft_values, then replace + # aircraft_values with this merged set + GASP_defaults.update(aircraft_values) + aircraft_values = GASP_defaults + + for var in initial_guesses: + if var in aircraft_values: + initial_guesses[var], _ = aircraft_values.get_item(var) + # update the options that depend on variables update_dependent_options(aircraft_values, dependent_options) - # TODO this is GASP only, don't always run it! These should go in a GASP-only options - # preprocessor ## STRUT AND FOLD ## if not aircraft_values.get_val(Aircraft.Wing.HAS_STRUT): aircraft_values.set_val( From 26c0aebde8365283e25b2393f9a04f419f98c04b Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 12 Jan 2024 14:55:19 -0600 Subject: [PATCH 067/188] Added initial pass of new climb phase --- .../flops_based/phases/simple_energy_phase.py | 2 - .../gasp_based/phases/new_climb_phase.py | 149 ++++++++++++++++++ 2 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 aviary/mission/gasp_based/phases/new_climb_phase.py diff --git a/aviary/mission/flops_based/phases/simple_energy_phase.py b/aviary/mission/flops_based/phases/simple_energy_phase.py index e5ffd1928..1fbacf297 100644 --- a/aviary/mission/flops_based/phases/simple_energy_phase.py +++ b/aviary/mission/flops_based/phases/simple_energy_phase.py @@ -1,5 +1,3 @@ -from math import isclose - import dymos as dm from aviary.mission.flops_based.phases.phase_builder_base import ( diff --git a/aviary/mission/gasp_based/phases/new_climb_phase.py b/aviary/mission/gasp_based/phases/new_climb_phase.py new file mode 100644 index 000000000..511a18fb0 --- /dev/null +++ b/aviary/mission/gasp_based/phases/new_climb_phase.py @@ -0,0 +1,149 @@ +import dymos as dm +from aviary.mission.flops_based.phases.phase_builder_base import ( + PhaseBuilderBase, InitialGuessState, InitialGuessTime) +from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.variables import Dynamic +from aviary.mission.gasp_based.ode.climb_ode import ClimbODE +from aviary.interface.default_phase_info.two_dof import default_mission_subsystems + + +class ClimbPhase(PhaseBuilderBase): + """ + A phase builder for a climb phase in a mission simulation. + + This class extends the PhaseBuilderBase class, providing specific implementations for + the climb phase of a flight mission. + + Attributes + ---------- + Inherits all attributes from PhaseBuilderBase. + + Methods + ------- + Inherits all methods from PhaseBuilderBase. + Additional method overrides and new methods specific to the climb phase are included. + """ + default_name = 'climb_phase' + default_ode_class = ClimbODE + + def __init__( + self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, core_subsystems=None, + external_subsystems=None, meta_data=None + ): + super().__init__( + name=name, subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, + core_subsystems=core_subsystems, external_subsystems=external_subsystems, + meta_data=meta_data + ) + + def build_phase(self, aviary_options: AviaryValues = None): + """ + Return a new climb phase for analysis using these constraints. + + If ode_class is None, ClimbODE is used as the default. + + Parameters + ---------- + aviary_options : AviaryValues + Collection of Aircraft/Mission specific options + + Returns + ------- + dymos.Phase + """ + phase = super().build_phase(aviary_options) + + # Custom configurations for the climb phase + user_options = self.user_options + + # States + phase.add_state( + Dynamic.Mission.ALTITUDE, + fix_initial=user_options.get_val('fix_initial'), + fix_final=False, + lower=user_options.get_val('alt_lower'), + upper=user_options.get_val('alt_upper'), + units="ft", + rate_source=Dynamic.Mission.ALTITUDE_RATE, + targets=Dynamic.Mission.ALTITUDE, + ref=user_options.get_val('alt_ref'), + ref0=user_options.get_val('alt_ref0'), + defect_ref=user_options.get_val('alt_defect_ref'), + ) + + phase.add_state( + Dynamic.Mission.MASS, + fix_initial=user_options.get_val('fix_initial'), + fix_final=False, + lower=user_options.get_val('mass_lower'), + upper=user_options.get_val('mass_upper'), + units="lbm", + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, + ref=user_options.get_val('mass_ref'), + ref0=user_options.get_val('mass_ref0'), + defect_ref=user_options.get_val('mass_defect_ref'), + ) + + # Boundary Constraints + if user_options.get_val('target_mach'): + phase.add_boundary_constraint( + Dynamic.Mission.MACH, loc="final", equals=user_options.get_val('mach_cruise'), units="unitless" + ) + + phase.add_boundary_constraint( + Dynamic.Mission.ALTITUDE, + loc="final", + equals=user_options.get_val('final_alt'), + units="ft", + ref=user_options.get_val('final_alt') + ) + + if user_options.get_val('required_available_climb_rate') is not None: + phase.add_boundary_constraint( + Dynamic.Mission.ALTITUDE_RATE, + loc="final", + lower=user_options.get_val('required_available_climb_rate'), + units="ft/min", + ref=1, + ) + + # Timeseries Outputs + phase.add_timeseries_output( + Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") + phase.add_timeseries_output("EAS", output_name="EAS", units="kn") + phase.add_timeseries_output( + Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units="lbm/s") + phase.add_timeseries_output("theta", output_name="theta", units="deg") + phase.add_timeseries_output("alpha", output_name="alpha", units="deg") + phase.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, + output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") + phase.add_timeseries_output( + "TAS_violation", output_name="TAS_violation", units="kn") + phase.add_timeseries_output("TAS", output_name="TAS", units="kn") + phase.add_timeseries_output("aero.CL", output_name="CL", units="unitless") + phase.add_timeseries_output( + Dynamic.Mission.THRUST_TOTAL, output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") + phase.add_timeseries_output("aero.CD", output_name="CD", units="unitless") + + return phase + +# Function to create and configure ClimbPhase + + +def get_climb_phase(user_options): + # Instantiate ClimbPhase with user options + climb_phase = ClimbPhase(user_options=user_options) + + # Build the phase + climb = climb_phase.build_phase() + + return climb + + +# Example usage +user_options = AviaryValues() +# Set the required user options +climb = get_climb_phase(user_options=user_options) From 83c3575d6fe546b8ac76dcb3c0d4676a528c27e7 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Fri, 12 Jan 2024 17:41:52 -0500 Subject: [PATCH 068/188] remove the tmate session --- .github/workflows/test_workflow.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 436b1947c..3edbe2f3e 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -213,10 +213,6 @@ jobs: python run_all.py cd ../.. - - name: Setup tmate session - uses: mxschmitt/action-tmate@v3 - - - name: Run tests if: matrix.MAKE_DOCS == 0 shell: bash -l {0} From 65c0876561c3d251740febf8d0930f0f7cfce9d8 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Fri, 12 Jan 2024 17:42:52 -0500 Subject: [PATCH 069/188] removed TESTFLO_RUNNING from the environment when running the dashboard test so the reports would be generated --- aviary/interface/test/test_simple_mission.py | 26 +++++++++----------- aviary/visualization/dashboard.py | 9 ------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/aviary/interface/test/test_simple_mission.py b/aviary/interface/test/test_simple_mission.py index f1b3b6f81..5c951b0ed 100644 --- a/aviary/interface/test/test_simple_mission.py +++ b/aviary/interface/test/test_simple_mission.py @@ -1,3 +1,4 @@ +import os import unittest from aviary.interface.methods_for_level1 import run_aviary from aviary.subsystems.test.test_dummy_subsystem import ArrayGuessSubsystemBuilder @@ -9,6 +10,7 @@ class AircraftMissionTestSuite(unittest.TestCase): def setUp(self): + # Load the phase_info and other common setup tasks self.phase_info = { "pre_mission": {"include_takeoff": False, "optimize_mass": True}, @@ -115,16 +117,16 @@ def run_mission(self, phase_info, optimizer): optimization_history_filename="driver_test.db") def test_mission_basic_and_dashboard(self): + # We need to remove the TESTFLO_RUNNING environment variable for this test to run. + # The reports code checks to see if TESTFLO_RUNNING is set and will not do anything if set + # But we need to remember whether it was set so we can restore it + testflo_running = os.environ.pop('TESTFLO_RUNNING', None) + prob = self.run_mission(self.phase_info, "SLSQP") - import os - import sys - print( - f"in test_mission_basic_and_dashboard pwd = {os.getcwd()}", file=sys.stderr) - print("in current directory these are the files") - files = os.listdir() - for file in files: - print(file) - print("end of current directory files") + + # restore what was there before running the test + if testflo_running is not None: + os.environ['TESTFLO_RUNNING'] = testflo_running self.assertIsNotNone(prob) self.assertFalse(prob.failed) @@ -136,11 +138,7 @@ def test_mission_basic_and_dashboard(self): try: subprocess.check_output(cmd.split()) except subprocess.CalledProcessError as err: - self.fail("Command '{}' failed. Return code: {} \n output: {} \n stderr: {} \n stdout: {}".format(cmd, - err.returncode, - err.output, - err.stderr, - err.stdout)) + self.fail("Command '{}' failed. Return code: {}".format(cmd, err.returncode)) @require_pyoptsparse(optimizer="IPOPT") def test_mission_basic_pyopt(self): diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index 7b1a49b52..aa1ebf8e2 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -311,15 +311,6 @@ def dashboard(script_name, problem_recorder, driver_recorder, port): """ reports_dir = f"reports/{script_name}/" - import os - print(f"in dashboard pwd = {os.getcwd()}") - - print("reports contents") - reports_dir_contents = os.listdir("reports") - for item in reports_dir_contents: - print(item) - print("end reports contents") - if not Path(reports_dir).is_dir(): raise ValueError( f"The script name, '{script_name}', does not have a reports folder associated with it. " From ddf590761306c0fa491626ad4493dc99a0e7169d Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Tue, 16 Jan 2024 13:22:58 -0500 Subject: [PATCH 070/188] first, tests running as expected --- aviary/interface/methods_for_level2.py | 17 +++++++++-------- aviary/mission/gasp_based/ode/accel_eom.py | 7 ++++--- aviary/mission/gasp_based/ode/accel_ode.py | 2 +- aviary/mission/gasp_based/ode/ascent_eom.py | 11 ++++++----- aviary/mission/gasp_based/ode/climb_eom.py | 15 ++++++++------- aviary/mission/gasp_based/ode/climb_ode.py | 2 +- aviary/mission/gasp_based/ode/descent_eom.py | 16 +++++++++------- aviary/mission/gasp_based/ode/descent_ode.py | 2 +- .../mission/gasp_based/ode/flight_path_eom.py | 11 ++++++----- .../mission/gasp_based/ode/flight_path_ode.py | 2 +- aviary/mission/gasp_based/ode/groundroll_eom.py | 11 ++++++----- aviary/mission/gasp_based/ode/rotation_eom.py | 11 ++++++----- .../gasp_based/ode/test/test_accel_eom.py | 3 ++- .../gasp_based/ode/test/test_climb_eom.py | 3 ++- .../gasp_based/ode/test/test_climb_ode.py | 4 ++-- .../gasp_based/ode/test/test_descent_eom.py | 3 ++- .../gasp_based/ode/test/test_descent_ode.py | 4 ++-- .../gasp_based/phases/2DOF_phase_builder.py | 5 +++-- aviary/mission/gasp_based/phases/accel_phase.py | 2 +- .../mission/gasp_based/phases/ascent_phase.py | 2 +- aviary/mission/gasp_based/phases/climb_phase.py | 2 +- aviary/mission/gasp_based/phases/desc_phase.py | 2 +- .../gasp_based/phases/groundroll_phase.py | 2 +- .../mission/gasp_based/phases/rotation_phase.py | 2 +- .../gasp_based/phases/run_phases/run_accel.py | 3 ++- .../gasp_based/phases/run_phases/run_climb.py | 2 +- .../run_phases/run_climb_test_FLOPS_prop.py | 2 +- .../phases/run_phases/run_groundroll.py | 2 +- .../phases/run_phases/run_rotation.py | 2 +- .../gasp_based/phases/run_phases/run_takeoff.py | 11 ++++++----- .../test_FLOPS_based_sizing_N3CC.py | 6 +++--- aviary/xdsm/accel_xdsm.py | 2 +- aviary/xdsm/climb_xdsm.py | 2 +- aviary/xdsm/descent1_xdsm.py | 2 +- aviary/xdsm/descent2_xdsm.py | 2 +- aviary/xdsm/groundroll_xdsm.py | 2 +- aviary/xdsm/statics_xdsm.py | 16 ++++++++-------- 37 files changed, 105 insertions(+), 90 deletions(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index cb9818663..62fee7599 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -1400,7 +1400,7 @@ def add_linkage_constraint(self, phase_a, phase_b, var_b): elif self.mission_method is TWO_DEGREES_OF_FREEDOM: if self.analysis_scheme is AnalysisScheme.COLLOCATION: self.traj.link_phases(["groundroll", "rotation", "ascent"], [ - "time", "TAS", "mass", "distance"], connected=True) + "time", "TAS", "mass", Dynamic.Mission.DISTANCE], connected=True) self.traj.link_phases( ["rotation", "ascent"], ["alpha"], connected=False, ref=5e1, @@ -1408,8 +1408,8 @@ def add_linkage_constraint(self, phase_a, phase_b, var_b): self.traj.add_linkage_constraint( "ascent", "accel", - "distance", - "distance", + Dynamic.Mission.DISTANCE, + Dynamic.Mission.DISTANCE, "final", "initial", connected=False, @@ -1422,13 +1422,14 @@ def add_linkage_constraint(self, phase_a, phase_b, var_b): "time", "mass", "TAS"], connected=True) self.traj.link_phases( phases=["accel", "climb1", "climb2"], - vars=["time", Dynamic.Mission.ALTITUDE, "mass", "distance"], + vars=["time", Dynamic.Mission.ALTITUDE, + "mass", Dynamic.Mission.DISTANCE], connected=True, ) self.traj.link_phases( phases=["desc1", "desc2"], - vars=["time", "mass", "distance"], + vars=["time", "mass", Dynamic.Mission.DISTANCE], connected=True, ) @@ -2063,11 +2064,11 @@ def _add_guesses(self, phase_name, phase, guesses): if self.mission_method is SIMPLE: control_keys = ["mach", "altitude"] - state_keys = ["mass", "range"] + state_keys = ["mass", Dynamic.Mission.RANGE] else: control_keys = ["velocity_rate", "throttle"] state_keys = ["altitude", "velocity", "mass", - "range", "TAS", "distance", "flight_path_angle", "alpha"] + Dynamic.Mission.RANGE, "TAS", Dynamic.Mission.DISTANCE, "flight_path_angle", "alpha"] if self.mission_method is TWO_DEGREES_OF_FREEDOM and phase_name == 'ascent': # Alpha is a control for ascent. control_keys.append('alpha') @@ -2171,7 +2172,7 @@ def _add_guesses(self, phase_name, phase, guesses): # Set the distance guesses as the initial values for the distance state variable self.set_val( f"traj.{phase_name}.states:distance", phase.interp( - "distance", ys=ys) + Dynamic.Mission.DISTANCE, ys=ys) ) def _add_solved_guesses(self, idx, phase_name, phase): diff --git a/aviary/mission/gasp_based/ode/accel_eom.py b/aviary/mission/gasp_based/ode/accel_eom.py index ca8939964..db3adba94 100644 --- a/aviary/mission/gasp_based/ode/accel_eom.py +++ b/aviary/mission/gasp_based/ode/accel_eom.py @@ -56,7 +56,7 @@ def setup(self): desc="rate of change of true air speed", ) self.add_output( - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, val=np.zeros(nn), units="ft/s", desc="rate of change of horizontal distance covered", @@ -65,7 +65,8 @@ def setup(self): self.declare_partials( "TAS_rate", [ Dynamic.Mission.MASS, Dynamic.Mission.DRAG, Dynamic.Mission.THRUST_TOTAL], rows=arange, cols=arange) - self.declare_partials("distance_rate", ["TAS"], rows=arange, cols=arange, val=1.) + self.declare_partials(Dynamic.Mission.DISTANCE_RATE, [ + "TAS"], rows=arange, cols=arange, val=1.) if analysis_scheme is AnalysisScheme.SHOOTING: self.add_input("t_curr", val=np.ones(nn), desc="time", units="s") @@ -83,7 +84,7 @@ def compute(self, inputs, outputs): TAS = inputs["TAS"] outputs["TAS_rate"] = (GRAV_ENGLISH_GASP / weight) * (thrust - drag) - outputs["distance_rate"] = TAS + outputs[Dynamic.Mission.DISTANCE_RATE] = TAS if analysis_scheme is AnalysisScheme.SHOOTING: outputs[Dynamic.Mission.ALTITUDE_RATE] = 0 diff --git a/aviary/mission/gasp_based/ode/accel_ode.py b/aviary/mission/gasp_based/ode/accel_ode.py index eae09fe28..4eac3fe2a 100644 --- a/aviary/mission/gasp_based/ode/accel_ode.py +++ b/aviary/mission/gasp_based/ode/accel_ode.py @@ -89,7 +89,7 @@ def setup(self): + sgm_inputs, promotes_outputs=[ "TAS_rate", - "distance_rate", ] + Dynamic.Mission.DISTANCE_RATE, ] + sgm_outputs, ) diff --git a/aviary/mission/gasp_based/ode/ascent_eom.py b/aviary/mission/gasp_based/ode/ascent_eom.py index aea1ab632..212354599 100644 --- a/aviary/mission/gasp_based/ode/ascent_eom.py +++ b/aviary/mission/gasp_based/ode/ascent_eom.py @@ -49,7 +49,7 @@ def setup(self): desc="altitude rate", units="ft/s") self.add_output( - "distance_rate", val=np.ones(nn), desc="distance rate", units="ft/s" + Dynamic.Mission.DISTANCE_RATE, val=np.ones(nn), desc="distance rate", units="ft/s" ) self.add_output( "normal_force", val=np.ones(nn), desc="normal forces", units="lbf" @@ -102,7 +102,7 @@ def setup_partials(self): Dynamic.Mission.ALTITUDE_RATE, [ "TAS", Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange) self.declare_partials( - "distance_rate", ["TAS", Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange + Dynamic.Mission.DISTANCE_RATE, ["TAS", Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange ) self.declare_partials( "normal_force", @@ -156,7 +156,7 @@ def compute(self, inputs, outputs): ) outputs[Dynamic.Mission.ALTITUDE_RATE] = TAS * np.sin(gamma) - outputs["distance_rate"] = TAS * np.cos(gamma) + outputs[Dynamic.Mission.DISTANCE_RATE] = TAS * np.cos(gamma) outputs["normal_force"] = normal_force outputs["fuselage_pitch"] = gamma * 180 / np.pi - i_wing + alpha @@ -281,8 +281,9 @@ def compute_partials(self, inputs, J): J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = TAS * np.cos(gamma) - J["distance_rate", "TAS"] = np.cos(gamma) - J["distance_rate", Dynamic.Mission.FLIGHT_PATH_ANGLE] = -TAS * np.sin(gamma) + J[Dynamic.Mission.DISTANCE_RATE, "TAS"] = np.cos(gamma) + J[Dynamic.Mission.DISTANCE_RATE, + Dynamic.Mission.FLIGHT_PATH_ANGLE] = -TAS * np.sin(gamma) J["normal_force", Dynamic.Mission.MASS] = dNF_dWeight * GRAV_ENGLISH_LBM J["normal_force", Dynamic.Mission.LIFT] = dNF_dLift diff --git a/aviary/mission/gasp_based/ode/climb_eom.py b/aviary/mission/gasp_based/ode/climb_eom.py index 436fd6fc2..50a06bab6 100644 --- a/aviary/mission/gasp_based/ode/climb_eom.py +++ b/aviary/mission/gasp_based/ode/climb_eom.py @@ -53,7 +53,7 @@ def setup(self): desc="rate of change of altitude", ) self.add_output( - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, val=np.zeros(nn), units="ft/s", desc="rate of change of horizontal distance covered", @@ -79,7 +79,7 @@ def setup(self): rows=arange, cols=arange) self.declare_partials( - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, ["TAS", Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.DRAG, Dynamic.Mission.MASS], rows=arange, cols=arange, @@ -113,7 +113,7 @@ def compute(self, inputs, outputs): gamma = np.arcsin((thrust - drag) / weight) outputs[Dynamic.Mission.ALTITUDE_RATE] = TAS * np.sin(gamma) - outputs["distance_rate"] = TAS * np.cos(gamma) + outputs[Dynamic.Mission.DISTANCE_RATE] = TAS * np.cos(gamma) outputs["required_lift"] = weight * np.cos(gamma) outputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] = gamma @@ -142,11 +142,12 @@ def compute_partials(self, inputs, J): J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.MASS] = \ TAS * np.cos(gamma) * dGamma_dWeight * GRAV_ENGLISH_LBM - J["distance_rate", "TAS"] = np.cos(gamma) - J["distance_rate", Dynamic.Mission.THRUST_TOTAL] = - \ + J[Dynamic.Mission.DISTANCE_RATE, "TAS"] = np.cos(gamma) + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.THRUST_TOTAL] = - \ TAS * np.sin(gamma) * dGamma_dThrust - J["distance_rate", Dynamic.Mission.DRAG] = -TAS * np.sin(gamma) * dGamma_dDrag - J["distance_rate", Dynamic.Mission.MASS] = \ + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.DRAG] = - \ + TAS * np.sin(gamma) * dGamma_dDrag + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.MASS] = \ -TAS * np.sin(gamma) * dGamma_dWeight * GRAV_ENGLISH_LBM J["required_lift", Dynamic.Mission.MASS] = ( diff --git a/aviary/mission/gasp_based/ode/climb_ode.py b/aviary/mission/gasp_based/ode/climb_ode.py index e9182e92b..da51cccba 100644 --- a/aviary/mission/gasp_based/ode/climb_ode.py +++ b/aviary/mission/gasp_based/ode/climb_ode.py @@ -191,7 +191,7 @@ def setup(self): integration_states, promotes_outputs=[ Dynamic.Mission.ALTITUDE_RATE, - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, "required_lift", Dynamic.Mission.FLIGHT_PATH_ANGLE, ], diff --git a/aviary/mission/gasp_based/ode/descent_eom.py b/aviary/mission/gasp_based/ode/descent_eom.py index 32a37c0bc..02e9ee5bc 100644 --- a/aviary/mission/gasp_based/ode/descent_eom.py +++ b/aviary/mission/gasp_based/ode/descent_eom.py @@ -51,7 +51,7 @@ def setup(self): desc="rate of change of altitude", ) self.add_output( - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, val=np.zeros(nn), units="ft/s", desc="rate of change of horizontal distance covered", @@ -77,7 +77,7 @@ def setup(self): rows=arange, cols=arange) self.declare_partials( - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, ["TAS", Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.DRAG, Dynamic.Mission.MASS], rows=arange, cols=arange, @@ -112,7 +112,7 @@ def compute(self, inputs, outputs): gamma = (thrust - drag) / weight outputs[Dynamic.Mission.ALTITUDE_RATE] = alt_rate = TAS * np.sin(gamma) - outputs["distance_rate"] = TAS * np.cos(gamma) + outputs[Dynamic.Mission.DISTANCE_RATE] = TAS * np.cos(gamma) outputs["required_lift"] = weight * np.cos(gamma) - thrust * np.sin(alpha) outputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] = gamma @@ -134,10 +134,12 @@ def compute_partials(self, inputs, J): J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.MASS] = TAS * \ np.cos(gamma) * (-(thrust - drag) / weight**2) * GRAV_ENGLISH_LBM - J["distance_rate", "TAS"] = np.cos(gamma) - J["distance_rate", Dynamic.Mission.THRUST_TOTAL] = -TAS * np.sin(gamma) / weight - J["distance_rate", Dynamic.Mission.DRAG] = -TAS * np.sin(gamma) * (-1 / weight) - J["distance_rate", Dynamic.Mission.MASS] = ( + J[Dynamic.Mission.DISTANCE_RATE, "TAS"] = np.cos(gamma) + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.THRUST_TOTAL] = - \ + TAS * np.sin(gamma) / weight + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.DRAG] = - \ + TAS * np.sin(gamma) * (-1 / weight) + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.MASS] = ( -TAS * np.sin(gamma) * (-(thrust - drag) / weight**2) * GRAV_ENGLISH_LBM ) diff --git a/aviary/mission/gasp_based/ode/descent_ode.py b/aviary/mission/gasp_based/ode/descent_ode.py index 3257fbb14..1e8eac07d 100644 --- a/aviary/mission/gasp_based/ode/descent_ode.py +++ b/aviary/mission/gasp_based/ode/descent_ode.py @@ -181,7 +181,7 @@ def setup(self): integration_states, promotes_outputs=[ Dynamic.Mission.ALTITUDE_RATE, - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, "required_lift", Dynamic.Mission.FLIGHT_PATH_ANGLE, ], diff --git a/aviary/mission/gasp_based/ode/flight_path_eom.py b/aviary/mission/gasp_based/ode/flight_path_eom.py index 7eb2e7624..57f1ae6a2 100644 --- a/aviary/mission/gasp_based/ode/flight_path_eom.py +++ b/aviary/mission/gasp_based/ode/flight_path_eom.py @@ -80,7 +80,7 @@ def setup(self): self.add_input("alpha", val=np.ones(nn), desc="angle of attack", units="deg") self.add_output( - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, val=np.ones(nn), desc="distance rate", units="ft/s", @@ -157,7 +157,7 @@ def setup_partials(self): ) self.declare_partials( - "distance_rate", ["TAS", Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange + Dynamic.Mission.DISTANCE_RATE, ["TAS", Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange ) # self.declare_partials("alpha_rate", ["*"], val=0.0) self.declare_partials( @@ -211,7 +211,7 @@ def compute(self, inputs, outputs): ) outputs[Dynamic.Mission.ALTITUDE_RATE] = TAS * np.sin(gamma) - outputs["distance_rate"] = TAS * np.cos(gamma) + outputs[Dynamic.Mission.DISTANCE_RATE] = TAS * np.cos(gamma) outputs["normal_force"] = normal_force @@ -343,8 +343,9 @@ def compute_partials(self, inputs, J): J["load_factor", Aircraft.Wing.INCIDENCE] = dTAcF_dIwing / \ (weight * np.cos(gamma)) - J["distance_rate", "TAS"] = np.cos(gamma) - J["distance_rate", Dynamic.Mission.FLIGHT_PATH_ANGLE] = -TAS * np.sin(gamma) + J[Dynamic.Mission.DISTANCE_RATE, "TAS"] = np.cos(gamma) + J[Dynamic.Mission.DISTANCE_RATE, + Dynamic.Mission.FLIGHT_PATH_ANGLE] = -TAS * np.sin(gamma) J["normal_force", Dynamic.Mission.MASS] = dNF_dWeight * GRAV_ENGLISH_LBM J["normal_force", Dynamic.Mission.LIFT] = dNF_dLift diff --git a/aviary/mission/gasp_based/ode/flight_path_ode.py b/aviary/mission/gasp_based/ode/flight_path_ode.py index 64542100b..e70ddb8d0 100644 --- a/aviary/mission/gasp_based/ode/flight_path_ode.py +++ b/aviary/mission/gasp_based/ode/flight_path_ode.py @@ -198,7 +198,7 @@ def setup(self): promotes_inputs=EOM_inputs, promotes_outputs=[ "TAS_rate", - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, "normal_force", "fuselage_pitch", "load_factor", diff --git a/aviary/mission/gasp_based/ode/groundroll_eom.py b/aviary/mission/gasp_based/ode/groundroll_eom.py index 34643768e..610c818b6 100644 --- a/aviary/mission/gasp_based/ode/groundroll_eom.py +++ b/aviary/mission/gasp_based/ode/groundroll_eom.py @@ -39,7 +39,7 @@ def setup(self): self.add_output(Dynamic.Mission.ALTITUDE_RATE, val=np.ones(nn), desc="altitude rate", units="ft/s") self.add_output( - "distance_rate", val=np.ones(nn), desc="distance rate", units="ft/s" + Dynamic.Mission.DISTANCE_RATE, val=np.ones(nn), desc="distance rate", units="ft/s" ) self.add_output( "normal_force", val=np.ones(nn), desc="normal forces", units="lbf" @@ -60,7 +60,7 @@ def setup(self): self.declare_partials(Dynamic.Mission.ALTITUDE_RATE, [ "TAS", Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange) self.declare_partials( - "distance_rate", ["TAS", Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange + Dynamic.Mission.DISTANCE_RATE, ["TAS", Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange ) self.declare_partials( "normal_force", @@ -121,7 +121,7 @@ def compute(self, inputs, outputs): outputs[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE] = np.zeros(nn) outputs[Dynamic.Mission.ALTITUDE_RATE] = TAS * np.sin(gamma) - outputs["distance_rate"] = TAS * np.cos(gamma) + outputs[Dynamic.Mission.DISTANCE_RATE] = TAS * np.cos(gamma) outputs["normal_force"] = normal_force outputs["fuselage_pitch"] = gamma * 180 / np.pi - i_wing + alpha @@ -204,8 +204,9 @@ def compute_partials(self, inputs, J): J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = TAS * np.cos(gamma) - J["distance_rate", "TAS"] = np.cos(gamma) - J["distance_rate", Dynamic.Mission.FLIGHT_PATH_ANGLE] = -TAS * np.sin(gamma) + J[Dynamic.Mission.DISTANCE_RATE, "TAS"] = np.cos(gamma) + J[Dynamic.Mission.DISTANCE_RATE, + Dynamic.Mission.FLIGHT_PATH_ANGLE] = -TAS * np.sin(gamma) J["normal_force", Dynamic.Mission.MASS] = dNF_dWeight * GRAV_ENGLISH_LBM J["normal_force", Dynamic.Mission.LIFT] = dNF_dLift diff --git a/aviary/mission/gasp_based/ode/rotation_eom.py b/aviary/mission/gasp_based/ode/rotation_eom.py index c42d922e7..f721a86e0 100644 --- a/aviary/mission/gasp_based/ode/rotation_eom.py +++ b/aviary/mission/gasp_based/ode/rotation_eom.py @@ -39,7 +39,7 @@ def setup(self): self.add_output(Dynamic.Mission.ALTITUDE_RATE, val=np.ones(nn), desc="altitude rate", units="ft/s") self.add_output( - "distance_rate", val=np.ones(nn), desc="distance rate", units="ft/s" + Dynamic.Mission.DISTANCE_RATE, val=np.ones(nn), desc="distance rate", units="ft/s" ) self.add_output( "normal_force", val=np.ones(nn), desc="normal forces", units="lbf" @@ -74,7 +74,7 @@ def setup_partials(self): self.declare_partials(Dynamic.Mission.ALTITUDE_RATE, [ "TAS", Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange) self.declare_partials( - "distance_rate", ["TAS", Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange + Dynamic.Mission.DISTANCE_RATE, ["TAS", Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=arange, cols=arange ) self.declare_partials( @@ -125,7 +125,7 @@ def compute(self, inputs, outputs): outputs[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE] = np.zeros(nn) outputs[Dynamic.Mission.ALTITUDE_RATE] = TAS * np.sin(gamma) - outputs["distance_rate"] = TAS * np.cos(gamma) + outputs[Dynamic.Mission.DISTANCE_RATE] = TAS * np.cos(gamma) outputs["normal_force"] = normal_force outputs["fuselage_pitch"] = gamma * 180 / np.pi - i_wing + alpha @@ -209,8 +209,9 @@ def compute_partials(self, inputs, J): J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = TAS * np.cos(gamma) - J["distance_rate", "TAS"] = np.cos(gamma) - J["distance_rate", Dynamic.Mission.FLIGHT_PATH_ANGLE] = -TAS * np.sin(gamma) + J[Dynamic.Mission.DISTANCE_RATE, "TAS"] = np.cos(gamma) + J[Dynamic.Mission.DISTANCE_RATE, + Dynamic.Mission.FLIGHT_PATH_ANGLE] = -TAS * np.sin(gamma) J["normal_force", Dynamic.Mission.MASS] = dNF_dWeight * GRAV_ENGLISH_LBM J["normal_force", Dynamic.Mission.LIFT] = dNF_dLift diff --git a/aviary/mission/gasp_based/ode/test/test_accel_eom.py b/aviary/mission/gasp_based/ode/test/test_accel_eom.py index b1f42e91a..61950cbc4 100644 --- a/aviary/mission/gasp_based/ode/test/test_accel_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_accel_eom.py @@ -48,7 +48,8 @@ def test_case1(self): # note: this was finite differenced from GASP. The fd value is: np.array([5.2353365, 5.2353365]) ) assert_near_equal( - self.prob["distance_rate"], np.array([425.32808399, 425.32808399]), tol + self.prob[Dynamic.Mission.DISTANCE_RATE], np.array( + [425.32808399, 425.32808399]), tol # note: this was finite differenced from GASP. The fd value is: np.array([441.6439, 441.6439]) ) diff --git a/aviary/mission/gasp_based/ode/test/test_climb_eom.py b/aviary/mission/gasp_based/ode/test/test_climb_eom.py index d9539a24e..940f0a7cb 100644 --- a/aviary/mission/gasp_based/ode/test/test_climb_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_climb_eom.py @@ -45,7 +45,8 @@ def test_case1(self): [6.24116612, 6.24116612]), tol ) # note: values from GASP are: np.array([5.9667, 5.9667]) assert_near_equal( - self.prob["distance_rate"], np.array([774.679584, 774.679584]), tol + self.prob[Dynamic.Mission.DISTANCE_RATE], np.array( + [774.679584, 774.679584]), tol # note: these values are finite differenced and lose accuracy. Fd values are: np.array([799.489, 799.489]) ) assert_near_equal( 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 9094977a5..5a895cd11 100644 --- a/aviary/mission/gasp_based/ode/test/test_climb_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_climb_ode.py @@ -48,7 +48,7 @@ def test_start_of_climb(self): "CD": 0.0307, Dynamic.Mission.ALTITUDE_RATE: 3186 / 60, # TAS (kts -> ft/s) * cos(gamma) - "distance_rate": (254 * 1.68781) * np.cos(np.deg2rad(7.12)), + Dynamic.Mission.DISTANCE_RATE: (254 * 1.68781) * np.cos(np.deg2rad(7.12)), Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL: -13505, # lbm/h "theta": np.deg2rad(12.31), Dynamic.Mission.FLIGHT_PATH_ANGLE: np.deg2rad(7.12), @@ -84,7 +84,7 @@ def test_end_of_climb(self): "CD": [0.0270, 0.0326], Dynamic.Mission.ALTITUDE_RATE: [3054 / 60, 453 / 60], # TAS (kts -> ft/s) * cos(gamma) - "distance_rate": [ + Dynamic.Mission.DISTANCE_RATE: [ (319 * 1.68781) * np.cos(np.deg2rad(5.42)), (459 * 1.68781) * np.cos(np.deg2rad(0.56)), ], diff --git a/aviary/mission/gasp_based/ode/test/test_descent_eom.py b/aviary/mission/gasp_based/ode/test/test_descent_eom.py index 00dfc13c9..b1885749a 100644 --- a/aviary/mission/gasp_based/ode/test/test_descent_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_descent_eom.py @@ -47,7 +47,8 @@ def test_case1(self): [-39.41011217, -39.41011217]), tol ) # note: values from GASP are: np.array([-39.75, -39.75]) assert_near_equal( - self.prob["distance_rate"], np.array([773.70165638, 773.70165638]), tol + self.prob[Dynamic.Mission.DISTANCE_RATE], np.array( + [773.70165638, 773.70165638]), tol # note: these values are finite differenced and lose accuracy. Fd values are:np.array([964.4634921, 964.4634921]) ) assert_near_equal( 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 b7a64e408..262871768 100644 --- a/aviary/mission/gasp_based/ode/test/test_descent_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_descent_ode.py @@ -48,7 +48,7 @@ def test_high_alt(self): "CD": np.array([0.0279, 0.0197]), Dynamic.Mission.ALTITUDE_RATE: np.array([-2385, -3076]) / 60, # TAS (ft/s) * cos(gamma) - "distance_rate": [ + Dynamic.Mission.DISTANCE_RATE: [ (459 * 1.68781) * np.cos(np.deg2rad(-2.94)), (437 * 1.68781) * np.cos(np.deg2rad(-3.98)), ], @@ -85,7 +85,7 @@ def test_low_alt(self): "CD": 0.0271, Dynamic.Mission.ALTITUDE_RATE: -1158 / 60, # TAS (ft/s) * cos(gamma) - "distance_rate": (255 * 1.68781) * np.cos(np.deg2rad(-2.56)), + Dynamic.Mission.DISTANCE_RATE: (255 * 1.68781) * np.cos(np.deg2rad(-2.56)), Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL: -1294, Dynamic.Mission.FLIGHT_PATH_ANGLE: np.deg2rad(-2.56), } diff --git a/aviary/mission/gasp_based/phases/2DOF_phase_builder.py b/aviary/mission/gasp_based/phases/2DOF_phase_builder.py index 1951b48ad..d8f0435c2 100644 --- a/aviary/mission/gasp_based/phases/2DOF_phase_builder.py +++ b/aviary/mission/gasp_based/phases/2DOF_phase_builder.py @@ -108,7 +108,7 @@ def build_phase(self): lower=self.bounds.get_val("distance_bounds")["value"][0], upper=self.bounds.get_val("distance_bounds")["value"][1], units=self.bounds.get_val("distance_bounds")["units"], - rate_source="distance_rate", + rate_source=Dynamic.Mission.DISTANCE_RATE, targets=Dynamic.Mission.DISTANCE, ref=self.scalers.get_val("distance_ref")["value"], ref0=self.scalers.get_val("distance_ref0")["value"], @@ -254,7 +254,8 @@ def linked_vars(phase1, phase2): # TODO: add other combinations of phases elif type1 == "cruise" and type2 == "descent": linked_vars = [] # TODO: update this elif type1 == "descent" and type2 == "descent": - linked_vars = ["time", Dynamic.Mission.ALTITUDE, "mass", "distance"] + linked_vars = ["time", Dynamic.Mission.ALTITUDE, + "mass", Dynamic.Mission.DISTANCE] else: raise om.AnalysisError( "You have provided a phase order which is not yet supported." diff --git a/aviary/mission/gasp_based/phases/accel_phase.py b/aviary/mission/gasp_based/phases/accel_phase.py index ed938768a..35cdec823 100644 --- a/aviary/mission/gasp_based/phases/accel_phase.py +++ b/aviary/mission/gasp_based/phases/accel_phase.py @@ -78,7 +78,7 @@ def get_accel( lower=distance_lower, upper=distance_upper, units="NM", - rate_source="distance_rate", + rate_source=Dynamic.Mission.DISTANCE_RATE, ref=distance_ref, ref0=distance_ref0, defect_ref=distance_defect_ref, diff --git a/aviary/mission/gasp_based/phases/ascent_phase.py b/aviary/mission/gasp_based/phases/ascent_phase.py index 6b9ed6747..28a2fa706 100644 --- a/aviary/mission/gasp_based/phases/ascent_phase.py +++ b/aviary/mission/gasp_based/phases/ascent_phase.py @@ -116,7 +116,7 @@ def get_ascent( lower=distance_lower, upper=distance_upper, units="ft", - rate_source="distance_rate", + rate_source=Dynamic.Mission.DISTANCE_RATE, ref=distance_ref, defect_ref=distance_defect_ref, ref0=distance_ref0, diff --git a/aviary/mission/gasp_based/phases/climb_phase.py b/aviary/mission/gasp_based/phases/climb_phase.py index 08a28330f..026ece771 100644 --- a/aviary/mission/gasp_based/phases/climb_phase.py +++ b/aviary/mission/gasp_based/phases/climb_phase.py @@ -90,7 +90,7 @@ def get_climb( lower=distance_lower, upper=distance_upper, units="NM", - rate_source="distance_rate", + rate_source=Dynamic.Mission.DISTANCE_RATE, ref=distance_ref, ref0=distance_ref0, defect_ref=distance_defect_ref, diff --git a/aviary/mission/gasp_based/phases/desc_phase.py b/aviary/mission/gasp_based/phases/desc_phase.py index 6f2eab9aa..0ace98f27 100644 --- a/aviary/mission/gasp_based/phases/desc_phase.py +++ b/aviary/mission/gasp_based/phases/desc_phase.py @@ -101,7 +101,7 @@ def get_descent( lower=distance_lower, upper=distance_upper, units="NM", - rate_source="distance_rate", + rate_source=Dynamic.Mission.DISTANCE_RATE, ref=distance_ref, ref0=distance_ref0, defect_ref=distance_defect_ref, diff --git a/aviary/mission/gasp_based/phases/groundroll_phase.py b/aviary/mission/gasp_based/phases/groundroll_phase.py index aa5a61df2..8b624b348 100644 --- a/aviary/mission/gasp_based/phases/groundroll_phase.py +++ b/aviary/mission/gasp_based/phases/groundroll_phase.py @@ -77,7 +77,7 @@ def get_groundroll( lower=distance_lower, upper=distance_upper, units="ft", - rate_source="distance_rate", + rate_source=Dynamic.Mission.DISTANCE_RATE, ref=distance_ref, defect_ref=distance_defect_ref, ref0=distance_ref0, diff --git a/aviary/mission/gasp_based/phases/rotation_phase.py b/aviary/mission/gasp_based/phases/rotation_phase.py index a0c4441db..c4997270e 100644 --- a/aviary/mission/gasp_based/phases/rotation_phase.py +++ b/aviary/mission/gasp_based/phases/rotation_phase.py @@ -97,7 +97,7 @@ def get_rotation( lower=distance_lower, upper=distance_upper, units="ft", - rate_source="distance_rate", + rate_source=Dynamic.Mission.DISTANCE_RATE, ref=distance_ref, ref0=distance_ref0, defect_ref=distance_defect_ref, diff --git a/aviary/mission/gasp_based/phases/run_phases/run_accel.py b/aviary/mission/gasp_based/phases/run_phases/run_accel.py index ce26a879e..ad1e5efd9 100644 --- a/aviary/mission/gasp_based/phases/run_phases/run_accel.py +++ b/aviary/mission/gasp_based/phases/run_phases/run_accel.py @@ -68,7 +68,8 @@ def run_accel(): accel.add_timeseries_output("EAS", output_name="EAS", units="kn") accel.add_timeseries_output("TAS", output_name="TAS", units="kn") accel.add_timeseries_output("mass", output_name="mass", units="lbm") - accel.add_timeseries_output("distance", output_name="distance", units="NM") + accel.add_timeseries_output(Dynamic.Mission.DISTANCE, + output_name=Dynamic.Mission.DISTANCE, units="NM") accel.timeseries_options['use_prefix'] = True accel.add_objective("time", loc="final") diff --git a/aviary/mission/gasp_based/phases/run_phases/run_climb.py b/aviary/mission/gasp_based/phases/run_phases/run_climb.py index 90d3a5376..fadcd2155 100644 --- a/aviary/mission/gasp_based/phases/run_phases/run_climb.py +++ b/aviary/mission/gasp_based/phases/run_phases/run_climb.py @@ -28,7 +28,7 @@ "time": ("TIME", "time", "s"), Dynamic.Mission.ALTITUDE: ("ALT", "states:altitude", "ft"), "mass": ("MASS", "states:mass", "lbm"), - Dynamic.Mission.DISTANCE: ("RANGE", "states:distance", "NM"), + Dynamic.Mission.DISTANCE: (Dynamic.Mission.RANGE, "states:distance", "NM"), Dynamic.Mission.MACH: ("MACH", Dynamic.Mission.MACH, None), "EAS": ("EAS", "EAS", "kn"), "alpha": ("ALPHA", "alpha", "deg"), diff --git a/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py b/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py index d9197c50b..fc3283d4c 100644 --- a/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py +++ b/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py @@ -30,7 +30,7 @@ "time": ("TIME", "time", "s"), Dynamic.Mission.ALTITUDE: ("ALT", "states:altitude", "ft"), "mass": ("MASS", "states:mass", "lbm"), - Dynamic.Mission.DISTANCE: ("RANGE", "states:distance", "NM"), + Dynamic.Mission.DISTANCE: (Dynamic.Mission.RANGE, "states:distance", "NM"), Dynamic.Mission.MACH: ("MACH", Dynamic.Mission.MACH, None), "EAS": ("EAS", "EAS", "kn"), "alpha": ("ALPHA", "alpha", "deg"), diff --git a/aviary/mission/gasp_based/phases/run_phases/run_groundroll.py b/aviary/mission/gasp_based/phases/run_phases/run_groundroll.py index 3f57333d4..f71e699ea 100644 --- a/aviary/mission/gasp_based/phases/run_phases/run_groundroll.py +++ b/aviary/mission/gasp_based/phases/run_phases/run_groundroll.py @@ -124,7 +124,7 @@ def run_groundroll(): p.set_val( "traj.groundroll.states:distance", - groundroll.interp("distance", [0, 1000]), + groundroll.interp(Dynamic.Mission.DISTANCE, [0, 1000]), units="ft", ) diff --git a/aviary/mission/gasp_based/phases/run_phases/run_rotation.py b/aviary/mission/gasp_based/phases/run_phases/run_rotation.py index ce2fb8130..ef6bd5b49 100644 --- a/aviary/mission/gasp_based/phases/run_phases/run_rotation.py +++ b/aviary/mission/gasp_based/phases/run_phases/run_rotation.py @@ -43,7 +43,7 @@ def run_rotation(make_plots=False): ) p.set_val( "traj.rotation.states:distance", - rotation.interp("distance", [3680.37217765, 4000]), + rotation.interp(Dynamic.Mission.DISTANCE, [3680.37217765, 4000]), units="ft", ) p.set_val("traj.rotation.t_duration", 50.0) diff --git a/aviary/mission/gasp_based/phases/run_phases/run_takeoff.py b/aviary/mission/gasp_based/phases/run_phases/run_takeoff.py index 1b859eb1c..41c33ddfe 100644 --- a/aviary/mission/gasp_based/phases/run_phases/run_takeoff.py +++ b/aviary/mission/gasp_based/phases/run_phases/run_takeoff.py @@ -53,7 +53,8 @@ def run_takeoff(make_plots=False): transcription=rotation_trans, ) traj.add_phase("rotation", rotation) - traj.link_phases(["groundroll", "rotation"], ["time", "TAS", "mass", "distance"]) + traj.link_phases(["groundroll", "rotation"], [ + "time", "TAS", "mass", Dynamic.Mission.DISTANCE]) ascent_trans = dm.Radau( num_segments=2, order=5, compressed=True, solve_segments=False @@ -66,7 +67,7 @@ def run_takeoff(make_plots=False): ) traj.add_phase("ascent", ascent) traj.link_phases( - ["rotation", "ascent"], ["time", "TAS", "mass", "distance", "alpha"] + ["rotation", "ascent"], ["time", "TAS", "mass", Dynamic.Mission.DISTANCE, "alpha"] ) p.model.promotes( "traj", @@ -142,7 +143,7 @@ def run_takeoff(make_plots=False): ) p.set_val( "traj.groundroll.states:distance", - groundroll.interp("distance", [0, 1000]), + groundroll.interp(Dynamic.Mission.DISTANCE, [0, 1000]), units="ft", ) p.set_val("traj.groundroll.t_duration", 50.0) @@ -158,7 +159,7 @@ def run_takeoff(make_plots=False): ) p.set_val( "traj.rotation.states:distance", - rotation.interp("distance", [3680.37217765, 4000]), + rotation.interp(Dynamic.Mission.DISTANCE, [3680.37217765, 4000]), units="ft", ) p.set_val("traj.rotation.t_duration", 50.0) @@ -179,7 +180,7 @@ def run_takeoff(make_plots=False): ) p.set_val( "traj.ascent.states:distance", - ascent.interp("distance", [4330.83393029, 5000]), + ascent.interp(Dynamic.Mission.DISTANCE, [4330.83393029, 5000]), units="ft", ) p.set_val("traj.ascent.t_initial", 31.2) 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 ef2a355a1..042f00fc1 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,7 @@ from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables_in import VariablesIn -from aviary.variable_info.variables import Aircraft, Mission +from aviary.variable_info.variables import Aircraft, Mission, Dynamic from aviary.subsystems.premission import CorePreMission from aviary.interface.default_phase_info.height_energy import default_premission_subsystems, default_mission_subsystems from aviary.utils.preprocessors import preprocess_crewpayload @@ -292,9 +292,9 @@ def run_trajectory(sim=True): promotes_outputs=['mission:*']) traj.link_phases(["climb", "cruise"], ["time", "altitude", - "velocity", "mass", "range"], connected=strong_couple) + "velocity", "mass", Dynamic.Mission.RANGE], connected=strong_couple) traj.link_phases(["cruise", "descent"], ["time", "altitude", - "velocity", "mass", "range"], connected=strong_couple) + "velocity", "mass", Dynamic.Mission.RANGE], connected=strong_couple) traj = setup_trajectory_params(prob.model, traj, aviary_inputs) diff --git a/aviary/xdsm/accel_xdsm.py b/aviary/xdsm/accel_xdsm.py index e833e5263..f407abc9c 100644 --- a/aviary/xdsm/accel_xdsm.py +++ b/aviary/xdsm/accel_xdsm.py @@ -33,7 +33,7 @@ x.add_output("fc", ["EAS"], side="right") x.add_output("aero", [Dynamic.Mission.LIFT, Dynamic.Mission.DRAG, "alpha"], side="right") # for accel_ode, CruiseAero(output_alpha=True). So alpha is not an input. -x.add_output("eom", ["TAS_rate", "distance_rate"], side="right") +x.add_output("eom", ["TAS_rate", Dynamic.Mission.DISTANCE_RATE], side="right") # make connections x.add_input("atmos", [Dynamic.Mission.ALTITUDE]) diff --git a/aviary/xdsm/climb_xdsm.py b/aviary/xdsm/climb_xdsm.py index 1e9dddadf..764ad79ca 100644 --- a/aviary/xdsm/climb_xdsm.py +++ b/aviary/xdsm/climb_xdsm.py @@ -75,7 +75,7 @@ # create outputs x.add_output("eom", [ Dynamic.Mission.ALTITUDE_RATE, - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, "required_lift", ], side="right") x.add_output("constraints", ["theta", "TAS_violation"], side="right") diff --git a/aviary/xdsm/descent1_xdsm.py b/aviary/xdsm/descent1_xdsm.py index 277268f2c..74e3b0f02 100644 --- a/aviary/xdsm/descent1_xdsm.py +++ b/aviary/xdsm/descent1_xdsm.py @@ -66,7 +66,7 @@ # create outputs x.add_output("eom", [ Dynamic.Mission.ALTITUDE_RATE, - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, "required_lift" ], side="right") diff --git a/aviary/xdsm/descent2_xdsm.py b/aviary/xdsm/descent2_xdsm.py index 99e0dfa6a..20ba3f889 100644 --- a/aviary/xdsm/descent2_xdsm.py +++ b/aviary/xdsm/descent2_xdsm.py @@ -54,7 +54,7 @@ # create outputs x.add_output("eom", [ Dynamic.Mission.ALTITUDE_RATE, - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, "required_lift" ], side="right") diff --git a/aviary/xdsm/groundroll_xdsm.py b/aviary/xdsm/groundroll_xdsm.py index b86d086d9..c032279f2 100644 --- a/aviary/xdsm/groundroll_xdsm.py +++ b/aviary/xdsm/groundroll_xdsm.py @@ -72,7 +72,7 @@ eom_output_list = [ Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Mission.ALTITUDE_RATE, - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, "alpha_rate", "normal_force", "fuselage_pitch", diff --git a/aviary/xdsm/statics_xdsm.py b/aviary/xdsm/statics_xdsm.py index 761845370..e10333dee 100644 --- a/aviary/xdsm/statics_xdsm.py +++ b/aviary/xdsm/statics_xdsm.py @@ -411,32 +411,32 @@ # Connect State Rates x.connect( "groundroll", "dymos", [ - "TAS_rate", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, "distance_rate"]) + "TAS_rate", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) x.connect("rotation", "dymos", ["TAS_rate", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, "alpha_rate"]) x.connect("ascent", "dymos", ["TAS_rate", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - "distance_rate", + Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], ) x.connect( "accelerate", "dymos", [ - "TAS_rate", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, "distance_rate"]) + "TAS_rate", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) x.connect("climb1", "dymos", [Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, "distance_rate"]) + Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) x.connect("climb2", "dymos", [Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, "distance_rate"]) + Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) x.connect("descent1", "dymos", [Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, "distance_rate"]) + Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) x.connect("descent2", "dymos", [Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, "distance_rate"]) + Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) x.write("statics_xdsm") x.write_sys_specs("statics_specs") From 8d383bc61004698f2bc00986a55fa90c5c81c9da Mon Sep 17 00:00:00 2001 From: Gregory Wrenn Date: Tue, 16 Jan 2024 15:51:02 -0500 Subject: [PATCH 071/188] [no ci] Changed the passenger count for the large single aisle models to 169 from 180. If appears the 180 was inadvertently taken from the passenger mass value. Reinstated the preprocessor.py check for consistency between total passengers and individual passenger class data. --- aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py | 2 +- .../large_single_aisle_1/large_single_aisle_1_GwGm.csv | 2 +- .../large_single_aisle_1/large_single_aisle_1_GwGm.dat | 2 +- aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv | 2 +- aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv | 2 +- .../test_aircraft/aircraft_for_bench_GwGm_solved.csv | 2 +- aviary/utils/preprocessors.py | 7 ++++--- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py b/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py index 113fc4748..0809183c3 100644 --- a/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py +++ b/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py @@ -13,7 +13,7 @@ V3_bug_fixed_options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') V3_bug_fixed_options.set_val( - Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + Aircraft.CrewPayload.NUM_PASSENGERS, val=169, units='unitless') V3_bug_fixed_options.set_val(Mission.Design.CRUISE_ALTITUDE, val=37500, units='ft') V3_bug_fixed_options.set_val( Aircraft.Wing.CHOOSE_FOLD_LOCATION, val=False, units='unitless') diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv index f2492d9fb..fd0946733 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv @@ -6,7 +6,7 @@ aircraft:controls:control_mass_increment,0,lbm aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless aircraft:crew_and_payload:cargo_mass,10040,lbm -aircraft:crew_and_payload:num_passengers,180,unitless +aircraft:crew_and_payload:num_passengers,169,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,16.5,unitless diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat index f23fff285..633061c3c 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat @@ -18,7 +18,7 @@ aircraft:engine:data_file=models/engines/turbofan_23k_1.deck HCK=4.5, ! mean fuselage cabin diameter minus mean fuselage nose diameter in feet (2.47) HTG=8., ! wing height about ground during ground run in feet (3.0) HWING=0.0, ! wing location on fuselage =0, low wing; =1 high wing - PAX=180., ! number of passenger seats excluding crew + PAX=169., ! number of passenger seats excluding crew PS=29.0, ! seat pitch in inches RELR=0.4524, ! cg of fuselage and contents, fraction fuselage(.4) if LCWING <> 0 SAB=6., ! seats abreast in fuselage diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv index 5c0d0b8a0..92d47e871 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv @@ -21,7 +21,7 @@ aircraft:crew_and_payload:num_flight_attendants,3,unitless aircraft:crew_and_payload:num_flight_crew,2,unitless aircraft:crew_and_payload:num_galley_crew,0,unitless aircraft:crew_and_payload:num_non_flight_crew,3,unitless -aircraft:crew_and_payload:num_passengers,180,unitless +aircraft:crew_and_payload:num_passengers,169,unitless aircraft:crew_and_payload:num_tourist_class,158,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:crew_and_payload:passenger_service_mass_scaler,1.0,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv index a71a6e26f..4789a1e54 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv @@ -5,7 +5,7 @@ aircraft:controls:control_mass_increment,0,lbm aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless aircraft:crew_and_payload:cargo_mass,10040,lbm -aircraft:crew_and_payload:num_passengers,180,unitless +aircraft:crew_and_payload:num_passengers,169,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,16.5,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwGm_solved.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwGm_solved.csv index 720764ca5..ba578e05d 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwGm_solved.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwGm_solved.csv @@ -5,7 +5,7 @@ aircraft:controls:control_mass_increment,0,lbm aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless aircraft:crew_and_payload:cargo_mass,10040,lbm -aircraft:crew_and_payload:num_passengers,180,unitless +aircraft:crew_and_payload:num_passengers,169,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,16.5,unitless diff --git a/aviary/utils/preprocessors.py b/aviary/utils/preprocessors.py index 28f222f7b..c2cce0604 100644 --- a/aviary/utils/preprocessors.py +++ b/aviary/utils/preprocessors.py @@ -55,9 +55,10 @@ def preprocess_crewpayload(aviary_options: AviaryValues): passenger_check += aviary_options.get_val( Aircraft.CrewPayload.NUM_BUSINESS_CLASS) passenger_check += aviary_options.get_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS) - # if passenger_count != passenger_check: - # raise om.AnalysisError( - # "ERROR: In preprocesssors.py: passenger_count does not equal the sum of firt class + business class + tourist class passengers.") + # only perform check if at least one passenger class is entered + if passenger_check > 0 and passenger_count != passenger_check: + raise om.AnalysisError( + "ERROR: In preprocesssors.py: passenger_count does not equal the sum of firt class + business class + tourist class passengers.") if Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS not in aviary_options: flight_attendants_count = 0 # assume no passengers From 0856cd846e448d8edee99cda28890a5d4084ec70 Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Tue, 16 Jan 2024 16:20:13 -0500 Subject: [PATCH 072/188] all tests as expected --- .../getting_started/onboarding_level2.ipynb | 2 +- .../getting_started/onboarding_level3.ipynb | 52 +-- ...S_based_detailed_takeoff_and_landing.ipynb | 4 +- ..._same_mission_at_different_UI_levels.ipynb | 22 +- .../default_phase_info/height_energy.py | 16 +- aviary/interface/methods_for_level2.py | 20 +- aviary/interface/test/test_phase_info.py | 2 +- aviary/mission/flops_based/ode/landing_eom.py | 159 +++++---- aviary/mission/flops_based/ode/landing_ode.py | 32 +- aviary/mission/flops_based/ode/mission_EOM.py | 2 +- aviary/mission/flops_based/ode/mission_ODE.py | 2 +- aviary/mission/flops_based/ode/range_rate.py | 10 +- .../flops_based/ode/simple_mission_EOM.py | 2 +- .../flops_based/ode/simple_mission_ODE.py | 2 +- aviary/mission/flops_based/ode/takeoff_eom.py | 237 ++++++------- aviary/mission/flops_based/ode/takeoff_ode.py | 32 +- .../flops_based/ode/test/test_landing_eom.py | 20 +- .../flops_based/ode/test/test_landing_ode.py | 20 +- .../flops_based/ode/test/test_mission_EOM.py | 2 +- .../flops_based/ode/test/test_range_rate.py | 4 +- .../flops_based/ode/test/test_takeoff_eom.py | 41 ++- .../flops_based/ode/test/test_takeoff_ode.py | 45 ++- .../test_bench_climb_large_single_aisle_1.py | 6 +- .../test_bench_climb_large_single_aisle_2.py | 6 +- ...bench_cruise_climb_large_single_aisle_1.py | 6 +- .../test_bench_cruise_large_single_aisle_1.py | 6 +- .../test_bench_cruise_large_single_aisle_2.py | 6 +- ...test_bench_descent_large_single_aisle_1.py | 8 +- ...test_bench_descent_large_single_aisle_2.py | 8 +- .../flops_based/phases/cruise_phase.py | 12 +- .../phases/detailed_landing_phases.py | 165 +++++---- .../phases/detailed_takeoff_phases.py | 319 +++++++++--------- .../flops_based/phases/energy_phase.py | 12 +- .../flops_based/phases/simple_energy_phase.py | 12 +- .../gasp_based/phases/run_phases/run_climb.py | 2 +- .../run_phases/run_climb_test_FLOPS_prop.py | 2 +- aviary/models/N3CC/N3CC_data.py | 136 ++++---- .../aerodynamics/flops_based/ground_effect.py | 36 +- .../flops_based/takeoff_aero_group.py | 12 +- .../flops_based/test/test_ground_effect.py | 9 +- .../test/test_takeoff_aero_group.py | 31 +- .../test/test_custom_engine_model.py | 6 +- aviary/utils/report.py | 2 +- .../test_FLOPS_balanced_field_length.py | 8 +- .../test_FLOPS_based_full_mission_N3CC.py | 27 +- ...based_full_mission_large_single_aisle_1.py | 27 +- ...based_full_mission_large_single_aisle_2.py | 27 +- .../test_FLOPS_based_sizing_N3CC.py | 27 +- .../test_FLOPS_detailed_landing.py | 10 +- .../test_FLOPS_detailed_takeoff.py | 9 +- .../test_full_mission_solved_ode.py | 12 +- .../test_subsystems_within_a_mission.py | 2 +- aviary/validation_cases/benchmark_utils.py | 2 +- .../flops_data/full_mission_test_data.py | 2 +- aviary/variable_info/variable_meta_data.py | 27 +- aviary/xdsm/statics_xdsm.py | 8 +- 56 files changed, 838 insertions(+), 880 deletions(-) diff --git a/aviary/docs/getting_started/onboarding_level2.ipynb b/aviary/docs/getting_started/onboarding_level2.ipynb index 0d47cdf7f..5bb5fb516 100644 --- a/aviary/docs/getting_started/onboarding_level2.ipynb +++ b/aviary/docs/getting_started/onboarding_level2.ipynb @@ -658,7 +658,7 @@ " 'altitude': ([35.e3, 35.e3], 'ft'),\n", " 'velocity': ([455.49, 455.49], 'kn'),\n", " 'mass': ([165.e3, 140.e3], 'lbm'),\n", - " 'range': ([160.3, 3243.9], 'nmi'),\n", + " 'distance': ([160.3, 3243.9], 'nmi'),\n", " 'velocity_rate': ([0., 0.], 'm/s**2'),\n", " 'throttle': ([0.95, 0.9], 'unitless'),\n", " }\n", diff --git a/aviary/docs/getting_started/onboarding_level3.ipynb b/aviary/docs/getting_started/onboarding_level3.ipynb index 67f10696b..38a6bc929 100644 --- a/aviary/docs/getting_started/onboarding_level3.ipynb +++ b/aviary/docs/getting_started/onboarding_level3.ipynb @@ -325,9 +325,9 @@ "##########################################\n", "\n", "traj.link_phases([\"climb\", \"cruise\"], [\"time\", Dynamic.Mission.ALTITUDE,\n", - " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple)\n", + " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple)\n", "traj.link_phases([\"cruise\", \"descent\"], [\"time\", Dynamic.Mission.ALTITUDE,\n", - " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple)\n", + " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple)\n", "\n", "traj = av.setup_trajectory_params(prob.model, traj, aviary_inputs)\n", "\n", @@ -365,7 +365,7 @@ "\n", "prob.model.connect('traj.climb.states:mass',\n", " 'takeoff_constraints.climb_start_mass', src_indices=[0])\n", - "prob.model.connect('traj.climb.states:range',\n", + "prob.model.connect('traj.climb.states:distance',\n", " 'takeoff_constraints.climb_start_range', src_indices=[0])\n", "prob.model.connect('traj.climb.states:velocity',\n", " 'takeoff_constraints.climb_start_vel', src_indices=[0])\n", @@ -375,7 +375,7 @@ "prob.model.connect(Mission.Takeoff.FINAL_MASS,\n", " 'traj.climb.initial_states:mass')\n", "prob.model.connect(Mission.Takeoff.GROUND_DISTANCE,\n", - " 'traj.climb.initial_states:range')\n", + " 'traj.climb.initial_states:distance')\n", "prob.model.connect(Mission.Takeoff.FINAL_VELOCITY,\n", " 'traj.climb.initial_states:velocity')\n", "prob.model.connect(Mission.Takeoff.FINAL_ALTITUDE,\n", @@ -443,8 +443,8 @@ " Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s')\n", "prob.set_val('traj.climb.states:mass', climb.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", - "prob.set_val('traj.climb.states:range', climb.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') # nmi\n", + "prob.set_val('traj.climb.states:distance', climb.interp(\n", + " Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') # nmi\n", "\n", "prob.set_val('traj.climb.controls:velocity_rate',\n", " climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.0]),\n", @@ -462,8 +462,8 @@ " Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s')\n", "prob.set_val('traj.cruise.states:mass', cruise.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", - "prob.set_val('traj.cruise.states:range', cruise.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi\n", + "prob.set_val('traj.cruise.states:distance', cruise.interp(\n", + " Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi\n", "\n", "prob.set_val('traj.cruise.controls:velocity_rate',\n", " cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]),\n", @@ -481,8 +481,8 @@ " Dynamic.Mission.VELOCITY, ys=[v_i_descent, v_f_descent]), units='m/s')\n", "prob.set_val('traj.descent.states:mass', descent.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", - "prob.set_val('traj.descent.states:range', descent.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m')\n", + "prob.set_val('traj.descent.states:distance', descent.interp(\n", + " Dynamic.Mission.DISTANCE, ys=[range_i_descent, range_f_descent]), units='m')\n", "\n", "prob.set_val('traj.descent.controls:velocity_rate',\n", " descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.0]),\n", @@ -502,7 +502,7 @@ "altitudes_climb = prob.get_val(\n", " 'traj.climb.timeseries.states:altitude', units='m')\n", "masses_climb = prob.get_val('traj.climb.timeseries.states:mass', units='kg')\n", - "ranges_climb = prob.get_val('traj.climb.timeseries.states:range', units='m')\n", + "ranges_climb = prob.get_val('traj.climb.timeseries.states:distance', units='m')\n", "velocities_climb = prob.get_val(\n", " 'traj.climb.timeseries.states:velocity', units='m/s')\n", "thrusts_climb = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N')\n", @@ -510,7 +510,7 @@ "altitudes_cruise = prob.get_val(\n", " 'traj.cruise.timeseries.states:altitude', units='m')\n", "masses_cruise = prob.get_val('traj.cruise.timeseries.states:mass', units='kg')\n", - "ranges_cruise = prob.get_val('traj.cruise.timeseries.states:range', units='m')\n", + "ranges_cruise = prob.get_val('traj.cruise.timeseries.states:distance', units='m')\n", "velocities_cruise = prob.get_val(\n", " 'traj.cruise.timeseries.states:velocity', units='m/s')\n", "thrusts_cruise = prob.get_val(\n", @@ -519,7 +519,7 @@ "altitudes_descent = prob.get_val(\n", " 'traj.descent.timeseries.states:altitude', units='m')\n", "masses_descent = prob.get_val('traj.descent.timeseries.states:mass', units='kg')\n", - "ranges_descent = prob.get_val('traj.descent.timeseries.states:range', units='m')\n", + "ranges_descent = prob.get_val('traj.descent.timeseries.states:distance', units='m')\n", "velocities_descent = prob.get_val(\n", " 'traj.descent.timeseries.states:velocity', units='m/s')\n", "thrusts_descent = prob.get_val(\n", @@ -721,7 +721,7 @@ " prob.model.connect(Mission.Takeoff.FINAL_MASS,\n", " 'traj.climb.initial_states:mass')\n", " prob.model.connect(Mission.Takeoff.GROUND_DISTANCE,\n", - " 'traj.climb.initial_states:range')\n", + " 'traj.climb.initial_states:distance')\n", " prob.model.connect(Mission.Takeoff.FINAL_VELOCITY,\n", " 'traj.climb.initial_states:velocity')\n", " prob.model.connect(Mission.Takeoff.FINAL_ALTITUDE,\n", @@ -768,8 +768,8 @@ " Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s')\n", " prob.set_val('traj.climb.states:mass', climb.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", - " prob.set_val('traj.climb.states:range', climb.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') # nmi\n", + " prob.set_val('traj.climb.states:distance', climb.interp(\n", + " Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') # nmi\n", "\n", " prob.set_val('traj.climb.controls:velocity_rate',\n", " climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.0]),\n", @@ -787,8 +787,8 @@ " Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s')\n", " prob.set_val('traj.cruise.states:mass', cruise.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", - " prob.set_val('traj.cruise.states:range', cruise.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi\n", + " prob.set_val('traj.cruise.states:distance', cruise.interp(\n", + " Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi\n", "\n", " prob.set_val('traj.cruise.controls:velocity_rate',\n", " cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]),\n", @@ -806,8 +806,8 @@ " Dynamic.Mission.VELOCITY, ys=[v_i_descent, v_f_descent]), units='m/s')\n", " prob.set_val('traj.descent.states:mass', descent.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", - " prob.set_val('traj.descent.states:range', descent.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m')\n", + " prob.set_val('traj.descent.states:distance', descent.interp(\n", + " Dynamic.Mission.DISTANCE, ys=[range_i_descent, range_f_descent]), units='m')\n", "\n", " prob.set_val('traj.descent.controls:velocity_rate',\n", " descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.0]),\n", @@ -964,9 +964,9 @@ " strong_couple = False\n", "\n", " traj.link_phases([\"climb\", \"cruise\"], [\"time\", Dynamic.Mission.ALTITUDE,\n", - " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple)\n", + " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple)\n", " traj.link_phases([\"cruise\", \"descent\"], [\"time\", Dynamic.Mission.ALTITUDE,\n", - " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple)\n", + " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple)\n", "\n", " traj = av.setup_trajectory_params(prob.model, traj, aviary_inputs)\n", "\n", @@ -976,7 +976,7 @@ "\n", " prob.model.connect('traj.climb.states:mass',\n", " 'takeoff_constraints.climb_start_mass', src_indices=[0])\n", - " prob.model.connect('traj.climb.states:range',\n", + " prob.model.connect('traj.climb.states:distance',\n", " 'takeoff_constraints.climb_start_range', src_indices=[0])\n", " prob.model.connect('traj.climb.states:velocity',\n", " 'takeoff_constraints.climb_start_vel', src_indices=[0])\n", @@ -1082,7 +1082,7 @@ " altitudes_climb = prob.get_val(\n", " 'traj.climb.timeseries.states:altitude', units='m')\n", " masses_climb = prob.get_val('traj.climb.timeseries.states:mass', units='kg')\n", - " ranges_climb = prob.get_val('traj.climb.timeseries.states:range', units='m')\n", + " ranges_climb = prob.get_val('traj.climb.timeseries.states:distance', units='m')\n", " velocities_climb = prob.get_val(\n", " 'traj.climb.timeseries.states:velocity', units='m/s')\n", " thrusts_climb = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N')\n", @@ -1090,7 +1090,7 @@ " altitudes_cruise = prob.get_val(\n", " 'traj.cruise.timeseries.states:altitude', units='m')\n", " masses_cruise = prob.get_val('traj.cruise.timeseries.states:mass', units='kg')\n", - " ranges_cruise = prob.get_val('traj.cruise.timeseries.states:range', units='m')\n", + " ranges_cruise = prob.get_val('traj.cruise.timeseries.states:distance', units='m')\n", " velocities_cruise = prob.get_val(\n", " 'traj.cruise.timeseries.states:velocity', units='m/s')\n", " thrusts_cruise = prob.get_val(\n", @@ -1099,7 +1099,7 @@ " altitudes_descent = prob.get_val(\n", " 'traj.descent.timeseries.states:altitude', units='m')\n", " masses_descent = prob.get_val('traj.descent.timeseries.states:mass', units='kg')\n", - " ranges_descent = prob.get_val('traj.descent.timeseries.states:range', units='m')\n", + " ranges_descent = prob.get_val('traj.descent.timeseries.states:distance', units='m')\n", " velocities_descent = prob.get_val(\n", " 'traj.descent.timeseries.states:velocity', units='m/s')\n", " thrusts_descent = prob.get_val(\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 c032c68dd..f89d2d31e 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 @@ -299,7 +299,7 @@ "liftoff = takeoff_trajectory_builder.get_phase('takeoff_liftoff')\n", "\n", "liftoff.add_objective(\n", - " Dynamic.Mission.RANGE, loc='final', ref=max_range, units=units)\n", + " Dynamic.Mission.DISTANCE, loc='final', ref=max_range, units=units)\n", "\n", "# Insert a constraint for a fake decision speed, until abort is added.\n", "takeoff.model.add_constraint(\n", @@ -551,7 +551,7 @@ "max_range, units = landing_fullstop_user_options.get_item('max_range')\n", "fullstop = landing_trajectory_builder.get_phase('landing_fullstop')\n", "\n", - "fullstop.add_objective(Dynamic.Mission.RANGE, loc='final', ref=max_range, units=units)\n", + "fullstop.add_objective(Dynamic.Mission.DISTANCE, loc='final', ref=max_range, units=units)\n", "\n", "landing.model.add_subsystem(\n", " 'input_sink',\n", 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 f76118110..e2ea405ec 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 @@ -67,7 +67,7 @@ " 'core_aerodynamics': {'method': 'computed'}\n", " },\n", " 'user_options': {\n", - " 'fix_initial': {Dynamic.Mission.MASS: False, Dynamic.Mission.RANGE: False},\n", + " 'fix_initial': {Dynamic.Mission.MASS: False, Dynamic.Mission.DISTANCE: False},\n", " 'fix_initial_time': True,\n", " 'fix_duration': False,\n", " 'num_segments': 6,\n", @@ -434,9 +434,9 @@ " promotes_outputs=['mission:*'])\n", "\n", "traj.link_phases([\"climb\", \"cruise\"], [\"time\", Dynamic.Mission.ALTITUDE,\n", - " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple)\n", + " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple)\n", "traj.link_phases([\"cruise\", \"descent\"], [\"time\", Dynamic.Mission.ALTITUDE,\n", - " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple)\n", + " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple)\n", "\n", "traj = av.setup_trajectory_params(prob.model, traj, aviary_inputs)\n", "\n", @@ -474,7 +474,7 @@ "\n", "prob.model.connect('traj.climb.states:mass',\n", " 'takeoff_constraints.climb_start_mass', src_indices=[0])\n", - "prob.model.connect('traj.climb.states:range',\n", + "prob.model.connect('traj.climb.states:distance',\n", " 'takeoff_constraints.climb_start_range', src_indices=[0])\n", "prob.model.connect('traj.climb.states:velocity',\n", " 'takeoff_constraints.climb_start_vel', src_indices=[0])\n", @@ -484,7 +484,7 @@ "prob.model.connect(Mission.Takeoff.FINAL_MASS,\n", " 'traj.climb.initial_states:mass')\n", "prob.model.connect(Mission.Takeoff.GROUND_DISTANCE,\n", - " 'traj.climb.initial_states:range')\n", + " 'traj.climb.initial_states:distance')\n", "prob.model.connect(Mission.Takeoff.FINAL_VELOCITY,\n", " 'traj.climb.initial_states:velocity')\n", "prob.model.connect(Mission.Takeoff.FINAL_ALTITUDE,\n", @@ -552,8 +552,8 @@ " Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s')\n", "prob.set_val('traj.climb.states:mass', climb.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", - "prob.set_val('traj.climb.states:range', climb.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') # nmi\n", + "prob.set_val('traj.climb.states:distance', climb.interp(\n", + " Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') # nmi\n", "\n", "prob.set_val('traj.climb.controls:velocity_rate',\n", " climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.0]),\n", @@ -571,8 +571,8 @@ " Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s')\n", "prob.set_val('traj.cruise.states:mass', cruise.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", - "prob.set_val('traj.cruise.states:range', cruise.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi\n", + "prob.set_val('traj.cruise.states:distance', cruise.interp(\n", + " Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi\n", "\n", "prob.set_val('traj.cruise.controls:velocity_rate',\n", " cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]),\n", @@ -590,8 +590,8 @@ " Dynamic.Mission.VELOCITY, ys=[v_i_descent, v_f_descent]), units='m/s')\n", "prob.set_val('traj.descent.states:mass', descent.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", - "prob.set_val('traj.descent.states:range', descent.interp(\n", - " Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m')\n", + "prob.set_val('traj.descent.states:distance', descent.interp(\n", + " Dynamic.Mission.DISTANCE, ys=[range_i_descent, range_f_descent]), units='m')\n", "\n", "prob.set_val('traj.descent.controls:velocity_rate',\n", " descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.0]),\n", diff --git a/aviary/interface/default_phase_info/height_energy.py b/aviary/interface/default_phase_info/height_energy.py index 66d584192..1b233943c 100644 --- a/aviary/interface/default_phase_info/height_energy.py +++ b/aviary/interface/default_phase_info/height_energy.py @@ -27,7 +27,7 @@ 'core_aerodynamics': {'method': 'computed'} }, 'user_options': { - 'fix_initial': {Dynamic.Mission.MASS: False, Dynamic.Mission.RANGE: False}, + 'fix_initial': {Dynamic.Mission.MASS: False, Dynamic.Mission.DISTANCE: False}, 'fix_initial_time': True, 'fix_duration': False, 'num_segments': 6, @@ -50,7 +50,7 @@ 'altitude': ([0., 35.e3], 'ft'), 'velocity': ([220., 455.49], 'kn'), 'mass': ([170.e3, 165.e3], 'lbm'), - 'range': ([0., 160.3], 'nmi'), + 'distance': ([0., 160.3], 'nmi'), 'velocity_rate': ([0.25, 0.05], 'm/s**2'), 'throttle': ([0.5, 0.5], 'unitless'), } @@ -82,7 +82,7 @@ 'altitude': ([35.e3, 35.e3], 'ft'), 'velocity': ([455.49, 455.49], 'kn'), 'mass': ([165.e3, 140.e3], 'lbm'), - 'range': ([160.3, 3243.9], 'nmi'), + 'distance': ([160.3, 3243.9], 'nmi'), 'velocity_rate': ([0., 0.], 'm/s**2'), 'throttle': ([0.95, 0.9], 'unitless'), } @@ -112,7 +112,7 @@ 'altitude': ([35.e3, 35.], 'ft'), 'velocity': ([455.49, 198.44], 'kn'), 'mass': ([120.e3, 115.e3], 'lbm'), - 'range': ([3243.9, 3378.7], 'nmi'), + 'distance': ([3243.9, 3378.7], 'nmi'), 'velocity_rate': ([-0.25, 0.0], 'm/s**2'), 'throttle': ([0., 0.], 'unitless'), } @@ -154,13 +154,13 @@ def phase_info_parameterization(phase_info, aviary_inputs): if range_cruise != old_range_cruise: range_scale = range_cruise / old_range_cruise - vals = phase_info['descent']['initial_guesses']['range'][0] + vals = phase_info['descent']['initial_guesses']['distance'][0] new_vals = [vals[0] * range_scale, vals[1] * range_scale] - phase_info['descent']['initial_guesses']['range'] = (new_vals, 'NM') + phase_info['descent']['initial_guesses']['distance'] = (new_vals, 'NM') - vals = phase_info['cruise']['initial_guesses']['range'][0] + vals = phase_info['cruise']['initial_guesses']['distance'][0] new_val = vals[1] * range_scale - phase_info['cruise']['initial_guesses']['range'] = ([vals[0], new_val], 'NM') + phase_info['cruise']['initial_guesses']['distance'] = ([vals[0], new_val], 'NM') # Altitude diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 62fee7599..da6f45b2d 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -840,7 +840,7 @@ def _get_solved_phase(self, phase_name): phase.set_state_options("mass", rate_source="dmass_dv", fix_initial=True, fix_final=False, lower=1, upper=195_000, ref=takeoff_mass, defect_ref=takeoff_mass) - phase.set_state_options(Dynamic.Mission.RANGE, rate_source="over_a", + phase.set_state_options(Dynamic.Mission.DISTANCE, rate_source="over_a", fix_initial=True, fix_final=False, lower=0, upper=2000., ref=1.e2, defect_ref=1.e2) phase.add_parameter("t_init_gear", units="s", @@ -879,7 +879,7 @@ def _get_solved_phase(self, phase_name): static_target=False) phase.set_time_options(fix_initial=False, fix_duration=False, - units="range_units", name=Dynamic.Mission.RANGE, + units="range_units", name=Dynamic.Mission.DISTANCE, duration_bounds=wrapped_convert_units( phase_options['duration_bounds'], "range_units"), duration_ref=wrapped_convert_units( @@ -1132,7 +1132,7 @@ def add_subsystem_timeseries_outputs(phase, phase_name): pass elif phase_name == "descent": phase.add_boundary_constraint( - Dynamic.Mission.RANGE, + Dynamic.Mission.DISTANCE, loc="final", equals=target_range, units="NM", @@ -1263,7 +1263,7 @@ def add_post_mission_systems(self, include_landing=True): ("range_resid", Mission.Constraints.RANGE_RESIDUAL)], ) - self.model.connect(f"traj.{phases[-1]}.timeseries.states:range", + self.model.connect(f"traj.{phases[-1]}.timeseries.states:distance", "range_constraint.actual_range", src_indices=[-1]) self.model.add_constraint( Mission.Constraints.RANGE_RESIDUAL, equals=0.0, ref=1.e2) @@ -1378,12 +1378,12 @@ def add_linkage_constraint(self, phase_a, phase_b, var_b): self.traj.link_phases(phases, vars=['time'], ref=100.) self.traj.link_phases(phases, vars=['mass'], ref=10.e3) self.traj.link_phases( - phases, vars=[Dynamic.Mission.RANGE], units='m', ref=10.e3) + phases, vars=[Dynamic.Mission.DISTANCE], units='m', ref=10.e3) self.traj.link_phases(phases[:7], vars=['TAS'], units='kn', ref=200.) elif self.mission_method is SIMPLE: self.traj.link_phases( - phases, ["time", Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=True) + phases, ["time", Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=True) self._link_phases_helper_with_options( phases, 'optimize_altitude', Dynamic.Mission.ALTITUDE, ref=1.e4) @@ -1393,7 +1393,7 @@ def add_linkage_constraint(self, phase_a, phase_b, var_b): elif self.mission_method is HEIGHT_ENERGY: self.traj.link_phases( phases, ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=False, ref=1.e4) + Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=False, ref=1.e4) self.traj.link_phases( phases, [Dynamic.Mission.VELOCITY], connected=False, ref=250.) @@ -2064,11 +2064,11 @@ def _add_guesses(self, phase_name, phase, guesses): if self.mission_method is SIMPLE: control_keys = ["mach", "altitude"] - state_keys = ["mass", Dynamic.Mission.RANGE] + state_keys = ["mass", Dynamic.Mission.DISTANCE] else: control_keys = ["velocity_rate", "throttle"] state_keys = ["altitude", "velocity", "mass", - Dynamic.Mission.RANGE, "TAS", Dynamic.Mission.DISTANCE, "flight_path_angle", "alpha"] + Dynamic.Mission.DISTANCE, "TAS", Dynamic.Mission.DISTANCE, "flight_path_angle", "alpha"] if self.mission_method is TWO_DEGREES_OF_FREEDOM and phase_name == 'ascent': # Alpha is a control for ascent. control_keys.append('alpha') @@ -2412,7 +2412,7 @@ def _add_flops_landing_systems(self): self.model.connect(Mission.Takeoff.FINAL_MASS, 'traj.climb.initial_states:mass') self.model.connect(Mission.Takeoff.GROUND_DISTANCE, - 'traj.climb.initial_states:range') + 'traj.climb.initial_states:distance') self.model.connect(Mission.Takeoff.FINAL_VELOCITY, 'traj.climb.initial_states:velocity') self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, diff --git a/aviary/interface/test/test_phase_info.py b/aviary/interface/test/test_phase_info.py index 3d470a70b..56abb3a0b 100644 --- a/aviary/interface/test/test_phase_info.py +++ b/aviary/interface/test/test_phase_info.py @@ -154,7 +154,7 @@ def test_phase_info_parameterization_flops(self): prob.run_model() - assert_near_equal(prob.get_val("traj.descent.timeseries.input_values:states:range", units='km')[-1], + assert_near_equal(prob.get_val("traj.descent.timeseries.input_values:states:distance", units='km')[-1], 5000.0 * 3378.7 / 3500) assert_near_equal(prob.get_val("traj.cruise.timeseries.input_values:states:altitude", units='ft')[0], 31000.0) diff --git a/aviary/mission/flops_based/ode/landing_eom.py b/aviary/mission/flops_based/ode/landing_eom.py index af73cc2fc..1a2d7a61c 100644 --- a/aviary/mission/flops_based/ode/landing_eom.py +++ b/aviary/mission/flops_based/ode/landing_eom.py @@ -13,10 +13,7 @@ from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import add_aviary_input from aviary.variable_info.variables import Aircraft -from aviary.variable_info.variables import Dynamic as _Dynamic -from aviary.variable_info.variables import Mission - -Dynamic = _Dynamic.Mission +from aviary.variable_info.variables import Dynamic, Mission class FlareEOM(om.Group): @@ -43,8 +40,8 @@ def setup(self): 'num_nodes': nn, 'climbing': True} - inputs = [Dynamic.FLIGHT_PATH_ANGLE, Dynamic.VELOCITY] - outputs = [Dynamic.RANGE_RATE, Dynamic.ALTITUDE_RATE] + inputs = [Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.VELOCITY] + outputs = [Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE] self.add_subsystem( 'distance_rates', @@ -57,8 +54,8 @@ def setup(self): 'aviary_options': aviary_options} inputs = [ - Dynamic.MASS, Dynamic.LIFT, Dynamic.THRUST_TOTAL, Dynamic.DRAG, - 'angle_of_attack', Dynamic.FLIGHT_PATH_ANGLE] + Dynamic.Mission.MASS, Dynamic.Mission.LIFT, Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.DRAG, + 'angle_of_attack', Dynamic.Mission.FLIGHT_PATH_ANGLE] outputs = ['forces_horizontal', 'forces_vertical'] @@ -68,7 +65,7 @@ def setup(self): promotes_inputs=inputs, promotes_outputs=outputs) - inputs = ['forces_horizontal', 'forces_vertical', Dynamic.MASS] + inputs = ['forces_horizontal', 'forces_vertical', Dynamic.Mission.MASS] outputs = ['acceleration_horizontal', 'acceleration_vertical'] self.add_subsystem( @@ -79,9 +76,9 @@ def setup(self): inputs = [ 'acceleration_horizontal', 'acceleration_vertical', - Dynamic.RANGE_RATE, Dynamic.ALTITUDE_RATE] + Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE] - outputs = [Dynamic.VELOCITY_RATE,] + outputs = [Dynamic.Mission.VELOCITY_RATE,] self.add_subsystem( 'velocity_rate', @@ -90,10 +87,10 @@ def setup(self): promotes_outputs=outputs) inputs = [ - Dynamic.RANGE_RATE, Dynamic.ALTITUDE_RATE, + Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE, 'acceleration_horizontal', 'acceleration_vertical'] - outputs = [Dynamic.FLIGHT_PATH_ANGLE_RATE] + outputs = [Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE] self.add_subsystem( 'flight_path_angle_rate', FlightPathAngleRate(num_nodes=nn), @@ -101,8 +98,8 @@ def setup(self): promotes_outputs=outputs) inputs = [ - Dynamic.MASS, Dynamic.LIFT, Dynamic.DRAG, - 'angle_of_attack', Dynamic.FLIGHT_PATH_ANGLE] + Dynamic.Mission.MASS, Dynamic.Mission.LIFT, Dynamic.Mission.DRAG, + 'angle_of_attack', Dynamic.Mission.FLIGHT_PATH_ANGLE] outputs = ['forces_perpendicular', 'required_thrust'] @@ -147,13 +144,14 @@ def setup(self): nn = options['num_nodes'] - add_aviary_input(self, Dynamic.MASS, val=np.ones(nn), units='kg') - add_aviary_input(self, Dynamic.LIFT, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.DRAG, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Mission.MASS, val=np.ones(nn), units='kg') + add_aviary_input(self, Dynamic.Mission.LIFT, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Mission.DRAG, val=np.ones(nn), units='N') self.add_input('angle_of_attack', val=np.zeros(nn), units='rad') - add_aviary_input(self, Dynamic.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units='rad') + add_aviary_input(self, Dynamic.Mission.FLIGHT_PATH_ANGLE, + val=np.zeros(nn), units='rad') self.add_output( 'forces_perpendicular', val=np.zeros(nn), units='N', @@ -182,14 +180,14 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') total_num_engines = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) - mass = inputs[Dynamic.MASS] - lift = inputs[Dynamic.LIFT] - drag = inputs[Dynamic.DRAG] + mass = inputs[Dynamic.Mission.MASS] + lift = inputs[Dynamic.Mission.LIFT] + drag = inputs[Dynamic.Mission.DRAG] weight = mass * grav_metric alpha = inputs['angle_of_attack'] - gamma = inputs[Dynamic.FLIGHT_PATH_ANGLE] + gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] # FLOPS measures glideslope below horizontal gamma = -gamma @@ -220,14 +218,14 @@ def compute_partials(self, inputs, J, discrete_inputs=None): t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') total_num_engines = aviary_options.get_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES) - mass = inputs[Dynamic.MASS] - lift = inputs[Dynamic.LIFT] - drag = inputs[Dynamic.DRAG] + mass = inputs[Dynamic.Mission.MASS] + lift = inputs[Dynamic.Mission.LIFT] + drag = inputs[Dynamic.Mission.DRAG] weight = mass * grav_metric alpha = inputs['angle_of_attack'] - gamma = inputs[Dynamic.FLIGHT_PATH_ANGLE] + gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] # FLOPS measures glideslope below horizontal gamma = -gamma @@ -246,20 +244,20 @@ def compute_partials(self, inputs, J, discrete_inputs=None): f_h = -grav_metric * s_gamma / c_angle f_v = grav_metric * c_gamma / s_angle - J[forces_key, Dynamic.MASS] = f_h - f_v - J[thrust_key, Dynamic.MASS] = (f_h + f_v) / (2.) + J[forces_key, Dynamic.Mission.MASS] = f_h - f_v + J[thrust_key, Dynamic.Mission.MASS] = (f_h + f_v) / (2.) f_h = 0. f_v = -1. / s_angle - J[forces_key, Dynamic.LIFT] = -f_v - J[thrust_key, Dynamic.LIFT] = f_v / (2.) + J[forces_key, Dynamic.Mission.LIFT] = -f_v + J[thrust_key, Dynamic.Mission.LIFT] = f_v / (2.) f_h = 1. / c_angle f_v = 0. - J[forces_key, Dynamic.DRAG] = f_h - J[thrust_key, Dynamic.DRAG] = f_h / (2.) + J[forces_key, Dynamic.Mission.DRAG] = f_h + J[thrust_key, Dynamic.Mission.DRAG] = f_h / (2.) # ddx(1 / cos(x)) = sec(x) * tan(x) = tan(x) / cos(x) # ddx(1 / sin(x)) = -csc(x) * cot(x) = -1 / (sin(x) * tan(x)) @@ -274,8 +272,8 @@ def compute_partials(self, inputs, J, discrete_inputs=None): f_h = -weight * c_gamma / c_angle f_v = -weight * s_gamma / s_angle - J[forces_key, Dynamic.FLIGHT_PATH_ANGLE] = - f_h + f_v - J[thrust_key, Dynamic.FLIGHT_PATH_ANGLE] = -(f_h + f_v) / (2.) + J[forces_key, Dynamic.Mission.FLIGHT_PATH_ANGLE] = - f_h + f_v + J[thrust_key, Dynamic.Mission.FLIGHT_PATH_ANGLE] = -(f_h + f_v) / (2.) class FlareSumForces(om.ExplicitComponent): @@ -298,14 +296,15 @@ def setup(self): nn = options['num_nodes'] - add_aviary_input(self, Dynamic.MASS, val=np.ones(nn), units='kg') - add_aviary_input(self, Dynamic.LIFT, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.THRUST_TOTAL, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.DRAG, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Mission.MASS, val=np.ones(nn), units='kg') + add_aviary_input(self, Dynamic.Mission.LIFT, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Mission.THRUST_TOTAL, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Mission.DRAG, val=np.ones(nn), units='N') self.add_input('angle_of_attack', val=np.zeros(nn), units='rad') - add_aviary_input(self, Dynamic.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units='rad') + add_aviary_input(self, Dynamic.Mission.FLIGHT_PATH_ANGLE, + val=np.zeros(nn), units='rad') self.add_output( 'forces_horizontal', val=np.zeros(nn), units='N', @@ -322,15 +321,15 @@ def setup_partials(self): rows_cols = np.arange(nn) - self.declare_partials('forces_horizontal', Dynamic.MASS, dependent=False) + self.declare_partials('forces_horizontal', Dynamic.Mission.MASS, dependent=False) self.declare_partials( - 'forces_vertical', Dynamic.MASS, val=-grav_metric, rows=rows_cols, + 'forces_vertical', Dynamic.Mission.MASS, val=-grav_metric, rows=rows_cols, cols=rows_cols) wrt = [ - Dynamic.LIFT, Dynamic.THRUST_TOTAL, Dynamic.DRAG, 'angle_of_attack', - Dynamic.FLIGHT_PATH_ANGLE] + Dynamic.Mission.LIFT, Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.DRAG, 'angle_of_attack', + Dynamic.Mission.FLIGHT_PATH_ANGLE] self.declare_partials('*', wrt, rows=rows_cols, cols=rows_cols) @@ -342,13 +341,13 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): alpha0 = aviary_options.get_val(Mission.Takeoff.ANGLE_OF_ATTACK_RUNWAY, 'rad') t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') - mass = inputs[Dynamic.MASS] - lift = inputs[Dynamic.LIFT] - thrust = inputs[Dynamic.THRUST_TOTAL] - drag = inputs[Dynamic.DRAG] + mass = inputs[Dynamic.Mission.MASS] + lift = inputs[Dynamic.Mission.LIFT] + thrust = inputs[Dynamic.Mission.THRUST_TOTAL] + drag = inputs[Dynamic.Mission.DRAG] alpha = inputs['angle_of_attack'] - gamma = inputs[Dynamic.FLIGHT_PATH_ANGLE] + gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] # FLOPS measures glideslope below horizontal gamma = -gamma @@ -380,13 +379,13 @@ def compute_partials(self, inputs, J, discrete_inputs=None): alpha0 = aviary_options.get_val(Mission.Takeoff.ANGLE_OF_ATTACK_RUNWAY, 'rad') t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') - mass = inputs[Dynamic.MASS] - lift = inputs[Dynamic.LIFT] - thrust = inputs[Dynamic.THRUST_TOTAL] - drag = inputs[Dynamic.DRAG] + mass = inputs[Dynamic.Mission.MASS] + lift = inputs[Dynamic.Mission.LIFT] + thrust = inputs[Dynamic.Mission.THRUST_TOTAL] + drag = inputs[Dynamic.Mission.DRAG] alpha = inputs['angle_of_attack'] - gamma = inputs[Dynamic.FLIGHT_PATH_ANGLE] + gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] # FLOPS measures glideslope below horizontal gamma = -gamma @@ -400,25 +399,25 @@ def compute_partials(self, inputs, J, discrete_inputs=None): s_gamma = np.sin(gamma) f_h_key = 'forces_horizontal' - J[f_h_key, Dynamic.LIFT] = -s_gamma + J[f_h_key, Dynamic.Mission.LIFT] = -s_gamma f_v_key = 'forces_vertical' - J[f_v_key, Dynamic.LIFT] = c_gamma + J[f_v_key, Dynamic.Mission.LIFT] = c_gamma - J[f_h_key, Dynamic.THRUST_TOTAL] = -c_angle - J[f_v_key, Dynamic.THRUST_TOTAL] = s_angle + J[f_h_key, Dynamic.Mission.THRUST_TOTAL] = -c_angle + J[f_v_key, Dynamic.Mission.THRUST_TOTAL] = s_angle - J[f_h_key, Dynamic.DRAG] = c_gamma - J[f_v_key, Dynamic.DRAG] = s_gamma + J[f_h_key, Dynamic.Mission.DRAG] = c_gamma + J[f_v_key, Dynamic.Mission.DRAG] = s_gamma J[f_h_key, 'angle_of_attack'] = thrust * s_angle J[f_v_key, 'angle_of_attack'] = thrust * c_angle f_h = -drag * s_gamma - lift * c_gamma - thrust * s_angle - J[f_h_key, Dynamic.FLIGHT_PATH_ANGLE] = -f_h + J[f_h_key, Dynamic.Mission.FLIGHT_PATH_ANGLE] = -f_h f_v = -lift * s_gamma + drag * c_gamma - thrust * c_angle - J[f_v_key, Dynamic.FLIGHT_PATH_ANGLE] = -f_v + J[f_v_key, Dynamic.Mission.FLIGHT_PATH_ANGLE] = -f_v class GroundSumForces(om.ExplicitComponent): @@ -442,10 +441,10 @@ def setup(self): nn = options['num_nodes'] - add_aviary_input(self, Dynamic.MASS, val=np.ones(nn), units='kg') - add_aviary_input(self, Dynamic.LIFT, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.THRUST_TOTAL, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.DRAG, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Mission.MASS, val=np.ones(nn), units='kg') + add_aviary_input(self, Dynamic.Mission.LIFT, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Mission.THRUST_TOTAL, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Mission.DRAG, val=np.ones(nn), units='N') self.add_output( 'forces_horizontal', val=np.zeros(nn), units='N', @@ -463,25 +462,25 @@ def setup_partials(self): rows_cols = np.arange(nn) self.declare_partials( - 'forces_vertical', Dynamic.MASS, val=-grav_metric, rows=rows_cols, + 'forces_vertical', Dynamic.Mission.MASS, val=-grav_metric, rows=rows_cols, cols=rows_cols) self.declare_partials( - 'forces_vertical', Dynamic.LIFT, val=1., rows=rows_cols, cols=rows_cols) + 'forces_vertical', Dynamic.Mission.LIFT, val=1., rows=rows_cols, cols=rows_cols) self.declare_partials( - 'forces_vertical', [Dynamic.THRUST_TOTAL, Dynamic.DRAG], dependent=False) + 'forces_vertical', [Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.DRAG], dependent=False) self.declare_partials( - 'forces_horizontal', [Dynamic.MASS, Dynamic.LIFT], rows=rows_cols, + 'forces_horizontal', [Dynamic.Mission.MASS, Dynamic.Mission.LIFT], rows=rows_cols, cols=rows_cols) self.declare_partials( - 'forces_horizontal', Dynamic.THRUST_TOTAL, val=-1., rows=rows_cols, + 'forces_horizontal', Dynamic.Mission.THRUST_TOTAL, val=-1., rows=rows_cols, cols=rows_cols) self.declare_partials( - 'forces_horizontal', Dynamic.DRAG, val=1., rows=rows_cols, cols=rows_cols) + 'forces_horizontal', Dynamic.Mission.DRAG, val=1., rows=rows_cols, cols=rows_cols) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): options = self.options @@ -489,10 +488,10 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): nn = options['num_nodes'] friction_coefficient = options['friction_coefficient'] - mass = inputs[Dynamic.MASS] - lift = inputs[Dynamic.LIFT] - thrust = inputs[Dynamic.THRUST_TOTAL] - drag = inputs[Dynamic.DRAG] + mass = inputs[Dynamic.Mission.MASS] + lift = inputs[Dynamic.Mission.LIFT] + thrust = inputs[Dynamic.Mission.THRUST_TOTAL] + drag = inputs[Dynamic.Mission.DRAG] weight = mass * grav_metric @@ -512,8 +511,8 @@ def compute_partials(self, inputs, J, discrete_inputs=None): nn = options['num_nodes'] friction_coefficient = options['friction_coefficient'] - mass = inputs[Dynamic.MASS] - lift = inputs[Dynamic.LIFT] + mass = inputs[Dynamic.Mission.MASS] + lift = inputs[Dynamic.Mission.LIFT] weight = mass * grav_metric @@ -523,8 +522,8 @@ def compute_partials(self, inputs, J, discrete_inputs=None): friction = np.zeros(nn) friction[idx_sup] = friction_coefficient * grav_metric - J['forces_horizontal', Dynamic.MASS] = friction + J['forces_horizontal', Dynamic.Mission.MASS] = friction friction = np.zeros(nn) friction[idx_sup] = -friction_coefficient - J['forces_horizontal', Dynamic.LIFT] = friction + J['forces_horizontal', Dynamic.Mission.LIFT] = friction diff --git a/aviary/mission/flops_based/ode/landing_ode.py b/aviary/mission/flops_based/ode/landing_ode.py index c768083bb..76f5f9a36 100644 --- a/aviary/mission/flops_based/ode/landing_ode.py +++ b/aviary/mission/flops_based/ode/landing_ode.py @@ -14,13 +14,9 @@ from aviary.mission.gasp_based.flight_conditions import FlightConditions from aviary.utils.aviary_values import AviaryValues from aviary.utils.functions import set_aviary_initial_values, promote_aircraft_and_mission_vars -from aviary.variable_info.variables import Aircraft -from aviary.variable_info.variables import Dynamic as _Dynamic -from aviary.variable_info.variables import Mission +from aviary.variable_info.variables import Aircraft, Dynamic, Mission from aviary.variable_info.variables_in import VariablesIn -Dynamic = _Dynamic.Mission - class ExternalSubsystemGroup(om.Group): def configure(self): @@ -79,16 +75,18 @@ def setup(self): self.add_subsystem( "USatm", USatm1976Comp(num_nodes=nn), - promotes_inputs=[("h", Dynamic.ALTITUDE)], + promotes_inputs=[("h", Dynamic.Mission.ALTITUDE)], promotes_outputs=[ - "rho", ("sos", Dynamic.SPEED_OF_SOUND), ("temp", Dynamic.TEMPERATURE), - ("pres", Dynamic.STATIC_PRESSURE), "viscosity"]) + "rho", ("sos", Dynamic.Mission.SPEED_OF_SOUND), ("temp", + Dynamic.Mission.TEMPERATURE), + ("pres", Dynamic.Mission.STATIC_PRESSURE), "viscosity"]) self.add_subsystem( "fc", FlightConditions(num_nodes=nn), - promotes_inputs=["rho", Dynamic.SPEED_OF_SOUND, ("TAS", Dynamic.VELOCITY)], - promotes_outputs=[Dynamic.DYNAMIC_PRESSURE, Dynamic.MACH, "EAS"]) + promotes_inputs=["rho", Dynamic.Mission.SPEED_OF_SOUND, + ("TAS", Dynamic.Mission.VELOCITY)], + promotes_outputs=[Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.MACH, "EAS"]) # NOTE: the following are potentially signficant differences in implementation # between FLOPS and Aviary: @@ -155,13 +153,13 @@ def setup(self): 'eoms', FlareEOM(**kwargs), promotes_inputs=[ - Dynamic.FLIGHT_PATH_ANGLE, Dynamic.VELOCITY, Dynamic.MASS, Dynamic.LIFT, - Dynamic.THRUST_TOTAL, Dynamic.DRAG, 'angle_of_attack', + Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.LIFT, + Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.DRAG, 'angle_of_attack', 'angle_of_attack_rate', Mission.Landing.FLARE_RATE ], promotes_outputs=[ - Dynamic.RANGE_RATE, Dynamic.ALTITUDE_RATE, Dynamic.VELOCITY_RATE, - Dynamic.FLIGHT_PATH_ANGLE_RATE, 'forces_perpendicular', + Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY_RATE, + Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, 'forces_perpendicular', 'required_thrust', 'net_alpha_rate' ] ) @@ -174,10 +172,10 @@ def setup(self): v={'units': 'm/s', 'shape': nn}, # NOTE: FLOPS detailed takeoff stall speed is not dynamic - see above v_stall={'units': 'm/s', 'shape': nn}), - promotes_inputs=[('v', Dynamic.VELOCITY), 'v_stall'], + promotes_inputs=[('v', Dynamic.Mission.VELOCITY), 'v_stall'], promotes_outputs=['v_over_v_stall']) - self.set_input_defaults(Dynamic.ALTITUDE, np.zeros(nn), 'm') - self.set_input_defaults(Dynamic.VELOCITY, np.zeros(nn), 'm/s') + self.set_input_defaults(Dynamic.Mission.ALTITUDE, np.zeros(nn), 'm') + self.set_input_defaults(Dynamic.Mission.VELOCITY, np.zeros(nn), 'm/s') set_aviary_initial_values(self, aviary_options) diff --git a/aviary/mission/flops_based/ode/mission_EOM.py b/aviary/mission/flops_based/ode/mission_EOM.py index 946a85468..74893c351 100644 --- a/aviary/mission/flops_based/ode/mission_EOM.py +++ b/aviary/mission/flops_based/ode/mission_EOM.py @@ -28,7 +28,7 @@ def setup(self): subsys=RangeRate(num_nodes=nn), promotes_inputs=[ Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY], - promotes_outputs=[Dynamic.Mission.RANGE_RATE]) + promotes_outputs=[Dynamic.Mission.DISTANCE_RATE]) self.add_subsystem(name='excess_specific_power', subsys=SpecificEnergyRate(num_nodes=nn), promotes_inputs=[(Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.THRUST_MAX_TOTAL), diff --git a/aviary/mission/flops_based/ode/mission_ODE.py b/aviary/mission/flops_based/ode/mission_ODE.py index 0ce3b3541..3aed55277 100644 --- a/aviary/mission/flops_based/ode/mission_ODE.py +++ b/aviary/mission/flops_based/ode/mission_ODE.py @@ -122,7 +122,7 @@ def setup(self): Dynamic.Mission.SPECIFIC_ENERGY_RATE, Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.ALTITUDE_RATE_MAX, - Dynamic.Mission.RANGE_RATE]) + Dynamic.Mission.DISTANCE_RATE]) self.set_input_defaults(Dynamic.Mission.MASS, val=np.ones(nn), units='kg') self.set_input_defaults(Dynamic.Mission.VELOCITY, val=np.ones(nn), units='m/s') diff --git a/aviary/mission/flops_based/ode/range_rate.py b/aviary/mission/flops_based/ode/range_rate.py index 9ef5d8fca..86614aeed 100644 --- a/aviary/mission/flops_based/ode/range_rate.py +++ b/aviary/mission/flops_based/ode/range_rate.py @@ -22,7 +22,7 @@ def setup(self): desc='current velocity', units='m/s') self.add_output( - Dynamic.Mission.RANGE_RATE, + Dynamic.Mission.DISTANCE_RATE, val=np.ones(nn), desc='current horizontal velocity (assumed no wind)', units='m/s') @@ -35,19 +35,19 @@ def compute(self, inputs, outputs): if (climb_rate_2 >= velocity_2).any(): raise om.AnalysisError( "WARNING: climb rate exceeds velocity (range_rate.py)") - outputs[Dynamic.Mission.RANGE_RATE] = (velocity_2 - climb_rate_2)**0.5 + outputs[Dynamic.Mission.DISTANCE_RATE] = (velocity_2 - climb_rate_2)**0.5 def setup_partials(self): arange = np.arange(self.options['num_nodes']) self.declare_partials( - Dynamic.Mission.RANGE_RATE, [ + Dynamic.Mission.DISTANCE_RATE, [ Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY], rows=arange, cols=arange) def compute_partials(self, inputs, J): climb_rate = inputs[Dynamic.Mission.ALTITUDE_RATE] velocity = inputs[Dynamic.Mission.VELOCITY] - J[Dynamic.Mission.RANGE_RATE, Dynamic.Mission.ALTITUDE_RATE] = -climb_rate / \ + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE] = -climb_rate / \ (velocity**2 - climb_rate**2)**0.5 - J[Dynamic.Mission.RANGE_RATE, Dynamic.Mission.VELOCITY] = velocity / \ + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.VELOCITY] = velocity / \ (velocity**2 - climb_rate**2)**0.5 diff --git a/aviary/mission/flops_based/ode/simple_mission_EOM.py b/aviary/mission/flops_based/ode/simple_mission_EOM.py index 8e3e25e1f..b726d17b6 100644 --- a/aviary/mission/flops_based/ode/simple_mission_EOM.py +++ b/aviary/mission/flops_based/ode/simple_mission_EOM.py @@ -25,7 +25,7 @@ def setup(self): subsys=RangeRate(num_nodes=nn), promotes_inputs=[ Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY], - promotes_outputs=[Dynamic.Mission.RANGE_RATE]) + promotes_outputs=[Dynamic.Mission.DISTANCE_RATE]) self.add_subsystem(name='excess_specific_power', subsys=SpecificEnergyRate(num_nodes=nn), diff --git a/aviary/mission/flops_based/ode/simple_mission_ODE.py b/aviary/mission/flops_based/ode/simple_mission_ODE.py index 58554956b..0a34ad7ee 100644 --- a/aviary/mission/flops_based/ode/simple_mission_ODE.py +++ b/aviary/mission/flops_based/ode/simple_mission_ODE.py @@ -148,7 +148,7 @@ def setup(self): promotes_outputs=[ Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, Dynamic.Mission.ALTITUDE_RATE_MAX, - Dynamic.Mission.RANGE_RATE, + Dynamic.Mission.DISTANCE_RATE, 'T_required', ]) diff --git a/aviary/mission/flops_based/ode/takeoff_eom.py b/aviary/mission/flops_based/ode/takeoff_eom.py index b50127327..058254c1f 100644 --- a/aviary/mission/flops_based/ode/takeoff_eom.py +++ b/aviary/mission/flops_based/ode/takeoff_eom.py @@ -8,10 +8,7 @@ from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import add_aviary_input, add_aviary_output -from aviary.variable_info.variables import Dynamic as _Dynamic -from aviary.variable_info.variables import Mission - -Dynamic = _Dynamic.Mission +from aviary.variable_info.variables import Dynamic, Mission class StallSpeed(om.ExplicitComponent): @@ -131,8 +128,8 @@ def setup(self): 'climbing': climbing } - inputs = [Dynamic.FLIGHT_PATH_ANGLE, Dynamic.VELOCITY] - outputs = [Dynamic.RANGE_RATE, Dynamic.ALTITUDE_RATE] + inputs = [Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.VELOCITY] + outputs = [Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE] self.add_subsystem( 'distance_rates', DistanceRates(**kwargs), @@ -197,11 +194,14 @@ def setup(self): nn = options['num_nodes'] - add_aviary_input(self, Dynamic.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units='rad') - add_aviary_input(self, Dynamic.VELOCITY, val=np.zeros(nn), units='m/s') + add_aviary_input(self, Dynamic.Mission.FLIGHT_PATH_ANGLE, + val=np.zeros(nn), units='rad') + add_aviary_input(self, Dynamic.Mission.VELOCITY, val=np.zeros(nn), units='m/s') - add_aviary_output(self, Dynamic.RANGE_RATE, val=np.zeros(nn), units='m/s') - add_aviary_output(self, Dynamic.ALTITUDE_RATE, val=np.zeros(nn), units='m/s') + add_aviary_output(self, Dynamic.Mission.DISTANCE_RATE, + val=np.zeros(nn), units='m/s') + add_aviary_output(self, Dynamic.Mission.ALTITUDE_RATE, + val=np.zeros(nn), units='m/s') def setup_partials(self): options = self.options @@ -215,18 +215,18 @@ def setup_partials(self): else: self.declare_partials( - Dynamic.RANGE_RATE, Dynamic.FLIGHT_PATH_ANGLE, dependent=False) + Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE, dependent=False) self.declare_partials( - Dynamic.RANGE_RATE, Dynamic.VELOCITY, val=np.identity(nn)) + Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.VELOCITY, val=np.identity(nn)) - self.declare_partials(Dynamic.ALTITUDE_RATE, '*', dependent=False) + self.declare_partials(Dynamic.Mission.ALTITUDE_RATE, '*', dependent=False) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - velocity = inputs[Dynamic.VELOCITY] + velocity = inputs[Dynamic.Mission.VELOCITY] if self.options['climbing']: - flight_path_angle = inputs[Dynamic.FLIGHT_PATH_ANGLE] + flight_path_angle = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] cgam = np.cos(flight_path_angle) range_rate = cgam * velocity @@ -234,26 +234,26 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): sgam = np.sin(flight_path_angle) altitude_rate = sgam * velocity - outputs[Dynamic.ALTITUDE_RATE] = altitude_rate + outputs[Dynamic.Mission.ALTITUDE_RATE] = altitude_rate else: range_rate = velocity - outputs[Dynamic.RANGE_RATE] = range_rate + outputs[Dynamic.Mission.DISTANCE_RATE] = range_rate def compute_partials(self, inputs, J, discrete_inputs=None): if self.options['climbing']: - flight_path_angle = inputs[Dynamic.FLIGHT_PATH_ANGLE] - velocity = inputs[Dynamic.VELOCITY] + flight_path_angle = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] + velocity = inputs[Dynamic.Mission.VELOCITY] cgam = np.cos(flight_path_angle) sgam = np.sin(flight_path_angle) - J[Dynamic.RANGE_RATE, Dynamic.FLIGHT_PATH_ANGLE] = -sgam * velocity - J[Dynamic.RANGE_RATE, Dynamic.VELOCITY] = cgam + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = -sgam * velocity + J[Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.VELOCITY] = cgam - J[Dynamic.ALTITUDE_RATE, Dynamic.FLIGHT_PATH_ANGLE] = cgam * velocity - J[Dynamic.ALTITUDE_RATE, Dynamic.VELOCITY] = sgam + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE] = cgam * velocity + J[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY] = sgam class Accelerations(om.ExplicitComponent): @@ -269,7 +269,7 @@ def initialize(self): def setup(self): nn = self.options['num_nodes'] - add_aviary_input(self, Dynamic.MASS, val=np.ones(nn), units='kg') + add_aviary_input(self, Dynamic.Mission.MASS, val=np.ones(nn), units='kg') self.add_input( 'forces_horizontal', val=np.zeros(nn), units='N', @@ -293,10 +293,10 @@ def setup_partials(self): rows_cols = np.arange(nn) self.declare_partials( - 'acceleration_horizontal', Dynamic.MASS, rows=rows_cols, cols=rows_cols) + 'acceleration_horizontal', Dynamic.Mission.MASS, rows=rows_cols, cols=rows_cols) self.declare_partials( - 'acceleration_vertical', Dynamic.MASS, rows=rows_cols, cols=rows_cols) + 'acceleration_vertical', Dynamic.Mission.MASS, rows=rows_cols, cols=rows_cols) self.declare_partials( 'acceleration_horizontal', 'forces_horizontal', rows=rows_cols, @@ -312,7 +312,7 @@ def setup_partials(self): 'acceleration_vertical', 'forces_vertical', rows=rows_cols, cols=rows_cols) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - mass = inputs[Dynamic.MASS] + mass = inputs[Dynamic.Mission.MASS] f_h = inputs['forces_horizontal'] f_v = inputs['forces_vertical'] @@ -323,14 +323,14 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): outputs['acceleration_vertical'] = a_v def compute_partials(self, inputs, J, discrete_inputs=None): - mass = inputs[Dynamic.MASS] + mass = inputs[Dynamic.Mission.MASS] f_h = inputs['forces_horizontal'] f_v = inputs['forces_vertical'] m2 = mass * mass - J['acceleration_horizontal', Dynamic.MASS] = -f_h / m2 - J['acceleration_vertical', Dynamic.MASS] = -f_v / m2 + J['acceleration_horizontal', Dynamic.Mission.MASS] = -f_h / m2 + J['acceleration_vertical', Dynamic.Mission.MASS] = -f_v / m2 J['acceleration_horizontal', 'forces_horizontal'] = 1. / mass @@ -358,10 +358,13 @@ def setup(self): 'acceleration_vertical', val=np.zeros(nn), desc='current vertical acceleration', units='m/s**2') - add_aviary_input(self, Dynamic.RANGE_RATE, val=np.zeros(nn), units='m/s') - add_aviary_input(self, Dynamic.ALTITUDE_RATE, val=np.zeros(nn), units='m/s') + add_aviary_input(self, Dynamic.Mission.DISTANCE_RATE, + val=np.zeros(nn), units='m/s') + add_aviary_input(self, Dynamic.Mission.ALTITUDE_RATE, + val=np.zeros(nn), units='m/s') - add_aviary_output(self, Dynamic.VELOCITY_RATE, val=np.ones(nn), units='m/s**2') + add_aviary_output(self, Dynamic.Mission.VELOCITY_RATE, + val=np.ones(nn), units='m/s**2') rows_cols = np.arange(nn) @@ -370,30 +373,30 @@ def setup(self): def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): a_h = inputs['acceleration_horizontal'] a_v = inputs['acceleration_vertical'] - v_h = inputs[Dynamic.RANGE_RATE] - v_v = inputs[Dynamic.ALTITUDE_RATE] + v_h = inputs[Dynamic.Mission.DISTANCE_RATE] + v_v = inputs[Dynamic.Mission.ALTITUDE_RATE] v_mag = np.sqrt(v_h**2 + v_v**2) - outputs[Dynamic.VELOCITY_RATE] = (a_h * v_h + a_v * v_v) / v_mag + outputs[Dynamic.Mission.VELOCITY_RATE] = (a_h * v_h + a_v * v_v) / v_mag def compute_partials(self, inputs, J, discrete_inputs=None): a_h = inputs['acceleration_horizontal'] a_v = inputs['acceleration_vertical'] - v_h = inputs[Dynamic.RANGE_RATE] - v_v = inputs[Dynamic.ALTITUDE_RATE] + v_h = inputs[Dynamic.Mission.DISTANCE_RATE] + v_v = inputs[Dynamic.Mission.ALTITUDE_RATE] num = (a_h * v_h + a_v * v_v) fact = v_h**2 + v_v**2 den = np.sqrt(fact) - J[Dynamic.VELOCITY_RATE, 'acceleration_horizontal'] = v_h / den - J[Dynamic.VELOCITY_RATE, 'acceleration_vertical'] = v_v / den + J[Dynamic.Mission.VELOCITY_RATE, 'acceleration_horizontal'] = v_h / den + J[Dynamic.Mission.VELOCITY_RATE, 'acceleration_vertical'] = v_v / den - J[Dynamic.VELOCITY_RATE, - Dynamic.RANGE_RATE] = a_h / den - 0.5 * num / fact**(3/2) * 2.0 * v_h + J[Dynamic.Mission.VELOCITY_RATE, + Dynamic.Mission.DISTANCE_RATE] = a_h / den - 0.5 * num / fact**(3/2) * 2.0 * v_h - J[Dynamic.VELOCITY_RATE, - Dynamic.ALTITUDE_RATE] = a_v / den - 0.5 * num / fact**(3/2) * 2.0 * v_v + J[Dynamic.Mission.VELOCITY_RATE, + Dynamic.Mission.ALTITUDE_RATE] = a_v / den - 0.5 * num / fact**(3/2) * 2.0 * v_v class FlightPathAngleRate(om.ExplicitComponent): @@ -409,8 +412,10 @@ def initialize(self): def setup(self): nn = self.options['num_nodes'] - add_aviary_input(self, Dynamic.RANGE_RATE, val=np.zeros(nn), units='m/s') - add_aviary_input(self, Dynamic.ALTITUDE_RATE, val=np.zeros(nn), units='m/s') + add_aviary_input(self, Dynamic.Mission.DISTANCE_RATE, + val=np.zeros(nn), units='m/s') + add_aviary_input(self, Dynamic.Mission.ALTITUDE_RATE, + val=np.zeros(nn), units='m/s') self.add_input( 'acceleration_horizontal', val=np.zeros(nn), @@ -425,25 +430,25 @@ def setup(self): ) add_aviary_output( - self, Dynamic.FLIGHT_PATH_ANGLE_RATE, val=np.zeros(nn), units='rad/s') + self, Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, val=np.zeros(nn), units='rad/s') rows_cols = np.arange(nn) self.declare_partials('*', '*', rows=rows_cols, cols=rows_cols) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): - v_h = inputs[Dynamic.RANGE_RATE] - v_v = inputs[Dynamic.ALTITUDE_RATE] + v_h = inputs[Dynamic.Mission.DISTANCE_RATE] + v_v = inputs[Dynamic.Mission.ALTITUDE_RATE] a_h = inputs['acceleration_horizontal'] a_v = inputs['acceleration_vertical'] x = (a_v * v_h - a_h * v_v) / (v_h**2 + v_v**2) - outputs[Dynamic.FLIGHT_PATH_ANGLE_RATE] = x + outputs[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE] = x def compute_partials(self, inputs, J, discrete_inputs=None): - v_h = inputs[Dynamic.RANGE_RATE] - v_v = inputs[Dynamic.ALTITUDE_RATE] + v_h = inputs[Dynamic.Mission.DISTANCE_RATE] + v_v = inputs[Dynamic.Mission.ALTITUDE_RATE] a_h = inputs['acceleration_horizontal'] a_v = inputs['acceleration_vertical'] @@ -458,10 +463,10 @@ def compute_partials(self, inputs, J, discrete_inputs=None): df_dav = v_h / den - J[Dynamic.FLIGHT_PATH_ANGLE_RATE, Dynamic.RANGE_RATE] = df_dvh - J[Dynamic.FLIGHT_PATH_ANGLE_RATE, Dynamic.ALTITUDE_RATE] = df_dvv - J[Dynamic.FLIGHT_PATH_ANGLE_RATE, 'acceleration_horizontal'] = df_dah - J[Dynamic.FLIGHT_PATH_ANGLE_RATE, 'acceleration_vertical'] = df_dav + J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Mission.DISTANCE_RATE] = df_dvh + J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, Dynamic.Mission.ALTITUDE_RATE] = df_dvv + J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, 'acceleration_horizontal'] = df_dah + J[Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, 'acceleration_vertical'] = df_dav class SumForces(om.ExplicitComponent): @@ -494,14 +499,15 @@ def setup(self): nn = options['num_nodes'] - add_aviary_input(self, Dynamic.MASS, val=np.ones(nn), units='kg') - add_aviary_input(self, Dynamic.LIFT, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.THRUST_TOTAL, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.DRAG, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Mission.MASS, val=np.ones(nn), units='kg') + add_aviary_input(self, Dynamic.Mission.LIFT, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Mission.THRUST_TOTAL, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Mission.DRAG, val=np.ones(nn), units='N') self.add_input('angle_of_attack', val=np.zeros(nn), units='rad') - add_aviary_input(self, Dynamic.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units='rad') + add_aviary_input(self, Dynamic.Mission.FLIGHT_PATH_ANGLE, + val=np.zeros(nn), units='rad') self.add_output( 'forces_horizontal', val=np.zeros(nn), units='N', @@ -520,15 +526,16 @@ def setup_partials(self): rows_cols = np.arange(nn) if climbing: - self.declare_partials('forces_horizontal', Dynamic.MASS, dependent=False) + self.declare_partials('forces_horizontal', + Dynamic.Mission.MASS, dependent=False) self.declare_partials( - 'forces_vertical', Dynamic.MASS, val=-grav_metric, rows=rows_cols, + 'forces_vertical', Dynamic.Mission.MASS, val=-grav_metric, rows=rows_cols, cols=rows_cols) wrt = [ - Dynamic.THRUST_TOTAL, Dynamic.LIFT, Dynamic.DRAG, 'angle_of_attack', - Dynamic.FLIGHT_PATH_ANGLE] + Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.LIFT, Dynamic.Mission.DRAG, 'angle_of_attack', + Dynamic.Mission.FLIGHT_PATH_ANGLE] self.declare_partials('*', wrt, rows=rows_cols, cols=rows_cols) @@ -539,26 +546,27 @@ def setup_partials(self): val = -grav_metric * mu self.declare_partials( - 'forces_horizontal', Dynamic.MASS, val=val, rows=rows_cols, + 'forces_horizontal', Dynamic.Mission.MASS, val=val, rows=rows_cols, cols=rows_cols) self.declare_partials( - 'forces_horizontal', Dynamic.LIFT, val=mu, rows=rows_cols, + 'forces_horizontal', Dynamic.Mission.LIFT, val=mu, rows=rows_cols, cols=rows_cols) t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') val = np.cos(t_inc) + np.sin(t_inc) * mu self.declare_partials( - 'forces_horizontal', Dynamic.THRUST_TOTAL, val=val, rows=rows_cols, + 'forces_horizontal', Dynamic.Mission.THRUST_TOTAL, val=val, rows=rows_cols, cols=rows_cols) self.declare_partials( - 'forces_horizontal', Dynamic.DRAG, val=-1., rows=rows_cols, + 'forces_horizontal', Dynamic.Mission.DRAG, val=-1., rows=rows_cols, cols=rows_cols) self.declare_partials( - 'forces_horizontal', ['angle_of_attack', Dynamic.FLIGHT_PATH_ANGLE], + 'forces_horizontal', ['angle_of_attack', + Dynamic.Mission.FLIGHT_PATH_ANGLE], dependent=False) self.declare_partials('forces_vertical', ['*'], dependent=False) @@ -571,10 +579,10 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') - mass = inputs[Dynamic.MASS] - lift = inputs[Dynamic.LIFT] - thrust = inputs[Dynamic.THRUST_TOTAL] - drag = inputs[Dynamic.DRAG] + mass = inputs[Dynamic.Mission.MASS] + lift = inputs[Dynamic.Mission.LIFT] + thrust = inputs[Dynamic.Mission.THRUST_TOTAL] + drag = inputs[Dynamic.Mission.DRAG] weight = mass * grav_metric @@ -587,7 +595,7 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): aviary_options.get_val(Mission.Takeoff.ANGLE_OF_ATTACK_RUNWAY, 'rad') alpha = inputs['angle_of_attack'] - gamma = inputs[Dynamic.FLIGHT_PATH_ANGLE] + gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] angle = alpha - alpha0 + t_inc + gamma @@ -631,12 +639,12 @@ def compute_partials(self, inputs, J, discrete_inputs=None): alpha0 = aviary_options.get_val(Mission.Takeoff.ANGLE_OF_ATTACK_RUNWAY, 'rad') t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') - lift = inputs[Dynamic.LIFT] - thrust = inputs[Dynamic.THRUST_TOTAL] - drag = inputs[Dynamic.DRAG] + lift = inputs[Dynamic.Mission.LIFT] + thrust = inputs[Dynamic.Mission.THRUST_TOTAL] + drag = inputs[Dynamic.Mission.DRAG] alpha = inputs['angle_of_attack'] - gamma = inputs[Dynamic.FLIGHT_PATH_ANGLE] + gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] angle = alpha - alpha0 + t_inc + gamma @@ -646,22 +654,22 @@ def compute_partials(self, inputs, J, discrete_inputs=None): c_gamma = np.cos(gamma) s_gamma = np.sin(gamma) - J['forces_horizontal', Dynamic.THRUST_TOTAL] = c_angle - J['forces_vertical', Dynamic.THRUST_TOTAL] = s_angle + J['forces_horizontal', Dynamic.Mission.THRUST_TOTAL] = c_angle + J['forces_vertical', Dynamic.Mission.THRUST_TOTAL] = s_angle - J['forces_horizontal', Dynamic.LIFT] = -s_gamma - J['forces_vertical', Dynamic.LIFT] = c_gamma + J['forces_horizontal', Dynamic.Mission.LIFT] = -s_gamma + J['forces_vertical', Dynamic.Mission.LIFT] = c_gamma - J['forces_horizontal', Dynamic.DRAG] = -c_gamma - J['forces_vertical', Dynamic.DRAG] = -s_gamma + J['forces_horizontal', Dynamic.Mission.DRAG] = -c_gamma + J['forces_vertical', Dynamic.Mission.DRAG] = -s_gamma J['forces_horizontal', 'angle_of_attack'] = -thrust * s_angle J['forces_vertical', 'angle_of_attack'] = thrust * c_angle - J['forces_horizontal', Dynamic.FLIGHT_PATH_ANGLE] = \ + J['forces_horizontal', Dynamic.Mission.FLIGHT_PATH_ANGLE] = \ -thrust * s_angle + drag * s_gamma - lift * c_gamma - J['forces_vertical', Dynamic.FLIGHT_PATH_ANGLE] = \ + J['forces_vertical', Dynamic.Mission.FLIGHT_PATH_ANGLE] = \ thrust * c_angle - drag * c_gamma - lift * s_gamma @@ -685,14 +693,15 @@ def setup(self): nn = options['num_nodes'] - add_aviary_input(self, Dynamic.MASS, val=np.ones(nn), units='kg') - add_aviary_input(self, Dynamic.LIFT, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.THRUST_TOTAL, val=np.ones(nn), units='N') - add_aviary_input(self, Dynamic.DRAG, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Mission.MASS, val=np.ones(nn), units='kg') + add_aviary_input(self, Dynamic.Mission.LIFT, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Mission.THRUST_TOTAL, val=np.ones(nn), units='N') + add_aviary_input(self, Dynamic.Mission.DRAG, val=np.ones(nn), units='N') self.add_input('angle_of_attack', val=np.zeros(nn), units='rad') - add_aviary_input(self, Dynamic.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units='rad') + add_aviary_input(self, Dynamic.Mission.FLIGHT_PATH_ANGLE, + val=np.zeros(nn), units='rad') self.add_output( 'climb_gradient_forces_horizontal', val=np.zeros(nn), units='N', @@ -714,22 +723,22 @@ def setup_partials(self): self.declare_partials( '*', [ - Dynamic.MASS, Dynamic.THRUST_TOTAL, 'angle_of_attack', - Dynamic.FLIGHT_PATH_ANGLE], + Dynamic.Mission.MASS, Dynamic.Mission.THRUST_TOTAL, 'angle_of_attack', + Dynamic.Mission.FLIGHT_PATH_ANGLE], rows=rows_cols, cols=rows_cols) self.declare_partials( - 'climb_gradient_forces_horizontal', Dynamic.DRAG, val=-1., + 'climb_gradient_forces_horizontal', Dynamic.Mission.DRAG, val=-1., rows=rows_cols, cols=rows_cols) self.declare_partials( - 'climb_gradient_forces_vertical', Dynamic.DRAG, dependent=False) + 'climb_gradient_forces_vertical', Dynamic.Mission.DRAG, dependent=False) self.declare_partials( - 'climb_gradient_forces_horizontal', Dynamic.LIFT, dependent=False) + 'climb_gradient_forces_horizontal', Dynamic.Mission.LIFT, dependent=False) self.declare_partials( - 'climb_gradient_forces_vertical', Dynamic.LIFT, val=1., + 'climb_gradient_forces_vertical', Dynamic.Mission.LIFT, val=1., rows=rows_cols, cols=rows_cols) def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): @@ -740,15 +749,15 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): alpha0 = aviary_options.get_val(Mission.Takeoff.ANGLE_OF_ATTACK_RUNWAY, 'rad') t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') - mass = inputs[Dynamic.MASS] - lift = inputs[Dynamic.LIFT] - thrust = inputs[Dynamic.THRUST_TOTAL] - drag = inputs[Dynamic.DRAG] + mass = inputs[Dynamic.Mission.MASS] + lift = inputs[Dynamic.Mission.LIFT] + thrust = inputs[Dynamic.Mission.THRUST_TOTAL] + drag = inputs[Dynamic.Mission.DRAG] weight = mass * grav_metric alpha = inputs['angle_of_attack'] - gamma = inputs[Dynamic.FLIGHT_PATH_ANGLE] + gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] angle = alpha - alpha0 + t_inc @@ -774,15 +783,15 @@ def compute_partials(self, inputs, J, discrete_inputs=None): alpha0 = aviary_options.get_val(Mission.Takeoff.ANGLE_OF_ATTACK_RUNWAY, 'rad') t_inc = aviary_options.get_val(Mission.Takeoff.THRUST_INCIDENCE, 'rad') - mass = inputs[Dynamic.MASS] - lift = inputs[Dynamic.LIFT] - thrust = inputs[Dynamic.THRUST_TOTAL] - drag = inputs[Dynamic.DRAG] + mass = inputs[Dynamic.Mission.MASS] + lift = inputs[Dynamic.Mission.LIFT] + thrust = inputs[Dynamic.Mission.THRUST_TOTAL] + drag = inputs[Dynamic.Mission.DRAG] weight = mass * grav_metric alpha = inputs['angle_of_attack'] - gamma = inputs[Dynamic.FLIGHT_PATH_ANGLE] + gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] angle = alpha - alpha0 + t_inc @@ -795,14 +804,14 @@ def compute_partials(self, inputs, J, discrete_inputs=None): f_h_key = 'climb_gradient_forces_horizontal' f_v_key = 'climb_gradient_forces_vertical' - J[f_h_key, Dynamic.MASS] = -grav_metric * s_gamma - J[f_v_key, Dynamic.MASS] = -grav_metric * c_gamma + J[f_h_key, Dynamic.Mission.MASS] = -grav_metric * s_gamma + J[f_v_key, Dynamic.Mission.MASS] = -grav_metric * c_gamma - J[f_h_key, Dynamic.THRUST_TOTAL] = c_angle - J[f_v_key, Dynamic.THRUST_TOTAL] = s_angle + J[f_h_key, Dynamic.Mission.THRUST_TOTAL] = c_angle + J[f_v_key, Dynamic.Mission.THRUST_TOTAL] = s_angle J[f_h_key, 'angle_of_attack'] = -thrust * s_angle J[f_v_key, 'angle_of_attack'] = thrust * c_angle - J[f_h_key, Dynamic.FLIGHT_PATH_ANGLE] = -weight * c_gamma - J[f_v_key, Dynamic.FLIGHT_PATH_ANGLE] = weight * s_gamma + J[f_h_key, Dynamic.Mission.FLIGHT_PATH_ANGLE] = -weight * c_gamma + J[f_v_key, Dynamic.Mission.FLIGHT_PATH_ANGLE] = weight * s_gamma diff --git a/aviary/mission/flops_based/ode/takeoff_ode.py b/aviary/mission/flops_based/ode/takeoff_ode.py index 73accaa91..e8304e181 100644 --- a/aviary/mission/flops_based/ode/takeoff_ode.py +++ b/aviary/mission/flops_based/ode/takeoff_ode.py @@ -9,13 +9,9 @@ from aviary.mission.gasp_based.flight_conditions import FlightConditions from aviary.utils.aviary_values import AviaryValues from aviary.utils.functions import set_aviary_initial_values, promote_aircraft_and_mission_vars -from aviary.variable_info.variables import Aircraft -from aviary.variable_info.variables import Dynamic as _Dynamic -from aviary.variable_info.variables import Mission +from aviary.variable_info.variables import Aircraft, Dynamic, Mission from aviary.variable_info.variables_in import VariablesIn -Dynamic = _Dynamic.Mission - class ExternalSubsystemGroup(om.Group): def configure(self): @@ -77,16 +73,18 @@ def setup(self): self.add_subsystem( "USatm", USatm1976Comp(num_nodes=nn), - promotes_inputs=[("h", Dynamic.ALTITUDE)], + promotes_inputs=[("h", Dynamic.Mission.ALTITUDE)], promotes_outputs=[ - "rho", ("sos", Dynamic.SPEED_OF_SOUND), ("temp", Dynamic.TEMPERATURE), - ("pres", Dynamic.STATIC_PRESSURE), "viscosity"]) + "rho", ("sos", Dynamic.Mission.SPEED_OF_SOUND), ("temp", + Dynamic.Mission.TEMPERATURE), + ("pres", Dynamic.Mission.STATIC_PRESSURE), "viscosity"]) self.add_subsystem( "fc", FlightConditions(num_nodes=nn), - promotes_inputs=["rho", Dynamic.SPEED_OF_SOUND, ("TAS", Dynamic.VELOCITY)], - promotes_outputs=[Dynamic.DYNAMIC_PRESSURE, Dynamic.MACH, "EAS"]) + promotes_inputs=["rho", Dynamic.Mission.SPEED_OF_SOUND, + ("TAS", Dynamic.Mission.VELOCITY)], + promotes_outputs=[Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.MACH, "EAS"]) # NOTE: the following are potentially signficant differences in implementation # between FLOPS and Aviary: @@ -154,11 +152,11 @@ def setup(self): self.add_subsystem( 'eoms', TakeoffEOM(**kwargs), promotes_inputs=[ - Dynamic.FLIGHT_PATH_ANGLE, Dynamic.VELOCITY, Dynamic.MASS, Dynamic.LIFT, - Dynamic.THRUST_TOTAL, Dynamic.DRAG, 'angle_of_attack'], + Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.LIFT, + Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.DRAG, 'angle_of_attack'], promotes_outputs=[ - Dynamic.RANGE_RATE, Dynamic.ALTITUDE_RATE, Dynamic.VELOCITY_RATE, - Dynamic.FLIGHT_PATH_ANGLE_RATE]) + Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY_RATE, + Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE]) self.add_subsystem( 'comp_v_ratio', @@ -168,11 +166,11 @@ def setup(self): v={'units': 'm/s', 'shape': nn}, # NOTE: FLOPS detailed takeoff stall speed is not dynamic - see above v_stall={'units': 'm/s', 'shape': nn}), - promotes_inputs=[('v', Dynamic.VELOCITY), 'v_stall'], + promotes_inputs=[('v', Dynamic.Mission.VELOCITY), 'v_stall'], promotes_outputs=['v_over_v_stall']) - self.set_input_defaults(Dynamic.ALTITUDE, np.zeros(nn), 'm') - self.set_input_defaults(Dynamic.VELOCITY, np.zeros(nn), 'm/s') + self.set_input_defaults(Dynamic.Mission.ALTITUDE, np.zeros(nn), 'm') + self.set_input_defaults(Dynamic.Mission.VELOCITY, np.zeros(nn), 'm/s') self.set_input_defaults(Mission.Design.GROSS_MASS, val=1.0, units='kg') set_aviary_initial_values(self, aviary_options) diff --git a/aviary/mission/flops_based/ode/test/test_landing_eom.py b/aviary/mission/flops_based/ode/test/test_landing_eom.py index 0afa883eb..ef4903f4e 100644 --- a/aviary/mission/flops_based/ode/test/test_landing_eom.py +++ b/aviary/mission/flops_based/ode/test/test_landing_eom.py @@ -6,9 +6,7 @@ from aviary.models.N3CC.N3CC_data import ( detailed_landing_flare, inputs) from aviary.validation_cases.validation_tests import do_validation_test -from aviary.variable_info.variables import Dynamic as _Dynamic - -Dynamic = _Dynamic.Mission +from aviary.variable_info.variables import Dynamic class FlareEOMTest(unittest.TestCase): @@ -34,15 +32,15 @@ def test_case(self): output_validation_data=detailed_landing_flare, input_keys=[ 'angle_of_attack', - Dynamic.FLIGHT_PATH_ANGLE, - Dynamic.VELOCITY, - Dynamic.MASS, - Dynamic.LIFT, - Dynamic.THRUST_TOTAL, - Dynamic.DRAG], + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Dynamic.Mission.VELOCITY, + Dynamic.Mission.MASS, + Dynamic.Mission.LIFT, + Dynamic.Mission.THRUST_TOTAL, + Dynamic.Mission.DRAG], output_keys=[ - Dynamic.RANGE_RATE, - Dynamic.ALTITUDE_RATE], + Dynamic.Mission.DISTANCE_RATE, + Dynamic.Mission.ALTITUDE_RATE], tol=1e-2, atol=1e-8, rtol=5e-10) 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 16e34c0f2..526fbc9cf 100644 --- a/aviary/mission/flops_based/ode/test/test_landing_ode.py +++ b/aviary/mission/flops_based/ode/test/test_landing_ode.py @@ -7,9 +7,7 @@ from aviary.models.N3CC.N3CC_data import ( detailed_landing_flare, inputs, landing_subsystem_options) from aviary.validation_cases.validation_tests import do_validation_test -from aviary.variable_info.variables import Dynamic as _Dynamic - -Dynamic = _Dynamic.Mission +from aviary.variable_info.variables import Dynamic class FlareODETest(unittest.TestCase): @@ -39,15 +37,15 @@ def test_case(self): output_validation_data=detailed_landing_flare, input_keys=[ 'angle_of_attack', - Dynamic.FLIGHT_PATH_ANGLE, - Dynamic.VELOCITY, - Dynamic.MASS, - Dynamic.LIFT, - Dynamic.THRUST_TOTAL, - Dynamic.DRAG], + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Dynamic.Mission.VELOCITY, + Dynamic.Mission.MASS, + Dynamic.Mission.LIFT, + Dynamic.Mission.THRUST_TOTAL, + Dynamic.Mission.DRAG], output_keys=[ - Dynamic.RANGE_RATE, - Dynamic.ALTITUDE_RATE], + Dynamic.Mission.DISTANCE_RATE, + Dynamic.Mission.ALTITUDE_RATE], tol=1e-2, atol=5e-9, rtol=5e-9, check_values=False, check_partials=True) diff --git a/aviary/mission/flops_based/ode/test/test_mission_EOM.py b/aviary/mission/flops_based/ode/test/test_mission_EOM.py index c2210d1f1..ea8e6be39 100644 --- a/aviary/mission/flops_based/ode/test/test_mission_EOM.py +++ b/aviary/mission/flops_based/ode/test/test_mission_EOM.py @@ -42,7 +42,7 @@ def test_case1(self): # - actual: 760.55416759 # - desired: 3.86361517135375 # Dynamic.Mission.ALTITUDE_RATE_MAX, - Dynamic.Mission.RANGE_RATE, + Dynamic.Mission.DISTANCE_RATE, Dynamic.Mission.SPECIFIC_ENERGY_RATE, Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS], tol=1e-12) diff --git a/aviary/mission/flops_based/ode/test/test_range_rate.py b/aviary/mission/flops_based/ode/test/test_range_rate.py index 7809e849e..e371e2212 100644 --- a/aviary/mission/flops_based/ode/test/test_range_rate.py +++ b/aviary/mission/flops_based/ode/test/test_range_rate.py @@ -17,7 +17,7 @@ def setUp(self): time, _ = data.get_item('time') prob.model.add_subsystem( - Dynamic.Mission.RANGE_RATE, + Dynamic.Mission.DISTANCE_RATE, RangeRate(num_nodes=len(time)), promotes_inputs=['*'], promotes_outputs=['*'], @@ -33,7 +33,7 @@ def test_case1(self): output_validation_data=data, input_keys=[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY], - output_keys=Dynamic.Mission.RANGE_RATE, + output_keys=Dynamic.Mission.DISTANCE_RATE, tol=1e-12) def test_IO(self): diff --git a/aviary/mission/flops_based/ode/test/test_takeoff_eom.py b/aviary/mission/flops_based/ode/test/test_takeoff_eom.py index 6494143ba..f92e04771 100644 --- a/aviary/mission/flops_based/ode/test/test_takeoff_eom.py +++ b/aviary/mission/flops_based/ode/test/test_takeoff_eom.py @@ -6,10 +6,7 @@ from aviary.models.N3CC.N3CC_data import ( detailed_takeoff_climbing, detailed_takeoff_ground, inputs) from aviary.validation_cases.validation_tests import do_validation_test -from aviary.variable_info.variables import Dynamic as _Dynamic -from aviary.variable_info.variables import Mission - -Dynamic = _Dynamic.Mission +from aviary.variable_info.variables import Dynamic, Mission class TakeoffEOMTest(unittest.TestCase): @@ -23,16 +20,16 @@ def test_case_ground(self): output_validation_data=detailed_takeoff_ground, input_keys=[ 'angle_of_attack', - Dynamic.FLIGHT_PATH_ANGLE, - Dynamic.VELOCITY, - Dynamic.MASS, - Dynamic.LIFT, - Dynamic.THRUST_TOTAL, - Dynamic.DRAG], + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Dynamic.Mission.VELOCITY, + Dynamic.Mission.MASS, + Dynamic.Mission.LIFT, + Dynamic.Mission.THRUST_TOTAL, + Dynamic.Mission.DRAG], output_keys=[ - Dynamic.RANGE_RATE, - Dynamic.ALTITUDE_RATE, - Dynamic.VELOCITY_RATE], + Dynamic.Mission.DISTANCE_RATE, + Dynamic.Mission.ALTITUDE_RATE, + Dynamic.Mission.VELOCITY_RATE], tol=1e-2) def test_case_climbing(self): @@ -45,16 +42,16 @@ def test_case_climbing(self): output_validation_data=detailed_takeoff_climbing, input_keys=[ 'angle_of_attack', - Dynamic.FLIGHT_PATH_ANGLE, - Dynamic.VELOCITY, - Dynamic.MASS, - Dynamic.LIFT, - Dynamic.THRUST_TOTAL, - Dynamic.DRAG], + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Dynamic.Mission.VELOCITY, + Dynamic.Mission.MASS, + Dynamic.Mission.LIFT, + Dynamic.Mission.THRUST_TOTAL, + Dynamic.Mission.DRAG], output_keys=[ - Dynamic.RANGE_RATE, - Dynamic.ALTITUDE_RATE, - Dynamic.VELOCITY_RATE], + Dynamic.Mission.DISTANCE_RATE, + Dynamic.Mission.ALTITUDE_RATE, + Dynamic.Mission.VELOCITY_RATE], tol=1e-2, atol=1e-9, rtol=1e-11) @staticmethod 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 fd39339e5..6ffbf6e20 100644 --- a/aviary/mission/flops_based/ode/test/test_takeoff_ode.py +++ b/aviary/mission/flops_based/ode/test/test_takeoff_ode.py @@ -8,10 +8,7 @@ from aviary.models.N3CC.N3CC_data import ( detailed_takeoff_climbing, detailed_takeoff_ground, takeoff_subsystem_options, inputs) from aviary.validation_cases.validation_tests import do_validation_test -from aviary.variable_info.variables import Dynamic as _Dynamic -from aviary.variable_info.variables import Mission - -Dynamic = _Dynamic.Mission +from aviary.variable_info.variables import Dynamic, Mission takeoff_subsystem_options = deepcopy(takeoff_subsystem_options) @@ -27,17 +24,17 @@ def test_case_ground(self): output_validation_data=detailed_takeoff_ground, input_keys=[ 'angle_of_attack', - Dynamic.FLIGHT_PATH_ANGLE, - Dynamic.ALTITUDE, - Dynamic.VELOCITY, - Dynamic.MASS, - Dynamic.LIFT, - Dynamic.THRUST_TOTAL, - Dynamic.DRAG], + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Dynamic.Mission.ALTITUDE, + Dynamic.Mission.VELOCITY, + Dynamic.Mission.MASS, + Dynamic.Mission.LIFT, + Dynamic.Mission.THRUST_TOTAL, + Dynamic.Mission.DRAG], output_keys=[ - Dynamic.RANGE_RATE, - Dynamic.ALTITUDE_RATE, - Dynamic.VELOCITY_RATE], + Dynamic.Mission.DISTANCE_RATE, + Dynamic.Mission.ALTITUDE_RATE, + Dynamic.Mission.VELOCITY_RATE], tol=1e-2, atol=1e-9, rtol=1e-11, check_values=False, check_partials=True) @@ -51,17 +48,17 @@ def test_case_climbing(self): output_validation_data=detailed_takeoff_climbing, input_keys=[ 'angle_of_attack', - Dynamic.FLIGHT_PATH_ANGLE, - Dynamic.ALTITUDE, - Dynamic.VELOCITY, - Dynamic.MASS, - Dynamic.LIFT, - Dynamic.THRUST_TOTAL, - Dynamic.DRAG], + Dynamic.Mission.FLIGHT_PATH_ANGLE, + Dynamic.Mission.ALTITUDE, + Dynamic.Mission.VELOCITY, + Dynamic.Mission.MASS, + Dynamic.Mission.LIFT, + Dynamic.Mission.THRUST_TOTAL, + Dynamic.Mission.DRAG], output_keys=[ - Dynamic.RANGE_RATE, - Dynamic.ALTITUDE_RATE, - Dynamic.VELOCITY_RATE], + Dynamic.Mission.DISTANCE_RATE, + Dynamic.Mission.ALTITUDE_RATE, + Dynamic.Mission.VELOCITY_RATE], tol=1e-2, atol=1e-9, rtol=1e-11, check_values=False, check_partials=True) diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py index 002760085..7c7c97277 100644 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py +++ b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py @@ -149,8 +149,8 @@ def run_trajectory(): Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s') prob.set_val('traj.climb.states:mass', climb.interp( Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') - prob.set_val('traj.climb.states:range', climb.interp( - Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') + prob.set_val('traj.climb.states:distance', climb.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') prob.set_val('traj.climb.controls:velocity_rate', climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.05]), @@ -179,7 +179,7 @@ def bench_test_climb_large_single_aisle_1(self): times = prob.get_val('traj.climb.timeseries.time', units='s') altitudes = prob.get_val('traj.climb.timeseries.states:altitude', units='m') masses = prob.get_val('traj.climb.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.climb.timeseries.states:range', units='m') + ranges = prob.get_val('traj.climb.timeseries.states:distance', units='m') velocities = prob.get_val('traj.climb.timeseries.states:velocity', units='m/s') thrusts = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N') diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py index f03466f7f..761b30e97 100644 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py +++ b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py @@ -152,8 +152,8 @@ def run_trajectory(): Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s') prob.set_val('traj.climb.states:mass', climb.interp( Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') - prob.set_val('traj.climb.states:range', climb.interp( - Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') # nmi + prob.set_val('traj.climb.states:distance', climb.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') # nmi prob.set_val('traj.climb.controls:velocity_rate', climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.05]), @@ -182,7 +182,7 @@ def bench_test_climb_large_single_aisle_2(self): times = prob.get_val('traj.climb.timeseries.time', units='s') altitudes = prob.get_val('traj.climb.timeseries.states:altitude', units='m') masses = prob.get_val('traj.climb.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.climb.timeseries.states:range', units='m') + ranges = prob.get_val('traj.climb.timeseries.states:distance', units='m') velocities = prob.get_val('traj.climb.timeseries.states:velocity', units='m/s') thrusts = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N') diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py index c88f5dd8e..7e6249379 100644 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py +++ b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py @@ -172,8 +172,8 @@ def run_trajectory(): velocity_i_cruise, velocity_f_cruise]), units='m/s') prob.set_val('traj.cruise.states:mass', cruise.interp( Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi + prob.set_val('traj.cruise.states:distance', cruise.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi prob.set_val('traj.cruise.controls:velocity_rate', cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), @@ -201,7 +201,7 @@ def bench_test_cruise_climb_large_single_aisle_1(self): times = prob.get_val('traj.cruise.timeseries.time', units='s') altitudes = prob.get_val('traj.cruise.timeseries.states:altitude', units='m') masses = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.cruise.timeseries.states:range', units='m') + ranges = prob.get_val('traj.cruise.timeseries.states:distance', units='m') velocities = prob.get_val('traj.cruise.timeseries.states:velocity', units='m/s') thrusts = prob.get_val('traj.cruise.timeseries.thrust_net_total', units='N') diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py index b9925cf5b..353a9acc0 100644 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py +++ b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py @@ -171,8 +171,8 @@ def run_trajectory(): Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s') prob.set_val('traj.cruise.states:mass', cruise.interp( Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi + prob.set_val('traj.cruise.states:distance', cruise.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi prob.set_val('traj.cruise.controls:velocity_rate', cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), @@ -203,7 +203,7 @@ def bench_test_cruise_large_single_aisle_1(self): times = prob.get_val('traj.cruise.timeseries.time', units='s') altitudes = prob.get_val('traj.cruise.timeseries.states:altitude', units='m') masses = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.cruise.timeseries.states:range', units='m') + ranges = prob.get_val('traj.cruise.timeseries.states:distance', units='m') velocities = prob.get_val('traj.cruise.timeseries.states:velocity', units='m/s') thrusts = prob.get_val('traj.cruise.timeseries.thrust_net_total', units='N') diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py index 8e1cfae23..26f8a4a1b 100644 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py +++ b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py @@ -162,8 +162,8 @@ def run_trajectory(): Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s') prob.set_val('traj.cruise.states:mass', cruise.interp( Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi + prob.set_val('traj.cruise.states:distance', cruise.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi prob.set_val('traj.cruise.controls:velocity_rate', cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), @@ -194,7 +194,7 @@ def bench_test_cruise_large_single_asile_2(self): times = prob.get_val('traj.cruise.timeseries.time', units='s') altitudes = prob.get_val('traj.cruise.timeseries.states:altitude', units='m') masses = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.cruise.timeseries.states:range', units='m') + ranges = prob.get_val('traj.cruise.timeseries.states:distance', units='m') velocities = prob.get_val('traj.cruise.timeseries.states:velocity', units='m/s') thrusts = prob.get_val('traj.cruise.timeseries.thrust_net', units='N') diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py index c1dba6168..811648701 100644 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py +++ b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py @@ -126,7 +126,7 @@ def run_trajectory(): descent = descent_options.build_phase(MissionODE, transcription) # descent.add_objective(Dynamic.Mission.MASS, ref=-1e4, loc='final') - descent.add_objective(Dynamic.Mission.RANGE, ref=-1e5, loc='final') + descent.add_objective(Dynamic.Mission.DISTANCE, ref=-1e5, loc='final') traj.add_phase('descent', descent) @@ -147,8 +147,8 @@ def run_trajectory(): Dynamic.Mission.VELOCITY, ys=[v_i_descent, v_f_descent]), units='m/s') prob.set_val('traj.descent.states:mass', descent.interp( Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') - prob.set_val('traj.descent.states:range', descent.interp( - Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m') + prob.set_val('traj.descent.states:distance', descent.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_descent, range_f_descent]), units='m') prob.set_val('traj.descent.controls:velocity_rate', descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), @@ -177,7 +177,7 @@ def bench_test_descent_large_single_aisle_1(self): times = prob.get_val('traj.descent.timeseries.time', units='s') altitudes = prob.get_val('traj.descent.timeseries.states:altitude', units='m') masses = prob.get_val('traj.descent.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.descent.timeseries.states:range', units='m') + ranges = prob.get_val('traj.descent.timeseries.states:distance', units='m') velocities = prob.get_val('traj.descent.timeseries.states:velocity', units='m/s') thrusts = prob.get_val('traj.descent.timeseries.thrust_net', units='N') diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py index e6378c4a2..251b86944 100644 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py +++ b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py @@ -127,7 +127,7 @@ def run_trajectory(): descent = descent_options.build_phase(MissionODE, transcription) - descent.add_objective(Dynamic.Mission.RANGE, ref=-1e5, loc='final') + descent.add_objective(Dynamic.Mission.DISTANCE, ref=-1e5, loc='final') traj.add_phase('descent', descent) traj = setup_trajectory_params(prob.model, traj, aviary_inputs) @@ -147,8 +147,8 @@ def run_trajectory(): Dynamic.Mission.VELOCITY, ys=[v_i, v_f]), units='m/s') prob.set_val('traj.descent.states:mass', descent.interp( Dynamic.Mission.MASS, ys=[mass_i, mass_f]), units='kg') - prob.set_val('traj.descent.states:range', descent.interp( - Dynamic.Mission.RANGE, ys=[range_i, range_f]), units='m') + prob.set_val('traj.descent.states:distance', descent.interp( + Dynamic.Mission.DISTANCE, ys=[range_i, range_f]), units='m') prob.set_val('traj.descent.controls:velocity_rate', descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), @@ -177,7 +177,7 @@ def bench_test_descent_large_single_aisle_2(self): times = prob.get_val('traj.descent.timeseries.time', units='s') altitudes = prob.get_val('traj.descent.timeseries.states:altitude', units='m') masses = prob.get_val('traj.descent.timeseries.states:mass', units='kg') - ranges = prob.get_val('traj.descent.timeseries.states:range', units='m') + ranges = prob.get_val('traj.descent.timeseries.states:distance', units='m') velocities = prob.get_val('traj.descent.timeseries.states:velocity', units='m/s') thrusts = prob.get_val('traj.descent.timeseries.thrust_net', units='N') diff --git a/aviary/mission/flops_based/phases/cruise_phase.py b/aviary/mission/flops_based/phases/cruise_phase.py index 2f861c585..4bc0f4796 100644 --- a/aviary/mission/flops_based/phases/cruise_phase.py +++ b/aviary/mission/flops_based/phases/cruise_phase.py @@ -212,13 +212,13 @@ def build_phase(self, aviary_options: AviaryValues = None): input_initial=input_initial_mass ) - input_initial_range = get_initial(input_initial, Dynamic.Mission.RANGE) - fix_initial_range = get_initial(fix_initial, Dynamic.Mission.RANGE, True) + input_initial_distance = get_initial(input_initial, Dynamic.Mission.DISTANCE) + fix_initial_distance = get_initial(fix_initial, Dynamic.Mission.DISTANCE, True) phase.add_state( - Dynamic.Mission.RANGE, fix_initial=fix_initial_range, fix_final=fix_final, + Dynamic.Mission.DISTANCE, fix_initial=fix_initial_distance, fix_final=fix_final, lower=0.0, ref=range_f_cruise, defect_ref=range_f_cruise, units='m', - rate_source=Dynamic.Mission.RANGE_RATE, - input_initial=input_initial_range + rate_source=Dynamic.Mission.DISTANCE_RATE, + input_initial=input_initial_distance ) phase = add_subsystem_variables_to_phase( @@ -413,7 +413,7 @@ def _extra_ode_init_kwargs(self): desc='initial guess for initial time and duration specified as a tuple') Cruise._add_initial_guess_meta_data( - InitialGuessState('range'), + InitialGuessState('distance'), desc='initial guess for horizontal distance traveled') Cruise._add_initial_guess_meta_data( diff --git a/aviary/mission/flops_based/phases/detailed_landing_phases.py b/aviary/mission/flops_based/phases/detailed_landing_phases.py index e71d350c5..ee46b4a1e 100644 --- a/aviary/mission/flops_based/phases/detailed_landing_phases.py +++ b/aviary/mission/flops_based/phases/detailed_landing_phases.py @@ -37,10 +37,7 @@ InitialGuessState, PhaseBuilderBase) from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Dynamic as _Dynamic -from aviary.variable_info.variables import Mission - -Dynamic = _Dynamic.Mission +from aviary.variable_info.variables import Dynamic, Mission @_init_initial_guess_meta_data @@ -151,39 +148,39 @@ def build_phase(self, aviary_options: AviaryValues = None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=False, fix_final=False, + Dynamic.Mission.DISTANCE, fix_initial=False, fix_final=False, upper=0, ref=max_range, defect_ref=max_range, units=units, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.ALTITUDE, fix_initial=False, fix_final=False, + Dynamic.Mission.ALTITUDE, fix_initial=False, fix_final=False, ref=altitude_ref, defect_ref=altitude_ref, units=units, - rate_source=Dynamic.ALTITUDE_RATE) + rate_source=Dynamic.Mission.ALTITUDE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=False, fix_final=False, + Dynamic.Mission.VELOCITY, fix_initial=False, fix_final=False, lower=0, ref=max_velocity, defect_ref=max_velocity, units=units, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) - phase.add_control(Dynamic.FLIGHT_PATH_ANGLE, opt=False, fix_initial=True) + phase.add_control(Dynamic.Mission.FLIGHT_PATH_ANGLE, opt=False, fix_initial=True) phase.add_state( - Dynamic.MASS, fix_initial=True, fix_final=False, + Dynamic.Mission.MASS, fix_initial=True, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', opt=False ) @@ -199,12 +196,12 @@ def build_phase(self, aviary_options: AviaryValues = None): ) phase.add_timeseries_output( - Dynamic.DRAG, output_name=Dynamic.DRAG, units='lbf' + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.THRUST_TOTAL, - output_name=Dynamic.THRUST_TOTAL, units='lbf' + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) initial_height, units = user_options.get_item('initial_height') @@ -215,7 +212,7 @@ def build_phase(self, aviary_options: AviaryValues = None): h = initial_height + airport_altitude phase.add_boundary_constraint( - Dynamic.ALTITUDE, loc='initial', equals=h, ref=h, units=units, linear=True) + Dynamic.Mission.ALTITUDE, loc='initial', equals=h, ref=h, units=units, linear=True) return phase @@ -262,7 +259,7 @@ def _extra_ode_init_kwargs(self): LandingApproachToMicP3._add_initial_guess_meta_data(InitialGuessState('altitude')) LandingApproachToMicP3._add_initial_guess_meta_data( - InitialGuessControl(Dynamic.FLIGHT_PATH_ANGLE)) + InitialGuessControl(Dynamic.Mission.FLIGHT_PATH_ANGLE)) # @_init_initial_guess_meta_data # <--- inherited from base class @@ -360,9 +357,9 @@ def build_phase(self, aviary_options: AviaryValues = None): # at the moment, these state options are the only differences between phases of # this class and phases of its base class - phase.set_state_options(Dynamic.RANGE, fix_final=True) - phase.set_state_options(Dynamic.VELOCITY, fix_final=True) - phase.set_state_options(Dynamic.MASS, fix_initial=False) + phase.set_state_options(Dynamic.Mission.DISTANCE, fix_final=True) + phase.set_state_options(Dynamic.Mission.VELOCITY, fix_final=True) + phase.set_state_options(Dynamic.Mission.MASS, fix_initial=False) return phase @@ -467,48 +464,49 @@ def build_phase(self, aviary_options: AviaryValues = None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=True, lower=0, ref=max_range, + Dynamic.Mission.DISTANCE, fix_initial=True, lower=0, ref=max_range, defect_ref=max_range, units=units, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, + Dynamic.Mission.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, defect_ref=altitude_ref, units=units, - rate_source=Dynamic.ALTITUDE_RATE) + rate_source=Dynamic.Mission.ALTITUDE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=True, lower=0, ref=max_velocity, + Dynamic.Mission.VELOCITY, fix_initial=True, lower=0, ref=max_velocity, defect_ref=max_velocity, units=units, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) - phase.add_control(Dynamic.FLIGHT_PATH_ANGLE, opt=False, fix_initial=False) + phase.add_control(Dynamic.Mission.FLIGHT_PATH_ANGLE, + opt=False, fix_initial=False) phase.add_state( - Dynamic.MASS, fix_initial=False, fix_final=False, + Dynamic.Mission.MASS, fix_initial=False, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', opt=False ) phase.add_control('angle_of_attack', opt=False, units='deg') phase.add_timeseries_output( - Dynamic.DRAG, output_name=Dynamic.DRAG, units='lbf' + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.THRUST_TOTAL, - output_name=Dynamic.THRUST_TOTAL, units='lbf' + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) obstacle_height, units = aviary_options.get_item( @@ -524,7 +522,7 @@ def build_phase(self, aviary_options: AviaryValues = None): h = obstacle_height + airport_altitude phase.add_boundary_constraint( - Dynamic.ALTITUDE, loc='initial', equals=h, ref=h, units=units, linear=True) + Dynamic.Mission.ALTITUDE, loc='initial', equals=h, ref=h, units=units, linear=True) return phase @@ -559,7 +557,7 @@ def _extra_ode_init_kwargs(self): LandingObstacleToFlare._add_initial_guess_meta_data(InitialGuessState('altitude')) LandingObstacleToFlare._add_initial_guess_meta_data( - InitialGuessControl(Dynamic.FLIGHT_PATH_ANGLE)) + InitialGuessControl(Dynamic.Mission.FLIGHT_PATH_ANGLE)) @_init_initial_guess_meta_data @@ -669,39 +667,40 @@ def build_phase(self, aviary_options: AviaryValues = None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=False, lower=0, ref=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, defect_ref=max_range, units=units, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.ALTITUDE, fix_initial=False, fix_final=True, + Dynamic.Mission.ALTITUDE, fix_initial=False, fix_final=True, lower=0, ref=altitude_ref, defect_ref=altitude_ref, units=units, - rate_source=Dynamic.ALTITUDE_RATE) + rate_source=Dynamic.Mission.ALTITUDE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, + Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, defect_ref=max_velocity, units=units, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) - phase.add_control(Dynamic.FLIGHT_PATH_ANGLE, fix_initial=False, opt=False) + phase.add_control(Dynamic.Mission.FLIGHT_PATH_ANGLE, + fix_initial=False, opt=False) phase.add_state( - Dynamic.MASS, fix_initial=False, fix_final=False, + Dynamic.Mission.MASS, fix_initial=False, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) # TODO: Upper limit is a bit of a hack. It hopefully won't be needed if we # can get some other constraints working. phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', lower=0.0, upper=0.2, opt=True ) @@ -719,12 +718,12 @@ def build_phase(self, aviary_options: AviaryValues = None): ) phase.add_timeseries_output( - Dynamic.DRAG, output_name=Dynamic.DRAG, units='lbf' + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.THRUST_TOTAL, - output_name=Dynamic.THRUST_TOTAL, units='lbf' + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) phase.add_timeseries_output( @@ -783,7 +782,7 @@ def _extra_ode_init_kwargs(self): LandingFlareToTouchdown._add_initial_guess_meta_data(InitialGuessState('altitude')) LandingFlareToTouchdown._add_initial_guess_meta_data( - InitialGuessControl(Dynamic.FLIGHT_PATH_ANGLE)) + InitialGuessControl(Dynamic.Mission.FLIGHT_PATH_ANGLE)) @_init_initial_guess_meta_data @@ -887,27 +886,27 @@ def build_phase(self, aviary_options=None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=False, lower=0, ref=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, defect_ref=max_range, units=units, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, + Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, defect_ref=max_velocity, units=units, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) phase.add_state( - Dynamic.MASS, fix_initial=False, fix_final=False, + Dynamic.Mission.MASS, fix_initial=False, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', opt=False ) @@ -920,12 +919,12 @@ def build_phase(self, aviary_options=None): fix_initial=False, ref=max_angle_of_attack) phase.add_timeseries_output( - Dynamic.DRAG, output_name=Dynamic.DRAG, units='lbf' + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.THRUST_TOTAL, - output_name=Dynamic.THRUST_TOTAL, units='lbf' + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) return phase @@ -1062,42 +1061,42 @@ def build_phase(self, aviary_options=None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=False, fix_final=False, + Dynamic.Mission.DISTANCE, fix_initial=False, fix_final=False, lower=0, ref=max_range, defect_ref=max_range, units=units, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=False, fix_final=True, + Dynamic.Mission.VELOCITY, fix_initial=False, fix_final=True, lower=0, ref=max_velocity, defect_ref=max_velocity, units=units, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) phase.add_state( - Dynamic.MASS, fix_initial=False, fix_final=False, + Dynamic.Mission.MASS, fix_initial=False, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) # TODO: Energy phase places this under an if num_engines > 0. phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', opt=False ) phase.add_parameter('angle_of_attack', val=0.0, opt=False, units='deg') phase.add_timeseries_output( - Dynamic.THRUST_TOTAL, - output_name=Dynamic.THRUST_TOTAL, units='lbf' + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) phase.add_timeseries_output( - Dynamic.DRAG, output_name=Dynamic.DRAG, units='lbf' + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' ) return phase @@ -1314,7 +1313,7 @@ def _add_phases(self, aviary_options: AviaryValues): def _link_phases(self): traj: dm.Trajectory = self._traj - basic_vars = ['time', 'range', 'velocity', 'mass'] + basic_vars = ['time', 'distance', 'velocity', 'mass'] ext_vars = basic_vars + ['angle_of_attack'] full_vars = ext_vars + ['altitude'] @@ -1329,7 +1328,7 @@ def _link_phases(self): obstacle_vars = ['mass', 'time', 'altitude', 'angle_of_attack'] traj.link_phases([p3_obstacle_name, obstacle_name], vars=obstacle_vars) - pre_obs_vars = obstacle_vars + ['range', 'velocity'] + pre_obs_vars = obstacle_vars + ['distance', 'velocity'] traj.link_phases([approach_p3_name, p3_obstacle_name], vars=pre_obs_vars) flare_name = self._flare_to_touchdown.name diff --git a/aviary/mission/flops_based/phases/detailed_takeoff_phases.py b/aviary/mission/flops_based/phases/detailed_takeoff_phases.py index 742c774f8..e637c2a46 100644 --- a/aviary/mission/flops_based/phases/detailed_takeoff_phases.py +++ b/aviary/mission/flops_based/phases/detailed_takeoff_phases.py @@ -51,10 +51,7 @@ InitialGuessState, InitialGuessTime, PhaseBuilderBase) from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import setup_trajectory_params -from aviary.variable_info.variables import Dynamic as _Dynamic -from aviary.variable_info.variables import Mission - -Dynamic = _Dynamic.Mission +from aviary.variable_info.variables import Dynamic, Mission def _init_initial_guess_meta_data(cls: PhaseBuilderBase): @@ -68,7 +65,7 @@ def _init_initial_guess_meta_data(cls: PhaseBuilderBase): desc='initial guess for initial time and duration specified as a tuple') cls._add_initial_guess_meta_data( - InitialGuessState('range'), + InitialGuessState('distance'), desc='initial guess for horizontal distance traveled') cls._add_initial_guess_meta_data( @@ -185,40 +182,40 @@ def build_phase(self, aviary_options=None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=True, lower=0, ref=max_range, + Dynamic.Mission.DISTANCE, fix_initial=True, lower=0, ref=max_range, defect_ref=max_range, units=units, upper=max_range, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=True, lower=0, ref=max_velocity, + Dynamic.Mission.VELOCITY, fix_initial=True, lower=0, ref=max_velocity, defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) phase.add_state( - Dynamic.MASS, fix_initial=True, fix_final=False, + Dynamic.Mission.MASS, fix_initial=True, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) # TODO: Energy phase places this under an if num_engines > 0. phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', opt=False ) phase.add_parameter('angle_of_attack', val=0.0, opt=False, units='deg') phase.add_timeseries_output( - Dynamic.THRUST_TOTAL, - output_name=Dynamic.THRUST_TOTAL, units='lbf' + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) phase.add_timeseries_output( - Dynamic.DRAG, output_name=Dynamic.DRAG, units='lbf' + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' ) return phase @@ -355,28 +352,28 @@ def build_phase(self, aviary_options=None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=False, lower=0, ref=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, defect_ref=max_range, units=units, upper=max_range, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, + Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) phase.add_state( - Dynamic.MASS, fix_initial=False, fix_final=False, + Dynamic.Mission.MASS, fix_initial=False, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) # TODO: Energy phase places this under an if num_engines > 0. phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', opt=False ) @@ -385,12 +382,12 @@ def build_phase(self, aviary_options=None): phase.add_parameter('angle_of_attack', val=0.0, opt=False, units='deg') phase.add_timeseries_output( - Dynamic.THRUST_TOTAL, - output_name=Dynamic.THRUST_TOTAL, units='lbf' + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) phase.add_timeseries_output( - Dynamic.DRAG, output_name=Dynamic.DRAG, units='lbf' + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' ) phase.add_timeseries_output( @@ -636,29 +633,29 @@ def build_phase(self, aviary_options=None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=False, lower=0, ref=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, defect_ref=max_range, units=units, upper=max_range, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, + Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) max_angle_of_attack, units = user_options.get_item('max_angle_of_attack') phase.add_state( - Dynamic.MASS, fix_initial=False, fix_final=False, + Dynamic.Mission.MASS, fix_initial=False, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', opt=False ) @@ -668,12 +665,12 @@ def build_phase(self, aviary_options=None): ref=max_angle_of_attack) phase.add_timeseries_output( - Dynamic.DRAG, output_name=Dynamic.DRAG, units='lbf' + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.THRUST_TOTAL, - output_name=Dynamic.THRUST_TOTAL, units='lbf' + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) phase.add_timeseries_output( @@ -824,42 +821,42 @@ def build_phase(self, aviary_options: AviaryValues = None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=False, lower=0, ref=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, defect_ref=max_range, units=units, upper=max_range, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.ALTITUDE, fix_initial=True, lower=0, ref=altitude_ref, + Dynamic.Mission.ALTITUDE, fix_initial=True, lower=0, ref=altitude_ref, defect_ref=altitude_ref, units=units, upper=altitude_ref, - rate_source=Dynamic.ALTITUDE_RATE) + rate_source=Dynamic.Mission.ALTITUDE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, + Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) flight_path_angle_ref, units = user_options.get_item('flight_path_angle_ref') phase.add_state( - Dynamic.FLIGHT_PATH_ANGLE, fix_initial=True, lower=0, + Dynamic.Mission.FLIGHT_PATH_ANGLE, fix_initial=True, lower=0, ref=flight_path_angle_ref, upper=flight_path_angle_ref, defect_ref=flight_path_angle_ref, units=units, - rate_source=Dynamic.FLIGHT_PATH_ANGLE_RATE) + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE) phase.add_state( - Dynamic.MASS, fix_initial=False, fix_final=False, + Dynamic.Mission.MASS, fix_initial=False, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', opt=False ) @@ -873,12 +870,12 @@ def build_phase(self, aviary_options: AviaryValues = None): ref=angle_of_attack_ref) phase.add_timeseries_output( - Dynamic.DRAG, output_name=Dynamic.DRAG, units='lbf' + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.THRUST_TOTAL, - output_name=Dynamic.THRUST_TOTAL, units='lbf' + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) obstacle_height, units = aviary_options.get_item( @@ -894,7 +891,7 @@ def build_phase(self, aviary_options: AviaryValues = None): h = obstacle_height + airport_altitude phase.add_boundary_constraint( - Dynamic.ALTITUDE, loc='final', equals=h, ref=h, units=units, linear=True) + Dynamic.Mission.ALTITUDE, loc='final', equals=h, ref=h, units=units, linear=True) phase.add_path_constraint( 'v_over_v_stall', lower=1.25, ref=2.0) @@ -947,7 +944,7 @@ def _extra_ode_init_kwargs(self): TakeoffLiftoffToObstacle._add_initial_guess_meta_data(InitialGuessState('altitude')) TakeoffLiftoffToObstacle._add_initial_guess_meta_data( - InitialGuessState(Dynamic.FLIGHT_PATH_ANGLE)) + InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE)) @_init_initial_guess_meta_data @@ -1060,42 +1057,42 @@ def build_phase(self, aviary_options: AviaryValues = None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=False, lower=0, ref=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, defect_ref=max_range, units=units, upper=max_range, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, + Dynamic.Mission.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, defect_ref=altitude_ref, units=units, - rate_source=Dynamic.ALTITUDE_RATE) + rate_source=Dynamic.Mission.ALTITUDE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, + Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) flight_path_angle_ref, units = user_options.get_item('flight_path_angle_ref') phase.add_state( - Dynamic.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, + Dynamic.Mission.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, ref=flight_path_angle_ref, defect_ref=flight_path_angle_ref, units=units, - rate_source=Dynamic.FLIGHT_PATH_ANGLE_RATE) + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE) phase.add_state( - Dynamic.MASS, fix_initial=False, fix_final=False, + Dynamic.Mission.MASS, fix_initial=False, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', opt=False ) @@ -1109,12 +1106,12 @@ def build_phase(self, aviary_options: AviaryValues = None): ref=angle_of_attack_ref) phase.add_timeseries_output( - Dynamic.DRAG, output_name=Dynamic.DRAG, units='lbf' + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.THRUST_TOTAL, - output_name=Dynamic.THRUST_TOTAL, units='lbf' + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) final_alt, units = user_options.get_item('mic_altitude') @@ -1125,7 +1122,7 @@ def build_phase(self, aviary_options: AviaryValues = None): h = final_alt + airport_altitude phase.add_boundary_constraint( - Dynamic.ALTITUDE, loc='final', equals=h, ref=h, units=units, linear=True) + Dynamic.Mission.ALTITUDE, loc='final', equals=h, ref=h, units=units, linear=True) phase.add_boundary_constraint( 'v_over_v_stall', loc='final', lower=1.25, ref=1.25) @@ -1179,7 +1176,7 @@ def _extra_ode_init_kwargs(self): TakeoffObstacleToMicP2._add_initial_guess_meta_data(InitialGuessState('altitude')) TakeoffObstacleToMicP2._add_initial_guess_meta_data( - InitialGuessState(Dynamic.FLIGHT_PATH_ANGLE)) + InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE)) @_init_initial_guess_meta_data @@ -1292,42 +1289,42 @@ def build_phase(self, aviary_options: AviaryValues = None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=False, lower=0, ref=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, defect_ref=max_range, units=units, upper=max_range, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, + Dynamic.Mission.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, defect_ref=altitude_ref, units=units, - rate_source=Dynamic.ALTITUDE_RATE) + rate_source=Dynamic.Mission.ALTITUDE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, + Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) flight_path_angle_ref, units = user_options.get_item('flight_path_angle_ref') phase.add_state( - Dynamic.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, + Dynamic.Mission.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, ref=flight_path_angle_ref, defect_ref=flight_path_angle_ref, units=units, - rate_source=Dynamic.FLIGHT_PATH_ANGLE_RATE) + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE) phase.add_state( - Dynamic.MASS, fix_initial=False, fix_final=False, + Dynamic.Mission.MASS, fix_initial=False, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', opt=False ) @@ -1341,12 +1338,12 @@ def build_phase(self, aviary_options: AviaryValues = None): ref=angle_of_attack_ref) phase.add_timeseries_output( - Dynamic.DRAG, output_name=Dynamic.DRAG, units='lbf' + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.THRUST_TOTAL, - output_name=Dynamic.THRUST_TOTAL, units='lbf' + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) # start engine cutback phase at this range, where this phase ends @@ -1356,7 +1353,7 @@ def build_phase(self, aviary_options: AviaryValues = None): final_range, units = user_options.get_item('final_range') phase.add_boundary_constraint( - Dynamic.RANGE, loc='final', equals=final_range, ref=final_range, + Dynamic.Mission.DISTANCE, loc='final', equals=final_range, ref=final_range, units=units, linear=True) phase.add_boundary_constraint( @@ -1412,7 +1409,7 @@ def _extra_ode_init_kwargs(self): TakeoffMicP2ToEngineCutback._add_initial_guess_meta_data(InitialGuessState('altitude')) TakeoffMicP2ToEngineCutback._add_initial_guess_meta_data( - InitialGuessState(Dynamic.FLIGHT_PATH_ANGLE)) + InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE)) @_init_initial_guess_meta_data @@ -1520,42 +1517,42 @@ def build_phase(self, aviary_options: AviaryValues = None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=False, lower=0, ref=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, defect_ref=max_range, units=units, upper=max_range, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, + Dynamic.Mission.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, defect_ref=altitude_ref, units=units, - rate_source=Dynamic.ALTITUDE_RATE) + rate_source=Dynamic.Mission.ALTITUDE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, + Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) flight_path_angle_ref, units = user_options.get_item('flight_path_angle_ref') phase.add_state( - Dynamic.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, + Dynamic.Mission.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, ref=flight_path_angle_ref, defect_ref=flight_path_angle_ref, units=units, - rate_source=Dynamic.FLIGHT_PATH_ANGLE_RATE) + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE) phase.add_state( - Dynamic.MASS, fix_initial=False, fix_final=False, + Dynamic.Mission.MASS, fix_initial=False, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', opt=False ) @@ -1569,12 +1566,12 @@ def build_phase(self, aviary_options: AviaryValues = None): ref=angle_of_attack_ref) phase.add_timeseries_output( - Dynamic.DRAG, output_name=Dynamic.DRAG, units='lbf' + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.THRUST_TOTAL, - output_name=Dynamic.THRUST_TOTAL, units='lbf' + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) phase.add_boundary_constraint( @@ -1623,7 +1620,7 @@ def _extra_ode_init_kwargs(self): TakeoffEngineCutback._add_initial_guess_meta_data(InitialGuessState('altitude')) TakeoffEngineCutback._add_initial_guess_meta_data( - InitialGuessState(Dynamic.FLIGHT_PATH_ANGLE)) + InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE)) @_init_initial_guess_meta_data @@ -1736,42 +1733,42 @@ def build_phase(self, aviary_options: AviaryValues = None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=False, lower=0, ref=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, defect_ref=max_range, units=units, upper=max_range, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, + Dynamic.Mission.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, defect_ref=altitude_ref, units=units, - rate_source=Dynamic.ALTITUDE_RATE) + rate_source=Dynamic.Mission.ALTITUDE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, + Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) flight_path_angle_ref, units = user_options.get_item('flight_path_angle_ref') phase.add_state( - Dynamic.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, + Dynamic.Mission.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, ref=flight_path_angle_ref, defect_ref=flight_path_angle_ref, units=units, - rate_source=Dynamic.FLIGHT_PATH_ANGLE_RATE) + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE) phase.add_state( - Dynamic.MASS, fix_initial=False, fix_final=False, + Dynamic.Mission.MASS, fix_initial=False, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', opt=False ) @@ -1785,18 +1782,18 @@ def build_phase(self, aviary_options: AviaryValues = None): ref=angle_of_attack_ref) phase.add_timeseries_output( - Dynamic.DRAG, output_name=Dynamic.DRAG, units='lbf' + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.THRUST_TOTAL, - output_name=Dynamic.THRUST_TOTAL, units='lbf' + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) mic_range, units = user_options.get_item('mic_range') phase.add_boundary_constraint( - Dynamic.RANGE, loc='final', equals=mic_range, ref=mic_range, + Dynamic.Mission.DISTANCE, loc='final', equals=mic_range, ref=mic_range, units=units, linear=True) phase.add_boundary_constraint( @@ -1852,7 +1849,7 @@ def _extra_ode_init_kwargs(self): TakeoffEngineCutbackToMicP1._add_initial_guess_meta_data(InitialGuessState('altitude')) TakeoffEngineCutbackToMicP1._add_initial_guess_meta_data( - InitialGuessState(Dynamic.FLIGHT_PATH_ANGLE)) + InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE)) @_init_initial_guess_meta_data @@ -1965,42 +1962,42 @@ def build_phase(self, aviary_options: AviaryValues = None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=False, lower=0, ref=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, defect_ref=max_range, units=units, upper=max_range, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') phase.add_state( - Dynamic.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, + Dynamic.Mission.ALTITUDE, fix_initial=False, lower=0, ref=altitude_ref, defect_ref=altitude_ref, units=units, - rate_source=Dynamic.ALTITUDE_RATE) + rate_source=Dynamic.Mission.ALTITUDE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, + Dynamic.Mission.VELOCITY, fix_initial=False, lower=0, ref=max_velocity, defect_ref=max_velocity, units=units, upper=max_velocity, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) flight_path_angle_ref, units = user_options.get_item('flight_path_angle_ref') phase.add_state( - Dynamic.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, + Dynamic.Mission.FLIGHT_PATH_ANGLE, fix_initial=False, lower=0, ref=flight_path_angle_ref, defect_ref=flight_path_angle_ref, units=units, - rate_source=Dynamic.FLIGHT_PATH_ANGLE_RATE) + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE) phase.add_state( - Dynamic.MASS, fix_initial=False, fix_final=False, + Dynamic.Mission.MASS, fix_initial=False, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', opt=False ) @@ -2014,18 +2011,18 @@ def build_phase(self, aviary_options: AviaryValues = None): ref=angle_of_attack_ref) phase.add_timeseries_output( - Dynamic.DRAG, output_name=Dynamic.DRAG, units='lbf' + Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' ) phase.add_timeseries_output( - Dynamic.THRUST_TOTAL, - output_name=Dynamic.THRUST_TOTAL, units='lbf' + Dynamic.Mission.THRUST_TOTAL, + output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) mic_range, units = user_options.get_item('mic_range') phase.add_boundary_constraint( - Dynamic.RANGE, loc='final', equals=mic_range, ref=mic_range, + Dynamic.Mission.DISTANCE, loc='final', equals=mic_range, ref=mic_range, units=units, linear=True) phase.add_boundary_constraint( @@ -2080,7 +2077,7 @@ def _extra_ode_init_kwargs(self): TakeoffMicP1ToClimb._add_initial_guess_meta_data(InitialGuessState('altitude')) TakeoffMicP1ToClimb._add_initial_guess_meta_data( - InitialGuessState(Dynamic.FLIGHT_PATH_ANGLE)) + InitialGuessState(Dynamic.Mission.FLIGHT_PATH_ANGLE)) @_init_initial_guess_meta_data @@ -2185,28 +2182,28 @@ def build_phase(self, aviary_options=None): max_range, units = user_options.get_item('max_range') phase.add_state( - Dynamic.RANGE, fix_initial=False, lower=0, ref=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, defect_ref=max_range, units=units, upper=max_range, - rate_source=Dynamic.RANGE_RATE) + rate_source=Dynamic.Mission.DISTANCE_RATE) max_velocity, units = user_options.get_item('max_velocity') phase.add_state( - Dynamic.VELOCITY, fix_initial=False, fix_final=True, + Dynamic.Mission.VELOCITY, fix_initial=False, fix_final=True, lower=0, ref=max_velocity, upper=max_velocity, defect_ref=max_velocity, units=units, - rate_source=Dynamic.VELOCITY_RATE) + rate_source=Dynamic.Mission.VELOCITY_RATE) phase.add_state( - Dynamic.MASS, fix_initial=False, fix_final=False, + Dynamic.Mission.MASS, fix_initial=False, fix_final=False, lower=0.0, ref=5e4, defect_ref=5e4, units='kg', - rate_source=Dynamic.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.MASS, + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, ) phase.add_control( - Dynamic.THROTTLE, - targets=Dynamic.THROTTLE, units='unitless', + Dynamic.Mission.THROTTLE, + targets=Dynamic.Mission.THROTTLE, units='unitless', opt=False ) @@ -2519,7 +2516,7 @@ def _link_phases(self): brake_release_name = self._brake_release_to_decision_speed.name decision_speed_name = self._decision_speed_to_rotate.name - basic_vars = ['time', 'range', 'velocity', 'mass'] + basic_vars = ['time', 'distance', 'velocity', 'mass'] traj.link_phases([brake_release_name, decision_speed_name], vars=basic_vars) @@ -2542,7 +2539,7 @@ def _link_phases(self): engine_cutback_to_mic_p1_name = self._engine_cutback_to_mic_p1.name mic_p1_to_climb_name = self._mic_p1_to_climb.name - acoustics_vars = ext_vars + [Dynamic.FLIGHT_PATH_ANGLE, 'altitude'] + acoustics_vars = ext_vars + [Dynamic.Mission.FLIGHT_PATH_ANGLE, 'altitude'] traj.link_phases( [liftoff_name, obstacle_to_mic_p2_name], @@ -2574,8 +2571,8 @@ def _link_phases(self): traj.link_phases([brake_name, abort_name], vars=basic_vars) traj.add_linkage_constraint( - phase_a=abort_name, var_a='range', loc_a='final', - phase_b=liftoff_name, var_b='range', loc_b='final', + phase_a=abort_name, var_a='distance', loc_a='final', + phase_b=liftoff_name, var_b='distance', loc_b='final', ref=self._balanced_field_ref) def _add_phase(self, phase_builder: PhaseBuilderBase, aviary_options: AviaryValues): diff --git a/aviary/mission/flops_based/phases/energy_phase.py b/aviary/mission/flops_based/phases/energy_phase.py index 94ac79e4a..65f6c2f2e 100644 --- a/aviary/mission/flops_based/phases/energy_phase.py +++ b/aviary/mission/flops_based/phases/energy_phase.py @@ -242,13 +242,13 @@ def build_phase(self, aviary_options: AviaryValues = None): input_initial=input_initial_mass ) - input_initial_range = get_initial(input_initial, Dynamic.Mission.RANGE) - fix_initial_range = get_initial(fix_initial, Dynamic.Mission.RANGE, True) + input_initial_distance = get_initial(input_initial, Dynamic.Mission.DISTANCE) + fix_initial_distance = get_initial(fix_initial, Dynamic.Mission.DISTANCE, True) phase.add_state( - Dynamic.Mission.RANGE, fix_initial=fix_initial_range, fix_final=fix_range, + Dynamic.Mission.DISTANCE, fix_initial=fix_initial_distance, fix_final=fix_range, lower=0.0, ref=1e6, defect_ref=1e6, units='m', - rate_source=Dynamic.Mission.RANGE_RATE, - input_initial=input_initial_range + rate_source=Dynamic.Mission.DISTANCE_RATE, + input_initial=input_initial_distance ) phase = add_subsystem_variables_to_phase( @@ -517,7 +517,7 @@ def _extra_ode_init_kwargs(self): desc='initial guess for initial time and duration specified as a tuple') EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('range'), + InitialGuessState('distance'), desc='initial guess for horizontal distance traveled') EnergyPhase._add_initial_guess_meta_data( diff --git a/aviary/mission/flops_based/phases/simple_energy_phase.py b/aviary/mission/flops_based/phases/simple_energy_phase.py index e5ffd1928..0927925dc 100644 --- a/aviary/mission/flops_based/phases/simple_energy_phase.py +++ b/aviary/mission/flops_based/phases/simple_energy_phase.py @@ -189,13 +189,13 @@ def build_phase(self, aviary_options: AviaryValues = None): # solve_segments='forward', ) - input_initial_range = get_initial(input_initial, Dynamic.Mission.RANGE) - fix_initial_range = get_initial(fix_initial, Dynamic.Mission.RANGE, True) + input_initial_distance = get_initial(input_initial, Dynamic.Mission.DISTANCE) + fix_initial_distance = get_initial(fix_initial, Dynamic.Mission.DISTANCE, True) phase.add_state( - Dynamic.Mission.RANGE, fix_initial=fix_initial_range, fix_final=False, + Dynamic.Mission.DISTANCE, fix_initial=fix_initial_distance, fix_final=False, lower=0.0, ref=1e6, defect_ref=1e8, units='m', - rate_source=Dynamic.Mission.RANGE_RATE, - input_initial=input_initial_range, + rate_source=Dynamic.Mission.DISTANCE_RATE, + input_initial=input_initial_distance, solve_segments='forward' if solve_for_range else None, ) @@ -385,7 +385,7 @@ def _extra_ode_init_kwargs(self): desc='initial guess for initial time and duration specified as a tuple') EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('range'), + InitialGuessState('distance'), desc='initial guess for horizontal distance traveled') EnergyPhase._add_initial_guess_meta_data( diff --git a/aviary/mission/gasp_based/phases/run_phases/run_climb.py b/aviary/mission/gasp_based/phases/run_phases/run_climb.py index fadcd2155..003222ec4 100644 --- a/aviary/mission/gasp_based/phases/run_phases/run_climb.py +++ b/aviary/mission/gasp_based/phases/run_phases/run_climb.py @@ -28,7 +28,7 @@ "time": ("TIME", "time", "s"), Dynamic.Mission.ALTITUDE: ("ALT", "states:altitude", "ft"), "mass": ("MASS", "states:mass", "lbm"), - Dynamic.Mission.DISTANCE: (Dynamic.Mission.RANGE, "states:distance", "NM"), + Dynamic.Mission.DISTANCE: (Dynamic.Mission.DISTANCE, "states:distance", "NM"), Dynamic.Mission.MACH: ("MACH", Dynamic.Mission.MACH, None), "EAS": ("EAS", "EAS", "kn"), "alpha": ("ALPHA", "alpha", "deg"), diff --git a/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py b/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py index fc3283d4c..13d7c45fc 100644 --- a/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py +++ b/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py @@ -30,7 +30,7 @@ "time": ("TIME", "time", "s"), Dynamic.Mission.ALTITUDE: ("ALT", "states:altitude", "ft"), "mass": ("MASS", "states:mass", "lbm"), - Dynamic.Mission.DISTANCE: (Dynamic.Mission.RANGE, "states:distance", "NM"), + Dynamic.Mission.DISTANCE: (Dynamic.Mission.DISTANCE, "states:distance", "NM"), Dynamic.Mission.MACH: ("MACH", Dynamic.Mission.MACH, None), "EAS": ("EAS", "EAS", "kn"), "alpha": ("ALPHA", "alpha", "deg"), diff --git a/aviary/models/N3CC/N3CC_data.py b/aviary/models/N3CC/N3CC_data.py index a163553ea..c8cce58c9 100644 --- a/aviary/models/N3CC/N3CC_data.py +++ b/aviary/models/N3CC/N3CC_data.py @@ -21,14 +21,10 @@ 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.variables import Aircraft -from aviary.variable_info.variables import Dynamic as _Dynamic -from aviary.variable_info.variables import Mission -from aviary.variable_info.variables import Settings +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 -Dynamic = _Dynamic.Mission N3CC = {} inputs = N3CC['inputs'] = AviaryValues() @@ -490,7 +486,7 @@ takeoff_brake_release_initial_guesses = AviaryValues() takeoff_brake_release_initial_guesses.set_val('times', [0., 30.], 's') -takeoff_brake_release_initial_guesses.set_val('range', [0., 4100.], 'ft') +takeoff_brake_release_initial_guesses.set_val('distance', [0., 4100.], 'ft') takeoff_brake_release_initial_guesses.set_val('velocity', [0.01, 150.], 'kn') gross_mass_units = 'lbm' @@ -523,7 +519,7 @@ takeoff_decision_speed_initial_guesses = AviaryValues() takeoff_decision_speed_initial_guesses.set_val('times', [30., 2.], 's') -takeoff_decision_speed_initial_guesses.set_val('range', [4100., 4500.], 'ft') +takeoff_decision_speed_initial_guesses.set_val('distance', [4100., 4500.], 'ft') takeoff_decision_speed_initial_guesses.set_val('velocity', [150., 160.], 'kn') takeoff_decision_speed_initial_guesses.set_val('mass', gross_mass, gross_mass_units) takeoff_decision_speed_initial_guesses.set_val('throttle', 1.) @@ -552,7 +548,7 @@ takeoff_rotate_initial_guesses = AviaryValues() takeoff_rotate_initial_guesses.set_val('times', [32., 1.], 's') -takeoff_rotate_initial_guesses.set_val('range', [4500, 4800.0], 'ft') +takeoff_rotate_initial_guesses.set_val('distance', [4500, 4800.0], 'ft') takeoff_rotate_initial_guesses.set_val('velocity', [160., 160.0], 'kn') takeoff_rotate_initial_guesses.set_val('throttle', 1.) takeoff_rotate_initial_guesses.set_val('angle_of_attack', [0., 8.], 'deg') @@ -585,11 +581,12 @@ takeoff_liftoff_initial_guesses = AviaryValues() takeoff_liftoff_initial_guesses.set_val('times', [33., 4.], 's') -takeoff_liftoff_initial_guesses.set_val('range', [4800, 5700.0], 'ft') +takeoff_liftoff_initial_guesses.set_val('distance', [4800, 5700.0], 'ft') takeoff_liftoff_initial_guesses.set_val('velocity', [160, 167.0], 'kn') takeoff_liftoff_initial_guesses.set_val('throttle', 1.) takeoff_liftoff_initial_guesses.set_val('altitude', [0, 35.0], 'ft') -takeoff_liftoff_initial_guesses.set_val(Dynamic.FLIGHT_PATH_ANGLE, [0, 6.0], 'deg') +takeoff_liftoff_initial_guesses.set_val( + Dynamic.Mission.FLIGHT_PATH_ANGLE, [0, 6.0], 'deg') takeoff_liftoff_initial_guesses.set_val('angle_of_attack', 8.117, 'deg') takeoff_liftoff_initial_guesses.set_val('mass', gross_mass, gross_mass_units) @@ -627,11 +624,12 @@ takeoff_mic_p2_initial_guesses = AviaryValues() takeoff_mic_p2_initial_guesses.set_val('times', [36., 18], 's') -takeoff_mic_p2_initial_guesses.set_val('range', [5700, 10000.0], 'ft') +takeoff_mic_p2_initial_guesses.set_val('distance', [5700, 10000.0], 'ft') takeoff_mic_p2_initial_guesses.set_val('velocity', [167, 167.0], 'kn') takeoff_mic_p2_initial_guesses.set_val('throttle', 1.) takeoff_mic_p2_initial_guesses.set_val('altitude', [35, 985.0], 'ft') -takeoff_mic_p2_initial_guesses.set_val(Dynamic.FLIGHT_PATH_ANGLE, [7.0, 10.0], 'deg') +takeoff_mic_p2_initial_guesses.set_val( + Dynamic.Mission.FLIGHT_PATH_ANGLE, [7.0, 10.0], 'deg') takeoff_mic_p2_initial_guesses.set_val('angle_of_attack', 8.117, 'deg') takeoff_mic_p2_initial_guesses.set_val('mass', gross_mass, gross_mass_units) @@ -679,13 +677,14 @@ takeoff_mic_p2_to_engine_cutback_initial_guesses = AviaryValues() takeoff_mic_p2_to_engine_cutback_initial_guesses.set_val('times', [53., 27], 's') -takeoff_mic_p2_to_engine_cutback_initial_guesses.set_val('range', [10000, 19000.0], 'ft') +takeoff_mic_p2_to_engine_cutback_initial_guesses.set_val( + 'distance', [10000, 19000.0], 'ft') takeoff_mic_p2_to_engine_cutback_initial_guesses.set_val('velocity', [167, 167.0], 'kn') takeoff_mic_p2_to_engine_cutback_initial_guesses.set_val('throttle', 1.0) takeoff_mic_p2_to_engine_cutback_initial_guesses.set_val('altitude', [985, 2500.0], 'ft') takeoff_mic_p2_to_engine_cutback_initial_guesses.set_val( - Dynamic.FLIGHT_PATH_ANGLE, [11.0, 10.0], 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, [11.0, 10.0], 'deg') takeoff_mic_p2_to_engine_cutback_initial_guesses.set_val('angle_of_attack', 5.0, 'deg') @@ -734,13 +733,13 @@ takeoff_engine_cutback_initial_guesses = AviaryValues() takeoff_engine_cutback_initial_guesses.set_val('times', [84., cutback_duration], 's') -takeoff_engine_cutback_initial_guesses.set_val('range', [19000, 20000.0], 'ft') +takeoff_engine_cutback_initial_guesses.set_val('distance', [19000, 20000.0], 'ft') takeoff_engine_cutback_initial_guesses.set_val('velocity', [167, 167.0], 'kn') takeoff_engine_cutback_initial_guesses.set_val('throttle', [1.0, cutback_throttle]) takeoff_engine_cutback_initial_guesses.set_val('altitude', [2500.0, 2600.0], 'ft') takeoff_engine_cutback_initial_guesses.set_val( - Dynamic.FLIGHT_PATH_ANGLE, [10.0, 10.0], 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, [10.0, 10.0], 'deg') takeoff_engine_cutback_initial_guesses.set_val('angle_of_attack', 5.0, 'deg') takeoff_engine_cutback_initial_guesses.set_val('mass', gross_mass, gross_mass_units) @@ -792,7 +791,8 @@ takeoff_engine_cutback_to_mic_p1_initial_guesses = AviaryValues() takeoff_engine_cutback_to_mic_p1_initial_guesses.set_val('times', [87., 10], 's') -takeoff_engine_cutback_to_mic_p1_initial_guesses.set_val('range', [20000, 21325.0], 'ft') +takeoff_engine_cutback_to_mic_p1_initial_guesses.set_val( + 'distance', [20000, 21325.0], 'ft') takeoff_engine_cutback_to_mic_p1_initial_guesses.set_val('velocity', [167, 167.0], 'kn') takeoff_engine_cutback_to_mic_p1_initial_guesses.set_val('throttle', cutback_throttle) @@ -800,7 +800,7 @@ 'altitude', [2600, 2700.0], 'ft') takeoff_engine_cutback_to_mic_p1_initial_guesses.set_val( - Dynamic.FLIGHT_PATH_ANGLE, 2.29, 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, 2.29, 'deg') takeoff_engine_cutback_to_mic_p1_initial_guesses.set_val('angle_of_attack', 5.0, 'deg') takeoff_engine_cutback_to_mic_p1_initial_guesses.set_val( @@ -842,11 +842,12 @@ takeoff_mic_p1_to_climb_initial_guesses = AviaryValues() takeoff_mic_p1_to_climb_initial_guesses.set_val('times', [95., 32], 's') -takeoff_mic_p1_to_climb_initial_guesses.set_val('range', [21325, 30000.0], 'ft') +takeoff_mic_p1_to_climb_initial_guesses.set_val('distance', [21325, 30000.0], 'ft') takeoff_mic_p1_to_climb_initial_guesses.set_val('velocity', [167, 167.0], 'kn') takeoff_mic_p1_to_climb_initial_guesses.set_val('throttle', cutback_throttle) takeoff_mic_p1_to_climb_initial_guesses.set_val('altitude', [2700, 3200.0], 'ft') -takeoff_mic_p1_to_climb_initial_guesses.set_val(Dynamic.FLIGHT_PATH_ANGLE, 2.29, 'deg') +takeoff_mic_p1_to_climb_initial_guesses.set_val( + Dynamic.Mission.FLIGHT_PATH_ANGLE, 2.29, 'deg') takeoff_mic_p1_to_climb_initial_guesses.set_val('angle_of_attack', 5.0, 'deg') takeoff_mic_p1_to_climb_initial_guesses.set_val('mass', gross_mass, gross_mass_units) @@ -867,51 +868,54 @@ detailed_takeoff = AviaryValues() detailed_takeoff.set_val('time', [0.77, 32.01, 33.00, 35.40], 's') -detailed_takeoff.set_val(Dynamic.RANGE, [3.08, 4626.88, 4893.40, 5557.61], 'ft') -detailed_takeoff.set_val(Dynamic.ALTITUDE, [0.00, 0.00, 0.64, 27.98], 'ft') +detailed_takeoff.set_val(Dynamic.Mission.DISTANCE, [ + 3.08, 4626.88, 4893.40, 5557.61], 'ft') +detailed_takeoff.set_val(Dynamic.Mission.ALTITUDE, [0.00, 0.00, 0.64, 27.98], 'ft') velocity = np.array([4.74, 157.58, 160.99, 166.68]) -detailed_takeoff.set_val(Dynamic.VELOCITY, velocity, 'kn') -detailed_takeoff.set_val(Dynamic.MACH, [0.007, 0.2342, 0.2393, 0.2477]) +detailed_takeoff.set_val(Dynamic.Mission.VELOCITY, velocity, 'kn') +detailed_takeoff.set_val(Dynamic.Mission.MACH, [0.007, 0.2342, 0.2393, 0.2477]) detailed_takeoff.set_val( - Dynamic.THRUST_TOTAL, [44038.8, 34103.4, 33929.0, 33638.2], 'lbf') + Dynamic.Mission.THRUST_TOTAL, [44038.8, 34103.4, 33929.0, 33638.2], 'lbf') detailed_takeoff.set_val('angle_of_attack', [0.000, 3.600, 8.117, 8.117], 'deg') -detailed_takeoff.set_val(Dynamic.FLIGHT_PATH_ANGLE, [0.000, 0.000, 0.612, 4.096], 'deg') +detailed_takeoff.set_val(Dynamic.Mission.FLIGHT_PATH_ANGLE, [ + 0.000, 0.000, 0.612, 4.096], 'deg') # missing from the default FLOPS output generated by hand # RANGE_RATE = VELOCITY * cos(flight_path_angle) range_rate = np.array([4.74, 157.58, 160.98, 166.25]) -detailed_takeoff.set_val(Dynamic.RANGE_RATE, range_rate, 'kn') +detailed_takeoff.set_val(Dynamic.Mission.DISTANCE_RATE, range_rate, 'kn') # ALTITUDE_RATE = VELOCITY * sin(flight_path_angle) altitude_rate = np.array([0.00, 0.00, 1.72, 11.91]) -detailed_takeoff.set_val(Dynamic.ALTITUDE_RATE, altitude_rate, 'kn') +detailed_takeoff.set_val(Dynamic.Mission.ALTITUDE_RATE, altitude_rate, 'kn') # NOTE FLOPS output is horizontal acceleration only # - divide the FLOPS values by the cos(flight_path_angle) -# detailed_takeoff.set_val(Dynamic.VELOCITY_RATE, [10.36, 6.20, 5.23, 2.69], 'ft/s**2') +# detailed_takeoff.set_val(Dynamic.Mission.VELOCITY_RATE, [10.36, 6.20, 5.23, 2.69], 'ft/s**2') velocity_rate = [10.36, 6.20, 5.23, 2.70] -detailed_takeoff.set_val(Dynamic.VELOCITY_RATE, velocity_rate, 'ft/s**2') +detailed_takeoff.set_val(Dynamic.Mission.VELOCITY_RATE, velocity_rate, 'ft/s**2') # NOTE FLOPS output is based on "constant" takeoff mass - assume gross weight # - currently neglecting taxi -detailed_takeoff.set_val(Dynamic.MASS, [129734., 129734., 129734., 129734.], 'lbm') +detailed_takeoff.set_val(Dynamic.Mission.MASS, [ + 129734., 129734., 129734., 129734.], 'lbm') lift_coeff = np.array([0.5580, 0.9803, 1.4831, 1.3952]) drag_coeff = np.array([0.0801, 0.0859, 0.1074, 0.1190]) S = inputs.get_val(Aircraft.Wing.AREA, 'm**2') -v = detailed_takeoff.get_val(Dynamic.VELOCITY, 'm/s') +v = detailed_takeoff.get_val(Dynamic.Mission.VELOCITY, 'm/s') # NOTE sea level; includes effect of FLOPS &TOLIN DTCT 10 DEG C rho = 1.18391 # kg/m**3 RHV2 = 0.5 * rho * v * v * S lift = RHV2 * lift_coeff # N -detailed_takeoff.set_val(Dynamic.LIFT, lift, 'N') +detailed_takeoff.set_val(Dynamic.Mission.LIFT, lift, 'N') drag = RHV2 * drag_coeff # N -detailed_takeoff.set_val(Dynamic.DRAG, drag, 'N') +detailed_takeoff.set_val(Dynamic.Mission.DRAG, drag, 'N') def _split_aviary_values(aviary_values, slicing): @@ -941,7 +945,7 @@ def _split_aviary_values(aviary_values, slicing): balanced_brake_release_initial_guesses = AviaryValues() balanced_brake_release_initial_guesses.set_val('times', [0., 30.], 's') -balanced_brake_release_initial_guesses.set_val('range', [0., 4100.], 'ft') +balanced_brake_release_initial_guesses.set_val('distance', [0., 4100.], 'ft') balanced_brake_release_initial_guesses.set_val('velocity', [0.01, 150.], 'kn') balanced_brake_release_initial_guesses.set_val('mass', gross_mass, gross_mass_units) balanced_brake_release_initial_guesses.set_val('throttle', 1.) @@ -971,7 +975,7 @@ def _split_aviary_values(aviary_values, slicing): engine_out_throttle = (num_engines - 1) / num_engines balanced_decision_speed_initial_guesses.set_val('times', [30., 2.], 's') -balanced_decision_speed_initial_guesses.set_val('range', [4100., 4500.], 'ft') +balanced_decision_speed_initial_guesses.set_val('distance', [4100., 4500.], 'ft') balanced_decision_speed_initial_guesses.set_val('velocity', [150., 160.], 'kn') balanced_decision_speed_initial_guesses.set_val('mass', gross_mass, gross_mass_units) balanced_decision_speed_initial_guesses.set_val('throttle', engine_out_throttle) @@ -999,7 +1003,7 @@ def _split_aviary_values(aviary_values, slicing): balanced_rotate_initial_guesses = AviaryValues() balanced_rotate_initial_guesses.set_val('times', [32., 1.], 's') -balanced_rotate_initial_guesses.set_val('range', [4500., 4800.], 'ft') +balanced_rotate_initial_guesses.set_val('distance', [4500., 4800.], 'ft') balanced_rotate_initial_guesses.set_val('velocity', [160., 160.], 'kn') balanced_rotate_initial_guesses.set_val('throttle', engine_out_throttle) balanced_rotate_initial_guesses.set_val('angle_of_attack', [0., 8.], 'deg') @@ -1031,11 +1035,12 @@ def _split_aviary_values(aviary_values, slicing): balanced_liftoff_initial_guesses = AviaryValues() balanced_liftoff_initial_guesses.set_val('times', [33., 4.], 's') -balanced_liftoff_initial_guesses.set_val('range', [4800., 7000.], 'ft') +balanced_liftoff_initial_guesses.set_val('distance', [4800., 7000.], 'ft') balanced_liftoff_initial_guesses.set_val('velocity', [160., 167.], 'kn') balanced_liftoff_initial_guesses.set_val('throttle', engine_out_throttle) balanced_liftoff_initial_guesses.set_val('altitude', [0., 35.], 'ft') -balanced_liftoff_initial_guesses.set_val(Dynamic.FLIGHT_PATH_ANGLE, [0., 5.], 'deg') +balanced_liftoff_initial_guesses.set_val( + Dynamic.Mission.FLIGHT_PATH_ANGLE, [0., 5.], 'deg') balanced_liftoff_initial_guesses.set_val('angle_of_attack', 8.117, 'deg') balanced_liftoff_initial_guesses.set_val('mass', gross_mass, gross_mass_units) @@ -1059,7 +1064,7 @@ def _split_aviary_values(aviary_values, slicing): balanced_delayed_brake_initial_guesses = AviaryValues() balanced_delayed_brake_initial_guesses.set_val('times', [30., 3.], 's') -balanced_delayed_brake_initial_guesses.set_val('range', [4100., 4600.], 'ft') +balanced_delayed_brake_initial_guesses.set_val('distance', [4100., 4600.], 'ft') balanced_delayed_brake_initial_guesses.set_val('velocity', [150., 150.], 'kn') balanced_delayed_brake_initial_guesses.set_val('mass', gross_mass, gross_mass_units) balanced_delayed_brake_initial_guesses.set_val('throttle', engine_out_throttle) @@ -1086,7 +1091,7 @@ def _split_aviary_values(aviary_values, slicing): balanced_abort_initial_guesses = AviaryValues() balanced_abort_initial_guesses.set_val('times', [32., 22.], 's') -balanced_abort_initial_guesses.set_val('range', [4600., 7000.], 'ft') +balanced_abort_initial_guesses.set_val('distance', [4600., 7000.], 'ft') balanced_abort_initial_guesses.set_val('velocity', [150., 0.01], 'kn') balanced_abort_initial_guesses.set_val('mass', gross_mass, gross_mass_units) balanced_abort_initial_guesses.set_val('throttle', 0.) @@ -1179,10 +1184,10 @@ def _split_aviary_values(aviary_values, slicing): base = values[0] values = values - base -detailed_landing.set_val(Dynamic.RANGE, values, 'ft') +detailed_landing.set_val(Dynamic.Mission.DISTANCE, values, 'ft') detailed_landing.set_val( - Dynamic.ALTITUDE, + Dynamic.Mission.ALTITUDE, [ 100, 100, 98, 96, 94, 92, 90, 88, 86, 84, 82, 80, 78, 76, 74, 72, 70, 68, 66, 64, @@ -1194,7 +1199,7 @@ def _split_aviary_values(aviary_values, slicing): 'ft') detailed_landing.set_val( - Dynamic.VELOCITY, + Dynamic.Mission.VELOCITY, np.array([ 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, 138.65, @@ -1206,7 +1211,7 @@ def _split_aviary_values(aviary_values, slicing): 'kn') detailed_landing.set_val( - Dynamic.MACH, + Dynamic.Mission.MACH, [ 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, 0.2061, @@ -1217,7 +1222,7 @@ def _split_aviary_values(aviary_values, slicing): 0.086, 0.0756, 0.0653, 0.0551, 0.045, 0.035, 0.025, 0.015, 0.0051, 0]) detailed_landing.set_val( - Dynamic.THRUST_TOTAL, + Dynamic.Mission.THRUST_TOTAL, [ 7614, 7614, 7607.7, 7601, 7593.9, 7586.4, 7578.5, 7570.2, 7561.3, 7551.8, 7541.8, 7531.1, 7519.7, 7507.6, 7494.6, 7480.6, 7465.7, 7449.7, 7432.5, 7414, @@ -1242,7 +1247,7 @@ def _split_aviary_values(aviary_values, slicing): # glide slope == flight path angle? detailed_landing.set_val( - Dynamic.FLIGHT_PATH_ANGLE, + Dynamic.Mission.FLIGHT_PATH_ANGLE, np.array([ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, @@ -1255,13 +1260,13 @@ def _split_aviary_values(aviary_values, slicing): # missing from the default FLOPS output generated by script # RANGE_RATE = VELOCITY * cos(flight_path_angle) -velocity: np.ndarray = detailed_landing.get_val(Dynamic.VELOCITY, 'kn') -flight_path_angle = detailed_landing.get_val(Dynamic.FLIGHT_PATH_ANGLE, 'rad') +velocity: np.ndarray = detailed_landing.get_val(Dynamic.Mission.VELOCITY, 'kn') +flight_path_angle = detailed_landing.get_val(Dynamic.Mission.FLIGHT_PATH_ANGLE, 'rad') range_rate = velocity * np.cos(-flight_path_angle) -detailed_landing.set_val(Dynamic.RANGE_RATE, range_rate, 'kn') +detailed_landing.set_val(Dynamic.Mission.DISTANCE_RATE, range_rate, 'kn') # ALTITUDE_RATE = VELOCITY * sin(flight_path_angle) altitude_rate = velocity * np.sin(flight_path_angle) -detailed_landing.set_val(Dynamic.ALTITUDE_RATE, altitude_rate, 'kn') +detailed_landing.set_val(Dynamic.Mission.ALTITUDE_RATE, altitude_rate, 'kn') # NOTE FLOPS output is horizontal acceleration only, and virtually no acceleration while # airborne @@ -1272,7 +1277,7 @@ def _split_aviary_values(aviary_values, slicing): detailed_landing_mass = 106292. # units='lbm' detailed_landing.set_val( - Dynamic.MASS, np.full(velocity.shape, detailed_landing_mass), 'lbm') + Dynamic.Mission.MASS, np.full(velocity.shape, detailed_landing_mass), 'lbm') # lift/drag is calculated very close to landing altitude (sea level, in this case)... lift_coeff = np.array([ @@ -1294,17 +1299,17 @@ def _split_aviary_values(aviary_values, slicing): 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785, 0.1785]) S = inputs.get_val(Aircraft.Wing.AREA, 'm**2') -v = detailed_landing.get_val(Dynamic.VELOCITY, 'm/s') +v = detailed_landing.get_val(Dynamic.Mission.VELOCITY, 'm/s') # NOTE sea level; includes effect of FLOPS &TOLIN DTCT 10 DEG C rho = 1.18391 # kg/m**3 RHV2 = 0.5 * rho * v * v * S lift = RHV2 * lift_coeff # N -detailed_landing.set_val(Dynamic.LIFT, lift, 'N') +detailed_landing.set_val(Dynamic.Mission.LIFT, lift, 'N') drag = RHV2 * drag_coeff # N -detailed_landing.set_val(Dynamic.DRAG, drag, 'N') +detailed_landing.set_val(Dynamic.Mission.DRAG, drag, 'N') # Flops variable APRANG apr_angle = -3.0 # deg @@ -1338,14 +1343,14 @@ def _split_aviary_values(aviary_values, slicing): landing_approach_to_mic_p3_initial_guesses = AviaryValues() landing_approach_to_mic_p3_initial_guesses.set_val('times', [-42., 15.], 's') -landing_approach_to_mic_p3_initial_guesses.set_val('range', [-4000., -2000.], 'ft') +landing_approach_to_mic_p3_initial_guesses.set_val('distance', [-4000., -2000.], 'ft') landing_approach_to_mic_p3_initial_guesses.set_val('velocity', 140., 'kn') landing_approach_to_mic_p3_initial_guesses.set_val('mass', detailed_landing_mass, 'lbm') landing_approach_to_mic_p3_initial_guesses.set_val('throttle', throttle) landing_approach_to_mic_p3_initial_guesses.set_val('altitude', [600., 394.], 'ft') landing_approach_to_mic_p3_initial_guesses.set_val( - Dynamic.FLIGHT_PATH_ANGLE, [apr_angle, apr_angle], 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, [apr_angle, apr_angle], 'deg') landing_approach_to_mic_p3_initial_guesses.set_val('angle_of_attack', 5.25, 'deg') @@ -1389,14 +1394,14 @@ def _split_aviary_values(aviary_values, slicing): landing_mic_p3_to_obstacle_initial_guesses = AviaryValues() landing_mic_p3_to_obstacle_initial_guesses.set_val('times', [-27., 27.], 's') -landing_mic_p3_to_obstacle_initial_guesses.set_val('range', [-2000., 0.], 'ft') +landing_mic_p3_to_obstacle_initial_guesses.set_val('distance', [-2000., 0.], 'ft') landing_mic_p3_to_obstacle_initial_guesses.set_val('velocity', 140., 'kn') landing_mic_p3_to_obstacle_initial_guesses.set_val('mass', detailed_landing_mass, 'lbm') landing_mic_p3_to_obstacle_initial_guesses.set_val('throttle', throttle) landing_mic_p3_to_obstacle_initial_guesses.set_val('altitude', [394., 50.], 'ft') landing_mic_p3_to_obstacle_initial_guesses.set_val( - Dynamic.FLIGHT_PATH_ANGLE, [apr_angle, apr_angle], 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, [apr_angle, apr_angle], 'deg') landing_mic_p3_to_obstacle_initial_guesses.set_val('angle_of_attack', 5.25, 'deg') @@ -1427,14 +1432,14 @@ def _split_aviary_values(aviary_values, slicing): landing_obstacle_initial_guesses = AviaryValues() landing_obstacle_initial_guesses.set_val('times', [0., 4.], 's') -landing_obstacle_initial_guesses.set_val('range', [0., 800.], 'ft') +landing_obstacle_initial_guesses.set_val('distance', [0., 800.], 'ft') landing_obstacle_initial_guesses.set_val('velocity', 140., 'kn') landing_obstacle_initial_guesses.set_val('mass', detailed_landing_mass, 'lbm') landing_obstacle_initial_guesses.set_val('throttle', throttle) landing_obstacle_initial_guesses.set_val('altitude', [50., 15.], 'ft') landing_obstacle_initial_guesses.set_val( - Dynamic.FLIGHT_PATH_ANGLE, [apr_angle, apr_angle], 'deg') + Dynamic.Mission.FLIGHT_PATH_ANGLE, [apr_angle, apr_angle], 'deg') landing_obstacle_initial_guesses.set_val('angle_of_attack', 5.2, 'deg') @@ -1469,12 +1474,13 @@ def _split_aviary_values(aviary_values, slicing): landing_flare_initial_guesses = AviaryValues() landing_flare_initial_guesses.set_val('times', [4., 6.], 's') -landing_flare_initial_guesses.set_val('range', [800., 1000.], 'ft') +landing_flare_initial_guesses.set_val('distance', [800., 1000.], 'ft') landing_flare_initial_guesses.set_val('velocity', 140., 'kn') landing_flare_initial_guesses.set_val('mass', detailed_landing_mass, 'lbm') landing_flare_initial_guesses.set_val('throttle', [throttle, throttle*4/7]) landing_flare_initial_guesses.set_val('altitude', [15., 0.], 'ft') -landing_flare_initial_guesses.set_val(Dynamic.FLIGHT_PATH_ANGLE, [apr_angle, 0.], 'deg') +landing_flare_initial_guesses.set_val( + Dynamic.Mission.FLIGHT_PATH_ANGLE, [apr_angle, 0.], 'deg') landing_flare_initial_guesses.set_val('angle_of_attack', [5.2, 7.5], 'deg') landing_flare_builder = LandingFlareToTouchdown( @@ -1504,7 +1510,7 @@ def _split_aviary_values(aviary_values, slicing): landing_touchdown_initial_guesses = AviaryValues() landing_touchdown_initial_guesses.set_val('times', [6., 9.], 's') -landing_touchdown_initial_guesses.set_val('range', [1000., 1400.], 'ft') +landing_touchdown_initial_guesses.set_val('distance', [1000., 1400.], 'ft') landing_touchdown_initial_guesses.set_val('velocity', [140., 135.], 'kn') landing_touchdown_initial_guesses.set_val('mass', detailed_landing_mass, 'lbm') landing_touchdown_initial_guesses.set_val('throttle', 0.) @@ -1536,7 +1542,7 @@ def _split_aviary_values(aviary_values, slicing): landing_fullstop_initial_guesses = AviaryValues() landing_fullstop_initial_guesses.set_val('times', [9., 29.], 's') -landing_fullstop_initial_guesses.set_val('range', [1400., 3500.], 'ft') +landing_fullstop_initial_guesses.set_val('distance', [1400., 3500.], 'ft') landing_fullstop_initial_guesses.set_val('velocity', [135., 0.01], 'kn') landing_fullstop_initial_guesses.set_val('mass', detailed_landing_mass, 'lbm') landing_fullstop_initial_guesses.set_val('throttle', 0.) diff --git a/aviary/subsystems/aerodynamics/flops_based/ground_effect.py b/aviary/subsystems/aerodynamics/flops_based/ground_effect.py index 27aee4eee..8a6efb8dc 100644 --- a/aviary/subsystems/aerodynamics/flops_based/ground_effect.py +++ b/aviary/subsystems/aerodynamics/flops_based/ground_effect.py @@ -11,10 +11,7 @@ import openmdao.api as om from aviary.variable_info.functions import add_aviary_input -from aviary.variable_info.variables import Aircraft -from aviary.variable_info.variables import Dynamic as _Dynamic - -Dynamic = _Dynamic.Mission +from aviary.variable_info.variables import Aircraft, Dynamic class GroundEffect(om.ExplicitComponent): @@ -41,9 +38,10 @@ def setup(self): self.add_input('angle_of_attack', val=np.zeros(nn), units='rad') - add_aviary_input(self, Dynamic.ALTITUDE, np.zeros(nn), units='m') + add_aviary_input(self, Dynamic.Mission.ALTITUDE, np.zeros(nn), units='m') - add_aviary_input(self, Dynamic.FLIGHT_PATH_ANGLE, val=np.zeros(nn), units='rad') + add_aviary_input(self, Dynamic.Mission.FLIGHT_PATH_ANGLE, + val=np.zeros(nn), units='rad') self.add_input( 'minimum_drag_coefficient', 0.0, @@ -83,14 +81,14 @@ def setup_partials(self): ) self.declare_partials( - 'lift_coefficient', [Dynamic.ALTITUDE, 'base_lift_coefficient'], + 'lift_coefficient', [Dynamic.Mission.ALTITUDE, 'base_lift_coefficient'], rows=rows_cols, cols=rows_cols ) self.declare_partials( 'lift_coefficient', [ - 'angle_of_attack', Dynamic.FLIGHT_PATH_ANGLE, 'minimum_drag_coefficient', + 'angle_of_attack', Dynamic.Mission.FLIGHT_PATH_ANGLE, 'minimum_drag_coefficient', 'base_drag_coefficient', ], dependent=False @@ -104,7 +102,7 @@ def setup_partials(self): self.declare_partials( 'drag_coefficient', [ - 'angle_of_attack', Dynamic.ALTITUDE, Dynamic.FLIGHT_PATH_ANGLE, + 'angle_of_attack', Dynamic.Mission.ALTITUDE, Dynamic.Mission.FLIGHT_PATH_ANGLE, 'base_drag_coefficient', 'base_lift_coefficient' ], rows=rows_cols, cols=rows_cols @@ -121,8 +119,8 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): ground_altitude = options['ground_altitude'] angle_of_attack = inputs['angle_of_attack'] - altitude = inputs[Dynamic.ALTITUDE] - flight_path_angle = inputs[Dynamic.FLIGHT_PATH_ANGLE] + altitude = inputs[Dynamic.Mission.ALTITUDE] + flight_path_angle = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] minimum_drag_coefficient = inputs['minimum_drag_coefficient'] base_lift_coefficient = inputs['base_lift_coefficient'] base_drag_coefficient = inputs['base_drag_coefficient'] @@ -177,8 +175,8 @@ def compute_partials(self, inputs, J, discrete_inputs=None): ground_altitude = options['ground_altitude'] angle_of_attack = inputs['angle_of_attack'] - altitude = inputs[Dynamic.ALTITUDE] - flight_path_angle = inputs[Dynamic.FLIGHT_PATH_ANGLE] + altitude = inputs[Dynamic.Mission.ALTITUDE] + flight_path_angle = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] minimum_drag_coefficient = inputs['minimum_drag_coefficient'] base_lift_coefficient = inputs['base_lift_coefficient'] base_drag_coefficient = inputs['base_drag_coefficient'] @@ -224,7 +222,7 @@ def compute_partials(self, inputs, J, discrete_inputs=None): (d_hf_alt * lift_coeff_factor_denom) - (height_factor * d_lcfd_alt) ) / lift_coeff_factor_denom**2 - J['lift_coefficient', Dynamic.ALTITUDE] = base_lift_coefficient * d_lcf_alt + J['lift_coefficient', Dynamic.Mission.ALTITUDE] = base_lift_coefficient * d_lcf_alt J['lift_coefficient', 'base_lift_coefficient'] = lift_coeff_factor # endregion lift_coefficient wrt [altitude, base_lift_coefficient] @@ -306,7 +304,7 @@ def compute_partials(self, inputs, J, discrete_inputs=None): d_dc_fpa = base_lift_coefficient * (lift_coeff_factor - 1.) * d_ca_fpa - J['drag_coefficient', Dynamic.FLIGHT_PATH_ANGLE] = d_dc_fpa + J['drag_coefficient', Dynamic.Mission.FLIGHT_PATH_ANGLE] = d_dc_fpa # endregion drag_coefficient wrt flight_path_angle # region drag_coefficient wrt altitude @@ -336,7 +334,7 @@ def compute_partials(self, inputs, J, discrete_inputs=None): + combined_angle * base_lift_coefficient * d_lcf_alt ) - J['drag_coefficient', Dynamic.ALTITUDE] = d_dc_alt + J['drag_coefficient', Dynamic.Mission.ALTITUDE] = d_dc_alt # endregion drag_coefficient wrt altitude # region drag_coefficient wrt minimum_drag_coefficient @@ -401,7 +399,7 @@ def compute_partials(self, inputs, J, discrete_inputs=None): # Check for out of ground effect. idx = np.where(ground_effect_state > 1.1) if idx: - J['drag_coefficient', Dynamic.ALTITUDE][idx] = 0.0 + J['drag_coefficient', Dynamic.Mission.ALTITUDE][idx] = 0.0 J['drag_coefficient', 'minimum_drag_coefficient'][idx] = 0.0 J['drag_coefficient', 'base_lift_coefficient'][idx] = 0.0 J['drag_coefficient', 'base_drag_coefficient'][idx] = 1.0 @@ -409,9 +407,9 @@ def compute_partials(self, inputs, J, discrete_inputs=None): J['drag_coefficient', Aircraft.Wing.HEIGHT][idx] = 0.0 J['drag_coefficient', Aircraft.Wing.SPAN][idx] = 0.0 J['drag_coefficient', 'angle_of_attack'][idx] = 0.0 - J['drag_coefficient', Dynamic.FLIGHT_PATH_ANGLE][idx] = 0.0 + J['drag_coefficient', Dynamic.Mission.FLIGHT_PATH_ANGLE][idx] = 0.0 - J['lift_coefficient', Dynamic.ALTITUDE][idx] = 0.0 + J['lift_coefficient', Dynamic.Mission.ALTITUDE][idx] = 0.0 J['lift_coefficient', 'base_lift_coefficient'][idx] = 1.0 J['lift_coefficient', Aircraft.Wing.ASPECT_RATIO][idx] = 0.0 J['lift_coefficient', Aircraft.Wing.HEIGHT][idx] = 0.0 diff --git a/aviary/subsystems/aerodynamics/flops_based/takeoff_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/takeoff_aero_group.py index d6245f60e..6185b25ca 100644 --- a/aviary/subsystems/aerodynamics/flops_based/takeoff_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/takeoff_aero_group.py @@ -11,11 +11,7 @@ GroundEffect from aviary.subsystems.aerodynamics.gasp_based.common import AeroForces from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.variables import Aircraft -from aviary.variable_info.variables import Dynamic as _Dynamic -from aviary.variable_info.variables import Mission - -Dynamic = _Dynamic.Mission +from aviary.variable_info.variables import Aircraft, Dynamic, Mission class TakeoffAeroGroup(om.Group): @@ -119,7 +115,7 @@ def setup(self): } inputs = [ - 'angle_of_attack', Dynamic.ALTITUDE, Dynamic.FLIGHT_PATH_ANGLE, + 'angle_of_attack', Dynamic.Mission.ALTITUDE, Dynamic.Mission.FLIGHT_PATH_ANGLE, ('minimum_drag_coefficient', Mission.Takeoff.DRAG_COEFFICIENT_MIN), Aircraft.Wing.ASPECT_RATIO, Aircraft.Wing.HEIGHT, Aircraft.Wing.SPAN @@ -173,8 +169,8 @@ def setup(self): self.connect('ground_effect.drag_coefficient', 'ground_effect_drag') self.connect('climb_drag_coefficient', 'aero_forces.CD') - inputs = [Dynamic.DYNAMIC_PRESSURE, Aircraft.Wing.AREA] - outputs = [Dynamic.LIFT, Dynamic.DRAG] + inputs = [Dynamic.Mission.DYNAMIC_PRESSURE, Aircraft.Wing.AREA] + outputs = [Dynamic.Mission.LIFT, Dynamic.Mission.DRAG] self.add_subsystem( 'aero_forces', AeroForces(num_nodes=nn), diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_ground_effect.py b/aviary/subsystems/aerodynamics/flops_based/test/test_ground_effect.py index 940981305..bfcf6c008 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_ground_effect.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_ground_effect.py @@ -6,10 +6,7 @@ from aviary.subsystems.aerodynamics.flops_based.ground_effect import GroundEffect from aviary.utils.aviary_values import AviaryValues, get_items -from aviary.variable_info.variables import Aircraft -from aviary.variable_info.variables import Dynamic as _Dynamic - -Dynamic = _Dynamic.Mission +from aviary.variable_info.variables import Aircraft, Dynamic class TestGroundEffect(unittest.TestCase): @@ -61,8 +58,8 @@ def make_problem(): inputs = AviaryValues({ 'angle_of_attack': (np.array([0., 2., 6]), 'deg'), - Dynamic.ALTITUDE: (np.array([100.0, 132, 155]), 'm'), - Dynamic.FLIGHT_PATH_ANGLE: (np.array([0., 0.5, 1.0]), 'deg'), + Dynamic.Mission.ALTITUDE: (np.array([100.0, 132, 155]), 'm'), + Dynamic.Mission.FLIGHT_PATH_ANGLE: (np.array([0., 0.5, 1.0]), 'deg'), 'minimum_drag_coefficient': minimum_drag_coefficient, 'base_lift_coefficient': base_lift_coefficient, 'base_drag_coefficient': base_drag_coefficient, diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_takeoff_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_takeoff_aero_group.py index e16c92fe4..076e84eaf 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_takeoff_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_takeoff_aero_group.py @@ -9,13 +9,9 @@ from aviary.utils.aviary_values import AviaryValues, get_items from aviary.models.N3CC.N3CC_data import ( N3CC, takeoff_subsystem_options, takeoff_subsystem_options_spoilers) -from aviary.variable_info.variables import Aircraft -from aviary.variable_info.variables import Dynamic as _Dynamic -from aviary.variable_info.variables import Mission +from aviary.variable_info.variables import Aircraft, Dynamic, Mission from aviary.variable_info.enums import LegacyCode -Dynamic = _Dynamic.Mission - class TestTakeoffAeroGroup(unittest.TestCase): @@ -80,18 +76,19 @@ def make_problem(subsystem_options={}): dynamic_inputs = AviaryValues({ 'angle_of_attack': (np.array([0., 2., 6.]), 'deg'), - Dynamic.ALTITUDE: (np.array([0., 32., 55.]), 'm'), - Dynamic.FLIGHT_PATH_ANGLE: (np.array([0., 0.5, 1.]), 'deg')}) + Dynamic.Mission.ALTITUDE: (np.array([0., 32., 55.]), 'm'), + Dynamic.Mission.FLIGHT_PATH_ANGLE: (np.array([0., 0.5, 1.]), 'deg')}) prob = om.Problem() prob.model.add_subsystem( "USatm", USatm1976Comp(num_nodes=nn), - promotes_inputs=[("h", Dynamic.ALTITUDE)], + promotes_inputs=[("h", Dynamic.Mission.ALTITUDE)], promotes_outputs=[ - "rho", ("sos", Dynamic.SPEED_OF_SOUND), ("temp", Dynamic.TEMPERATURE), - ("pres", Dynamic.STATIC_PRESSURE), "viscosity"]) + "rho", ("sos", Dynamic.Mission.SPEED_OF_SOUND), ("temp", + Dynamic.Mission.TEMPERATURE), + ("pres", Dynamic.Mission.STATIC_PRESSURE), "viscosity"]) aero_builder = CoreAerodynamicsBuilder(code_origin=LegacyCode.FLOPS) @@ -104,7 +101,7 @@ def make_problem(subsystem_options={}): **subsystem_options['core_aerodynamics']), promotes_outputs=aero_builder.mission_outputs(**subsystem_options['core_aerodynamics'])) - prob.model.set_input_defaults(Dynamic.ALTITUDE, np.zeros(nn), 'm') + prob.model.set_input_defaults(Dynamic.Mission.ALTITUDE, np.zeros(nn), 'm') prob.setup(force_alloc_complex=True) @@ -135,9 +132,9 @@ def make_problem(subsystem_options={}): # - generate new regression data if, and only if, takeoff aero group is updated with a # more trusted implementation _regression_data = AviaryValues({ - Dynamic.LIFT: ( + Dynamic.Mission.LIFT: ( [3028.138891962988, 4072.059743068957, 6240.85493286], _units_lift), - Dynamic.DRAG: ( + Dynamic.Mission.DRAG: ( [434.6285684000267, 481.5245555324278, 586.0976806512001], _units_drag)}) # NOTE: @@ -146,9 +143,9 @@ def make_problem(subsystem_options={}): # - generate new regression data if, and only if, takeoff aero group is updated with a # more trusted implementation _regression_data_spoiler = AviaryValues({ - Dynamic.LIFT: ( + Dynamic.Mission.LIFT: ( [-1367.5937129210124, -323.67286181504335, 1845.1223279759993], _units_lift), - Dynamic.DRAG: ( + Dynamic.Mission.DRAG: ( [895.9091503940268, 942.8051375264279, 1047.3782626452], _units_drag)}) @@ -204,8 +201,8 @@ def _generate_regression_data(subsystem_options={}): prob.run_model() - lift = prob.get_val(Dynamic.LIFT, _units_lift) - drag = prob.get_val(Dynamic.DRAG, _units_drag) + lift = prob.get_val(Dynamic.Mission.LIFT, _units_lift) + drag = prob.get_val(Dynamic.Mission.DRAG, _units_drag) prob.check_partials(compact_print=True, method="cs") diff --git a/aviary/subsystems/propulsion/test/test_custom_engine_model.py b/aviary/subsystems/propulsion/test/test_custom_engine_model.py index c6ed1c751..0bfeafbce 100644 --- a/aviary/subsystems/propulsion/test/test_custom_engine_model.py +++ b/aviary/subsystems/propulsion/test/test_custom_engine_model.py @@ -168,7 +168,7 @@ def test_custom_engine(self): 'altitude': ([35.e3, 35.e3], 'ft'), 'velocity': ([455.49, 455.49], 'kn'), 'mass': ([130.e3, 128.e3], 'lbm'), - 'range': ([0., 300.], 'nmi'), + 'distance': ([0., 300.], 'nmi'), 'velocity_rate': ([0., 0.], 'm/s**2'), 'throttle': ([0.6, 0.6], 'unitless'), } @@ -235,7 +235,7 @@ def test_custom_engine(self): 'traj.phases.cruise.indep_states.states:altitude', 'traj.phases.cruise.indep_states.states:velocity', 'traj.phases.cruise.indep_states.states:mass', - 'traj.phases.cruise.indep_states.states:range', + 'traj.phases.cruise.indep_states.states:distance', ] # Check that all expected variable names are present in design_vars @@ -250,7 +250,7 @@ def test_custom_engine(self): # print the mass and range assert_near_equal(design_vars_dict['traj.phases.cruise.indep_states.states:mass']['val'], [ 58967.0081, 58805.95966377, 58583.74569223, 58513.41573, 58352.36729377, 58130.15332223, 58059.82336], tolerance=tol) - assert_near_equal(design_vars_dict['traj.phases.cruise.indep_states.states:range']['val'], [ + assert_near_equal(design_vars_dict['traj.phases.cruise.indep_states.states:distance']['val'], [ 0., 98633.17494548, 234726.82505452, 277800., 376433.17494548, 512526.82505452, 555600.], tolerance=tol) diff --git a/aviary/utils/report.py b/aviary/utils/report.py index df0e2b08e..c0076e17e 100644 --- a/aviary/utils/report.py +++ b/aviary/utils/report.py @@ -234,7 +234,7 @@ def report_benchmark_comparison( # check_val = no_size_yes_pyCycle if base == 'FLOPS': check_val = FLOPS_base - distance_name = 'traj.descent.timeseries.states:range' + distance_name = 'traj.descent.timeseries.states:distance' landing_dist_name = Mission.Landing.GROUND_DISTANCE else: distance_name = "traj.desc2.timeseries.states:distance" 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 aff3bb72c..a3908a1da 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 @@ -18,13 +18,11 @@ balanced_trajectory_builder as _takeoff_trajectory_builder from aviary.models.N3CC.N3CC_data import \ inputs as _inputs -from aviary.variable_info.variables import Dynamic as _Dynamic +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.premission import CorePreMission -Dynamic = _Dynamic.Mission - @use_tempdirs class TestFLOPSBalancedFieldLength(unittest.TestCase): @@ -95,7 +93,7 @@ def _do_run(self, driver: Driver, optimizer, *args): liftoff = takeoff_trajectory_builder.get_phase('balanced_liftoff') liftoff.add_objective( - Dynamic.RANGE, loc='final', ref=max_range, units=units) + Dynamic.Mission.DISTANCE, loc='final', ref=max_range, units=units) takeoff.model.add_subsystem( 'input_sink', @@ -128,7 +126,7 @@ def _do_run(self, driver: Driver, optimizer, *args): # N3CC FLOPS output Line 2282 desired = 7032.65 actual = takeoff.model.get_val( - 'traj.balanced_liftoff.states:range', units='ft')[-1] + 'traj.balanced_liftoff.states:distance', units='ft')[-1] assert_near_equal(actual, desired, 2e-2) # Decision Time diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py index 7041b7cb8..53264e0d9 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py @@ -253,9 +253,9 @@ def run_trajectory(driver: Driver, sim=True): promotes_outputs=['mission:*']) traj.link_phases(["climb", "cruise"], ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple) + Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) traj.link_phases(["cruise", "descent"], ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple) + Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) traj = setup_trajectory_params(prob.model, traj, aviary_inputs) @@ -293,7 +293,7 @@ def run_trajectory(driver: Driver, sim=True): prob.model.connect('traj.climb.states:mass', 'takeoff_constraints.climb_start_mass', src_indices=[0]) - prob.model.connect('traj.climb.states:range', + prob.model.connect('traj.climb.states:distance', 'takeoff_constraints.climb_start_range', src_indices=[0]) prob.model.connect('traj.climb.states:velocity', 'takeoff_constraints.climb_start_vel', src_indices=[0]) @@ -303,7 +303,7 @@ def run_trajectory(driver: Driver, sim=True): prob.model.connect(Mission.Takeoff.FINAL_MASS, 'traj.climb.initial_states:mass') prob.model.connect(Mission.Takeoff.GROUND_DISTANCE, - 'traj.climb.initial_states:range') + 'traj.climb.initial_states:distance') prob.model.connect(Mission.Takeoff.FINAL_VELOCITY, 'traj.climb.initial_states:velocity') prob.model.connect(Mission.Takeoff.FINAL_ALTITUDE, @@ -371,8 +371,8 @@ def run_trajectory(driver: Driver, sim=True): Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s') prob.set_val('traj.climb.states:mass', climb.interp( Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') - prob.set_val('traj.climb.states:range', climb.interp( - Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') # nmi + prob.set_val('traj.climb.states:distance', climb.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') # nmi prob.set_val('traj.climb.controls:velocity_rate', climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.0]), @@ -390,8 +390,8 @@ def run_trajectory(driver: Driver, sim=True): Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s') prob.set_val('traj.cruise.states:mass', cruise.interp( Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi + prob.set_val('traj.cruise.states:distance', cruise.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi prob.set_val('traj.cruise.controls:velocity_rate', cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), @@ -409,8 +409,8 @@ def run_trajectory(driver: Driver, sim=True): Dynamic.Mission.VELOCITY, ys=[v_i_descent, v_f_descent]), units='m/s') prob.set_val('traj.descent.states:mass', descent.interp( Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') - prob.set_val('traj.descent.states:range', descent.interp( - Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m') + prob.set_val('traj.descent.states:distance', descent.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_descent, range_f_descent]), units='m') prob.set_val('traj.descent.controls:velocity_rate', descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.0]), @@ -446,7 +446,7 @@ def _do_run(self, driver): altitudes_climb = prob.get_val( 'traj.climb.timeseries.states:altitude', units='m') masses_climb = prob.get_val('traj.climb.timeseries.states:mass', units='kg') - ranges_climb = prob.get_val('traj.climb.timeseries.states:range', units='m') + ranges_climb = prob.get_val('traj.climb.timeseries.states:distance', units='m') velocities_climb = prob.get_val( 'traj.climb.timeseries.states:velocity', units='m/s') thrusts_climb = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N') @@ -454,7 +454,7 @@ def _do_run(self, driver): altitudes_cruise = prob.get_val( 'traj.cruise.timeseries.states:altitude', units='m') masses_cruise = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges_cruise = prob.get_val('traj.cruise.timeseries.states:range', units='m') + ranges_cruise = prob.get_val('traj.cruise.timeseries.states:distance', units='m') velocities_cruise = prob.get_val( 'traj.cruise.timeseries.states:velocity', units='m/s') thrusts_cruise = prob.get_val( @@ -463,7 +463,8 @@ def _do_run(self, driver): altitudes_descent = prob.get_val( 'traj.descent.timeseries.states:altitude', units='m') masses_descent = prob.get_val('traj.descent.timeseries.states:mass', units='kg') - ranges_descent = prob.get_val('traj.descent.timeseries.states:range', units='m') + ranges_descent = prob.get_val( + 'traj.descent.timeseries.states:distance', units='m') velocities_descent = prob.get_val( 'traj.descent.timeseries.states:velocity', units='m/s') thrusts_descent = prob.get_val( diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py index 55bfd2fbd..b7143e37c 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py @@ -259,9 +259,9 @@ def run_trajectory(sim=True): promotes_outputs=['mission:*']) traj.link_phases(["climb", "cruise"], ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple) + Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) traj.link_phases(["cruise", "descent"], ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple) + Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) traj = setup_trajectory_params(prob.model, traj, aviary_inputs) @@ -299,7 +299,7 @@ def run_trajectory(sim=True): prob.model.connect('traj.climb.states:mass', 'takeoff_constraints.climb_start_mass', src_indices=[0]) - prob.model.connect('traj.climb.states:range', + prob.model.connect('traj.climb.states:distance', 'takeoff_constraints.climb_start_range', src_indices=[0]) prob.model.connect('traj.climb.states:velocity', 'takeoff_constraints.climb_start_vel', src_indices=[0]) @@ -309,7 +309,7 @@ def run_trajectory(sim=True): prob.model.connect(Mission.Takeoff.FINAL_MASS, 'traj.climb.initial_states:mass') prob.model.connect(Mission.Takeoff.GROUND_DISTANCE, - 'traj.climb.initial_states:range') + 'traj.climb.initial_states:distance') prob.model.connect(Mission.Takeoff.FINAL_VELOCITY, 'traj.climb.initial_states:velocity') prob.model.connect(Mission.Takeoff.FINAL_ALTITUDE, @@ -377,8 +377,8 @@ def run_trajectory(sim=True): Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s') prob.set_val('traj.climb.states:mass', climb.interp( Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') - prob.set_val('traj.climb.states:range', climb.interp( - Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') # nmi + prob.set_val('traj.climb.states:distance', climb.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') # nmi prob.set_val('traj.climb.controls:velocity_rate', climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.05]), @@ -396,8 +396,8 @@ def run_trajectory(sim=True): Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s') prob.set_val('traj.cruise.states:mass', cruise.interp( Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi + prob.set_val('traj.cruise.states:distance', cruise.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi prob.set_val('traj.cruise.controls:velocity_rate', cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), @@ -415,8 +415,8 @@ def run_trajectory(sim=True): Dynamic.Mission.VELOCITY, ys=[v_i_descent, v_f_descent]), units='m/s') prob.set_val('traj.descent.states:mass', descent.interp( Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') - prob.set_val('traj.descent.states:range', descent.interp( - Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m') + prob.set_val('traj.descent.states:distance', descent.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_descent, range_f_descent]), units='m') prob.set_val('traj.descent.controls:velocity_rate', descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.05]), @@ -447,7 +447,7 @@ def bench_test_full_mission_large_single_aisle_1(self): altitudes_climb = prob.get_val( 'traj.climb.timeseries.states:altitude', units='m') masses_climb = prob.get_val('traj.climb.timeseries.states:mass', units='kg') - ranges_climb = prob.get_val('traj.climb.timeseries.states:range', units='m') + ranges_climb = prob.get_val('traj.climb.timeseries.states:distance', units='m') velocities_climb = prob.get_val( 'traj.climb.timeseries.states:velocity', units='m/s') thrusts_climb = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N') @@ -455,7 +455,7 @@ def bench_test_full_mission_large_single_aisle_1(self): altitudes_cruise = prob.get_val( 'traj.cruise.timeseries.states:altitude', units='m') masses_cruise = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges_cruise = prob.get_val('traj.cruise.timeseries.states:range', units='m') + ranges_cruise = prob.get_val('traj.cruise.timeseries.states:distance', units='m') velocities_cruise = prob.get_val( 'traj.cruise.timeseries.states:velocity', units='m/s') thrusts_cruise = prob.get_val( @@ -464,7 +464,8 @@ def bench_test_full_mission_large_single_aisle_1(self): altitudes_descent = prob.get_val( 'traj.descent.timeseries.states:altitude', units='m') masses_descent = prob.get_val('traj.descent.timeseries.states:mass', units='kg') - ranges_descent = prob.get_val('traj.descent.timeseries.states:range', units='m') + ranges_descent = prob.get_val( + 'traj.descent.timeseries.states:distance', units='m') velocities_descent = prob.get_val( 'traj.descent.timeseries.states:velocity', units='m/s') thrusts_descent = prob.get_val( diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py index 7a8c71ba1..37b176bc6 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py @@ -253,9 +253,9 @@ def run_trajectory(sim=True): promotes_outputs=['mission:*']) traj.link_phases(["climb", "cruise"], ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple) + Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) traj.link_phases(["cruise", "descent"], ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.RANGE], connected=strong_couple) + Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) traj = setup_trajectory_params(prob.model, traj, aviary_inputs) @@ -293,7 +293,7 @@ def run_trajectory(sim=True): prob.model.connect('traj.climb.states:mass', 'takeoff_constraints.climb_start_mass', src_indices=[0]) - prob.model.connect('traj.climb.states:range', + prob.model.connect('traj.climb.states:distance', 'takeoff_constraints.climb_start_range', src_indices=[0]) prob.model.connect('traj.climb.states:velocity', 'takeoff_constraints.climb_start_vel', src_indices=[0]) @@ -303,7 +303,7 @@ def run_trajectory(sim=True): prob.model.connect(Mission.Takeoff.FINAL_MASS, 'traj.climb.initial_states:mass') prob.model.connect(Mission.Takeoff.GROUND_DISTANCE, - 'traj.climb.initial_states:range') + 'traj.climb.initial_states:distance') prob.model.connect(Mission.Takeoff.FINAL_VELOCITY, 'traj.climb.initial_states:velocity') prob.model.connect(Mission.Takeoff.FINAL_ALTITUDE, @@ -363,8 +363,8 @@ def run_trajectory(sim=True): Dynamic.Mission.VELOCITY, ys=[v_i_climb, v_f_climb]), units='m/s') prob.set_val('traj.climb.states:mass', climb.interp( Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') - prob.set_val('traj.climb.states:range', climb.interp( - Dynamic.Mission.RANGE, ys=[range_i_climb, range_f_climb]), units='m') # nmi + prob.set_val('traj.climb.states:distance', climb.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') # nmi prob.set_val('traj.climb.controls:velocity_rate', climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.05]), @@ -382,8 +382,8 @@ def run_trajectory(sim=True): Dynamic.Mission.VELOCITY, ys=[v_i_cruise, v_f_cruise]), units='m/s') prob.set_val('traj.cruise.states:mass', cruise.interp( Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - Dynamic.Mission.RANGE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi + prob.set_val('traj.cruise.states:distance', cruise.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi prob.set_val('traj.cruise.controls:velocity_rate', cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), @@ -401,8 +401,8 @@ def run_trajectory(sim=True): Dynamic.Mission.VELOCITY, ys=[v_i_descent, v_f_descent]), units='m/s') prob.set_val('traj.descent.states:mass', descent.interp( Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') - prob.set_val('traj.descent.states:range', descent.interp( - Dynamic.Mission.RANGE, ys=[range_i_descent, range_f_descent]), units='m') + prob.set_val('traj.descent.states:distance', descent.interp( + Dynamic.Mission.DISTANCE, ys=[range_i_descent, range_f_descent]), units='m') prob.set_val('traj.descent.controls:velocity_rate', descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.0]), @@ -433,7 +433,7 @@ def bench_test_full_mission_large_single_aisle_2(self): altitudes_climb = prob.get_val( 'traj.climb.timeseries.states:altitude', units='m') masses_climb = prob.get_val('traj.climb.timeseries.states:mass', units='kg') - ranges_climb = prob.get_val('traj.climb.timeseries.states:range', units='m') + ranges_climb = prob.get_val('traj.climb.timeseries.states:distance', units='m') velocities_climb = prob.get_val( 'traj.climb.timeseries.states:velocity', units='m/s') thrusts_climb = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N') @@ -441,7 +441,7 @@ def bench_test_full_mission_large_single_aisle_2(self): altitudes_cruise = prob.get_val( 'traj.cruise.timeseries.states:altitude', units='m') masses_cruise = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges_cruise = prob.get_val('traj.cruise.timeseries.states:range', units='m') + ranges_cruise = prob.get_val('traj.cruise.timeseries.states:distance', units='m') velocities_cruise = prob.get_val( 'traj.cruise.timeseries.states:velocity', units='m/s') thrusts_cruise = prob.get_val( @@ -450,7 +450,8 @@ def bench_test_full_mission_large_single_aisle_2(self): altitudes_descent = prob.get_val( 'traj.descent.timeseries.states:altitude', units='m') masses_descent = prob.get_val('traj.descent.timeseries.states:mass', units='kg') - ranges_descent = prob.get_val('traj.descent.timeseries.states:range', units='m') + ranges_descent = prob.get_val( + 'traj.descent.timeseries.states:distance', units='m') velocities_descent = prob.get_val( 'traj.descent.timeseries.states:velocity', units='m/s') thrusts_descent = prob.get_val( 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 042f00fc1..d94000a25 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 @@ -292,9 +292,9 @@ def run_trajectory(sim=True): promotes_outputs=['mission:*']) traj.link_phases(["climb", "cruise"], ["time", "altitude", - "velocity", "mass", Dynamic.Mission.RANGE], connected=strong_couple) + "velocity", "mass", Dynamic.Mission.DISTANCE], connected=strong_couple) traj.link_phases(["cruise", "descent"], ["time", "altitude", - "velocity", "mass", Dynamic.Mission.RANGE], connected=strong_couple) + "velocity", "mass", Dynamic.Mission.DISTANCE], connected=strong_couple) traj = setup_trajectory_params(prob.model, traj, aviary_inputs) @@ -332,7 +332,7 @@ def run_trajectory(sim=True): prob.model.connect('traj.climb.states:mass', 'takeoff_constraints.climb_start_mass', src_indices=[0]) - prob.model.connect('traj.climb.states:range', + prob.model.connect('traj.climb.states:distance', 'takeoff_constraints.climb_start_range', src_indices=[0]) prob.model.connect('traj.climb.states:velocity', 'takeoff_constraints.climb_start_vel', src_indices=[0]) @@ -342,7 +342,7 @@ def run_trajectory(sim=True): prob.model.connect(Mission.Takeoff.FINAL_MASS, 'traj.climb.initial_states:mass') prob.model.connect(Mission.Takeoff.GROUND_DISTANCE, - 'traj.climb.initial_states:range') + 'traj.climb.initial_states:distance') prob.model.connect(Mission.Takeoff.FINAL_VELOCITY, 'traj.climb.initial_states:velocity') prob.model.connect(Mission.Takeoff.FINAL_ALTITUDE, @@ -453,8 +453,8 @@ def run_trajectory(sim=True): 'velocity', ys=[v_i_climb, v_f_climb]), units='m/s') prob.set_val('traj.climb.states:mass', climb.interp( 'mass', ys=[mass_i_climb, mass_f_climb]), units='kg') - prob.set_val('traj.climb.states:range', climb.interp( - 'range', ys=[range_i_climb, range_f_climb]), units='m') # nmi + prob.set_val('traj.climb.states:distance', climb.interp( + 'distance', ys=[range_i_climb, range_f_climb]), units='m') # nmi prob.set_val('traj.climb.controls:velocity_rate', climb.interp('velocity_rate', ys=[0.25, 0.05]), @@ -472,8 +472,8 @@ def run_trajectory(sim=True): 'velocity', ys=[v_i_cruise, v_f_cruise]), units='m/s') prob.set_val('traj.cruise.states:mass', cruise.interp( 'mass', ys=[mass_i_cruise, mass_f_cruise]), units='kg') - prob.set_val('traj.cruise.states:range', cruise.interp( - 'range', ys=[range_i_cruise, range_f_cruise]), units='m') # nmi + prob.set_val('traj.cruise.states:distance', cruise.interp( + 'distance', ys=[range_i_cruise, range_f_cruise]), units='m') # nmi prob.set_val('traj.cruise.controls:velocity_rate', cruise.interp('velocity_rate', ys=[0.0, 0.0]), @@ -491,8 +491,8 @@ def run_trajectory(sim=True): 'velocity', ys=[v_i_descent, v_f_descent]), units='m/s') prob.set_val('traj.descent.states:mass', descent.interp( 'mass', ys=[mass_i_descent, mass_f_descent]), units='kg') - prob.set_val('traj.descent.states:range', descent.interp( - 'range', ys=[range_i_descent, range_f_descent]), units='m') + prob.set_val('traj.descent.states:distance', descent.interp( + 'distance', ys=[range_i_descent, range_f_descent]), units='m') prob.set_val('traj.descent.controls:velocity_rate', descent.interp('velocity_rate', ys=[-0.25, 0.05]), @@ -526,7 +526,7 @@ def bench_test_sizing_N3CC(self): altitudes_climb = prob.get_val( 'traj.climb.timeseries.states:altitude', units='m') masses_climb = prob.get_val('traj.climb.timeseries.states:mass', units='kg') - ranges_climb = prob.get_val('traj.climb.timeseries.states:range', units='m') + ranges_climb = prob.get_val('traj.climb.timeseries.states:distance', units='m') velocities_climb = prob.get_val( 'traj.climb.timeseries.states:velocity', units='m/s') thrusts_climb = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N') @@ -534,7 +534,7 @@ def bench_test_sizing_N3CC(self): altitudes_cruise = prob.get_val( 'traj.cruise.timeseries.states:altitude', units='m') masses_cruise = prob.get_val('traj.cruise.timeseries.states:mass', units='kg') - ranges_cruise = prob.get_val('traj.cruise.timeseries.states:range', units='m') + ranges_cruise = prob.get_val('traj.cruise.timeseries.states:distance', units='m') velocities_cruise = prob.get_val( 'traj.cruise.timeseries.states:velocity', units='m/s') thrusts_cruise = prob.get_val( @@ -543,7 +543,8 @@ def bench_test_sizing_N3CC(self): altitudes_descent = prob.get_val( 'traj.descent.timeseries.states:altitude', units='m') masses_descent = prob.get_val('traj.descent.timeseries.states:mass', units='kg') - ranges_descent = prob.get_val('traj.descent.timeseries.states:range', units='m') + ranges_descent = prob.get_val( + 'traj.descent.timeseries.states:distance', units='m') velocities_descent = prob.get_val( 'traj.descent.timeseries.states:velocity', units='m/s') thrusts_descent = prob.get_val( 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 512b710d8..3da1a98ba 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py @@ -17,15 +17,12 @@ landing_trajectory_builder as _landing_trajectory_builder, landing_fullstop_user_options as _landing_fullstop_user_options) -from aviary.variable_info.variables import Dynamic as _Dynamic +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.variable_info.variables_in import VariablesIn -Dynamic = _Dynamic.Mission - - @use_tempdirs class TestFLOPSDetailedLanding(unittest.TestCase): # @require_pyoptsparse(optimizer='IPOPT') @@ -90,7 +87,8 @@ def _do_run(self, driver: Driver, optimizer, *args): max_range, units = landing_fullstop_user_options.get_item('max_range') fullstop = landing_trajectory_builder.get_phase('landing_fullstop') - fullstop.add_objective(Dynamic.RANGE, loc='final', ref=max_range, units=units) + fullstop.add_objective(Dynamic.Mission.DISTANCE, loc='final', + ref=max_range, units=units) landing.model.add_subsystem( 'input_sink', @@ -123,7 +121,7 @@ def _do_run(self, driver: Driver, optimizer, *args): desired = 3409.47 # ft actual = landing.model.get_val( - 'traj.landing_fullstop.states:range', units='ft')[-1] + 'traj.landing_fullstop.states:distance', units='ft')[-1] assert_near_equal(actual, desired, 0.05) 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 bc403ccbf..c16facd15 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py @@ -17,15 +17,12 @@ takeoff_trajectory_builder as _takeoff_trajectory_builder, takeoff_liftoff_user_options as _takeoff_liftoff_user_options) -from aviary.variable_info.variables import Aircraft, Dynamic as _Dynamic +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.variable_info.variables_in import VariablesIn -Dynamic = _Dynamic.Mission - - @use_tempdirs class TestFLOPSDetailedTakeoff(unittest.TestCase): @require_pyoptsparse(optimizer='IPOPT') @@ -97,7 +94,7 @@ def _do_run(self, driver: Driver, optimizer, *args): liftoff = takeoff_trajectory_builder.get_phase('takeoff_liftoff') liftoff.add_objective( - Dynamic.RANGE, loc='final', ref=max_range, units=units) + Dynamic.Mission.DISTANCE, loc='final', ref=max_range, units=units) # Insert a constraint for a fake decision speed, until abort is added. takeoff.model.add_constraint( @@ -140,7 +137,7 @@ def _do_run(self, driver: Driver, optimizer, *args): desired = 5649.9 # ft actual = takeoff.model.get_val( - 'traj.takeoff_liftoff.states:range', units='ft')[-1] + 'traj.takeoff_liftoff.states:distance', units='ft')[-1] assert_near_equal(actual, desired, 2e-2) diff --git a/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py b/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py index f09ffd6ed..e5f7c4ca9 100644 --- a/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py +++ b/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py @@ -293,7 +293,7 @@ def run_mission(optimizer): phase.set_state_options("mass", rate_source="dmass_dv", fix_initial=True, fix_final=False, lower=1, upper=195_000, ref=takeoff_mass, defect_ref=takeoff_mass) - phase.set_state_options(Dynamic.Mission.RANGE, rate_source="over_a", + phase.set_state_options(Dynamic.Mission.DISTANCE, rate_source="over_a", fix_initial=True, fix_final=False, lower=0, upper=2000., ref=1.e2, defect_ref=1.e2) phase.add_parameter("t_init_gear", units="s", @@ -330,7 +330,7 @@ def run_mission(optimizer): static_target=False) phase.set_time_options(fix_initial=False, fix_duration=False, - units="range_units", name=Dynamic.Mission.RANGE, + units="range_units", name=Dynamic.Mission.DISTANCE, duration_bounds=duration_bounds, duration_ref=duration_ref, initial_bounds=initial_bounds, initial_ref=initial_ref) @@ -425,7 +425,7 @@ def run_mission(optimizer): pass elif phase_name == "descent": phase.add_boundary_constraint( - Dynamic.Mission.RANGE, + Dynamic.Mission.DISTANCE, loc="final", equals=target_range, units="NM", @@ -510,7 +510,7 @@ def run_mission(optimizer): traj.link_phases(phases[6:], vars=[Dynamic.Mission.ALTITUDE], ref=10.e3) traj.link_phases(phases, vars=['time'], ref=100.) traj.link_phases(phases, vars=['mass'], ref=10.e3) - traj.link_phases(phases, vars=[Dynamic.Mission.RANGE], units='m', ref=10.e3) + traj.link_phases(phases, vars=[Dynamic.Mission.DISTANCE], units='m', ref=10.e3) traj.link_phases(phases[:7], vars=['TAS'], units='kn', ref=200.) # traj.link_phases(phases[7:], vars=['TAS'], units='kn', ref=200.) @@ -641,9 +641,9 @@ def run_mission(optimizer): if phase_name == "groundroll": ranges.extend( - p.get_val(f"traj.{phase_name}.timeseries.states:range", units="m")[0]) + p.get_val(f"traj.{phase_name}.timeseries.states:distance", units="m")[0]) ranges.extend( - p.get_val(f"traj.{phase_name}.timeseries.states:range", units="m")[-1]) + p.get_val(f"traj.{phase_name}.timeseries.states:distance", units="m")[-1]) masses.extend( p.get_val(f"traj.{phase_name}.timeseries.mass", units="lbm")[0]) diff --git a/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py b/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py index f4491a79a..9158440ad 100644 --- a/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py +++ b/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py @@ -53,7 +53,7 @@ def setUp(self): 'altitude': ([35.e3, 35.e3], 'ft'), 'velocity': ([455.49, 455.49], 'kn'), 'mass': ([130.e3, 120.e3], 'lbm'), - 'range': ([0., 3000.], 'NM'), + 'distance': ([0., 3000.], 'NM'), 'velocity_rate': ([0., 0.], 'm/s**2'), 'throttle': ([0.6, 0.6], 'unitless'), } diff --git a/aviary/validation_cases/benchmark_utils.py b/aviary/validation_cases/benchmark_utils.py index 8540817a2..a5a66b39f 100644 --- a/aviary/validation_cases/benchmark_utils.py +++ b/aviary/validation_cases/benchmark_utils.py @@ -27,7 +27,7 @@ def compare_against_expected_values(prob, expected_dict): masses.extend( prob.get_val(f'traj.{phase}.timeseries.states:mass', units='kg')) ranges.extend( - prob.get_val(f'traj.{phase}.timeseries.states:range', units='m')) + prob.get_val(f'traj.{phase}.timeseries.states:distance', units='m')) velocities.extend(prob.get_val( f'traj.{phase}.timeseries.states:velocity', units='m/s')) diff --git a/aviary/validation_cases/validation_data/flops_data/full_mission_test_data.py b/aviary/validation_cases/validation_data/flops_data/full_mission_test_data.py index 7e09b2d2b..02aca9e40 100644 --- a/aviary/validation_cases/validation_data/flops_data/full_mission_test_data.py +++ b/aviary/validation_cases/validation_data/flops_data/full_mission_test_data.py @@ -123,7 +123,7 @@ data.set_val( # state_rates:range - Dynamic.Mission.RANGE_RATE, + Dynamic.Mission.DISTANCE_RATE, val=[163.776550884386, 232.775306059091, 117.631414542995, ], units='m/s', ) diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index 94d66ccdc..580c381be 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -5852,7 +5852,7 @@ add_meta_data( Dynamic.Mission.DISTANCE, meta_data=_MetaData, - historical_name={"GASP": None, + historical_name={"GASP": 'range', "FLOPS": None, "LEAPS1": None }, @@ -5863,7 +5863,7 @@ add_meta_data( Dynamic.Mission.DISTANCE_RATE, meta_data=_MetaData, - historical_name={"GASP": None, + historical_name={"GASP": 'range_rate', "FLOPS": None, "LEAPS1": None }, @@ -6078,29 +6078,6 @@ desc='Current total rate of nitrous oxide (NOx) production by the vehicle' ) -add_meta_data( - Dynamic.Mission.RANGE, - meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='nm', - desc='Current cumulative ground distance the vehicle has flown' -) - -add_meta_data( - Dynamic.Mission.RANGE_RATE, - meta_data=_MetaData, - historical_name={"GASP": None, - "FLOPS": None, - "LEAPS1": None - }, - units='nm/s', - desc='Current rate of change in cumulative ground distance (ground velocity) for ' - 'the vehicle' -) - add_meta_data( Dynamic.Mission.SPECIFIC_ENERGY_RATE, meta_data=_MetaData, diff --git a/aviary/xdsm/statics_xdsm.py b/aviary/xdsm/statics_xdsm.py index e10333dee..e4583c487 100644 --- a/aviary/xdsm/statics_xdsm.py +++ b/aviary/xdsm/statics_xdsm.py @@ -28,7 +28,7 @@ x.add_system("landing", GROUP, [r"\textbf{Landing}"]) x.add_system("fuelburn", FUNC, ["FuelBurn"]) x.add_system("mass_diff", FUNC, ["MassDifference"]) -x.add_system(Dynamic.Mission.RANGE, FUNC, ["RangeConstraint"]) +x.add_system(Dynamic.Mission.DISTANCE, FUNC, ["RangeConstraint"]) if simplified is False: # independent vars input to ParamPort, common to all phases @@ -339,7 +339,7 @@ ) x.add_input("fuelburn", [Aircraft.Fuel.FUEL_MARGIN, Mission.Summary.GROSS_MASS]) - x.add_input(Dynamic.Mission.RANGE, [Mission.Design.RANGE]) + x.add_input(Dynamic.Mission.DISTANCE, [Mission.Design.RANGE]) # Create outputs x.add_output("landing", [Mission.Landing.GROUND_DISTANCE], side="right") @@ -367,7 +367,7 @@ ) x.connect("dymos", "descent1", [Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS]) x.connect("dymos", "fuelburn", [Mission.Landing.TOUCHDOWN_MASS]) -x.connect("dymos", Dynamic.Mission.RANGE, [Mission.Summary.RANGE]) +x.connect("dymos", Dynamic.Mission.DISTANCE, [Mission.Summary.RANGE]) x.connect("cruise", "dymos", ["cruise_time_final", "cruise_range_final"]) # Add Design Variables @@ -405,7 +405,7 @@ # Add Constraints x.connect("dymos", "opt", [r"\mathcal{R}"]) x.connect("mass_diff", "opt", [Mission.Constraints.MASS_RESIDUAL]) -x.connect(Dynamic.Mission.RANGE, "opt", [Mission.Constraints.RANGE_RESIDUAL]) +x.connect(Dynamic.Mission.DISTANCE, "opt", [Mission.Constraints.RANGE_RESIDUAL]) x.connect("poly", "opt", ["h_init_gear", "h_init_flaps"]) # Connect State Rates From 40db5168f38a6473f46d97caddb871493cd1d0b0 Mon Sep 17 00:00:00 2001 From: jkirk5 Date: Tue, 16 Jan 2024 16:35:59 -0500 Subject: [PATCH 073/188] Modified test to use loading inputs from AviaryValues Doc update --- .../getting_started/onboarding_level2.ipynb | 13 ++++++++----- aviary/docs/user_guide/input_files.ipynb | 2 +- .../benchmark_tests/test_0_iters.py | 19 +++++++++++-------- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/aviary/docs/getting_started/onboarding_level2.ipynb b/aviary/docs/getting_started/onboarding_level2.ipynb index 0d47cdf7f..4f07f7394 100644 --- a/aviary/docs/getting_started/onboarding_level2.ipynb +++ b/aviary/docs/getting_started/onboarding_level2.ipynb @@ -206,11 +206,14 @@ "source": [ "is a function that has a few tasks:\n", "\n", - "- read aircraft deck file `aircraft_filename`\n", - "- read phase info file `phase_info`\n", - "- build core subsystems, including setting up engines\n", + "- Read aircraft deck file `aircraft_filename`\n", + "- Read phase info file `phase_info`\n", + "- Build core subsystems\n", "\n", - "We have seen `aircraft_filename` file (a `.csv` file) in our level 1 examples. In [level 1](onboarding_level1), we simply called it input file. Engine is built by using `aircraft:engine:data_file` in the .csv file. For example in `aircraft_for_bench_GwGm.csv` file, we see:\n", + "We have seen `aircraft_filename` file (a `.csv` file) in our level 1 examples. In [level 1](onboarding_level1), we simply called it input file. An aircraft model can also be directly defined in Python, by setting up an `AviaryValues` object with the desired inputs and options normally found in an input file. That object can be provided in the place of `aircraft_filename`.\n", + "\n", + "\n", + "Engines are built by using `aircraft:engine:data_file` in the .csv file. For example in `aircraft_for_bench_GwGm.csv` file, we see:\n", "\n", "```\n", "aircraft:engine:data_file,models/engines/turbofan_28k.deck,unitless\n", @@ -226,7 +229,7 @@ "| 0.0, | 0.0, | 42.0, | 21214.0, | 0.0, | 5979.1, | 19.8547 |\n", "| 0.0, | 0.0, | 38.0, | 17356.9, | 0.0, | 4795.2, | 17.5877 |\n", "\n", - "The engine builder allows users to provide an `EngineModel` instance of their own to use in Aviary's propulsion systems.\n", + "Users can provide an `EngineModel` instance of their own to use in Aviary's propulsion systems by adding it to `engine_models`.\n", "\n", "Other subsystems, including mass, geometry, and aerodynamics, are set up according to which legacy code options the user has specified in their input file, using `settings:equations_of_motion` and `settings:mass_method`. Aerodynamics is set up to match the selected equations of motion, while geometry will use either GASP, FLOPS, or both methods as required to calculate all values needed by other subsystems.\n", "\n", diff --git a/aviary/docs/user_guide/input_files.ipynb b/aviary/docs/user_guide/input_files.ipynb index 39e37182e..cf8a12fb5 100644 --- a/aviary/docs/user_guide/input_files.ipynb +++ b/aviary/docs/user_guide/input_files.ipynb @@ -18,7 +18,7 @@ "source": [ "## Aviary Aircraft Input Files\n", "\n", - "Aviary uses a .csv file to load in information about the aircraft to be designed.\n", + "Aviary can use a .csv file to load in information about the aircraft to be designed.\n", "The file format is straightforward and follows the convention of `name, value, units` for each row.\n", "The names of the variables are detailed in the [Understanding Variable Metadata doc page](variable_metadata).\n", "\n", diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index 31761bd19..6121652f6 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -7,6 +7,9 @@ from aviary.interface.default_phase_info.two_dof import phase_info as two_dof_phase_info from aviary.interface.default_phase_info.height_energy import phase_info as height_energy_phase_info from aviary.interface.default_phase_info.solved import phase_info as solved_phase_info +from aviary.interface.default_phase_info.simple import phase_info as simple_phase_info +from aviary.models.N3CC.N3CC_data import inputs +from aviary.variable_info.variables import Settings from aviary.variable_info.enums import EquationsOfMotion @@ -35,7 +38,7 @@ def build_and_run_problem(self, input_filename, phase_info, objective_type=None) class TwoDOFZeroItersTestCase(BaseProblemPhaseTestCase): @require_pyoptsparse(optimizer="IPOPT") - def test_gasp_zero_iters(self): + def test_zero_iters_2DOF(self): local_phase_info = deepcopy(two_dof_phase_info) self.build_and_run_problem('models/test_aircraft/aircraft_for_bench_GwGm.csv', local_phase_info) @@ -45,14 +48,14 @@ def test_gasp_zero_iters(self): class HEZeroItersTestCase(BaseProblemPhaseTestCase): @require_pyoptsparse(optimizer="IPOPT") - def test_height_energy_zero_iters(self): - local_phase_info = deepcopy(height_energy_phase_info) - self.build_and_run_problem('models/test_aircraft/aircraft_for_bench_FwFm.csv', - local_phase_info) + def test_zero_iters_height_energy(self): + local_phase_info = deepcopy(simple_phase_info) + inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.SIMPLE) + self.build_and_run_problem(inputs, local_phase_info) @use_tempdirs -class SolvedProblemTestCase(BaseProblemPhaseTestCase): +class SolvedZeroItersTestCase(BaseProblemPhaseTestCase): @require_pyoptsparse(optimizer="IPOPT") def test_zero_iters_solved(self): @@ -64,5 +67,5 @@ def test_zero_iters_solved(self): if __name__ == "__main__": # unittest.main() - test = SolvedProblemTestCase() - test.test_zero_iters_solved() + test = HEZeroItersTestCase() + test.test_zero_iters_height_energy() From 4eed4b23de8df2b067bfb01c10aa68056c703a94 Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Tue, 16 Jan 2024 16:43:02 -0500 Subject: [PATCH 074/188] touched up variables.py --- aviary/variable_info/variable_meta_data.py | 8 ++++---- aviary/variable_info/variables.py | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index 580c381be..f3d6e8ae6 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -5852,8 +5852,8 @@ add_meta_data( Dynamic.Mission.DISTANCE, meta_data=_MetaData, - historical_name={"GASP": 'range', - "FLOPS": None, + historical_name={"GASP": None, + "FLOPS": 'range', "LEAPS1": None }, units='NM', @@ -5863,8 +5863,8 @@ add_meta_data( Dynamic.Mission.DISTANCE_RATE, meta_data=_MetaData, - historical_name={"GASP": 'range_rate', - "FLOPS": None, + historical_name={"GASP": None, + "FLOPS": 'range_rate', "LEAPS1": None }, units='NM/s', diff --git a/aviary/variable_info/variables.py b/aviary/variable_info/variables.py index a64d774f4..9b0923133 100644 --- a/aviary/variable_info/variables.py +++ b/aviary/variable_info/variables.py @@ -598,8 +598,6 @@ class Mission: MASS_RATE = 'mass_rate' NOX_RATE = 'nox_rate' NOX_RATE_TOTAL = 'nox_rate_total' - RANGE = 'range' - RANGE_RATE = 'range_rate' SPECIFIC_ENERGY = 'specific_energy' SPECIFIC_ENERGY_RATE = 'specific_energy_rate' SPECIFIC_ENERGY_RATE_EXCESS = 'specific_energy_rate_excess' From 6bc9b3431dede22fb987cae18b0fef6f8f3d72cf Mon Sep 17 00:00:00 2001 From: johnjasa Date: Tue, 16 Jan 2024 22:03:08 -0600 Subject: [PATCH 075/188] Working on new climb phase --- .../interface/default_phase_info/two_dof.py | 109 +++++----- aviary/interface/methods_for_level1.py | 3 +- aviary/interface/methods_for_level2.py | 53 +++-- aviary/interface/utils/check_phase_info.py | 7 - .../flops_based/phases/phase_builder_base.py | 4 +- .../mission/gasp_based/phases/climb_phase.py | 1 + .../gasp_based/phases/new_climb_phase.py | 192 ++++++++++++++---- 7 files changed, 237 insertions(+), 132 deletions(-) diff --git a/aviary/interface/default_phase_info/two_dof.py b/aviary/interface/default_phase_info/two_dof.py index a34a5098d..4b2e51716 100644 --- a/aviary/interface/default_phase_info/two_dof.py +++ b/aviary/interface/default_phase_info/two_dof.py @@ -1,5 +1,3 @@ -import numpy as np - from aviary.variable_info.enums import SpeedType from aviary.subsystems.propulsion.propulsion_builder import CorePropulsionBuilder from aviary.subsystems.geometry.geometry_builder import CoreGeometryBuilder @@ -11,11 +9,6 @@ GASP = LegacyCode.GASP -throttle_max = 1.0 -throttle_climb = 0.956 -throttle_cruise = 0.930 -throttle_idle = 0.0 - prop = CorePropulsionBuilder('core_propulsion', BaseMetaData) mass = CoreMassBuilder('core_mass', BaseMetaData, GASP) aero = CoreAerodynamicsBuilder('core_aerodynamics', BaseMetaData, GASP) @@ -46,7 +39,6 @@ 'distance_upper': (10.e3, 'ft'), 'distance_ref': (3000, 'ft'), 'distance_defect_ref': (3000, 'ft'), - 'throttle_setting': throttle_max, 'initial_guesses': { 'times': ([0.0, 40.0], 's'), 'TAS': ([0.066, 143.1], 'kn'), @@ -77,7 +69,6 @@ 'angle_ref': (5., 'deg'), 'angle_defect_ref': (5., 'deg'), 'normal_ref': (10000, 'lbf'), - 'throttle_setting': throttle_max, 'initial_guesses': { 'times': ([40.0, 5.0], 's'), 'alpha': ([0.0, 2.5], 'deg'), @@ -116,7 +107,6 @@ 'pitch_constraint_lower': (0., 'deg'), 'pitch_constraint_upper': (15., 'deg'), 'pitch_constraint_ref': (1., 'deg'), - 'throttle_setting': throttle_max, 'initial_guesses': { 'times': ([45., 25.], 's'), 'flight_path_angle': ([0.0, 8.], 'deg'), @@ -150,7 +140,6 @@ 'distance_upper': (150, 'NM'), 'distance_ref': (5, 'NM'), 'distance_defect_ref': (5, 'NM'), - 'throttle_setting': throttle_max, 'initial_guesses': { 'times': ([70., 13.], 's'), 'TAS': ([185., 250.], 'kn'), @@ -159,28 +148,29 @@ } }, 'climb1': { - 'num_segments': 1, - 'order': 3, - 'fix_initial': False, - 'EAS_target': (250, 'kn'), - 'mach_cruise': 0.8, - 'target_mach': False, - 'final_alt': (10.e3, 'ft'), - 'time_initial_bounds': ((20, 200), 's'), - 'duration_bounds': ((30, 300), 's'), - 'duration_ref': (1000, 's'), - 'alt_lower': (400, 'ft'), - 'alt_upper': (11_000, 'ft'), - 'alt_ref': (10.e3, 'ft'), - 'mass_lower': (0, 'lbm'), - 'mass_upper': (None, 'lbm'), - 'mass_ref': (150_000, 'lbm'), - 'mass_defect_ref': (150_000, 'lbm'), - 'distance_lower': (0, 'NM'), - 'distance_upper': (500, 'NM'), - 'distance_ref': (10, 'NM'), - 'distance_ref0': (0, 'NM'), - 'throttle_setting': throttle_climb, + 'user_options': { + 'num_segments': 1, + 'order': 3, + 'fix_initial': False, + 'EAS_target': (250, 'kn'), + 'mach_cruise': 0.8, + 'target_mach': False, + 'final_alt': (10.e3, 'ft'), + 'time_initial_bounds': ((20, 200), 's'), + 'duration_bounds': ((30, 300), 's'), + 'duration_ref': (1000, 's'), + 'alt_lower': (400, 'ft'), + 'alt_upper': (11_000, 'ft'), + 'alt_ref': (10.e3, 'ft'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (150_000, 'lbm'), + 'mass_defect_ref': (150_000, 'lbm'), + 'distance_lower': (0, 'NM'), + 'distance_upper': (500, 'NM'), + 'distance_ref': (10, 'NM'), + 'distance_ref0': (0, 'NM'), + }, 'initial_guesses': { 'times': ([1., 2.], 'min'), 'distance': ([20.e3, 100.e3], 'ft'), @@ -189,31 +179,32 @@ } }, 'climb2': { - 'num_segments': 3, - 'order': 3, - 'fix_initial': False, - 'EAS_target': (270, 'kn'), - 'mach_cruise': 0.8, - 'target_mach': True, - 'final_alt': (37.5e3, 'ft'), - 'required_available_climb_rate': (0.1, 'ft/min'), - 'time_initial_bounds': ((10, 700), 's'), - 'duration_bounds': ((200, 17_000), 's'), - 'duration_ref': (5000, 's'), - 'alt_lower': (9000, 'ft'), - 'alt_upper': (40000, 'ft'), - 'alt_ref': (30000, 'ft'), - 'alt_ref0': (0, 'ft'), - 'mass_lower': (0, 'lbm'), - 'mass_upper': (None, 'lbm'), - 'mass_ref': (150_000, 'lbm'), - 'mass_defect_ref': (150_000, 'lbm'), - 'distance_lower': (10, 'NM'), - 'distance_upper': (1000, 'NM'), - 'distance_ref': (500, 'NM'), - 'distance_ref0': (0, 'NM'), - 'distance_defect_ref': (500, 'NM'), - 'throttle_setting': throttle_climb, + 'user_options': { + 'num_segments': 3, + 'order': 3, + 'fix_initial': False, + 'EAS_target': (270, 'kn'), + 'mach_cruise': 0.8, + 'target_mach': True, + 'final_alt': (37.5e3, 'ft'), + 'required_available_climb_rate': (0.1, 'ft/min'), + 'time_initial_bounds': ((10, 700), 's'), + 'duration_bounds': ((200, 17_000), 's'), + 'duration_ref': (5000, 's'), + 'alt_lower': (9000, 'ft'), + 'alt_upper': (40000, 'ft'), + 'alt_ref': (30000, 'ft'), + 'alt_ref0': (0, 'ft'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (150_000, 'lbm'), + 'mass_defect_ref': (150_000, 'lbm'), + 'distance_lower': (10, 'NM'), + 'distance_upper': (1000, 'NM'), + 'distance_ref': (500, 'NM'), + 'distance_ref0': (0, 'NM'), + 'distance_defect_ref': (500, 'NM'), + }, 'initial_guesses': { 'times': ([216., 1300.], 's'), 'distance': ([100.e3, 200.e3], 'ft'), @@ -259,7 +250,6 @@ 'distance_ref': (mission_distance, 'NM'), 'distance_ref0': (0, 'NM'), 'distance_defect_ref': (100, 'NM'), - 'throttle_setting': throttle_idle, 'initial_guesses': { 'mass': (136000., 'lbm'), 'altitude': ([37.5e3, 10.e3], 'ft'), @@ -294,7 +284,6 @@ 'distance_upper': (5000, 'NM'), 'distance_ref': (3500, 'NM'), 'distance_defect_ref': (100, 'NM'), - 'throttle_setting': throttle_idle, 'initial_guesses': { 'mass': (136000., 'lbm'), 'altitude': ([10.e3, 1.e3], 'ft'), diff --git a/aviary/interface/methods_for_level1.py b/aviary/interface/methods_for_level1.py index d5c04a1e9..eef49bbf1 100644 --- a/aviary/interface/methods_for_level1.py +++ b/aviary/interface/methods_for_level1.py @@ -66,8 +66,7 @@ def run_aviary(aircraft_filename, phase_info, optimizer=None, # Allow for user overrides here prob.load_inputs(aircraft_filename, phase_info) - -# Preprocess inputs + # Preprocess inputs prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index cb9818663..290f04872 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -1,6 +1,5 @@ import csv import warnings -from packaging import version import inspect from pathlib import Path from datetime import datetime @@ -14,7 +13,6 @@ import openmdao.api as om from openmdao.utils.units import convert_units -from openmdao.utils.units import valid_units from aviary.constants import GRAV_ENGLISH_LBM, RHO_SEA_LEVEL_ENGLISH from aviary.mission.flops_based.phases.build_landing import Landing @@ -32,6 +30,7 @@ from aviary.mission.gasp_based.phases.accel_phase import get_accel from aviary.mission.gasp_based.phases.ascent_phase import get_ascent from aviary.mission.gasp_based.phases.climb_phase import get_climb +from aviary.mission.gasp_based.phases.new_climb_phase import ClimbPhase from aviary.mission.gasp_based.phases.desc_phase import get_descent from aviary.mission.gasp_based.phases.groundroll_phase import get_groundroll from aviary.mission.gasp_based.phases.landing_group import LandingSegment @@ -205,8 +204,6 @@ def load_inputs(self, input_filename, phase_info=None, engine_builder=None): # Access the phase_info variable from the loaded module phase_info = outputted_phase_info.phase_info - print('Loaded outputted_phase_info.py generated with GUI') - else: if self.mission_method is TWO_DEGREES_OF_FREEDOM: from aviary.interface.default_phase_info.two_dof import phase_info @@ -559,6 +556,10 @@ def _get_2dof_phase(self, phase_name): # Get the phase options for the specified phase name phase_options = self.phase_info[phase_name] + subsystems = self.core_subsystems + default_mission_subsystems = [ + subsystems['aerodynamics'], subsystems['propulsion']] + if 'cruise' in phase_name: phase = dm.AnalyticPhase( ode_class=BreguetCruiseODESolution, @@ -582,9 +583,12 @@ def _get_2dof_phase(self, phase_name): ) phase.add_parameter(Dynamic.Mission.ALTITUDE, opt=False, - val=self.phase_info['climb2']['final_alt'][0], units=self.phase_info['climb2']['final_alt'][1]) + val=self.phase_info['climb2']['user_options']['final_alt'][0], units=self.phase_info['climb2']['user_options']['final_alt'][1]) + mach_cruise = self.phase_info['climb2']['user_options']['mach_cruise'] + if type(mach_cruise) is tuple: + mach_cruise = mach_cruise[0] phase.add_parameter(Dynamic.Mission.MACH, opt=False, - val=self.phase_info['climb2']['mach_cruise']) + val=mach_cruise) phase.add_parameter("initial_distance", opt=False, val=0.0, units="NM", static_target=True) phase.add_parameter("initial_time", opt=False, val=0.0, @@ -593,13 +597,6 @@ def _get_2dof_phase(self, phase_name): phase.add_timeseries_output("time", units="s") else: - # Create a Radau transcription scheme object with the specified num_segments and order - transcription = dm.Radau( - num_segments=phase_options['num_segments'], - order=phase_options['order'], - compressed=True, - solve_segments=False) - # Create a dictionary of phase functions phase_functions = { 'groundroll': get_groundroll, @@ -611,8 +608,22 @@ def _get_2dof_phase(self, phase_name): # Set the phase function based on the phase name if 'climb' in phase_name: phase_functions[phase_name] = get_climb + num_segments = phase_options['user_options']['num_segments'] + order = phase_options['user_options']['order'] elif 'desc' in phase_name: phase_functions[phase_name] = get_descent + num_segments = phase_options['num_segments'] + order = phase_options['order'] + else: + num_segments = phase_options['num_segments'] + order = phase_options['order'] + + # Create a Radau transcription scheme object with the specified num_segments and order + transcription = dm.Radau( + num_segments=num_segments, + order=order, + compressed=True, + solve_segments=False) # Get the phase function corresponding to the phase name phase_func = phase_functions.get(phase_name) @@ -620,7 +631,7 @@ def _get_2dof_phase(self, phase_name): # Calculate the phase by calling the phase function # with the transcription object and remaining phase options trimmed_phase_options = {k: v for k, v in phase_options.items( - ) if k not in ['num_segments', 'order', 'initial_guesses', 'throttle_setting', 'external_subsystems']} + ) if k not in ['num_segments', 'order', 'initial_guesses', 'external_subsystems']} # define expected units for each phase option expected_units = { @@ -649,10 +660,16 @@ def _get_2dof_phase(self, phase_name): trimmed_phase_options[key] = wrapped_convert_units( value, expected_unit) - phase = phase_func( - ode_args=self.ode_args, - transcription=transcription, - **trimmed_phase_options) + if 'climb' in phase_name: + phase_object = ClimbPhase.from_phase_info( + phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) + phase = phase_object.build_phase(aviary_options=self.aviary_inputs) + + else: + phase = phase_func( + ode_args=self.ode_args, + transcription=transcription, + **trimmed_phase_options) phase.add_control( Dynamic.Mission.THROTTLE, targets=Dynamic.Mission.THROTTLE, units='unitless', diff --git a/aviary/interface/utils/check_phase_info.py b/aviary/interface/utils/check_phase_info.py index 1e592be4d..68cda2e83 100644 --- a/aviary/interface/utils/check_phase_info.py +++ b/aviary/interface/utils/check_phase_info.py @@ -102,7 +102,6 @@ def check_phase_info(phase_info, mission_method): 'time_initial_bounds': tuple, 'time_initial_ref': tuple, 'alt_constraint_ref': tuple, - 'throttle_setting': float, } phase_keys_gasp = { @@ -113,7 +112,6 @@ def check_phase_info(phase_info, mission_method): **common_TAS, **common_mass, **common_distance, - 'throttle_setting': float, 'distance_defect_ref': tuple, }, 'rotation': { @@ -123,7 +121,6 @@ def check_phase_info(phase_info, mission_method): **common_distance, **common_angle, 'normal_ref': tuple, - 'throttle_setting': float, 'TAS_ref0': tuple, 'distance_defect_ref': tuple, }, @@ -140,7 +137,6 @@ def check_phase_info(phase_info, mission_method): 'pitch_constraint_lower': tuple, 'pitch_constraint_upper': tuple, 'pitch_constraint_ref': tuple, - 'throttle_setting': float, 'TAS_ref0': tuple, 'distance_defect_ref': tuple, }, @@ -153,7 +149,6 @@ def check_phase_info(phase_info, mission_method): **common_TAS, **common_mass, **common_distance, - 'throttle_setting': float, 'TAS_ref0': tuple, 'distance_defect_ref': tuple, }, @@ -167,7 +162,6 @@ def check_phase_info(phase_info, mission_method): **common_alt, **common_mass, **common_distance, - 'throttle_setting': float, 'distance_ref0': tuple, }, 'climb2': { @@ -181,7 +175,6 @@ def check_phase_info(phase_info, mission_method): **common_alt, **common_mass, **common_distance, - 'throttle_setting': float, 'alt_ref0': tuple, 'distance_ref0': tuple, 'distance_defect_ref': tuple, diff --git a/aviary/mission/flops_based/phases/phase_builder_base.py b/aviary/mission/flops_based/phases/phase_builder_base.py index b299689c5..2ec5f8b0e 100644 --- a/aviary/mission/flops_based/phases/phase_builder_base.py +++ b/aviary/mission/flops_based/phases/phase_builder_base.py @@ -481,7 +481,7 @@ def to_phase_info(self): return (self.name, phase_info) @classmethod - def from_phase_info(cls, name, phase_info: dict, core_subsystems=None, meta_data=None): + def from_phase_info(cls, name, phase_info: dict, core_subsystems=None, meta_data=None, transcription=None): ''' Return a new phase builder based on the specified phase info. @@ -518,7 +518,7 @@ def from_phase_info(cls, name, phase_info: dict, core_subsystems=None, meta_data phase_builder = cls( name, subsystem_options=subsystem_options, user_options=user_options, initial_guesses=initial_guesses, meta_data=meta_data, - core_subsystems=core_subsystems, external_subsystems=external_subsystems) + core_subsystems=core_subsystems, external_subsystems=external_subsystems, transcription=transcription) return phase_builder diff --git a/aviary/mission/gasp_based/phases/climb_phase.py b/aviary/mission/gasp_based/phases/climb_phase.py index 08a28330f..c4791dbf1 100644 --- a/aviary/mission/gasp_based/phases/climb_phase.py +++ b/aviary/mission/gasp_based/phases/climb_phase.py @@ -33,6 +33,7 @@ def get_climb( distance_ref0=0, distance_defect_ref=None, ): + ode_init_kwargs = dict( EAS_target=EAS_target, mach_cruise=mach_cruise, diff --git a/aviary/mission/gasp_based/phases/new_climb_phase.py b/aviary/mission/gasp_based/phases/new_climb_phase.py index 511a18fb0..0f517b9a2 100644 --- a/aviary/mission/gasp_based/phases/new_climb_phase.py +++ b/aviary/mission/gasp_based/phases/new_climb_phase.py @@ -1,10 +1,9 @@ -import dymos as dm from aviary.mission.flops_based.phases.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime) + PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic from aviary.mission.gasp_based.ode.climb_ode import ClimbODE -from aviary.interface.default_phase_info.two_dof import default_mission_subsystems +from aviary.variable_info.variable_meta_data import _MetaData class ClimbPhase(PhaseBuilderBase): @@ -26,6 +25,15 @@ class ClimbPhase(PhaseBuilderBase): default_name = 'climb_phase' default_ode_class = ClimbODE + __slots__ = ('external_subsystems', 'meta_data') + + # region : derived type customization points + _meta_data_ = {} + + _initial_guesses_meta_data_ = {} + + default_meta_data = _MetaData + def __init__( self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, ode_class=None, transcription=None, core_subsystems=None, @@ -34,10 +42,20 @@ def __init__( super().__init__( name=name, subsystem_options=subsystem_options, user_options=user_options, initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, - core_subsystems=core_subsystems, external_subsystems=external_subsystems, - meta_data=meta_data + core_subsystems=core_subsystems, ) + # TODO: support external_subsystems and meta_data in the base class + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + + self.meta_data = meta_data + def build_phase(self, aviary_options: AviaryValues = None): """ Return a new climb phase for analysis using these constraints. @@ -58,58 +76,105 @@ def build_phase(self, aviary_options: AviaryValues = None): # Custom configurations for the climb phase user_options = self.user_options + fix_initial = user_options.get_val('fix_initial') + mach_cruise = user_options.get_val('mach_cruise') + target_mach = user_options.get_val('target_mach') + final_alt = user_options.get_val('final_alt', units='ft') + required_available_climb_rate = user_options.get_val( + 'required_available_climb_rate', units='ft/min') + time_initial_bounds = user_options.get_val('time_initial_bounds', units='s') + duration_bounds = user_options.get_val('duration_bounds', units='s') + duration_ref = user_options.get_val('duration_ref', units='s') + alt_lower = user_options.get_val('alt_lower', units='ft') + alt_upper = user_options.get_val('alt_upper', units='ft') + alt_ref = user_options.get_val('alt_ref', units='ft') + alt_ref0 = user_options.get_val('alt_ref0', units='ft') + alt_defect_ref = user_options.get_val('alt_defect_ref', units='ft') + mass_lower = user_options.get_val('mass_lower', units='lbm') + mass_upper = user_options.get_val('mass_upper', units='lbm') + mass_ref = user_options.get_val('mass_ref', units='lbm') + mass_ref0 = user_options.get_val('mass_ref0', units='lbm') + mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') + distance_lower = user_options.get_val('distance_lower', units='NM') + distance_upper = user_options.get_val('distance_upper', units='NM') + distance_ref = user_options.get_val('distance_ref', units='NM') + distance_ref0 = user_options.get_val('distance_ref0', units='NM') + distance_defect_ref = user_options.get_val('distance_defect_ref', units='NM') + + phase.set_time_options( + fix_initial=fix_initial, + initial_bounds=time_initial_bounds, + duration_bounds=duration_bounds, + duration_ref=duration_ref, + units="s", + ) + # States phase.add_state( Dynamic.Mission.ALTITUDE, - fix_initial=user_options.get_val('fix_initial'), + fix_initial=fix_initial, fix_final=False, - lower=user_options.get_val('alt_lower'), - upper=user_options.get_val('alt_upper'), + lower=alt_lower, + upper=alt_upper, units="ft", rate_source=Dynamic.Mission.ALTITUDE_RATE, targets=Dynamic.Mission.ALTITUDE, - ref=user_options.get_val('alt_ref'), - ref0=user_options.get_val('alt_ref0'), - defect_ref=user_options.get_val('alt_defect_ref'), + ref=alt_ref, + ref0=alt_ref0, + defect_ref=alt_defect_ref, ) phase.add_state( Dynamic.Mission.MASS, - fix_initial=user_options.get_val('fix_initial'), + fix_initial=fix_initial, fix_final=False, - lower=user_options.get_val('mass_lower'), - upper=user_options.get_val('mass_upper'), + lower=mass_lower, + upper=mass_upper, units="lbm", rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, targets=Dynamic.Mission.MASS, - ref=user_options.get_val('mass_ref'), - ref0=user_options.get_val('mass_ref0'), - defect_ref=user_options.get_val('mass_defect_ref'), + ref=mass_ref, + ref0=mass_ref0, + defect_ref=mass_defect_ref, ) - # Boundary Constraints - if user_options.get_val('target_mach'): - phase.add_boundary_constraint( - Dynamic.Mission.MACH, loc="final", equals=user_options.get_val('mach_cruise'), units="unitless" - ) + phase.add_state( + Dynamic.Mission.DISTANCE, + fix_initial=fix_initial, + fix_final=False, + lower=distance_lower, + upper=distance_upper, + units="NM", + rate_source="distance_rate", + ref=distance_ref, + ref0=distance_ref0, + defect_ref=distance_defect_ref, + ) + # Boundary Constraints phase.add_boundary_constraint( Dynamic.Mission.ALTITUDE, loc="final", - equals=user_options.get_val('final_alt'), + equals=final_alt, units="ft", - ref=user_options.get_val('final_alt') + ref=final_alt, ) - if user_options.get_val('required_available_climb_rate') is not None: + if required_available_climb_rate is not None: + # TODO: this should be altitude rate max phase.add_boundary_constraint( Dynamic.Mission.ALTITUDE_RATE, loc="final", - lower=user_options.get_val('required_available_climb_rate'), + lower=required_available_climb_rate, units="ft/min", ref=1, ) + if target_mach: + phase.add_boundary_constraint( + Dynamic.Mission.MACH, loc="final", equals=mach_cruise, + ) + # Timeseries Outputs phase.add_timeseries_output( Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") @@ -130,20 +195,61 @@ def build_phase(self, aviary_options: AviaryValues = None): return phase -# Function to create and configure ClimbPhase - - -def get_climb_phase(user_options): - # Instantiate ClimbPhase with user options - climb_phase = ClimbPhase(user_options=user_options) - - # Build the phase - climb = climb_phase.build_phase() - - return climb - - -# Example usage -user_options = AviaryValues() -# Set the required user options -climb = get_climb_phase(user_options=user_options) + def _extra_ode_init_kwargs(self): + """ + Return extra kwargs required for initializing the ODE. + """ + # TODO: support external_subsystems and meta_data in the base class + return { + 'EAS_target': self.user_options.get_val('EAS_target', units='kn'), + 'mach_cruise': self.user_options.get_val('mach_cruise'), + } + + +# Adding metadata for the ClimbPhase +ClimbPhase._add_meta_data('fix_initial', val=False) +ClimbPhase._add_meta_data('EAS_target', val=0) +ClimbPhase._add_meta_data('mach_cruise', val=0) +ClimbPhase._add_meta_data('target_mach', val=False) +ClimbPhase._add_meta_data('final_alt', val=0) +ClimbPhase._add_meta_data('required_available_climb_rate', val=None, units='ft/min') +ClimbPhase._add_meta_data('time_initial_bounds', val=(0, 0), units='s') +ClimbPhase._add_meta_data('duration_bounds', val=(0, 0), units='s') +ClimbPhase._add_meta_data('duration_ref', val=1, units='s') +ClimbPhase._add_meta_data('alt_lower', val=0, units='ft') +ClimbPhase._add_meta_data('alt_upper', val=0, units='ft') +ClimbPhase._add_meta_data('alt_ref', val=1, units='ft') +ClimbPhase._add_meta_data('alt_ref0', val=0, units='ft') +ClimbPhase._add_meta_data('alt_defect_ref', val=None, units='ft') +ClimbPhase._add_meta_data('mass_lower', val=0, units='lbm') +ClimbPhase._add_meta_data('mass_upper', val=0, units='lbm') +ClimbPhase._add_meta_data('mass_ref', val=1, units='lbm') +ClimbPhase._add_meta_data('mass_ref0', val=0, units='lbm') +ClimbPhase._add_meta_data('mass_defect_ref', val=None, units='lbm') +ClimbPhase._add_meta_data('distance_lower', val=0, units='NM') +ClimbPhase._add_meta_data('distance_upper', val=0, units='NM') +ClimbPhase._add_meta_data('distance_ref', val=1, units='NM') +ClimbPhase._add_meta_data('distance_ref0', val=0, units='NM') +ClimbPhase._add_meta_data('distance_defect_ref', val=None, units='NM') +ClimbPhase._add_meta_data('num_segments', val=None, units='unitless') +ClimbPhase._add_meta_data('order', val=None, units='unitless') + +ClimbPhase._add_initial_guess_meta_data( + InitialGuessTime(), + desc='initial guess for initial time and duration specified as a tuple') + +ClimbPhase._add_initial_guess_meta_data( + InitialGuessState('distance'), + desc='initial guess for horizontal distance traveled') + +ClimbPhase._add_initial_guess_meta_data( + InitialGuessState('altitude'), + desc='initial guess for vertical distances') + +ClimbPhase._add_initial_guess_meta_data( + InitialGuessState('mass'), + desc='initial guess for mass') + +ClimbPhase._add_initial_guess_meta_data( + InitialGuessControl('throttle'), + desc='initial guess for throttle') From 80cf3b67b998c31901cf964e12f98c54f02b6848 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Tue, 16 Jan 2024 23:11:24 -0600 Subject: [PATCH 076/188] Fixed benches and docs --- .../FLOPS_based_detailed_takeoff_and_landing.ipynb | 4 ++-- ...xamples_of_the_same_mission_at_different_UI_levels.ipynb | 6 +++--- aviary/validation_cases/benchmark_utils.py | 2 -- 3 files changed, 5 insertions(+), 7 deletions(-) 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 f89d2d31e..e13abbf88 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 @@ -144,7 +144,7 @@ "takeoff_brake_release_initial_guesses = av.AviaryValues()\n", "\n", "takeoff_brake_release_initial_guesses.set_val('times', [0., 30.], 's')\n", - "takeoff_brake_release_initial_guesses.set_val('range', [0., 4100.], 'ft')\n", + "takeoff_brake_release_initial_guesses.set_val('distance', [0., 4100.], 'ft')\n", "takeoff_brake_release_initial_guesses.set_val('velocity', [0.01, 150.], 'kn')\n", "\n", "gross_mass_units = 'lbm'\n", @@ -449,7 +449,7 @@ "landing_approach_to_mic_p3_initial_guesses = av.AviaryValues()\n", "\n", "landing_approach_to_mic_p3_initial_guesses.set_val('times', [-42., 15.], 's')\n", - "landing_approach_to_mic_p3_initial_guesses.set_val('range', [-4000., -2000.], 'ft')\n", + "landing_approach_to_mic_p3_initial_guesses.set_val('distance', [-4000., -2000.], 'ft')\n", "landing_approach_to_mic_p3_initial_guesses.set_val('velocity', 140., 'kn')\n", "landing_approach_to_mic_p3_initial_guesses.set_val('mass', detailed_landing_mass, 'lbm')\n", "landing_approach_to_mic_p3_initial_guesses.set_val('throttle', throttle)\n", 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 e2ea405ec..c4b1637cf 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 @@ -90,7 +90,7 @@ " 'altitude': ([0., 35.e3], 'ft'),\n", " 'velocity': ([220., 455.49], 'kn'),\n", " 'mass': ([170.e3, 165.e3], 'lbm'),\n", - " 'range': ([0., 160.3], 'nmi'),\n", + " 'distance': ([0., 160.3], 'nmi'),\n", " 'velocity_rate': ([0.25, 0.05], 'm/s**2'),\n", " 'throttle': ([0.5, 0.5], 'unitless'),\n", " }\n", @@ -122,7 +122,7 @@ " 'altitude': ([35.e3, 35.e3], 'ft'),\n", " 'velocity': ([455.49, 455.49], 'kn'),\n", " 'mass': ([165.e3, 140.e3], 'lbm'),\n", - " 'range': ([160.3, 3243.9], 'nmi'),\n", + " 'distance': ([160.3, 3243.9], 'nmi'),\n", " 'velocity_rate': ([0., 0.], 'm/s**2'),\n", " 'throttle': ([0.95, 0.9], 'unitless'),\n", " }\n", @@ -152,7 +152,7 @@ " 'altitude': ([35.e3, 35.], 'ft'),\n", " 'velocity': ([455.49, 198.44], 'kn'),\n", " 'mass': ([120.e3, 115.e3], 'lbm'),\n", - " 'range': ([3243.9, 3378.7], 'nmi'),\n", + " 'distance': ([3243.9, 3378.7], 'nmi'),\n", " 'velocity_rate': ([-0.25, 0.0], 'm/s**2'),\n", " 'throttle': ([0., 0.], 'unitless'),\n", " }\n", diff --git a/aviary/validation_cases/benchmark_utils.py b/aviary/validation_cases/benchmark_utils.py index 082047908..0d2186576 100644 --- a/aviary/validation_cases/benchmark_utils.py +++ b/aviary/validation_cases/benchmark_utils.py @@ -40,8 +40,6 @@ def compare_against_expected_values(prob, expected_dict, simple_flag=False): prob.get_val(f'traj.{phase}.timeseries.states:mass', units='kg')) ranges.extend( prob.get_val(f'traj.{phase}.timeseries.states:distance', units='m')) - velocities.extend(prob.get_val( - f'traj.{phase}.timeseries.states:velocity', units='m/s')) times = np.array(times) altitudes = np.array(altitudes) From a1974e28d0b90b1d8f0b990d80540dc87490e912 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 17 Jan 2024 09:44:06 -0600 Subject: [PATCH 077/188] Updated more range->distance calls --- aviary/constants.py | 2 +- aviary/docs/examples/OAS_subsystem.ipynb | 6 +-- .../examples/additional_flight_phases.ipynb | 14 +++--- ...oupled_aircraft_mission_optimization.ipynb | 6 +-- .../docs/examples/more_advanced_example.ipynb | 6 +-- .../examples/simple_mission_example.ipynb | 6 +-- .../onboarding_ext_subsystem.ipynb | 6 +-- .../getting_started/onboarding_level3.ipynb | 48 +++++++++---------- ..._same_mission_at_different_UI_levels.ipynb | 27 +++++------ .../OAS_weight/run_simple_OAS_mission.py | 6 +-- aviary/examples/run_aviary_example.py | 6 +-- aviary/interface/default_phase_info/simple.py | 6 +-- aviary/interface/graphical_input.py | 10 ++-- aviary/interface/methods_for_level2.py | 14 +++--- aviary/interface/test/test_simple_mission.py | 14 +++--- .../flops_based/phases/simple_energy_phase.py | 6 +-- .../ode/unsteady_solved/gamma_comp.py | 6 +-- .../unsteady_solved/unsteady_solved_eom.py | 6 +-- .../unsteady_solved_flight_conditions.py | 4 +- .../unsteady_solved/unsteady_solved_ode.py | 9 ++-- aviary/utils/Fortran_to_Aviary.py | 4 +- .../benchmark_tests/test_bench_FwFm.py | 6 +-- .../benchmark_tests/test_bench_GwFm.py | 6 +-- .../test_full_mission_solved_ode.py | 10 ++-- 24 files changed, 117 insertions(+), 117 deletions(-) diff --git a/aviary/constants.py b/aviary/constants.py index 55dfca1d5..c7770d804 100644 --- a/aviary/constants.py +++ b/aviary/constants.py @@ -1,6 +1,6 @@ import openmdao.utils.units as units -units.add_unit('range_units', '1*m') +units.add_unit('distance_units', '1*m') GRAV_METRIC_GASP = 9.81 # m/s^2 GRAV_ENGLISH_GASP = 32.2 # ft/s^2 diff --git a/aviary/docs/examples/OAS_subsystem.ipynb b/aviary/docs/examples/OAS_subsystem.ipynb index 3e7db68f6..cff6691c7 100644 --- a/aviary/docs/examples/OAS_subsystem.ipynb +++ b/aviary/docs/examples/OAS_subsystem.ipynb @@ -254,7 +254,7 @@ " 'polynomial_control_order': 1,\n", " 'num_segments': 5,\n", " 'order': 3,\n", - " 'solve_for_range': False,\n", + " 'solve_for_distance': False,\n", " 'initial_mach': (0.2, 'unitless'),\n", " 'final_mach': (0.72, 'unitless'),\n", " 'mach_bounds': ((0.18, 0.74), 'unitless'),\n", @@ -278,7 +278,7 @@ " 'polynomial_control_order': 1,\n", " 'num_segments': 5,\n", " 'order': 3,\n", - " 'solve_for_range': False,\n", + " 'solve_for_distance': False,\n", " 'initial_mach': (0.72, 'unitless'),\n", " 'final_mach': (0.72, 'unitless'),\n", " 'mach_bounds': ((0.7, 0.74), 'unitless'),\n", @@ -302,7 +302,7 @@ " 'polynomial_control_order': 1,\n", " 'num_segments': 5,\n", " 'order': 3,\n", - " 'solve_for_range': False,\n", + " 'solve_for_distance': False,\n", " 'initial_mach': (0.72, 'unitless'),\n", " 'final_mach': (0.36, 'unitless'),\n", " 'mach_bounds': ((0.34, 0.74), 'unitless'),\n", diff --git a/aviary/docs/examples/additional_flight_phases.ipynb b/aviary/docs/examples/additional_flight_phases.ipynb index a28066d63..7a5cf85a8 100644 --- a/aviary/docs/examples/additional_flight_phases.ipynb +++ b/aviary/docs/examples/additional_flight_phases.ipynb @@ -38,7 +38,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 3,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.2, \"unitless\"),\n", " \"final_mach\": (0.72, \"unitless\"),\n", " \"mach_bounds\": ((0.18, 0.74), \"unitless\"),\n", @@ -62,7 +62,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 3,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.72, \"unitless\"),\n", " \"final_mach\": (0.72, \"unitless\"),\n", " \"mach_bounds\": ((0.7, 0.74), \"unitless\"),\n", @@ -86,7 +86,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 3,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.72, \"unitless\"),\n", " \"final_mach\": (0.74, \"unitless\"),\n", " \"mach_bounds\": ((0.7, 0.76), \"unitless\"),\n", @@ -110,7 +110,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 3,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.74, \"unitless\"),\n", " \"final_mach\": (0.74, \"unitless\"),\n", " \"mach_bounds\": ((0.72, 0.76), \"unitless\"),\n", @@ -134,7 +134,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 3,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.74, \"unitless\"),\n", " \"final_mach\": (0.76, \"unitless\"),\n", " \"mach_bounds\": ((0.72, 0.78), \"unitless\"),\n", @@ -158,7 +158,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 3,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.76, \"unitless\"),\n", " \"final_mach\": (0.76, \"unitless\"),\n", " \"mach_bounds\": ((0.74, 0.78), \"unitless\"),\n", @@ -182,7 +182,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 3,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.76, \"unitless\"),\n", " \"final_mach\": (0.2, \"unitless\"),\n", " \"mach_bounds\": ((0.18, 0.78), \"unitless\"),\n", diff --git a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb index 850f8a627..b39e7217d 100644 --- a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb +++ b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb @@ -54,7 +54,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 5,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.2, \"unitless\"),\n", " \"final_mach\": (0.72, \"unitless\"),\n", " \"mach_bounds\": ((0.18, 0.84), \"unitless\"),\n", @@ -78,7 +78,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 5,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.72, \"unitless\"),\n", " \"final_mach\": (0.80, \"unitless\"),\n", " \"mach_bounds\": ((0.7, 0.84), \"unitless\"),\n", @@ -102,7 +102,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 5,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.72, \"unitless\"),\n", " \"final_mach\": (0.21, \"unitless\"),\n", " \"mach_bounds\": ((0.19, 0.84), \"unitless\"),\n", diff --git a/aviary/docs/examples/more_advanced_example.ipynb b/aviary/docs/examples/more_advanced_example.ipynb index ee8e50ece..bd2875bca 100644 --- a/aviary/docs/examples/more_advanced_example.ipynb +++ b/aviary/docs/examples/more_advanced_example.ipynb @@ -36,7 +36,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 3,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.2, \"unitless\"),\n", " \"final_mach\": (0.72, \"unitless\"),\n", " \"mach_bounds\": ((0.18, 0.74), \"unitless\"),\n", @@ -60,7 +60,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 3,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.72, \"unitless\"),\n", " \"final_mach\": (0.72, \"unitless\"),\n", " \"mach_bounds\": ((0.7, 0.74), \"unitless\"),\n", @@ -84,7 +84,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 3,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.72, \"unitless\"),\n", " \"final_mach\": (0.2, \"unitless\"),\n", " \"mach_bounds\": ((0.18, 0.74), \"unitless\"),\n", diff --git a/aviary/docs/examples/simple_mission_example.ipynb b/aviary/docs/examples/simple_mission_example.ipynb index 40556809d..6c3f17509 100644 --- a/aviary/docs/examples/simple_mission_example.ipynb +++ b/aviary/docs/examples/simple_mission_example.ipynb @@ -143,7 +143,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 2,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.2, \"unitless\"),\n", " \"final_mach\": (0.72, \"unitless\"),\n", " \"mach_bounds\": ((0.18, 0.74), \"unitless\"),\n", @@ -167,7 +167,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 2,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.72, \"unitless\"),\n", " \"final_mach\": (0.72, \"unitless\"),\n", " \"mach_bounds\": ((0.7, 0.74), \"unitless\"),\n", @@ -191,7 +191,7 @@ " \"polynomial_control_order\": 1,\n", " \"num_segments\": 2,\n", " \"order\": 3,\n", - " \"solve_for_range\": False,\n", + " \"solve_for_distance\": False,\n", " \"initial_mach\": (0.72, \"unitless\"),\n", " \"final_mach\": (0.2, \"unitless\"),\n", " \"mach_bounds\": ((0.18, 0.74), \"unitless\"),\n", diff --git a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb index 5b6ac3718..e9a66393a 100644 --- a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb +++ b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb @@ -532,7 +532,7 @@ " 'polynomial_control_order': 1,\n", " 'num_segments': 5,\n", " 'order': 3,\n", - " 'solve_for_range': False,\n", + " 'solve_for_distance': False,\n", " 'initial_mach': (0.2, 'unitless'),\n", " 'final_mach': (0.72, 'unitless'),\n", " 'mach_bounds': ((0.18, 0.74), 'unitless'),\n", @@ -556,7 +556,7 @@ " 'polynomial_control_order': 1,\n", " 'num_segments': 5,\n", " 'order': 3,\n", - " 'solve_for_range': False,\n", + " 'solve_for_distance': False,\n", " 'initial_mach': (0.72, 'unitless'),\n", " 'final_mach': (0.72, 'unitless'),\n", " 'mach_bounds': ((0.7, 0.74), 'unitless'),\n", @@ -580,7 +580,7 @@ " 'polynomial_control_order': 1,\n", " 'num_segments': 5,\n", " 'order': 3,\n", - " 'solve_for_range': False,\n", + " 'solve_for_distance': False,\n", " 'initial_mach': (0.72, 'unitless'),\n", " 'final_mach': (0.36, 'unitless'),\n", " 'mach_bounds': ((0.34, 0.74), 'unitless'),\n", diff --git a/aviary/docs/getting_started/onboarding_level3.ipynb b/aviary/docs/getting_started/onboarding_level3.ipynb index 38a6bc929..6d8915358 100644 --- a/aviary/docs/getting_started/onboarding_level3.ipynb +++ b/aviary/docs/getting_started/onboarding_level3.ipynb @@ -136,8 +136,8 @@ "# mach_i_climb = 0.3\n", "mach_i_climb = 0.2\n", "mach_f_climb = cruise_mach\n", - "range_i_climb = 0*_units.nautical_mile # m\n", - "range_f_climb = 160.3*_units.nautical_mile # m\n", + "distance_i_climb = 0*_units.nautical_mile # m\n", + "distance_f_climb = 160.3*_units.nautical_mile # m\n", "t_i_climb = 2 * _units.minute # sec\n", "t_f_climb = 26.20*_units.minute # sec\n", "t_duration_climb = t_f_climb - t_i_climb\n", @@ -152,8 +152,8 @@ "v_f_cruise = 455.49*_units.knot # m/s\n", "mach_min_cruise = cruise_mach\n", "mach_max_cruise = cruise_mach\n", - "range_i_cruise = 160.3*_units.nautical_mile # m\n", - "range_f_cruise = 3243.9*_units.nautical_mile # m\n", + "distance_i_cruise = 160.3*_units.nautical_mile # m\n", + "distance_f_cruise = 3243.9*_units.nautical_mile # m\n", "t_i_cruise = 26.20*_units.minute # sec\n", "t_f_cruise = 432.38*_units.minute # sec\n", "t_duration_cruise = t_f_cruise - t_i_cruise\n", @@ -168,8 +168,8 @@ "mach_f_descent = 0.3\n", "mass_i_descent = 102000*_units.pound\n", "mass_f_descent = 101000*_units.pound\n", - "range_i_descent = 3243.9*_units.nautical_mile\n", - "range_f_descent = 3378.7*_units.nautical_mile\n", + "distance_i_descent = 3243.9*_units.nautical_mile\n", + "distance_f_descent = 3378.7*_units.nautical_mile\n", "t_i_descent = 432.38*_units.minute\n", "t_f_descent = 461.62*_units.minute\n", "t_duration_descent = t_f_descent - t_i_descent\n", @@ -340,13 +340,13 @@ " om.ExecComp(\n", " [\n", " \"takeoff_mass_con=takeoff_mass-climb_start_mass\",\n", - " \"takeoff_range_con=takeoff_range-climb_start_range\",\n", + " \"takeoff_distance_con=takeoff_range-climb_start_range\",\n", " \"takeoff_vel_con=takeoff_vel-climb_start_vel\",\n", " \"takeoff_alt_con=takeoff_alt-climb_start_alt\"\n", " ],\n", " takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'},\n", " climb_start_mass={'units': 'lbm'},\n", - " takeoff_range_con={'units': 'ft'}, takeoff_range={'units': 'ft'},\n", + " takeoff_distance_con={'units': 'ft'}, takeoff_range={'units': 'ft'},\n", " climb_start_range={'units': 'ft'},\n", " takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'},\n", " climb_start_vel={'units': 'm/s'},\n", @@ -359,7 +359,7 @@ " (\"takeoff_vel\", Mission.Takeoff.FINAL_VELOCITY),\n", " (\"takeoff_alt\", Mission.Takeoff.FINAL_ALTITUDE),\n", " ],\n", - " promotes_outputs=[\"takeoff_mass_con\", \"takeoff_range_con\",\n", + " promotes_outputs=[\"takeoff_mass_con\", \"takeoff_distance_con\",\n", " \"takeoff_vel_con\", \"takeoff_alt_con\"],\n", ")\n", "\n", @@ -444,7 +444,7 @@ "prob.set_val('traj.climb.states:mass', climb.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", "prob.set_val('traj.climb.states:distance', climb.interp(\n", - " Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') # nmi\n", + " Dynamic.Mission.DISTANCE, ys=[distance_i_climb, distance_f_climb]), units='m') # nmi\n", "\n", "prob.set_val('traj.climb.controls:velocity_rate',\n", " climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.0]),\n", @@ -463,7 +463,7 @@ "prob.set_val('traj.cruise.states:mass', cruise.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", "prob.set_val('traj.cruise.states:distance', cruise.interp(\n", - " Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi\n", + " Dynamic.Mission.DISTANCE, ys=[distance_i_cruise, distance_f_cruise]), units='m') # nmi\n", "\n", "prob.set_val('traj.cruise.controls:velocity_rate',\n", " cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]),\n", @@ -482,7 +482,7 @@ "prob.set_val('traj.descent.states:mass', descent.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", "prob.set_val('traj.descent.states:distance', descent.interp(\n", - " Dynamic.Mission.DISTANCE, ys=[range_i_descent, range_f_descent]), units='m')\n", + " Dynamic.Mission.DISTANCE, ys=[distance_i_descent, distance_f_descent]), units='m')\n", "\n", "prob.set_val('traj.descent.controls:velocity_rate',\n", " descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.0]),\n", @@ -605,8 +605,8 @@ "# mach_i_climb = 0.3\n", "mach_i_climb = 0.2\n", "mach_f_climb = cruise_mach\n", - "range_i_climb = 0*_units.nautical_mile # m\n", - "range_f_climb = 160.3*_units.nautical_mile # m\n", + "distance_i_climb = 0*_units.nautical_mile # m\n", + "distance_f_climb = 160.3*_units.nautical_mile # m\n", "t_i_climb = 2 * _units.minute # sec\n", "t_f_climb = 26.20*_units.minute # sec\n", "t_duration_climb = t_f_climb - t_i_climb\n", @@ -621,8 +621,8 @@ "v_f_cruise = 455.49*_units.knot # m/s\n", "mach_min_cruise = cruise_mach\n", "mach_max_cruise = cruise_mach\n", - "range_i_cruise = 160.3*_units.nautical_mile # m\n", - "range_f_cruise = 3243.9*_units.nautical_mile # m\n", + "distance_i_cruise = 160.3*_units.nautical_mile # m\n", + "distance_f_cruise = 3243.9*_units.nautical_mile # m\n", "t_i_cruise = 26.20*_units.minute # sec\n", "t_f_cruise = 432.38*_units.minute # sec\n", "t_duration_cruise = t_f_cruise - t_i_cruise\n", @@ -637,8 +637,8 @@ "mach_f_descent = 0.3\n", "mass_i_descent = 102000*_units.pound\n", "mass_f_descent = 101000*_units.pound\n", - "range_i_descent = 3243.9*_units.nautical_mile\n", - "range_f_descent = 3378.7*_units.nautical_mile\n", + "distance_i_descent = 3243.9*_units.nautical_mile\n", + "distance_f_descent = 3378.7*_units.nautical_mile\n", "t_i_descent = 432.38*_units.minute\n", "t_f_descent = 461.62*_units.minute\n", "t_duration_descent = t_f_descent - t_i_descent\n", @@ -695,13 +695,13 @@ " om.ExecComp(\n", " [\n", " \"takeoff_mass_con=takeoff_mass-climb_start_mass\",\n", - " \"takeoff_range_con=takeoff_range-climb_start_range\",\n", + " \"takeoff_distance_con=takeoff_range-climb_start_range\",\n", " \"takeoff_vel_con=takeoff_vel-climb_start_vel\",\n", " \"takeoff_alt_con=takeoff_alt-climb_start_alt\"\n", " ],\n", " takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'},\n", " climb_start_mass={'units': 'lbm'},\n", - " takeoff_range_con={'units': 'ft'}, takeoff_range={'units': 'ft'},\n", + " takeoff_distance_con={'units': 'ft'}, takeoff_range={'units': 'ft'},\n", " climb_start_range={'units': 'ft'},\n", " takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'},\n", " climb_start_vel={'units': 'm/s'},\n", @@ -714,7 +714,7 @@ " (\"takeoff_vel\", Mission.Takeoff.FINAL_VELOCITY),\n", " (\"takeoff_alt\", Mission.Takeoff.FINAL_ALTITUDE),\n", " ],\n", - " promotes_outputs=[\"takeoff_mass_con\", \"takeoff_range_con\",\n", + " promotes_outputs=[\"takeoff_mass_con\", \"takeoff_distance_con\",\n", " \"takeoff_vel_con\", \"takeoff_alt_con\"],\n", " )\n", "\n", @@ -769,7 +769,7 @@ " prob.set_val('traj.climb.states:mass', climb.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", " prob.set_val('traj.climb.states:distance', climb.interp(\n", - " Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') # nmi\n", + " Dynamic.Mission.DISTANCE, ys=[distance_i_climb, distance_f_climb]), units='m') # nmi\n", "\n", " prob.set_val('traj.climb.controls:velocity_rate',\n", " climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.0]),\n", @@ -788,7 +788,7 @@ " prob.set_val('traj.cruise.states:mass', cruise.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", " prob.set_val('traj.cruise.states:distance', cruise.interp(\n", - " Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi\n", + " Dynamic.Mission.DISTANCE, ys=[distance_i_cruise, distance_f_cruise]), units='m') # nmi\n", "\n", " prob.set_val('traj.cruise.controls:velocity_rate',\n", " cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]),\n", @@ -807,7 +807,7 @@ " prob.set_val('traj.descent.states:mass', descent.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", " prob.set_val('traj.descent.states:distance', descent.interp(\n", - " Dynamic.Mission.DISTANCE, ys=[range_i_descent, range_f_descent]), units='m')\n", + " Dynamic.Mission.DISTANCE, ys=[distance_i_descent, distance_f_descent]), units='m')\n", "\n", " prob.set_val('traj.descent.controls:velocity_rate',\n", " descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.0]),\n", 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 c4b1637cf..11ae2115a 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 @@ -115,7 +115,7 @@ " 'max_mach': 0.79,\n", " 'required_available_climb_rate': (1.524, 'm/s'),\n", " 'mass_f_cruise': (1.e4, 'kg'),\n", - " 'range_f_cruise': (1.e6, 'm'),\n", + " 'distance_f_cruise': (1.e6, 'm'),\n", " },\n", " 'initial_guesses': {\n", " 'times': ([26.2, 406.18], 'min'),\n", @@ -170,7 +170,6 @@ "# Allow for user overrides here\n", "prob.load_inputs(csv_path, phase_info)\n", "\n", - "prob.check_and_preprocess_inputs()\n", "\n", "prob.add_pre_mission_systems()\n", @@ -261,8 +260,8 @@ "# mach_i_climb = 0.3\n", "mach_i_climb = 0.2\n", "mach_f_climb = 0.79\n", - "range_i_climb = 0*_units.nautical_mile # m\n", - "range_f_climb = 160.3*_units.nautical_mile # m\n", + "distance_i_climb = 0*_units.nautical_mile # m\n", + "distance_f_climb = 160.3*_units.nautical_mile # m\n", "t_i_climb = 2 * _units.minute # sec\n", "t_f_climb = 26.20*_units.minute # sec\n", "t_duration_climb = t_f_climb - t_i_climb\n", @@ -279,8 +278,8 @@ "# mach_f_cruise = 0.79\n", "mach_min_cruise = 0.79\n", "mach_max_cruise = 0.79\n", - "range_i_cruise = 160.3*_units.nautical_mile # m\n", - "range_f_cruise = 3243.9*_units.nautical_mile # m\n", + "distance_i_cruise = 160.3*_units.nautical_mile # m\n", + "distance_f_cruise = 3243.9*_units.nautical_mile # m\n", "t_i_cruise = 26.20*_units.minute # sec\n", "t_f_cruise = 432.38*_units.minute # sec\n", "t_duration_cruise = t_f_cruise - t_i_cruise\n", @@ -295,8 +294,8 @@ "mach_f_descent = 0.3\n", "mass_i_descent = 143521*_units.pound\n", "mass_f_descent = 143035*_units.pound\n", - "range_i_descent = 3243.9*_units.nautical_mile\n", - "range_f_descent = 3378.7*_units.nautical_mile\n", + "distance_i_descent = 3243.9*_units.nautical_mile\n", + "distance_f_descent = 3378.7*_units.nautical_mile\n", "t_i_descent = 432.38*_units.minute\n", "t_f_descent = 461.62*_units.minute\n", "t_duration_descent = t_f_descent - t_i_descent\n", @@ -449,13 +448,13 @@ " om.ExecComp(\n", " [\n", " \"takeoff_mass_con=takeoff_mass-climb_start_mass\",\n", - " \"takeoff_range_con=takeoff_range-climb_start_range\",\n", + " \"takeoff_distance_con=takeoff_range-climb_start_range\",\n", " \"takeoff_vel_con=takeoff_vel-climb_start_vel\",\n", " \"takeoff_alt_con=takeoff_alt-climb_start_alt\"\n", " ],\n", " takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'},\n", " climb_start_mass={'units': 'lbm'},\n", - " takeoff_range_con={'units': 'ft'}, takeoff_range={'units': 'ft'},\n", + " takeoff_distance_con={'units': 'ft'}, takeoff_range={'units': 'ft'},\n", " climb_start_range={'units': 'ft'},\n", " takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'},\n", " climb_start_vel={'units': 'm/s'},\n", @@ -468,7 +467,7 @@ " (\"takeoff_vel\", Mission.Takeoff.FINAL_VELOCITY),\n", " (\"takeoff_alt\", Mission.Takeoff.FINAL_ALTITUDE),\n", " ],\n", - " promotes_outputs=[\"takeoff_mass_con\", \"takeoff_range_con\",\n", + " promotes_outputs=[\"takeoff_mass_con\", \"takeoff_distance_con\",\n", " \"takeoff_vel_con\", \"takeoff_alt_con\"],\n", ")\n", "\n", @@ -553,7 +552,7 @@ "prob.set_val('traj.climb.states:mass', climb.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", "prob.set_val('traj.climb.states:distance', climb.interp(\n", - " Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') # nmi\n", + " Dynamic.Mission.DISTANCE, ys=[distance_i_climb, distance_f_climb]), units='m') # nmi\n", "\n", "prob.set_val('traj.climb.controls:velocity_rate',\n", " climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.0]),\n", @@ -572,7 +571,7 @@ "prob.set_val('traj.cruise.states:mass', cruise.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", "prob.set_val('traj.cruise.states:distance', cruise.interp(\n", - " Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi\n", + " Dynamic.Mission.DISTANCE, ys=[distance_i_cruise, distance_f_cruise]), units='m') # nmi\n", "\n", "prob.set_val('traj.cruise.controls:velocity_rate',\n", " cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]),\n", @@ -591,7 +590,7 @@ "prob.set_val('traj.descent.states:mass', descent.interp(\n", " Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", "prob.set_val('traj.descent.states:distance', descent.interp(\n", - " Dynamic.Mission.DISTANCE, ys=[range_i_descent, range_f_descent]), units='m')\n", + " Dynamic.Mission.DISTANCE, ys=[distance_i_descent, distance_f_descent]), units='m')\n", "\n", "prob.set_val('traj.descent.controls:velocity_rate',\n", " descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.0]),\n", diff --git a/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py b/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py index 064c86985..156676327 100644 --- a/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py +++ b/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py @@ -33,7 +33,7 @@ 'polynomial_control_order': 1, 'num_segments': 5, 'order': 3, - 'solve_for_range': False, + 'solve_for_distance': False, 'initial_mach': (0.2, 'unitless'), 'final_mach': (0.72, 'unitless'), 'mach_bounds': ((0.18, 0.74), 'unitless'), @@ -57,7 +57,7 @@ 'polynomial_control_order': 1, 'num_segments': 5, 'order': 3, - 'solve_for_range': False, + 'solve_for_distance': False, 'initial_mach': (0.72, 'unitless'), 'final_mach': (0.72, 'unitless'), 'mach_bounds': ((0.7, 0.74), 'unitless'), @@ -81,7 +81,7 @@ 'polynomial_control_order': 1, 'num_segments': 5, 'order': 3, - 'solve_for_range': False, + 'solve_for_distance': False, 'initial_mach': (0.72, 'unitless'), 'final_mach': (0.36, 'unitless'), 'mach_bounds': ((0.34, 0.74), 'unitless'), diff --git a/aviary/examples/run_aviary_example.py b/aviary/examples/run_aviary_example.py index 73d80aa7e..875a5f456 100644 --- a/aviary/examples/run_aviary_example.py +++ b/aviary/examples/run_aviary_example.py @@ -21,7 +21,7 @@ "polynomial_control_order": 1, "num_segments": 5, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.2, "unitless"), "final_mach": (0.72, "unitless"), "mach_bounds": ((0.18, 0.74), "unitless"), @@ -45,7 +45,7 @@ "polynomial_control_order": 1, "num_segments": 5, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.72, "unitless"), "final_mach": (0.72, "unitless"), "mach_bounds": ((0.7, 0.74), "unitless"), @@ -69,7 +69,7 @@ "polynomial_control_order": 1, "num_segments": 5, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.72, "unitless"), "final_mach": (0.36, "unitless"), "mach_bounds": ((0.34, 0.74), "unitless"), diff --git a/aviary/interface/default_phase_info/simple.py b/aviary/interface/default_phase_info/simple.py index 29dcd56ea..4aceafb61 100644 --- a/aviary/interface/default_phase_info/simple.py +++ b/aviary/interface/default_phase_info/simple.py @@ -26,7 +26,7 @@ "polynomial_control_order": 1, "num_segments": 5, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.2, "unitless"), "final_mach": (0.72, "unitless"), "mach_bounds": ((0.18, 0.74), "unitless"), @@ -51,7 +51,7 @@ "polynomial_control_order": 1, "num_segments": 5, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.72, "unitless"), "final_mach": (0.72, "unitless"), "mach_bounds": ((0.7, 0.74), "unitless"), @@ -75,7 +75,7 @@ "polynomial_control_order": 1, "num_segments": 5, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.72, "unitless"), "final_mach": (0.36, "unitless"), "mach_bounds": ((0.34, 0.74), "unitless"), diff --git a/aviary/interface/graphical_input.py b/aviary/interface/graphical_input.py index 1fb3c7c18..eae7cea41 100644 --- a/aviary/interface/graphical_input.py +++ b/aviary/interface/graphical_input.py @@ -148,7 +148,7 @@ def create_bounds(center): 'use_polynomial_control': True, 'num_segments': num_segments, 'order': 3, - 'solve_for_range': False, + 'solve_for_distance': False, 'initial_mach': (mach_values[i], 'unitless'), 'final_mach': (mach_values[i+1], 'unitless'), 'mach_bounds': ((np.min(mach_values[i:i+2]) - 0.02, np.max(mach_values[i:i+2]) + 0.02), 'unitless'), @@ -178,7 +178,7 @@ def create_bounds(center): if 'pre_mission' in phase_name or 'post_mission' in phase_name: continue phase_info[phase_name]['user_options'].update({ - 'solve_for_range': user_choices.get('solve_for_range', False), + 'solve_for_distance': user_choices.get('solve_for_distance', False), }) # Apply global settings if required @@ -307,9 +307,9 @@ def __init__(self): tk.Checkbutton(checkbox_frame, text="Constrain Range", variable=self.constrain_range_var).pack(anchor="w") self.constrain_range_var.set(True) - self.solve_for_range_var = tk.BooleanVar() + self.solve_for_distance_var = tk.BooleanVar() tk.Checkbutton(checkbox_frame, text="Solve for Range", - variable=self.solve_for_range_var).pack(anchor="w") + variable=self.solve_for_distance_var).pack(anchor="w") # Textbox for Polynomial Control Order self.polynomial_order_var = tk.StringVar() @@ -458,7 +458,7 @@ def on_done(self, event=None): # event=None to handle both button click and key # Retrieve user choices from checkboxes user_choices = { "constrain_range": self.constrain_range_var.get(), - "solve_for_range": self.solve_for_range_var.get() + "solve_for_distance": self.solve_for_distance_var.get() } polynomial_order = int(self.polynomial_order_var.get()) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index b61d11d24..de2413cdf 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -882,15 +882,15 @@ def _get_solved_phase(self, phase_name): static_target=False) phase.set_time_options(fix_initial=False, fix_duration=False, - units="range_units", name=Dynamic.Mission.DISTANCE, + units="distance_units", name=Dynamic.Mission.DISTANCE, duration_bounds=wrapped_convert_units( - phase_options['duration_bounds'], "range_units"), + phase_options['duration_bounds'], "distance_units"), duration_ref=wrapped_convert_units( - phase_options['duration_ref'], "range_units"), + phase_options['duration_ref'], "distance_units"), initial_bounds=wrapped_convert_units( - phase_options['initial_bounds'], "range_units"), + phase_options['initial_bounds'], "distance_units"), initial_ref=wrapped_convert_units( - phase_options['initial_ref'], "range_units"), + phase_options['initial_ref'], "distance_units"), ) if phase_name == "cruise" or phase_name == "descent": @@ -2250,9 +2250,9 @@ def _add_solved_guesses(self, idx, phase_name, phase): if phase_name != "groundroll": range_initial = range_guesses[idx] self.set_val(f"traj.{phase_name}.t_initial", - range_initial, units='range_units') + range_initial, units='distance_units') self.set_val(f"traj.{phase_name}.t_duration", - range_guesses[idx+1] - range_initial, units='range_units') + range_guesses[idx+1] - range_initial, units='distance_units') self.set_val( f"traj.{phase_name}.polynomial_controls:altitude", diff --git a/aviary/interface/test/test_simple_mission.py b/aviary/interface/test/test_simple_mission.py index 74ad71aa8..d5643c06a 100644 --- a/aviary/interface/test/test_simple_mission.py +++ b/aviary/interface/test/test_simple_mission.py @@ -23,7 +23,7 @@ def setUp(self): "polynomial_control_order": 1, "num_segments": 5, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.2, "unitless"), "final_mach": (0.72, "unitless"), "mach_bounds": ((0.18, 0.74), "unitless"), @@ -47,7 +47,7 @@ def setUp(self): "polynomial_control_order": 1, "num_segments": 5, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.72, "unitless"), "final_mach": (0.72, "unitless"), "mach_bounds": ((0.7, 0.74), "unitless"), @@ -71,7 +71,7 @@ def setUp(self): "polynomial_control_order": 1, "num_segments": 5, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.72, "unitless"), "final_mach": (0.36, "unitless"), "mach_bounds": ((0.34, 0.74), "unitless"), @@ -163,17 +163,17 @@ def test_mission_optimize_altitude_only(self): self.assertFalse(prob.failed) @require_pyoptsparse(optimizer="IPOPT") - def test_mission_solve_for_range(self): + def test_mission_solve_for_distance(self): modified_phase_info = self.phase_info.copy() for phase in ["climb_1", "climb_2", "descent_1"]: - modified_phase_info[phase]["user_options"]["solve_for_range"] = True + modified_phase_info[phase]["user_options"]["solve_for_distance"] = True prob = self.run_mission(modified_phase_info, "IPOPT") self.assertFalse(prob.failed) - def test_mission_solve_for_range(self): + def test_mission_solve_for_distance(self): modified_phase_info = self.phase_info.copy() for phase in ["climb_1", "climb_2", "descent_1"]: - modified_phase_info[phase]["user_options"]["solve_for_range"] = True + modified_phase_info[phase]["user_options"]["solve_for_distance"] = True prob = self.run_mission(modified_phase_info, "SLSQP") self.assertFalse(prob.failed) diff --git a/aviary/mission/flops_based/phases/simple_energy_phase.py b/aviary/mission/flops_based/phases/simple_energy_phase.py index ae0a2192d..65782f9f0 100644 --- a/aviary/mission/flops_based/phases/simple_energy_phase.py +++ b/aviary/mission/flops_based/phases/simple_energy_phase.py @@ -160,7 +160,7 @@ def build_phase(self, aviary_options: AviaryValues = None): final_mach = user_options.get_item('final_mach')[0] initial_altitude = user_options.get_item('initial_altitude')[0] final_altitude = user_options.get_item('final_altitude')[0] - solve_for_range = user_options.get_val('solve_for_range') + solve_for_distance = user_options.get_val('solve_for_distance') no_descent = user_options.get_val('no_descent') no_climb = user_options.get_val('no_climb') @@ -197,7 +197,7 @@ def build_phase(self, aviary_options: AviaryValues = None): lower=0.0, ref=1e6, defect_ref=1e8, units='m', rate_source=Dynamic.Mission.DISTANCE_RATE, input_initial=input_initial_distance, - solve_segments='forward' if solve_for_range else None, + solve_segments='forward' if solve_for_distance else None, ) phase = add_subsystem_variables_to_phase( @@ -416,7 +416,7 @@ def _extra_ode_init_kwargs(self): EnergyPhase._add_meta_data('altitude_bounds', val=(0., 60.e3), units='ft') -EnergyPhase._add_meta_data('solve_for_range', val=False) +EnergyPhase._add_meta_data('solve_for_distance', val=False) EnergyPhase._add_initial_guess_meta_data( InitialGuessTime(), diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/gamma_comp.py b/aviary/mission/gasp_based/ode/unsteady_solved/gamma_comp.py index 7155905ea..527a049d8 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/gamma_comp.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/gamma_comp.py @@ -15,16 +15,16 @@ def initialize(self): def setup(self): nn = self.options["num_nodes"] - self.add_input("dh_dr", shape=nn, units="m/range_units", + self.add_input("dh_dr", shape=nn, units="m/distance_units", desc="change in altitude wrt range") - self.add_input("d2h_dr2", shape=nn, units="m/range_units**2", + self.add_input("d2h_dr2", shape=nn, units="m/distance_units**2", desc="second derivative of altitude wrt range") self.add_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, shape=nn, units="rad", desc="flight path angle") - self.add_output("dgam_dr", shape=nn, units="rad/range_units", + self.add_output("dgam_dr", shape=nn, units="rad/distance_units", desc="change in flight path angle per unit range traversed") def setup_partials(self): diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_eom.py b/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_eom.py index 8a87a968d..aefd0f5e5 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_eom.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_eom.py @@ -46,12 +46,12 @@ def setup(self): self.add_input(Dynamic.Mission.FLIGHT_PATH_ANGLE, val=np.zeros( nn), desc="flight path angle", units="rad") self.add_input("dh_dr", val=np.zeros( - nn), desc="d(alt)/d(range)", units="m/range_units") + nn), desc="d(alt)/d(range)", units="m/distance_units") self.add_input("d2h_dr2", val=np.zeros( - nn), desc="d(climb_rate)/d(range)", units="1/range_units") + nn), desc="d(climb_rate)/d(range)", units="1/distance_units") # Outputs - self.add_output("dt_dr", shape=nn, units="s/range_units", + self.add_output("dt_dr", shape=nn, units="s/distance_units", desc="Seconds passed per each meter of range covered.", tags=['dymos.state_rate_source:time', 'dymos.state_units:s']) self.add_output("normal_force", val=np.ones(nn), units="N", diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_flight_conditions.py b/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_flight_conditions.py index 008393c10..f1cdbbc31 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_flight_conditions.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_flight_conditions.py @@ -107,7 +107,7 @@ def setup(self): self.add_input( "dTAS_dr", val=np.zeros(nn), - units="m/s/range_units", + units="m/s/distance_units", desc="change in true air speed per unit range", ) @@ -206,7 +206,7 @@ def setup(self): self.add_input( "dmach_dr", val=np.zeros(nn), - units="unitless/range_units", + units="unitless/distance_units", desc="change in mach number per unit range", ) self.add_input( diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_ode.py b/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_ode.py index 591f0c7a7..5ad1015b5 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_ode.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/unsteady_solved_ode.py @@ -214,8 +214,8 @@ def setup(self): self.add_subsystem("mass_rate", om.ExecComp("dmass_dr = fuelflow * dt_dr", fuelflow={"units": "lbm/s", "shape": nn}, - dt_dr={"units": "s/range_units", "shape": nn}, - dmass_dr={"units": "lbm/range_units", + dt_dr={"units": "s/distance_units", "shape": nn}, + dmass_dr={"units": "lbm/distance_units", "shape": nn, "tags": ['dymos.state_rate_source:mass', 'dymos.state_units:lbm']}, @@ -241,5 +241,6 @@ def setup(self): name=Dynamic.Mission.ALTITUDE, val=10000. * onn, units="ft") - self.set_input_defaults(name="dh_dr", val=0. * onn, units="ft/range_units") - self.set_input_defaults(name="d2h_dr2", val=0. * onn, units="ft/range_units**2") + self.set_input_defaults(name="dh_dr", val=0. * onn, units="ft/distance_units") + self.set_input_defaults(name="d2h_dr2", val=0. * onn, + units="ft/distance_units**2") diff --git a/aviary/utils/Fortran_to_Aviary.py b/aviary/utils/Fortran_to_Aviary.py index 3273f0ee5..468b8745a 100644 --- a/aviary/utils/Fortran_to_Aviary.py +++ b/aviary/utils/Fortran_to_Aviary.py @@ -352,7 +352,7 @@ def update_gasp_options(vehicle_data): ## PROBLEM TYPE ## # if multiple values of target_range are specified, use the one that corresponds to the problem_type - design_range, range_units = input_values.get_item(Mission.Design.RANGE) + design_range, distance_units = input_values.get_item(Mission.Design.RANGE) try: problem_type = input_values.get_val('problem_type')[0] except KeyError: @@ -372,7 +372,7 @@ def update_gasp_options(vehicle_data): else: if design_range == 0: input_values.set_val('problem_type', ['fallout']) - input_values.set_val(Mission.Design.RANGE, [design_range], range_units) + input_values.set_val(Mission.Design.RANGE, [design_range], distance_units) ## STRUT AND FOLD ## strut_loc = input_values.get_val(Aircraft.Strut.ATTACHMENT_LOCATION, 'ft')[0] diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index 4a38398fb..0f588f9f0 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -284,7 +284,7 @@ def bench_test_swap_4_FwFm_simple(self): "use_polynomial_control": False, "num_segments": 6, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.2, "unitless"), "final_mach": (0.79, "unitless"), "mach_bounds": ((0.1, 0.8), "unitless"), @@ -310,7 +310,7 @@ def bench_test_swap_4_FwFm_simple(self): "use_polynomial_control": True, "num_segments": 1, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.79, "unitless"), "final_mach": (0.79, "unitless"), "mach_bounds": ((0.78, 0.8), "unitless"), @@ -335,7 +335,7 @@ def bench_test_swap_4_FwFm_simple(self): "use_polynomial_control": False, "num_segments": 5, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.79, "unitless"), "final_mach": (0.3, "unitless"), "mach_bounds": ((0.2, 0.8), "unitless"), diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py index 73a21c057..78945eeba 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py @@ -289,7 +289,7 @@ def bench_test_swap_1_GwFm_simple(self): "use_polynomial_control": False, "num_segments": 6, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.2, "unitless"), "final_mach": (0.79, "unitless"), "mach_bounds": ((0.1, 0.8), "unitless"), @@ -315,7 +315,7 @@ def bench_test_swap_1_GwFm_simple(self): "use_polynomial_control": True, "num_segments": 1, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.79, "unitless"), "final_mach": (0.79, "unitless"), "mach_bounds": ((0.78, 0.8), "unitless"), @@ -339,7 +339,7 @@ def bench_test_swap_1_GwFm_simple(self): "use_polynomial_control": False, "num_segments": 5, "order": 3, - "solve_for_range": False, + "solve_for_distance": False, "initial_mach": (0.79, "unitless"), "final_mach": (0.3, "unitless"), "mach_bounds": ((0.2, 0.8), "unitless"), diff --git a/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py b/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py index e5f7c4ca9..f6ae77aa5 100644 --- a/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py +++ b/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py @@ -330,7 +330,7 @@ def run_mission(optimizer): static_target=False) phase.set_time_options(fix_initial=False, fix_duration=False, - units="range_units", name=Dynamic.Mission.DISTANCE, + units="distance_units", name=Dynamic.Mission.DISTANCE, duration_bounds=duration_bounds, duration_ref=duration_ref, initial_bounds=initial_bounds, initial_ref=initial_ref) @@ -590,9 +590,9 @@ def run_mission(optimizer): if phase_name != "groundroll": range_initial = range_guesses[idx] p.set_val(f"traj.{phase_name}.t_initial", - range_initial, units='range_units') + range_initial, units='distance_units') p.set_val(f"traj.{phase_name}.t_duration", - range_guesses[idx+1] - range_initial, units='range_units') + range_guesses[idx+1] - range_initial, units='distance_units') p.set_val( f"traj.{phase_name}.polynomial_controls:altitude", @@ -658,12 +658,12 @@ def run_mission(optimizer): p.get_val(f"traj.{phase_name}.timeseries.TAS", units="kn")[-1]) else: range_initial = p.get_val( - f"traj.{phase_name}.t_initial", units='range_units') + f"traj.{phase_name}.t_initial", units='distance_units') if idx > 1: ranges.extend(range_initial) if idx == (len(traj._phases) - 1): ranges.extend( - p.get_val(f"traj.{phase_name}.t_duration", units='range_units') + range_initial) + p.get_val(f"traj.{phase_name}.t_duration", units='distance_units') + range_initial) masses.extend( p.get_val(f"traj.{phase_name}.timeseries.mass", units="lbm")[-1]) alts.extend( From e58da6187c3c8bbd2e9c42fc07de1cffde3d65cb Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 17 Jan 2024 09:52:42 -0600 Subject: [PATCH 078/188] More range->distance --- ...e_same_mission_at_different_UI_levels.ipynb | 2 +- .../default_phase_info/height_energy.py | 2 +- aviary/interface/methods_for_level2.py | 6 +++--- aviary/interface/utils/check_phase_info.py | 2 +- .../test_bench_climb_large_single_aisle_1.py | 6 +++--- .../test_bench_climb_large_single_aisle_2.py | 6 +++--- ..._bench_cruise_climb_large_single_aisle_1.py | 8 ++++---- .../test_bench_cruise_large_single_aisle_1.py | 6 +++--- .../test_bench_cruise_large_single_aisle_2.py | 6 +++--- .../test_bench_descent_large_single_aisle_1.py | 6 +++--- .../test_bench_descent_large_single_aisle_2.py | 6 +++--- .../mission/flops_based/phases/cruise_phase.py | 6 +++--- .../gasp_based/ode/breguet_cruise_ode.py | 2 +- aviary/mission/gasp_based/phases/breguet.py | 6 +++--- .../test/test_custom_engine_model.py | 2 +- .../test_FLOPS_based_full_mission_N3CC.py | 18 +++++++++--------- ..._based_full_mission_large_single_aisle_1.py | 18 +++++++++--------- ..._based_full_mission_large_single_aisle_2.py | 18 +++++++++--------- .../test_FLOPS_based_sizing_N3CC.py | 18 +++++++++--------- .../test_full_mission_solved_ode.py | 12 ++++++------ .../test_subsystems_within_a_mission.py | 2 +- aviary/xdsm/cruise_xdsm.py | 2 +- aviary/xdsm/statics_xdsm.py | 4 ++-- 23 files changed, 82 insertions(+), 82 deletions(-) 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 11ae2115a..1cbe7da34 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 @@ -536,7 +536,7 @@ "prob.setup()\n", "\n", "###########################################\n", - "# Intial Settings for States and Controls #\n", + "# Initial Settings for States and Controls #\n", "###########################################\n", "\n", "prob.set_val('traj.climb.t_initial', t_i_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 1b233943c..c6504dd4c 100644 --- a/aviary/interface/default_phase_info/height_energy.py +++ b/aviary/interface/default_phase_info/height_energy.py @@ -75,7 +75,7 @@ 'max_mach': 0.79, 'required_available_climb_rate': (1.524, 'm/s'), 'mass_f_cruise': (1.e4, 'kg'), - 'range_f_cruise': (1.e6, 'm'), + 'distance_f_cruise': (1.e6, 'm'), }, 'initial_guesses': { 'times': ([26.2, 406.18], 'min'), diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index de2413cdf..e1e0665da 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -2248,11 +2248,11 @@ def _add_solved_guesses(self, idx, phase_name, phase): time_guesses = np.hstack((0., np.cumsum(range_durations / mean_TAS))) if phase_name != "groundroll": - range_initial = range_guesses[idx] + distance_initial = range_guesses[idx] self.set_val(f"traj.{phase_name}.t_initial", - range_initial, units='distance_units') + distance_initial, units='distance_units') self.set_val(f"traj.{phase_name}.t_duration", - range_guesses[idx+1] - range_initial, units='distance_units') + range_guesses[idx+1] - distance_initial, units='distance_units') self.set_val( f"traj.{phase_name}.polynomial_controls:altitude", diff --git a/aviary/interface/utils/check_phase_info.py b/aviary/interface/utils/check_phase_info.py index cc40add8b..bf50c25b0 100644 --- a/aviary/interface/utils/check_phase_info.py +++ b/aviary/interface/utils/check_phase_info.py @@ -40,7 +40,7 @@ def check_phase_info(phase_info, mission_method): 'max_mach': float, 'required_available_climb_rate': tuple, 'mass_f_cruise': tuple, - 'range_f_cruise': tuple, + 'distance_f_cruise': tuple, 'fix_final': bool, } diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py index 7c7c97277..bea55f9e3 100644 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py +++ b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_1.py @@ -84,8 +84,8 @@ def run_trajectory(): v_f_climb = 455.49*_units.knot # m/s mach_i_climb = 0.3 mach_f_climb = 0.79 - range_i_climb = 0*_units.nautical_mile # m - range_f_climb = 160.3*_units.nautical_mile # m + distance_i_climb = 0*_units.nautical_mile # m + distance_f_climb = 160.3*_units.nautical_mile # m t_i_climb = 2 * _units.minute # sec t_f_climb = 26.20*_units.minute # sec t_duration_climb = t_f_climb - t_i_climb @@ -150,7 +150,7 @@ def run_trajectory(): prob.set_val('traj.climb.states:mass', climb.interp( Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') prob.set_val('traj.climb.states:distance', climb.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') + Dynamic.Mission.DISTANCE, ys=[distance_i_climb, distance_f_climb]), units='m') prob.set_val('traj.climb.controls:velocity_rate', climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.05]), diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py index 761b30e97..571762eed 100644 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py +++ b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_climb_large_single_aisle_2.py @@ -78,8 +78,8 @@ def run_trajectory(): v_f_climb = 452.61 * _units.knot # m/s mach_i_climb = 0.3 mach_f_climb = 0.775 - range_i_climb = 0 * _units.nautical_mile # m - range_f_climb = 124 * _units.nautical_mile # m + distance_i_climb = 0 * _units.nautical_mile # m + distance_f_climb = 124 * _units.nautical_mile # m t_i_climb = 0 t_f_climb = 20.14 * _units.minute # sec @@ -153,7 +153,7 @@ def run_trajectory(): prob.set_val('traj.climb.states:mass', climb.interp( Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') prob.set_val('traj.climb.states:distance', climb.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') # nmi + Dynamic.Mission.DISTANCE, ys=[distance_i_climb, distance_f_climb]), units='m') # nmi prob.set_val('traj.climb.controls:velocity_rate', climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.05]), diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py index 7e6249379..3b4fa232b 100644 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py +++ b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_climb_large_single_aisle_1.py @@ -84,8 +84,8 @@ def run_trajectory(): mach_f_cruise = 0.79 mach_min_cruise = 0.78999 mach_max_cruise = 0.79001 - range_i_cruise = 160.3*_units.nautical_mile # m - range_f_cruise = 3243.9*_units.nautical_mile # m + distance_i_cruise = 160.3*_units.nautical_mile # m + distance_f_cruise = 3243.9*_units.nautical_mile # m t_i_cruise = 26.20*_units.minute # sec t_f_cruise = 432.38*_units.minute # sec t_duration_cruise = t_f_cruise - t_i_cruise @@ -116,7 +116,7 @@ def run_trajectory(): no_descent=True, velocity_f_cruise=velocity_f_cruise, mass_f_cruise=mass_f_cruise, - range_f_cruise=range_f_cruise, + distance_f_cruise=distance_f_cruise, ) @@ -173,7 +173,7 @@ def run_trajectory(): prob.set_val('traj.cruise.states:mass', cruise.interp( Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') prob.set_val('traj.cruise.states:distance', cruise.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi + Dynamic.Mission.DISTANCE, ys=[distance_i_cruise, distance_f_cruise]), units='m') # nmi prob.set_val('traj.cruise.controls:velocity_rate', cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py index 353a9acc0..396b54d0f 100644 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py +++ b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_1.py @@ -88,8 +88,8 @@ def run_trajectory(): mach_f_cruise = 0.79 mach_min_cruise = 0.79 mach_max_cruise = 0.79 - range_i_cruise = 160.3*_units.nautical_mile # m - range_f_cruise = 3243.9*_units.nautical_mile # m + distance_i_cruise = 160.3*_units.nautical_mile # m + distance_f_cruise = 3243.9*_units.nautical_mile # m t_i_cruise = 26.20*_units.minute # sec t_f_cruise = 432.38*_units.minute # sec t_duration_cruise = t_f_cruise - t_i_cruise @@ -172,7 +172,7 @@ def run_trajectory(): prob.set_val('traj.cruise.states:mass', cruise.interp( Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') prob.set_val('traj.cruise.states:distance', cruise.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi + Dynamic.Mission.DISTANCE, ys=[distance_i_cruise, distance_f_cruise]), units='m') # nmi prob.set_val('traj.cruise.controls:velocity_rate', cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py index 26f8a4a1b..fa568f67f 100644 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py +++ b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_cruise_large_single_aisle_2.py @@ -91,8 +91,8 @@ def run_trajectory(): mach_f_cruise = 0.785 mach_min_cruise = 0.785 mach_max_cruise = 0.785 - range_i_cruise = 116.6*_units.nautical_mile # m - range_f_cruise = 2558.3*_units.nautical_mile # m + distance_i_cruise = 116.6*_units.nautical_mile # m + distance_f_cruise = 2558.3*_units.nautical_mile # m t_i_cruise = 19.08*_units.minute # sec t_f_cruise = 342.77*_units.minute # sec t_duration_cruise = t_f_cruise - t_i_cruise # sec @@ -163,7 +163,7 @@ def run_trajectory(): prob.set_val('traj.cruise.states:mass', cruise.interp( Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') prob.set_val('traj.cruise.states:distance', cruise.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi + Dynamic.Mission.DISTANCE, ys=[distance_i_cruise, distance_f_cruise]), units='m') # nmi prob.set_val('traj.cruise.controls:velocity_rate', cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py index 811648701..1ee66a43d 100644 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py +++ b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_1.py @@ -86,8 +86,8 @@ def run_trajectory(): mach_f_descent = 0.3 mass_i_descent = 143521*_units.pound mass_f_descent = 143035*_units.pound - range_i_descent = 3243.9*_units.nautical_mile - range_f_descent = 3378.7*_units.nautical_mile + distance_i_descent = 3243.9*_units.nautical_mile + distance_f_descent = 3378.7*_units.nautical_mile t_i_descent = 432.38*_units.minute t_f_descent = 461.62*_units.minute t_duration_descent = t_f_descent - t_i_descent @@ -148,7 +148,7 @@ def run_trajectory(): prob.set_val('traj.descent.states:mass', descent.interp( Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') prob.set_val('traj.descent.states:distance', descent.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_descent, range_f_descent]), units='m') + Dynamic.Mission.DISTANCE, ys=[distance_i_descent, distance_f_descent]), units='m') prob.set_val('traj.descent.controls:velocity_rate', descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), diff --git a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py index 251b86944..1395dfbc8 100644 --- a/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py +++ b/aviary/mission/flops_based/phases/benchmark_tests/test_bench_descent_large_single_aisle_2.py @@ -89,8 +89,8 @@ def run_trajectory(): mach_f = 0.3 mass_i = 140515*_units.pound mass_f = 140002*_units.pound - range_i = 2830.8*_units.nautical_mile - range_f = 2960.0*_units.nautical_mile + distance_i = 2830.8*_units.nautical_mile + distance_f = 2960.0*_units.nautical_mile t_i_descent = 0.0 t_f_descent = 2000.0 @@ -148,7 +148,7 @@ def run_trajectory(): prob.set_val('traj.descent.states:mass', descent.interp( Dynamic.Mission.MASS, ys=[mass_i, mass_f]), units='kg') prob.set_val('traj.descent.states:distance', descent.interp( - Dynamic.Mission.DISTANCE, ys=[range_i, range_f]), units='m') + Dynamic.Mission.DISTANCE, ys=[distance_i, distance_f]), units='m') prob.set_val('traj.descent.controls:velocity_rate', descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), diff --git a/aviary/mission/flops_based/phases/cruise_phase.py b/aviary/mission/flops_based/phases/cruise_phase.py index 4bc0f4796..184297c14 100644 --- a/aviary/mission/flops_based/phases/cruise_phase.py +++ b/aviary/mission/flops_based/phases/cruise_phase.py @@ -177,7 +177,7 @@ def build_phase(self, aviary_options: AviaryValues = None): num_engines = len(aviary_options.get_val('engine_models')) input_initial = user_options.get_val('input_initial') mass_f_cruise = user_options.get_val('mass_f_cruise', units='kg') - range_f_cruise = user_options.get_val('range_f_cruise', units='m') + distance_f_cruise = user_options.get_val('distance_f_cruise', units='m') polynomial_control_order = user_options.get_item('polynomial_control_order')[0] ############## @@ -216,7 +216,7 @@ def build_phase(self, aviary_options: AviaryValues = None): fix_initial_distance = get_initial(fix_initial, Dynamic.Mission.DISTANCE, True) phase.add_state( Dynamic.Mission.DISTANCE, fix_initial=fix_initial_distance, fix_final=fix_final, - lower=0.0, ref=range_f_cruise, defect_ref=range_f_cruise, units='m', + lower=0.0, ref=distance_f_cruise, defect_ref=distance_f_cruise, units='m', rate_source=Dynamic.Mission.DISTANCE_RATE, input_initial=input_initial_distance ) @@ -396,7 +396,7 @@ def _extra_ode_init_kwargs(self): Cruise._add_meta_data('mass_f_cruise', val=1.e4, units='kg') -Cruise._add_meta_data('range_f_cruise', val=1.e6, units='m') +Cruise._add_meta_data('distance_f_cruise', val=1.e6, units='m') Cruise._add_meta_data( 'required_available_climb_rate', val=None, units='m/s', diff --git a/aviary/mission/gasp_based/ode/breguet_cruise_ode.py b/aviary/mission/gasp_based/ode/breguet_cruise_ode.py index 8097210ac..a67cca601 100644 --- a/aviary/mission/gasp_based/ode/breguet_cruise_ode.py +++ b/aviary/mission/gasp_based/ode/breguet_cruise_ode.py @@ -125,7 +125,7 @@ def setup(self): "eom", RangeComp(num_nodes=nn), promotes_inputs=[ - ("cruise_range_initial", "initial_distance"), + ("cruise_distance_initial", "initial_distance"), ("cruise_time_initial", "initial_time"), "mass", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, diff --git a/aviary/mission/gasp_based/phases/breguet.py b/aviary/mission/gasp_based/phases/breguet.py index 762dd8278..f798d3735 100644 --- a/aviary/mission/gasp_based/phases/breguet.py +++ b/aviary/mission/gasp_based/phases/breguet.py @@ -15,7 +15,7 @@ def setup(self): self.add_input("cruise_time_initial", val=0.0, units="s", desc="time at which cruise begins") - self.add_input("cruise_range_initial", val=0.0, units="NM", + self.add_input("cruise_distance_initial", val=0.0, units="NM", desc="range reference at which cruise begins") self.add_input("TAS_cruise", val=0.8 * np.ones(nn), @@ -64,7 +64,7 @@ def setup_partials(self): self.declare_partials( "cruise_time", [Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, "mass", "TAS_cruise"], rows=rs, cols=cs) - self.declare_partials("cruise_range", "cruise_range_initial", val=1.0) + self.declare_partials("cruise_range", "cruise_distance_initial", val=1.0) self.declare_partials("cruise_time", "cruise_time_initial", val=1.0) # Allocated memory so we don't have to repeatedly do it in compute_partials @@ -78,7 +78,7 @@ def compute(self, inputs, outputs): v_x = inputs["TAS_cruise"] m = inputs["mass"] FF = -inputs[Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL] - r0 = inputs["cruise_range_initial"] + r0 = inputs["cruise_distance_initial"] t0 = inputs["cruise_time_initial"] FF_1 = FF[:-1] # Initial fuel flow across each two-node pair diff --git a/aviary/subsystems/propulsion/test/test_custom_engine_model.py b/aviary/subsystems/propulsion/test/test_custom_engine_model.py index 0bfeafbce..693c7871c 100644 --- a/aviary/subsystems/propulsion/test/test_custom_engine_model.py +++ b/aviary/subsystems/propulsion/test/test_custom_engine_model.py @@ -161,7 +161,7 @@ def test_custom_engine(self): 'required_available_climb_rate': (1.524, 'm/s'), 'input_initial': False, 'mass_f_cruise': (1.e4, 'lbm'), - 'range_f_cruise': (1.e6, 'm'), + 'distance_f_cruise': (1.e6, 'm'), }, 'initial_guesses': { 'times': ([0., 30.], 'min'), diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py index 53264e0d9..4ae6d3e1d 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py @@ -81,8 +81,8 @@ def run_trajectory(driver: Driver, sim=True): # mach_i_climb = 0.3 mach_i_climb = 0.2 mach_f_climb = cruise_mach - range_i_climb = 0*_units.nautical_mile # m - range_f_climb = 160.3*_units.nautical_mile # m + distance_i_climb = 0*_units.nautical_mile # m + distance_f_climb = 160.3*_units.nautical_mile # m t_i_climb = 2 * _units.minute # sec t_f_climb = 26.20*_units.minute # sec t_duration_climb = t_f_climb - t_i_climb @@ -97,8 +97,8 @@ def run_trajectory(driver: Driver, sim=True): v_f_cruise = 455.49*_units.knot # m/s mach_min_cruise = cruise_mach mach_max_cruise = cruise_mach - range_i_cruise = 160.3*_units.nautical_mile # m - range_f_cruise = 3243.9*_units.nautical_mile # m + distance_i_cruise = 160.3*_units.nautical_mile # m + distance_f_cruise = 3243.9*_units.nautical_mile # m t_i_cruise = 26.20*_units.minute # sec t_f_cruise = 432.38*_units.minute # sec t_duration_cruise = t_f_cruise - t_i_cruise @@ -113,8 +113,8 @@ def run_trajectory(driver: Driver, sim=True): mach_f_descent = 0.3 mass_i_descent = 102000*_units.pound mass_f_descent = 101000*_units.pound - range_i_descent = 3243.9*_units.nautical_mile - range_f_descent = 3378.7*_units.nautical_mile + distance_i_descent = 3243.9*_units.nautical_mile + distance_f_descent = 3378.7*_units.nautical_mile t_i_descent = 432.38*_units.minute t_f_descent = 461.62*_units.minute t_duration_descent = t_f_descent - t_i_descent @@ -372,7 +372,7 @@ def run_trajectory(driver: Driver, sim=True): prob.set_val('traj.climb.states:mass', climb.interp( Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') prob.set_val('traj.climb.states:distance', climb.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') # nmi + Dynamic.Mission.DISTANCE, ys=[distance_i_climb, distance_f_climb]), units='m') # nmi prob.set_val('traj.climb.controls:velocity_rate', climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.0]), @@ -391,7 +391,7 @@ def run_trajectory(driver: Driver, sim=True): prob.set_val('traj.cruise.states:mass', cruise.interp( Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') prob.set_val('traj.cruise.states:distance', cruise.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi + Dynamic.Mission.DISTANCE, ys=[distance_i_cruise, distance_f_cruise]), units='m') # nmi prob.set_val('traj.cruise.controls:velocity_rate', cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), @@ -410,7 +410,7 @@ def run_trajectory(driver: Driver, sim=True): prob.set_val('traj.descent.states:mass', descent.interp( Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') prob.set_val('traj.descent.states:distance', descent.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_descent, range_f_descent]), units='m') + Dynamic.Mission.DISTANCE, ys=[distance_i_descent, distance_f_descent]), units='m') prob.set_val('traj.descent.controls:velocity_rate', descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.0]), diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py index b7143e37c..a5b6cca94 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py @@ -87,8 +87,8 @@ def run_trajectory(sim=True): # mach_i_climb = 0.3 mach_i_climb = 0.2 mach_f_climb = 0.79 - range_i_climb = 0*_units.nautical_mile # m - range_f_climb = 160.3*_units.nautical_mile # m + distance_i_climb = 0*_units.nautical_mile # m + distance_f_climb = 160.3*_units.nautical_mile # m t_i_climb = 2 * _units.minute # sec t_f_climb = 26.20*_units.minute # sec t_duration_climb = t_f_climb - t_i_climb @@ -105,8 +105,8 @@ def run_trajectory(sim=True): # mach_f_cruise = 0.79 mach_min_cruise = 0.79 mach_max_cruise = 0.79 - range_i_cruise = 160.3*_units.nautical_mile # m - range_f_cruise = 3243.9*_units.nautical_mile # m + distance_i_cruise = 160.3*_units.nautical_mile # m + distance_f_cruise = 3243.9*_units.nautical_mile # m t_i_cruise = 26.20*_units.minute # sec t_f_cruise = 432.38*_units.minute # sec t_duration_cruise = t_f_cruise - t_i_cruise @@ -121,8 +121,8 @@ def run_trajectory(sim=True): mach_f_descent = 0.3 mass_i_descent = 143521*_units.pound mass_f_descent = 143035*_units.pound - range_i_descent = 3243.9*_units.nautical_mile - range_f_descent = 3378.7*_units.nautical_mile + distance_i_descent = 3243.9*_units.nautical_mile + distance_f_descent = 3378.7*_units.nautical_mile t_i_descent = 432.38*_units.minute t_f_descent = 461.62*_units.minute t_duration_descent = t_f_descent - t_i_descent @@ -378,7 +378,7 @@ def run_trajectory(sim=True): prob.set_val('traj.climb.states:mass', climb.interp( Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') prob.set_val('traj.climb.states:distance', climb.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') # nmi + Dynamic.Mission.DISTANCE, ys=[distance_i_climb, distance_f_climb]), units='m') # nmi prob.set_val('traj.climb.controls:velocity_rate', climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.05]), @@ -397,7 +397,7 @@ def run_trajectory(sim=True): prob.set_val('traj.cruise.states:mass', cruise.interp( Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') prob.set_val('traj.cruise.states:distance', cruise.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi + Dynamic.Mission.DISTANCE, ys=[distance_i_cruise, distance_f_cruise]), units='m') # nmi prob.set_val('traj.cruise.controls:velocity_rate', cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), @@ -416,7 +416,7 @@ def run_trajectory(sim=True): prob.set_val('traj.descent.states:mass', descent.interp( Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') prob.set_val('traj.descent.states:distance', descent.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_descent, range_f_descent]), units='m') + Dynamic.Mission.DISTANCE, ys=[distance_i_descent, distance_f_descent]), units='m') prob.set_val('traj.descent.controls:velocity_rate', descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.05]), diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py index 37b176bc6..76566f394 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py @@ -85,8 +85,8 @@ def run_trajectory(sim=True): v_f_climb = 452.61*_units.knot # m/s mach_i_climb = 0.2 # TODO: (need to compute this in takeoff) mach_f_climb = 0.785 - range_i_climb = 0*_units.nautical_mile # m (comes from takeoff) - range_f_climb = 124*_units.nautical_mile # m + distance_i_climb = 0*_units.nautical_mile # m (comes from takeoff) + distance_f_climb = 124*_units.nautical_mile # m t_i_climb = 0 t_duration_climb = 20.14*_units.minute # sec @@ -101,8 +101,8 @@ def run_trajectory(sim=True): mach_f_cruise = 0.785 mach_min_cruise = 0.785 mach_max_cruise = 0.785 - range_i_cruise = 124*_units.nautical_mile # m - range_f_cruise = 2830.8*_units.nautical_mile # m + distance_i_cruise = 124*_units.nautical_mile # m + distance_f_cruise = 2830.8*_units.nautical_mile # m t_i_cruise = t_i_climb + t_duration_climb # sec t_duration_cruise = (378.95)*_units.minute - t_duration_climb # sec @@ -114,8 +114,8 @@ def run_trajectory(sim=True): mass_f_descent = 140002*_units.pound # kg mach_i_descent = mach_f_cruise mach_f_descent = 0.3 - range_i_descent = 2830.8*_units.nautical_mile # m - range_f_descent = 2960.0*_units.nautical_mile # m + distance_i_descent = 2830.8*_units.nautical_mile # m + distance_f_descent = 2960.0*_units.nautical_mile # m t_i_descent = t_duration_cruise+t_duration_climb # sec t_duration_descent = 2000 # sec @@ -364,7 +364,7 @@ def run_trajectory(sim=True): prob.set_val('traj.climb.states:mass', climb.interp( Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg') prob.set_val('traj.climb.states:distance', climb.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m') # nmi + Dynamic.Mission.DISTANCE, ys=[distance_i_climb, distance_f_climb]), units='m') # nmi prob.set_val('traj.climb.controls:velocity_rate', climb.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.25, 0.05]), @@ -383,7 +383,7 @@ def run_trajectory(sim=True): prob.set_val('traj.cruise.states:mass', cruise.interp( Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg') prob.set_val('traj.cruise.states:distance', cruise.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m') # nmi + Dynamic.Mission.DISTANCE, ys=[distance_i_cruise, distance_f_cruise]), units='m') # nmi prob.set_val('traj.cruise.controls:velocity_rate', cruise.interp(Dynamic.Mission.VELOCITY_RATE, ys=[0.0, 0.0]), @@ -402,7 +402,7 @@ def run_trajectory(sim=True): prob.set_val('traj.descent.states:mass', descent.interp( Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg') prob.set_val('traj.descent.states:distance', descent.interp( - Dynamic.Mission.DISTANCE, ys=[range_i_descent, range_f_descent]), units='m') + Dynamic.Mission.DISTANCE, ys=[distance_i_descent, distance_f_descent]), units='m') prob.set_val('traj.descent.controls:velocity_rate', descent.interp(Dynamic.Mission.VELOCITY_RATE, ys=[-0.25, 0.0]), 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 d94000a25..4d05ca9f4 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 @@ -101,8 +101,8 @@ def run_trajectory(sim=True): # mach_i_climb = 0.3 mach_i_climb = 0.2 mach_f_climb = 0.79 - range_i_climb = 0*_units.nautical_mile # m - range_f_climb = 160.3*_units.nautical_mile # m + distance_i_climb = 0*_units.nautical_mile # m + distance_f_climb = 160.3*_units.nautical_mile # m t_i_climb = 2 * _units.minute # sec t_f_climb = 26.20*_units.minute # sec t_duration_climb = t_f_climb - t_i_climb @@ -117,8 +117,8 @@ def run_trajectory(sim=True): v_f_cruise = 455.49*_units.knot # m/s mach_min_cruise = 0.79 mach_max_cruise = 0.79 - range_i_cruise = 160.3*_units.nautical_mile # m - range_f_cruise = 3243.9*_units.nautical_mile # m + distance_i_cruise = 160.3*_units.nautical_mile # m + distance_f_cruise = 3243.9*_units.nautical_mile # m t_i_cruise = 26.20*_units.minute # sec t_f_cruise = 432.38*_units.minute # sec t_duration_cruise = t_f_cruise - t_i_cruise @@ -133,8 +133,8 @@ def run_trajectory(sim=True): mach_f_descent = 0.3 mass_i_descent = 102000*_units.pound mass_f_descent = 101000*_units.pound - range_i_descent = 3243.9*_units.nautical_mile - range_f_descent = 3378.7*_units.nautical_mile + distance_i_descent = 3243.9*_units.nautical_mile + distance_f_descent = 3378.7*_units.nautical_mile t_i_descent = 432.38*_units.minute t_f_descent = 461.62*_units.minute t_duration_descent = t_f_descent - t_i_descent @@ -454,7 +454,7 @@ def run_trajectory(sim=True): prob.set_val('traj.climb.states:mass', climb.interp( 'mass', ys=[mass_i_climb, mass_f_climb]), units='kg') prob.set_val('traj.climb.states:distance', climb.interp( - 'distance', ys=[range_i_climb, range_f_climb]), units='m') # nmi + 'distance', ys=[distance_i_climb, distance_f_climb]), units='m') # nmi prob.set_val('traj.climb.controls:velocity_rate', climb.interp('velocity_rate', ys=[0.25, 0.05]), @@ -473,7 +473,7 @@ def run_trajectory(sim=True): prob.set_val('traj.cruise.states:mass', cruise.interp( 'mass', ys=[mass_i_cruise, mass_f_cruise]), units='kg') prob.set_val('traj.cruise.states:distance', cruise.interp( - 'distance', ys=[range_i_cruise, range_f_cruise]), units='m') # nmi + 'distance', ys=[distance_i_cruise, distance_f_cruise]), units='m') # nmi prob.set_val('traj.cruise.controls:velocity_rate', cruise.interp('velocity_rate', ys=[0.0, 0.0]), @@ -492,7 +492,7 @@ def run_trajectory(sim=True): prob.set_val('traj.descent.states:mass', descent.interp( 'mass', ys=[mass_i_descent, mass_f_descent]), units='kg') prob.set_val('traj.descent.states:distance', descent.interp( - 'distance', ys=[range_i_descent, range_f_descent]), units='m') + 'distance', ys=[distance_i_descent, distance_f_descent]), units='m') prob.set_val('traj.descent.controls:velocity_rate', descent.interp('velocity_rate', ys=[-0.25, 0.05]), diff --git a/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py b/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py index f6ae77aa5..e1894f237 100644 --- a/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py +++ b/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py @@ -588,11 +588,11 @@ def run_mission(optimizer): for idx, (phase_name, phase) in enumerate(traj._phases.items()): if phase_name != "groundroll": - range_initial = range_guesses[idx] + distance_initial = range_guesses[idx] p.set_val(f"traj.{phase_name}.t_initial", - range_initial, units='distance_units') + distance_initial, units='distance_units') p.set_val(f"traj.{phase_name}.t_duration", - range_guesses[idx+1] - range_initial, units='distance_units') + range_guesses[idx+1] - distance_initial, units='distance_units') p.set_val( f"traj.{phase_name}.polynomial_controls:altitude", @@ -657,13 +657,13 @@ def run_mission(optimizer): TASs.extend( p.get_val(f"traj.{phase_name}.timeseries.TAS", units="kn")[-1]) else: - range_initial = p.get_val( + distance_initial = p.get_val( f"traj.{phase_name}.t_initial", units='distance_units') if idx > 1: - ranges.extend(range_initial) + ranges.extend(distance_initial) if idx == (len(traj._phases) - 1): ranges.extend( - p.get_val(f"traj.{phase_name}.t_duration", units='distance_units') + range_initial) + p.get_val(f"traj.{phase_name}.t_duration", units='distance_units') + distance_initial) masses.extend( p.get_val(f"traj.{phase_name}.timeseries.mass", units="lbm")[-1]) alts.extend( diff --git a/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py b/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py index 9158440ad..f1b16fb74 100644 --- a/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py +++ b/aviary/validation_cases/benchmark_tests/test_subsystems_within_a_mission.py @@ -46,7 +46,7 @@ def setUp(self): 'required_available_climb_rate': (1.524, 'm/s'), 'input_initial': False, 'mass_f_cruise': (1.e4, 'lbm'), - 'range_f_cruise': (1.e6, 'm'), + 'distance_f_cruise': (1.e6, 'm'), }, 'initial_guesses': { 'times': ([0., 15000.], 's'), diff --git a/aviary/xdsm/cruise_xdsm.py b/aviary/xdsm/cruise_xdsm.py index 73ff201cc..2f7b5675f 100644 --- a/aviary/xdsm/cruise_xdsm.py +++ b/aviary/xdsm/cruise_xdsm.py @@ -40,7 +40,7 @@ ]) x.add_input("breguet_eom", [ Dynamic.Mission.MASS, - "cruise_range_initial", + "cruise_distance_initial", "cruise_time_initial", ]) x.add_input("weight", ["mass"]) diff --git a/aviary/xdsm/statics_xdsm.py b/aviary/xdsm/statics_xdsm.py index e4583c487..2d5c5eed5 100644 --- a/aviary/xdsm/statics_xdsm.py +++ b/aviary/xdsm/statics_xdsm.py @@ -363,12 +363,12 @@ Dynamic.Mission.MACH, "mass_initial", "cruise_time_initial", - "cruise_range_initial"], + "cruise_distance_initial"], ) x.connect("dymos", "descent1", [Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS]) x.connect("dymos", "fuelburn", [Mission.Landing.TOUCHDOWN_MASS]) x.connect("dymos", Dynamic.Mission.DISTANCE, [Mission.Summary.RANGE]) -x.connect("cruise", "dymos", ["cruise_time_final", "cruise_range_final"]) +x.connect("cruise", "dymos", ["cruise_time_final", "cruise_distance_final"]) # Add Design Variables x.connect( From cae8c66ce562297b3aab0619e4037f26d213f95f Mon Sep 17 00:00:00 2001 From: Gregory Wrenn Date: Wed, 17 Jan 2024 11:03:25 -0500 Subject: [PATCH 079/188] [no ci] Changed NUM_PASSENGERS to 169 from 180 in one test file to match passenger class entries. Reinstated the test to check that passenger class data match the total number of passengers when both types are input. --- aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv | 2 +- aviary/utils/preprocessors.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv index 5c0d0b8a0..92d47e871 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv @@ -21,7 +21,7 @@ aircraft:crew_and_payload:num_flight_attendants,3,unitless aircraft:crew_and_payload:num_flight_crew,2,unitless aircraft:crew_and_payload:num_galley_crew,0,unitless aircraft:crew_and_payload:num_non_flight_crew,3,unitless -aircraft:crew_and_payload:num_passengers,180,unitless +aircraft:crew_and_payload:num_passengers,169,unitless aircraft:crew_and_payload:num_tourist_class,158,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:crew_and_payload:passenger_service_mass_scaler,1.0,unitless diff --git a/aviary/utils/preprocessors.py b/aviary/utils/preprocessors.py index 28f222f7b..c2cce0604 100644 --- a/aviary/utils/preprocessors.py +++ b/aviary/utils/preprocessors.py @@ -55,9 +55,10 @@ def preprocess_crewpayload(aviary_options: AviaryValues): passenger_check += aviary_options.get_val( Aircraft.CrewPayload.NUM_BUSINESS_CLASS) passenger_check += aviary_options.get_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS) - # if passenger_count != passenger_check: - # raise om.AnalysisError( - # "ERROR: In preprocesssors.py: passenger_count does not equal the sum of firt class + business class + tourist class passengers.") + # only perform check if at least one passenger class is entered + if passenger_check > 0 and passenger_count != passenger_check: + raise om.AnalysisError( + "ERROR: In preprocesssors.py: passenger_count does not equal the sum of firt class + business class + tourist class passengers.") if Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS not in aviary_options: flight_attendants_count = 0 # assume no passengers From e41821f29c50650d41d431dd021bf0e15ba75f49 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 17 Jan 2024 10:16:36 -0600 Subject: [PATCH 080/188] Fixed doc --- aviary/docs/getting_started/onboarding_level2.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/docs/getting_started/onboarding_level2.ipynb b/aviary/docs/getting_started/onboarding_level2.ipynb index 5bb5fb516..3a4fd85ce 100644 --- a/aviary/docs/getting_started/onboarding_level2.ipynb +++ b/aviary/docs/getting_started/onboarding_level2.ipynb @@ -651,7 +651,7 @@ " 'fix_final': False,\n", " 'required_available_climb_rate': (1.524, 'm/s'),\n", " 'mass_f_cruise': (1.e4, 'lbm'),\n", - " 'range_f_cruise': (1.e6, 'm'),\n", + " 'distance_f_cruise': (1.e6, 'm'),\n", " },\n", " 'initial_guesses': {\n", " 'times': ([26.2, 406.18], 'min'),\n", From 8c28e95ad0257fd4778c3bc812a45e8376f5bc1b Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 17 Jan 2024 10:35:21 -0600 Subject: [PATCH 081/188] Added new accel phase --- .../interface/default_phase_info/two_dof.py | 42 ++-- aviary/interface/methods_for_level2.py | 7 +- .../gasp_based/phases/new_accel_phase.py | 208 ++++++++++++++++++ 3 files changed, 236 insertions(+), 21 deletions(-) create mode 100644 aviary/mission/gasp_based/phases/new_accel_phase.py diff --git a/aviary/interface/default_phase_info/two_dof.py b/aviary/interface/default_phase_info/two_dof.py index 4b2e51716..5c60b298e 100644 --- a/aviary/interface/default_phase_info/two_dof.py +++ b/aviary/interface/default_phase_info/two_dof.py @@ -120,26 +120,28 @@ } }, 'accel': { - 'num_segments': 1, - 'order': 3, - 'fix_initial': False, - 'alt': (500, 'ft'), - 'EAS_constraint_eq': (250, 'kn'), - 'time_initial_bounds': ((5, 1000), 's'), - 'duration_bounds': ((1, 200), 's'), - 'duration_ref': (1000, 's'), - 'TAS_lower': (150, 'kn'), - 'TAS_upper': (270, 'kn'), - 'TAS_ref': (250, 'kn'), - 'TAS_ref0': (150, 'kn'), - 'mass_lower': (0, 'lbm'), - 'mass_upper': (None, 'lbm'), - 'mass_ref': (150_000, 'lbm'), - 'mass_defect_ref': (150_000, 'lbm'), - 'distance_lower': (0, 'NM'), - 'distance_upper': (150, 'NM'), - 'distance_ref': (5, 'NM'), - 'distance_defect_ref': (5, 'NM'), + 'user_options': { + 'num_segments': 1, + 'order': 3, + 'fix_initial': False, + 'alt': (500, 'ft'), + 'EAS_constraint_eq': (250, 'kn'), + 'time_initial_bounds': ((5, 1000), 's'), + 'duration_bounds': ((1, 200), 's'), + 'duration_ref': (1000, 's'), + 'TAS_lower': (150, 'kn'), + 'TAS_upper': (270, 'kn'), + 'TAS_ref': (250, 'kn'), + 'TAS_ref0': (150, 'kn'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (150_000, 'lbm'), + 'mass_defect_ref': (150_000, 'lbm'), + 'distance_lower': (0, 'NM'), + 'distance_upper': (150, 'NM'), + 'distance_ref': (5, 'NM'), + 'distance_defect_ref': (5, 'NM'), + }, 'initial_guesses': { 'times': ([70., 13.], 's'), 'TAS': ([185., 250.], 'kn'), diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 290f04872..b62a06e1e 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -31,6 +31,7 @@ from aviary.mission.gasp_based.phases.ascent_phase import get_ascent from aviary.mission.gasp_based.phases.climb_phase import get_climb from aviary.mission.gasp_based.phases.new_climb_phase import ClimbPhase +from aviary.mission.gasp_based.phases.new_accel_phase import AccelPhase from aviary.mission.gasp_based.phases.desc_phase import get_descent from aviary.mission.gasp_based.phases.groundroll_phase import get_groundroll from aviary.mission.gasp_based.phases.landing_group import LandingSegment @@ -606,7 +607,7 @@ def _get_2dof_phase(self, phase_name): } # Set the phase function based on the phase name - if 'climb' in phase_name: + if 'climb' in phase_name or 'accel' in phase_name: phase_functions[phase_name] = get_climb num_segments = phase_options['user_options']['num_segments'] order = phase_options['user_options']['order'] @@ -664,6 +665,10 @@ def _get_2dof_phase(self, phase_name): phase_object = ClimbPhase.from_phase_info( phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) phase = phase_object.build_phase(aviary_options=self.aviary_inputs) + elif 'accel' in phase_name: + phase_object = AccelPhase.from_phase_info( + phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) + phase = phase_object.build_phase(aviary_options=self.aviary_inputs) else: phase = phase_func( diff --git a/aviary/mission/gasp_based/phases/new_accel_phase.py b/aviary/mission/gasp_based/phases/new_accel_phase.py new file mode 100644 index 000000000..bff6bac20 --- /dev/null +++ b/aviary/mission/gasp_based/phases/new_accel_phase.py @@ -0,0 +1,208 @@ +from aviary.mission.flops_based.phases.phase_builder_base import ( + PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.variables import Dynamic +from aviary.mission.gasp_based.ode.accel_ode import AccelODE +from aviary.variable_info.variable_meta_data import _MetaData + + +class AccelPhase(PhaseBuilderBase): + """ + A phase builder for an acceleration phase in a mission simulation. + + This class extends the PhaseBuilderBase class, providing specific implementations for + the acceleration phase of a flight mission. + + Attributes + ---------- + Inherits all attributes from PhaseBuilderBase. + + Methods + ------- + Inherits all methods from PhaseBuilderBase. + Additional method overrides and new methods specific to the acceleration phase are included. + """ + default_name = 'accel_phase' + default_ode_class = AccelODE + + __slots__ = ('external_subsystems', 'meta_data') + + _meta_data_ = {} + _initial_guesses_meta_data_ = {} + + default_meta_data = _MetaData + + def __init__( + self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, core_subsystems=None, + external_subsystems=None, meta_data=None + ): + super().__init__( + name=name, subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, + core_subsystems=core_subsystems, + ) + + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + + self.meta_data = meta_data + + def build_phase(self, aviary_options: AviaryValues = None): + """ + Return a new acceleration phase for analysis using these constraints. + + Parameters + ---------- + aviary_options : AviaryValues + Collection of Aircraft/Mission specific options + + Returns + ------- + dymos.Phase + """ + phase = super().build_phase(aviary_options) + user_options = self.user_options + + # Extracting and setting options + fix_initial = user_options.get_val('fix_initial') + EAS_constraint_eq = user_options.get_val('EAS_constraint_eq', units='kn') + time_initial_bounds = user_options.get_val('time_initial_bounds', units='s') + duration_bounds = user_options.get_val('duration_bounds', units='s') + duration_ref = user_options.get_val('duration_ref', units='s') + TAS_lower = user_options.get_val('TAS_lower', units='kn') + TAS_upper = user_options.get_val('TAS_upper', units='kn') + TAS_ref = user_options.get_val('TAS_ref', units='kn') + TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') + TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') + mass_lower = user_options.get_val('mass_lower', units='lbm') + mass_upper = user_options.get_val('mass_upper', units='lbm') + mass_ref = user_options.get_val('mass_ref', units='lbm') + mass_ref0 = user_options.get_val('mass_ref0', units='lbm') + mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') + distance_lower = user_options.get_val('distance_lower', units='NM') + distance_upper = user_options.get_val('distance_upper', units='NM') + distance_ref = user_options.get_val('distance_ref', units='NM') + distance_ref0 = user_options.get_val('distance_ref0', units='NM') + distance_defect_ref = user_options.get_val('distance_defect_ref', units='NM') + alt = user_options.get_val('alt', units='ft') + + phase.set_time_options( + fix_initial=fix_initial, + initial_bounds=time_initial_bounds, + duration_bounds=duration_bounds, + units="s", + duration_ref=duration_ref, + ) + + # States + phase.add_state( + "TAS", + fix_initial=fix_initial, + fix_final=False, + lower=TAS_lower, + upper=TAS_upper, + units="kn", + rate_source="TAS_rate", + targets="TAS", + ref=TAS_ref, + ref0=TAS_ref0, + defect_ref=TAS_defect_ref, + ) + + phase.add_state( + Dynamic.Mission.MASS, + fix_initial=fix_initial, + fix_final=False, + lower=mass_lower, + upper=mass_upper, + units="lbm", + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, + ref=mass_ref, + ref0=mass_ref0, + defect_ref=mass_defect_ref, + ) + + phase.add_state( + Dynamic.Mission.DISTANCE, + fix_initial=fix_initial, + fix_final=False, + lower=distance_lower, + upper=distance_upper, + units="NM", + rate_source="distance_rate", + ref=distance_ref, + ref0=distance_ref0, + defect_ref=distance_defect_ref, + ) + + # Boundary Constraints + phase.add_boundary_constraint( + "EAS", loc="final", equals=EAS_constraint_eq, units="kn", ref=EAS_constraint_eq + ) + + phase.add_parameter(Dynamic.Mission.ALTITUDE, opt=False, units="ft", val=alt) + + # Timeseries Outputs + phase.add_timeseries_output("EAS", output_name="EAS", units="kn") + phase.add_timeseries_output( + Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") + phase.add_timeseries_output("alpha", output_name="alpha", units="deg") + phase.add_timeseries_output("aero.CL", output_name="CL", units="unitless") + phase.add_timeseries_output( + Dynamic.Mission.THRUST_TOTAL, output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") + phase.add_timeseries_output("aero.CD", output_name="CD", units="unitless") + + return phase + + +# Adding metadata for the AccelPhase +AccelPhase._add_meta_data('fix_initial', val=False) +AccelPhase._add_meta_data('EAS_constraint_eq', val=250, units='kn') +AccelPhase._add_meta_data('time_initial_bounds', val=(0, 0), units='s') +AccelPhase._add_meta_data('duration_bounds', val=(0, 0), units='s') +AccelPhase._add_meta_data('duration_ref', val=1, units='s') +AccelPhase._add_meta_data('TAS_lower', val=0, units='kn') +AccelPhase._add_meta_data('TAS_upper', val=0, units='kn') +AccelPhase._add_meta_data('TAS_ref', val=1, units='kn') +AccelPhase._add_meta_data('TAS_ref0', val=0, units='kn') +AccelPhase._add_meta_data('TAS_defect_ref', val=None, units='kn') +AccelPhase._add_meta_data('mass_lower', val=0, units='lbm') +AccelPhase._add_meta_data('mass_upper', val=0, units='lbm') +AccelPhase._add_meta_data('mass_ref', val=1, units='lbm') +AccelPhase._add_meta_data('mass_ref0', val=0, units='lbm') +AccelPhase._add_meta_data('mass_defect_ref', val=None, units='lbm') +AccelPhase._add_meta_data('distance_lower', val=0, units='NM') +AccelPhase._add_meta_data('distance_upper', val=0, units='NM') +AccelPhase._add_meta_data('distance_ref', val=1, units='NM') +AccelPhase._add_meta_data('distance_ref0', val=0, units='NM') +AccelPhase._add_meta_data('distance_defect_ref', val=None, units='NM') +AccelPhase._add_meta_data('alt', val=500, units='ft') +AccelPhase._add_meta_data('num_segments', val=None, units='unitless') +AccelPhase._add_meta_data('order', val=None, units='unitless') + +AccelPhase._add_initial_guess_meta_data( + InitialGuessTime(), + desc='initial guess for initial time and duration specified as a tuple') + +AccelPhase._add_initial_guess_meta_data( + InitialGuessState('TAS'), + desc='initial guess for true airspeed') + +AccelPhase._add_initial_guess_meta_data( + InitialGuessState('mass'), + desc='initial guess for mass') + +AccelPhase._add_initial_guess_meta_data( + InitialGuessState('distance'), + desc='initial guess for horizontal distance traveled') + +AccelPhase._add_initial_guess_meta_data( + InitialGuessControl('throttle'), + desc='initial guess for throttle') From 07bf6cd5a27606815f2c4c31d730d91a9416d169 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 17 Jan 2024 11:34:24 -0600 Subject: [PATCH 082/188] Added new ascent phase --- .../interface/default_phase_info/two_dof.py | 64 ++-- aviary/interface/methods_for_level2.py | 19 +- .../gasp_based/phases/new_ascent_phase.py | 288 ++++++++++++++++++ 3 files changed, 336 insertions(+), 35 deletions(-) create mode 100644 aviary/mission/gasp_based/phases/new_ascent_phase.py diff --git a/aviary/interface/default_phase_info/two_dof.py b/aviary/interface/default_phase_info/two_dof.py index 5c60b298e..8caff38c4 100644 --- a/aviary/interface/default_phase_info/two_dof.py +++ b/aviary/interface/default_phase_info/two_dof.py @@ -78,35 +78,37 @@ } }, 'ascent': { - 'num_segments': 4, - 'order': 3, - 'fix_initial': False, - 'TAS_lower': (0, 'kn'), - 'TAS_upper': (700, 'kn'), - 'TAS_ref': (200, 'kn'), - 'TAS_ref0': (0, 'kn'), - 'mass_lower': (0, 'lbm'), - 'mass_upper': (None, 'lbm'), - 'mass_ref': (150_000, 'lbm'), - 'mass_defect_ref': (150_000, 'lbm'), - 'distance_lower': (0, 'ft'), - 'distance_upper': (15_000, 'ft'), - 'distance_ref': (1e4, 'ft'), - 'distance_defect_ref': (1e4, 'ft'), - 'alt_lower': (0, 'ft'), - 'alt_upper': (700, 'ft'), - 'alt_ref': (1000, 'ft'), - 'alt_defect_ref': (1000, 'ft'), - 'alt_constraint_eq': (500, 'ft'), - 'alt_constraint_ref': (500, 'ft'), - 'alt_constraint_ref0': (0, 'ft'), - 'angle_lower': (-10, 'deg'), - 'angle_upper': (20, 'deg'), - 'angle_ref': (1, 'deg'), - 'angle_defect_ref': (1.0, 'deg'), - 'pitch_constraint_lower': (0., 'deg'), - 'pitch_constraint_upper': (15., 'deg'), - 'pitch_constraint_ref': (1., 'deg'), + 'user_options': { + 'num_segments': 4, + 'order': 3, + 'fix_initial': False, + 'TAS_lower': (0, 'kn'), + 'TAS_upper': (700, 'kn'), + 'TAS_ref': (200, 'kn'), + 'TAS_ref0': (0, 'kn'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (150_000, 'lbm'), + 'mass_defect_ref': (150_000, 'lbm'), + 'distance_lower': (0, 'ft'), + 'distance_upper': (15_000, 'ft'), + 'distance_ref': (1e4, 'ft'), + 'distance_defect_ref': (1e4, 'ft'), + 'alt_lower': (0, 'ft'), + 'alt_upper': (700, 'ft'), + 'alt_ref': (1000, 'ft'), + 'alt_defect_ref': (1000, 'ft'), + 'alt_constraint_eq': (500, 'ft'), + 'alt_constraint_ref': (500, 'ft'), + 'alt_constraint_ref0': (0, 'ft'), + 'angle_lower': (-10, 'deg'), + 'angle_upper': (20, 'deg'), + 'angle_ref': (57.2958, 'deg'), + 'angle_defect_ref': (1.0, 'deg'), + 'pitch_constraint_lower': (0., 'deg'), + 'pitch_constraint_upper': (15., 'deg'), + 'pitch_constraint_ref': (1., 'deg'), + }, 'initial_guesses': { 'times': ([45., 25.], 's'), 'flight_path_angle': ([0.0, 8.], 'deg'), @@ -114,8 +116,8 @@ 'TAS': ([150., 185.], 'kn'), 'distance': ([4.e3, 10.e3], 'ft'), 'altitude': ([0.0, 500.], 'ft'), - 'tau_gear': (0.2, None), - 'tau_flaps': (0.9, None), + 'tau_gear': (0.2, 'unitless'), + 'tau_flaps': (0.9, 'unitless'), 'throttle': ([0.956, 0.956], 'unitless'), } }, diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index b62a06e1e..25da8dd49 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -32,6 +32,7 @@ from aviary.mission.gasp_based.phases.climb_phase import get_climb from aviary.mission.gasp_based.phases.new_climb_phase import ClimbPhase from aviary.mission.gasp_based.phases.new_accel_phase import AccelPhase +from aviary.mission.gasp_based.phases.new_ascent_phase import AscentPhase from aviary.mission.gasp_based.phases.desc_phase import get_descent from aviary.mission.gasp_based.phases.groundroll_phase import get_groundroll from aviary.mission.gasp_based.phases.landing_group import LandingSegment @@ -463,7 +464,13 @@ def _add_gasp_takeoff_systems(self): self.model.add_subsystem( "event_xform", om.ExecComp( - ["t_init_gear=m*tau_gear+b", "t_init_flaps=m*tau_flaps+b"], units="s" + ["t_init_gear=m*tau_gear+b", "t_init_flaps=m*tau_flaps+b"], + t_init_gear={"units": "s"}, + t_init_flaps={"units": "s"}, + tau_gear={"units": "unitless"}, + tau_flaps={"units": "unitless"}, + m={"units": "s"}, + b={"units": "s"}, ), promotes_inputs=[ "tau_gear", @@ -607,7 +614,7 @@ def _get_2dof_phase(self, phase_name): } # Set the phase function based on the phase name - if 'climb' in phase_name or 'accel' in phase_name: + if 'climb' in phase_name or 'accel' in phase_name or 'ascent' in phase_name: phase_functions[phase_name] = get_climb num_segments = phase_options['user_options']['num_segments'] order = phase_options['user_options']['order'] @@ -669,6 +676,10 @@ def _get_2dof_phase(self, phase_name): phase_object = AccelPhase.from_phase_info( phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) phase = phase_object.build_phase(aviary_options=self.aviary_inputs) + elif 'ascent' in phase_name: + phase_object = AscentPhase.from_phase_info( + phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) + phase = phase_object.build_phase(aviary_options=self.aviary_inputs) else: phase = phase_func( @@ -1685,9 +1696,9 @@ def add_design_variables(self): self.model.add_design_var(Mission.Takeoff.ASCENT_DURATION, lower=1, upper=1000, ref=10.) self.model.add_design_var("tau_gear", lower=0.01, - upper=1.0, units="s", ref=1) + upper=1.0, units="unitless", ref=1) self.model.add_design_var("tau_flaps", lower=0.01, - upper=1.0, units="s", ref=1) + upper=1.0, units="unitless", ref=1) self.model.add_constraint( "h_fit.h_init_gear", equals=50.0, units="ft", ref=50.0) self.model.add_constraint("h_fit.h_init_flaps", diff --git a/aviary/mission/gasp_based/phases/new_ascent_phase.py b/aviary/mission/gasp_based/phases/new_ascent_phase.py new file mode 100644 index 000000000..467fcdb1f --- /dev/null +++ b/aviary/mission/gasp_based/phases/new_ascent_phase.py @@ -0,0 +1,288 @@ +from aviary.mission.flops_based.phases.phase_builder_base import ( + PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.variables import Dynamic +from aviary.mission.gasp_based.ode.ascent_ode import AscentODE +from aviary.variable_info.variable_meta_data import _MetaData + +import numpy as np + + +class AscentPhase(PhaseBuilderBase): + default_name = 'ascent_phase' + default_ode_class = AscentODE + + __slots__ = ('external_subsystems', 'meta_data') + + _meta_data_ = {} + _initial_guesses_meta_data_ = {} + + default_meta_data = _MetaData + + def __init__( + self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, core_subsystems=None, + external_subsystems=None, meta_data=None + ): + super().__init__( + name=name, subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, + core_subsystems=core_subsystems, + ) + + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + + self.meta_data = meta_data + + def build_phase(self, aviary_options: AviaryValues = None): + phase = super().build_phase(aviary_options) + + # Retrieve user options values + user_options = self.user_options + angle_lower = user_options.get_val('angle_lower', units='rad') + angle_upper = user_options.get_val('angle_upper', units='rad') + angle_ref = user_options.get_val('angle_ref', units='rad') + angle_ref0 = user_options.get_val('angle_ref0', units='rad') + angle_defect_ref = user_options.get_val('angle_defect_ref', units='rad') + alt_lower = user_options.get_val('alt_lower', units='ft') + alt_upper = user_options.get_val('alt_upper', units='ft') + alt_ref = user_options.get_val('alt_ref', units='ft') + alt_ref0 = user_options.get_val('alt_ref0', units='ft') + alt_defect_ref = user_options.get_val('alt_defect_ref', units='ft') + alt_constraint_eq = user_options.get_val('alt_constraint_eq', units='ft') + alt_constraint_ref = user_options.get_val('alt_constraint_ref', units='ft') + alt_constraint_ref0 = user_options.get_val('alt_constraint_ref0', units='ft') + TAS_lower = user_options.get_val('TAS_lower', units='kn') + TAS_upper = user_options.get_val('TAS_upper', units='kn') + TAS_ref = user_options.get_val('TAS_ref', units='kn') + TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') + TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') + mass_lower = user_options.get_val('mass_lower', units='lbm') + mass_upper = user_options.get_val('mass_upper', units='lbm') + mass_ref = user_options.get_val('mass_ref', units='lbm') + mass_ref0 = user_options.get_val('mass_ref0', units='lbm') + mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') + distance_lower = user_options.get_val('distance_lower', units='ft') + distance_upper = user_options.get_val('distance_upper', units='ft') + distance_ref = user_options.get_val('distance_ref', units='ft') + distance_ref0 = user_options.get_val('distance_ref0', units='ft') + distance_defect_ref = user_options.get_val('distance_defect_ref', units='ft') + pitch_constraint_lower = user_options.get_val( + 'pitch_constraint_lower', units='deg') + pitch_constraint_upper = user_options.get_val( + 'pitch_constraint_upper', units='deg') + pitch_constraint_ref = user_options.get_val('pitch_constraint_ref', units='deg') + alpha_constraint_lower = user_options.get_val( + 'alpha_constraint_lower', units='rad') + alpha_constraint_upper = user_options.get_val( + 'alpha_constraint_upper', units='rad') + alpha_constraint_ref = user_options.get_val('alpha_constraint_ref', units='rad') + + phase.set_time_options( + units="s", + targets="t_curr", + input_initial=True, + input_duration=True, + ) + + phase.add_state( + Dynamic.Mission.FLIGHT_PATH_ANGLE, + fix_initial=True, + fix_final=False, + lower=angle_lower, + upper=angle_upper, + units="rad", + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + ref=angle_ref, + defect_ref=angle_defect_ref, + ref0=angle_ref0, + ) + + phase.add_state( + Dynamic.Mission.ALTITUDE, + fix_initial=True, + fix_final=False, + lower=alt_lower, + upper=alt_upper, + units="ft", + rate_source=Dynamic.Mission.ALTITUDE_RATE, + ref=alt_ref, + defect_ref=alt_defect_ref, + ref0=alt_ref0, + ) + + phase.add_state( + "TAS", + fix_initial=user_options.get_val('fix_initial'), + fix_final=False, + lower=TAS_lower, + upper=TAS_upper, + units="kn", + rate_source="TAS_rate", + ref=TAS_ref, + defect_ref=TAS_defect_ref, + ref0=TAS_ref0, + ) + + phase.add_state( + Dynamic.Mission.MASS, + fix_initial=user_options.get_val('fix_initial'), + fix_final=False, + lower=mass_lower, + upper=mass_upper, + units="lbm", + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + ref=mass_ref, + defect_ref=mass_defect_ref, + ref0=mass_ref0, + ) + + phase.add_state( + Dynamic.Mission.DISTANCE, + fix_initial=user_options.get_val('fix_initial'), + fix_final=False, + lower=distance_lower, + upper=distance_upper, + units="ft", + rate_source="distance_rate", + ref=distance_ref, + defect_ref=distance_defect_ref, + ref0=distance_ref0, + ) + + phase.add_boundary_constraint( + Dynamic.Mission.ALTITUDE, + loc="final", + equals=alt_constraint_eq, + units="ft", + ref=alt_constraint_ref, + ref0=alt_constraint_ref0, + ) + + phase.add_path_constraint( + "load_factor", + upper=1.10, + lower=0.0 + ) + + phase.add_path_constraint( + "fuselage_pitch", + "theta", + lower=pitch_constraint_lower, + upper=pitch_constraint_upper, + units="deg", + ref=pitch_constraint_ref, + ) + + phase.add_control( + "alpha", + val=0, + lower=alpha_constraint_lower, + upper=alpha_constraint_upper, + units="rad", + ref=alpha_constraint_ref, + opt=True, + ) + + phase.add_parameter("t_init_gear", units="s", + static_target=True, opt=False, val=38.25) + + phase.add_parameter("t_init_flaps", units="s", + static_target=True, opt=False, val=48.21) + + phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") + phase.add_timeseries_output("normal_force") + phase.add_timeseries_output(Dynamic.Mission.MACH) + phase.add_timeseries_output("EAS", units="kn") + phase.add_timeseries_output(Dynamic.Mission.LIFT) + phase.add_timeseries_output("CL") + phase.add_timeseries_output("CD") + + return phase + + +# Adding metadata for the AscentPhase +AscentPhase._add_meta_data('fix_initial', val=False) +AscentPhase._add_meta_data('angle_lower', val=-15 * np.pi / 180, units='rad') +AscentPhase._add_meta_data('angle_upper', val=25 * np.pi / 180, units='rad') +AscentPhase._add_meta_data('angle_ref', val=np.deg2rad(1), units='rad') +AscentPhase._add_meta_data('angle_ref0', val=0, units='rad') +AscentPhase._add_meta_data('angle_defect_ref', val=0.01, units='rad') +AscentPhase._add_meta_data('alt_lower', val=0, units='ft') +AscentPhase._add_meta_data('alt_upper', val=700, units='ft') +AscentPhase._add_meta_data('alt_ref', val=100, units='ft') +AscentPhase._add_meta_data('alt_ref0', val=0, units='ft') +AscentPhase._add_meta_data('alt_defect_ref', val=100, units='ft') +AscentPhase._add_meta_data('alt_constraint_eq', val=500, units='ft') +AscentPhase._add_meta_data('alt_constraint_ref', val=100, units='ft') +AscentPhase._add_meta_data('alt_constraint_ref0', val=0, units='ft') +AscentPhase._add_meta_data('TAS_lower', val=0, units='kn') +AscentPhase._add_meta_data('TAS_upper', val=1000, units='kn') +AscentPhase._add_meta_data('TAS_ref', val=1e2, units='kn') +AscentPhase._add_meta_data('TAS_ref0', val=0, units='kn') +AscentPhase._add_meta_data('TAS_defect_ref', val=None, units='kn') +AscentPhase._add_meta_data('mass_lower', val=0, units='lbm') +AscentPhase._add_meta_data('mass_upper', val=190_000, units='lbm') +AscentPhase._add_meta_data('mass_ref', val=100_000, units='lbm') +AscentPhase._add_meta_data('mass_ref0', val=0, units='lbm') +AscentPhase._add_meta_data('mass_defect_ref', val=1e2, units='lbm') +AscentPhase._add_meta_data('distance_lower', val=0, units='ft') +AscentPhase._add_meta_data('distance_upper', val=10.e3, units='ft') +AscentPhase._add_meta_data('distance_ref', val=3000, units='ft') +AscentPhase._add_meta_data('distance_ref0', val=0, units='ft') +AscentPhase._add_meta_data('distance_defect_ref', val=3000, units='ft') +AscentPhase._add_meta_data('pitch_constraint_lower', val=0, units='deg') +AscentPhase._add_meta_data('pitch_constraint_upper', val=15, units='deg') +AscentPhase._add_meta_data('pitch_constraint_ref', val=1, units='deg') +AscentPhase._add_meta_data('alpha_constraint_lower', val=np.deg2rad(-30), units='rad') +AscentPhase._add_meta_data('alpha_constraint_upper', val=np.deg2rad(30), units='rad') +AscentPhase._add_meta_data('alpha_constraint_ref', val=np.deg2rad(5), units='rad') +AscentPhase._add_meta_data('num_segments', val=None, units='unitless') +AscentPhase._add_meta_data('order', val=None, units='unitless') + +# Adding initial guess metadata +AscentPhase._add_initial_guess_meta_data( + InitialGuessTime(), + desc='initial guess for time options') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessState('flight_path_angle'), + desc='initial guess for flight path angle state') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessState('altitude'), + desc='initial guess for altitude state') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessState('TAS'), + desc='initial guess for true airspeed state') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessState('mass'), + desc='initial guess for mass state') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessState('distance'), + desc='initial guess for distance state') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessControl('alpha'), + desc='initial guess for angle of attack control') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessControl('tau_gear'), + desc='when the gear is retracted') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessControl('tau_flaps'), + desc='when the flaps are retracted') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessControl('throttle'), + desc='initial guess for throttle') From 733ccf150c19cbf411f1436a2cbcea677d6bd3c4 Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Wed, 17 Jan 2024 14:14:31 -0500 Subject: [PATCH 083/188] upd climb_ode with Altitude_rate_max output --- aviary/mission/gasp_based/ode/climb_ode.py | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/aviary/mission/gasp_based/ode/climb_ode.py b/aviary/mission/gasp_based/ode/climb_ode.py index e9182e92b..2a7ea910e 100644 --- a/aviary/mission/gasp_based/ode/climb_ode.py +++ b/aviary/mission/gasp_based/ode/climb_ode.py @@ -14,6 +14,8 @@ from aviary.subsystems.propulsion.propulsion_mission import PropulsionMission from aviary.variable_info.enums import AnalysisScheme, AlphaModes, SpeedType from aviary.variable_info.variables import Dynamic +from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate +from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate class ClimbODE(BaseODE): @@ -197,6 +199,28 @@ def setup(self): ], ) + lift_balance_group.add_subsystem( + name='SPECIFIC_ENERGY_RATE_EXCESS', + subsys=SpecificEnergyRate(num_nodes=nn), + promotes_inputs=["TAS", Dynamic.Mission.MASS, + Dynamic.Mission.THRUST_MAX_TOTAL, Dynamic.Mission.DRAG], + promotes_outputs=[(Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS)] + ) + + # Note when TAS_rate = 0, SPECIFIC_ENERGY_RATE_EXCESS = ALTITUDE_RATE_MAX + lift_balance_group.add_subsystem( + name='ALTITUDE_RATE_MAX', + subsys=AltitudeRate(num_nodes=nn), + promotes_inputs=[ + (Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS), + "TAS_rate", + "TAS"], + promotes_outputs=[ + (Dynamic.Mission.ALTITUDE_RATE, + Dynamic.Mission.ALTITUDE_RATE_MAX)]) + self.AddAlphaControl( alpha_group=lift_balance_group, alpha_mode=AlphaModes.REQUIRED_LIFT, From 70c5d4494ad29a4852f593409995f6eb660f9a82 Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Wed, 17 Jan 2024 14:35:08 -0500 Subject: [PATCH 084/188] moved ALTITUDE_RATE_MAX calc outside of balance, climb tests failing cannot find THRUST_MAX_TOTAL --- aviary/mission/gasp_based/ode/climb_ode.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/aviary/mission/gasp_based/ode/climb_ode.py b/aviary/mission/gasp_based/ode/climb_ode.py index 2a7ea910e..c85752ac4 100644 --- a/aviary/mission/gasp_based/ode/climb_ode.py +++ b/aviary/mission/gasp_based/ode/climb_ode.py @@ -199,24 +199,25 @@ def setup(self): ], ) - lift_balance_group.add_subsystem( + # defalting to outside the balance to minimize calcs. + self.add_subsystem( name='SPECIFIC_ENERGY_RATE_EXCESS', subsys=SpecificEnergyRate(num_nodes=nn), - promotes_inputs=["TAS", Dynamic.Mission.MASS, + promotes_inputs=[(Dynamic.Mission.VELOCITY, "TAS"), Dynamic.Mission.MASS, Dynamic.Mission.THRUST_MAX_TOTAL, Dynamic.Mission.DRAG], promotes_outputs=[(Dynamic.Mission.SPECIFIC_ENERGY_RATE, Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS)] ) # Note when TAS_rate = 0, SPECIFIC_ENERGY_RATE_EXCESS = ALTITUDE_RATE_MAX - lift_balance_group.add_subsystem( + self.add_subsystem( name='ALTITUDE_RATE_MAX', subsys=AltitudeRate(num_nodes=nn), promotes_inputs=[ (Dynamic.Mission.SPECIFIC_ENERGY_RATE, Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS), - "TAS_rate", - "TAS"], + (Dynamic.Mission.VELOCITY_RATE, "TAS_rate"), + (Dynamic.Mission.VELOCITY, "TAS")], promotes_outputs=[ (Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.ALTITUDE_RATE_MAX)]) From 808e673d5a17636876ed1f0c645e1d6a2391257b Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Wed, 17 Jan 2024 14:41:18 -0500 Subject: [PATCH 085/188] Adding tmate session --- .github/workflows/test_workflow.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 3edbe2f3e..6927d7b51 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -213,6 +213,10 @@ jobs: python run_all.py cd ../.. + # - name: Setup tmate session + # uses: mxschmitt/action-tmate@v3 + + - name: Run tests if: matrix.MAKE_DOCS == 0 shell: bash -l {0} From 44bc2ced430c75bb6fa81fc906c18baa5aebc07b Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 17 Jan 2024 13:44:46 -0600 Subject: [PATCH 086/188] Added descent phase --- .../interface/default_phase_info/two_dof.py | 110 ++++----- aviary/interface/methods_for_level2.py | 11 +- .../gasp_based/phases/new_descent_phase.py | 213 ++++++++++++++++++ 3 files changed, 276 insertions(+), 58 deletions(-) create mode 100644 aviary/mission/gasp_based/phases/new_descent_phase.py diff --git a/aviary/interface/default_phase_info/two_dof.py b/aviary/interface/default_phase_info/two_dof.py index 8caff38c4..9747fa2eb 100644 --- a/aviary/interface/default_phase_info/two_dof.py +++ b/aviary/interface/default_phase_info/two_dof.py @@ -104,7 +104,7 @@ 'angle_lower': (-10, 'deg'), 'angle_upper': (20, 'deg'), 'angle_ref': (57.2958, 'deg'), - 'angle_defect_ref': (1.0, 'deg'), + 'angle_defect_ref': (57.2958, 'deg'), 'pitch_constraint_lower': (0., 'deg'), 'pitch_constraint_upper': (15., 'deg'), 'pitch_constraint_ref': (1., 'deg'), @@ -227,33 +227,35 @@ } }, 'desc1': { - 'num_segments': 3, - 'order': 3, - 'fix_initial': False, - 'input_initial': False, - 'EAS_limit': (350, 'kn'), - 'mach_cruise': 0.8, - 'input_speed_type': SpeedType.MACH, - 'final_alt': (10.e3, 'ft'), - 'time_initial_bounds': ((1000, 35_000), 's'), - 'time_initial_ref': (10_000, 's'), - 'duration_bounds': ((300., 900.), 's'), - 'duration_ref': (1000, 's'), - 'alt_lower': (1000, 'ft'), - 'alt_upper': (40_000, 'ft'), - 'alt_ref': (30_000, 'ft'), - 'alt_ref0': (0, 'ft'), - 'alt_constraint_ref': (10000, 'ft'), - 'mass_lower': (0, 'lbm'), - 'mass_upper': (None, 'lbm'), - 'mass_ref': (140_000, 'lbm'), - 'mass_ref0': (0, 'lbm'), - 'mass_defect_ref': (140_000, 'lbm'), - 'distance_lower': (3000., 'NM'), - 'distance_upper': (5000., 'NM'), - 'distance_ref': (mission_distance, 'NM'), - 'distance_ref0': (0, 'NM'), - 'distance_defect_ref': (100, 'NM'), + 'user_options': { + 'num_segments': 3, + 'order': 3, + 'fix_initial': False, + 'input_initial': False, + 'EAS_limit': (350, 'kn'), + 'mach_cruise': 0.8, + 'input_speed_type': SpeedType.MACH, + 'final_alt': (10.e3, 'ft'), + 'time_initial_bounds': ((1000, 35_000), 's'), + 'time_initial_ref': (10_000, 's'), + 'duration_bounds': ((300., 900.), 's'), + 'duration_ref': (1000, 's'), + 'alt_lower': (1000, 'ft'), + 'alt_upper': (40_000, 'ft'), + 'alt_ref': (30_000, 'ft'), + 'alt_ref0': (0, 'ft'), + 'alt_constraint_ref': (10000, 'ft'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (140_000, 'lbm'), + 'mass_ref0': (0, 'lbm'), + 'mass_defect_ref': (140_000, 'lbm'), + 'distance_lower': (3000., 'NM'), + 'distance_upper': (5000., 'NM'), + 'distance_ref': (mission_distance, 'NM'), + 'distance_ref0': (0, 'NM'), + 'distance_defect_ref': (100, 'NM'), + }, 'initial_guesses': { 'mass': (136000., 'lbm'), 'altitude': ([37.5e3, 10.e3], 'ft'), @@ -263,31 +265,33 @@ } }, 'desc2': { - 'num_segments': 1, - 'order': 7, - 'fix_initial': False, - 'input_initial': False, - 'EAS_limit': (250, 'kn'), - 'mach_cruise': 0.80, - 'input_speed_type': SpeedType.EAS, - 'final_alt': (1000, 'ft'), - 'time_initial_bounds': ((2000, 50_000), 's'), - 'time_initial_ref': (15000, 's'), - 'duration_bounds': ((100., 5000), 's'), - 'duration_ref': (500, 's'), - 'alt_lower': (500, 'ft'), - 'alt_upper': (11_000, 'ft'), - 'alt_ref': (10.e3, 'ft'), - 'alt_ref0': (1000, 'ft'), - 'alt_constraint_ref': (1000, 'ft'), - 'mass_lower': (0, 'lbm'), - 'mass_upper': (None, 'lbm'), - 'mass_ref': (150_000, 'lbm'), - 'mass_defect_ref': (150_000, 'lbm'), - 'distance_lower': (0, 'NM'), - 'distance_upper': (5000, 'NM'), - 'distance_ref': (3500, 'NM'), - 'distance_defect_ref': (100, 'NM'), + 'user_options': { + 'num_segments': 1, + 'order': 7, + 'fix_initial': False, + 'input_initial': False, + 'EAS_limit': (250, 'kn'), + 'mach_cruise': 0.80, + 'input_speed_type': SpeedType.EAS, + 'final_alt': (1000, 'ft'), + 'time_initial_bounds': ((2000, 50_000), 's'), + 'time_initial_ref': (15000, 's'), + 'duration_bounds': ((100., 5000), 's'), + 'duration_ref': (500, 's'), + 'alt_lower': (500, 'ft'), + 'alt_upper': (11_000, 'ft'), + 'alt_ref': (10.e3, 'ft'), + 'alt_ref0': (1000, 'ft'), + 'alt_constraint_ref': (1000, 'ft'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (150_000, 'lbm'), + 'mass_defect_ref': (150_000, 'lbm'), + 'distance_lower': (0, 'NM'), + 'distance_upper': (5000, 'NM'), + 'distance_ref': (3500, 'NM'), + 'distance_defect_ref': (100, 'NM'), + }, 'initial_guesses': { 'mass': (136000., 'lbm'), 'altitude': ([10.e3, 1.e3], 'ft'), diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 25da8dd49..799237fa3 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -33,6 +33,7 @@ from aviary.mission.gasp_based.phases.new_climb_phase import ClimbPhase from aviary.mission.gasp_based.phases.new_accel_phase import AccelPhase from aviary.mission.gasp_based.phases.new_ascent_phase import AscentPhase +from aviary.mission.gasp_based.phases.new_descent_phase import DescentPhase from aviary.mission.gasp_based.phases.desc_phase import get_descent from aviary.mission.gasp_based.phases.groundroll_phase import get_groundroll from aviary.mission.gasp_based.phases.landing_group import LandingSegment @@ -614,14 +615,10 @@ def _get_2dof_phase(self, phase_name): } # Set the phase function based on the phase name - if 'climb' in phase_name or 'accel' in phase_name or 'ascent' in phase_name: + if 'climb' in phase_name or 'accel' in phase_name or 'ascent' in phase_name or 'desc' in phase_name: phase_functions[phase_name] = get_climb num_segments = phase_options['user_options']['num_segments'] order = phase_options['user_options']['order'] - elif 'desc' in phase_name: - phase_functions[phase_name] = get_descent - num_segments = phase_options['num_segments'] - order = phase_options['order'] else: num_segments = phase_options['num_segments'] order = phase_options['order'] @@ -680,6 +677,10 @@ def _get_2dof_phase(self, phase_name): phase_object = AscentPhase.from_phase_info( phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) phase = phase_object.build_phase(aviary_options=self.aviary_inputs) + elif 'desc' in phase_name: + phase_object = DescentPhase.from_phase_info( + phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) + phase = phase_object.build_phase(aviary_options=self.aviary_inputs) else: phase = phase_func( diff --git a/aviary/mission/gasp_based/phases/new_descent_phase.py b/aviary/mission/gasp_based/phases/new_descent_phase.py new file mode 100644 index 000000000..42af7f5bb --- /dev/null +++ b/aviary/mission/gasp_based/phases/new_descent_phase.py @@ -0,0 +1,213 @@ +from aviary.mission.flops_based.phases.phase_builder_base import ( + PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.variables import Dynamic +from aviary.variable_info.enums import SpeedType +from aviary.mission.gasp_based.ode.descent_ode import DescentODE +from aviary.variable_info.variable_meta_data import _MetaData + + +class DescentPhase(PhaseBuilderBase): + default_name = 'descent_phase' + default_ode_class = DescentODE + + __slots__ = ('external_subsystems', 'meta_data') + + _meta_data_ = {} + _initial_guesses_meta_data_ = {} + + default_meta_data = _MetaData + + def __init__( + self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, core_subsystems=None, + external_subsystems=None, meta_data=None + ): + super().__init__( + name=name, subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, + core_subsystems=core_subsystems, + ) + + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + + self.meta_data = meta_data + + def build_phase(self, aviary_options: AviaryValues = None): + phase = super().build_phase(aviary_options) + + # Retrieve user options values + user_options = self.user_options + time_initial_bounds = user_options.get_val('time_initial_bounds', units='s') + duration_bounds = user_options.get_val('duration_bounds', units='s') + fix_initial = user_options.get_val('fix_initial') + input_initial = user_options.get_val('input_initial') + duration_ref = user_options.get_val('duration_ref', units='s') + time_initial_ref = user_options.get_val('time_initial_ref', units='s') + alt_lower = user_options.get_val('alt_lower', units='ft') + alt_upper = user_options.get_val('alt_upper', units='ft') + alt_ref = user_options.get_val('alt_ref', units='ft') + alt_ref0 = user_options.get_val('alt_ref0', units='ft') + alt_defect_ref = user_options.get_val('alt_defect_ref', units='ft') + final_alt = user_options.get_val('final_alt', units='ft') + alt_constraint_ref = user_options.get_val('alt_constraint_ref', units='ft') + mass_lower = user_options.get_val('mass_lower', units='lbm') + mass_upper = user_options.get_val('mass_upper', units='lbm') + mass_ref = user_options.get_val('mass_ref', units='lbm') + mass_ref0 = user_options.get_val('mass_ref0', units='lbm') + mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') + distance_lower = user_options.get_val('distance_lower', units='NM') + distance_upper = user_options.get_val('distance_upper', units='NM') + distance_ref = user_options.get_val('distance_ref', units='NM') + distance_ref0 = user_options.get_val('distance_ref0', units='NM') + distance_defect_ref = user_options.get_val('distance_defect_ref', units='NM') + input_speed_type = user_options.get_val('input_speed_type') + EAS_limit = user_options.get_val('EAS_limit', units='kn') + + # Time options + phase.set_time_options( + initial_bounds=time_initial_bounds, + duration_bounds=duration_bounds, + fix_initial=fix_initial, + input_initial=input_initial, + units="s", + duration_ref=duration_ref, + initial_ref=time_initial_ref, + ) + + # Add states + phase.add_state( + Dynamic.Mission.ALTITUDE, + fix_initial=True, + fix_final=False, + lower=alt_lower, + upper=alt_upper, + units="ft", + rate_source=Dynamic.Mission.ALTITUDE_RATE, + targets=Dynamic.Mission.ALTITUDE, + ref=alt_ref, + ref0=alt_ref0, + defect_ref=alt_defect_ref, + ) + + phase.add_state( + Dynamic.Mission.MASS, + fix_initial=fix_initial, + input_initial=input_initial, + fix_final=False, + lower=mass_lower, + upper=mass_upper, + units="lbm", + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, + ref=mass_ref, + ref0=mass_ref0, + defect_ref=mass_defect_ref, + ) + + phase.add_state( + Dynamic.Mission.DISTANCE, + fix_initial=fix_initial, + input_initial=input_initial, + fix_final=False, + lower=distance_lower, + upper=distance_upper, + units="NM", + rate_source="distance_rate", + ref=distance_ref, + ref0=distance_ref0, + defect_ref=distance_defect_ref, + ) + + # Add boundary constraint + phase.add_boundary_constraint( + Dynamic.Mission.ALTITUDE, + loc="final", + equals=final_alt, + units="ft", + ref=alt_constraint_ref) + + # Add parameter if necessary + if input_speed_type == SpeedType.EAS: + phase.add_parameter("EAS", opt=False, units="kn", val=EAS_limit) + + # Add timeseries outputs + phase.add_timeseries_output( + Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") + phase.add_timeseries_output("EAS", output_name="EAS", units="kn") + phase.add_timeseries_output("TAS", output_name="TAS", units="kn") + phase.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, + output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") + phase.add_timeseries_output("alpha", output_name="alpha", units="deg") + phase.add_timeseries_output("theta", output_name="theta", units="deg") + phase.add_timeseries_output("aero.CL", output_name="CL", units="unitless") + phase.add_timeseries_output( + Dynamic.Mission.THRUST_TOTAL, output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") + phase.add_timeseries_output("aero.CD", output_name="CD", units="unitless") + + return phase + + def _extra_ode_init_kwargs(self): + """ + Return extra kwargs required for initializing the ODE. + """ + # TODO: support external_subsystems and meta_data in the base class + return { + 'input_speed_type': self.user_options.get_val('input_speed_type'), + 'mach_cruise': self.user_options.get_val('mach_cruise'), + 'EAS_limit': self.user_options.get_val('EAS_limit', 'kn'), + } + + +# Adding metadata for the DescentPhase +DescentPhase._add_meta_data('fix_initial', val=False) +DescentPhase._add_meta_data('input_initial', val=False) +DescentPhase._add_meta_data('EAS_limit', val=0, units='kn') +DescentPhase._add_meta_data('mach_cruise', val=0) +DescentPhase._add_meta_data('input_speed_type', val=SpeedType.MACH) +DescentPhase._add_meta_data('final_alt', val=0, units='ft') +DescentPhase._add_meta_data('time_initial_bounds', val=(0, 0), units='s') +DescentPhase._add_meta_data('time_initial_ref', val=1, units='s') +DescentPhase._add_meta_data('duration_bounds', val=(0, 0), units='s') +DescentPhase._add_meta_data('duration_ref', val=1, units='s') +DescentPhase._add_meta_data('alt_lower', val=0, units='ft') +DescentPhase._add_meta_data('alt_upper', val=0, units='ft') +DescentPhase._add_meta_data('alt_ref', val=1, units='ft') +DescentPhase._add_meta_data('alt_ref0', val=0, units='ft') +DescentPhase._add_meta_data('alt_defect_ref', val=None, units='ft') +DescentPhase._add_meta_data('alt_constraint_ref', val=None, units='ft') +DescentPhase._add_meta_data('mass_lower', val=0, units='lbm') +DescentPhase._add_meta_data('mass_upper', val=0, units='lbm') +DescentPhase._add_meta_data('mass_ref', val=1, units='lbm') +DescentPhase._add_meta_data('mass_ref0', val=0, units='lbm') +DescentPhase._add_meta_data('mass_defect_ref', val=None, units='lbm') +DescentPhase._add_meta_data('distance_lower', val=0, units='NM') +DescentPhase._add_meta_data('distance_upper', val=0, units='NM') +DescentPhase._add_meta_data('distance_ref', val=1, units='NM') +DescentPhase._add_meta_data('distance_ref0', val=0, units='NM') +DescentPhase._add_meta_data('distance_defect_ref', val=None, units='NM') +DescentPhase._add_meta_data('num_segments', val=None, units='unitless') +DescentPhase._add_meta_data('order', val=None, units='unitless') + +# Adding initial guess metadata +DescentPhase._add_initial_guess_meta_data( + InitialGuessTime(), + desc='initial guess for time options') +DescentPhase._add_initial_guess_meta_data( + InitialGuessState('altitude'), + desc='initial guess for altitude state') +DescentPhase._add_initial_guess_meta_data( + InitialGuessState('mass'), + desc='initial guess for mass state') +DescentPhase._add_initial_guess_meta_data( + InitialGuessState('distance'), + desc='initial guess for distance state') +DescentPhase._add_initial_guess_meta_data( + InitialGuessControl('throttle'), + desc='initial guess for throttle') From c6216fffc8e6be89e4d6178eb78da1dfb88b7bdf Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Wed, 17 Jan 2024 14:45:18 -0500 Subject: [PATCH 087/188] Adding and uncommentingtmate session --- .github/workflows/test_workflow.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 6927d7b51..436b1947c 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -213,8 +213,8 @@ jobs: python run_all.py cd ../.. - # - name: Setup tmate session - # uses: mxschmitt/action-tmate@v3 + - name: Setup tmate session + uses: mxschmitt/action-tmate@v3 - name: Run tests From 2caa2a6cbc3ad8802387e2af3fb62c5eb202be13 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 17 Jan 2024 15:01:06 -0600 Subject: [PATCH 088/188] All gasp phases added --- .../interface/default_phase_info/two_dof.py | 88 +++---- aviary/interface/methods_for_level2.py | 76 +----- .../gasp_based/phases/new_groundroll_phase.py | 183 +++++++++++++++ .../gasp_based/phases/new_rotation_phase.py | 218 ++++++++++++++++++ 4 files changed, 459 insertions(+), 106 deletions(-) create mode 100644 aviary/mission/gasp_based/phases/new_groundroll_phase.py create mode 100644 aviary/mission/gasp_based/phases/new_rotation_phase.py diff --git a/aviary/interface/default_phase_info/two_dof.py b/aviary/interface/default_phase_info/two_dof.py index 9747fa2eb..a4ade5db0 100644 --- a/aviary/interface/default_phase_info/two_dof.py +++ b/aviary/interface/default_phase_info/two_dof.py @@ -21,24 +21,26 @@ phase_info = { 'groundroll': { - 'num_segments': 1, - 'order': 3, - 'connect_initial_mass': False, - 'fix_initial': True, - 'fix_initial_mass': False, - 'duration_ref': (50., 's'), - 'duration_bounds': ((1., 100.), 's'), - 'TAS_lower': (0, 'kn'), - 'TAS_upper': (1000, 'kn'), - 'TAS_ref': (150, 'kn'), - 'mass_lower': (0, 'lbm'), - 'mass_upper': (None, 'lbm'), - 'mass_ref': (150_000, 'lbm'), - 'mass_defect_ref': (150_000, 'lbm'), - 'distance_lower': (0, 'ft'), - 'distance_upper': (10.e3, 'ft'), - 'distance_ref': (3000, 'ft'), - 'distance_defect_ref': (3000, 'ft'), + 'user_options': { + 'num_segments': 1, + 'order': 3, + 'connect_initial_mass': False, + 'fix_initial': True, + 'fix_initial_mass': False, + 'duration_ref': (50., 's'), + 'duration_bounds': ((1., 100.), 's'), + 'TAS_lower': (0, 'kn'), + 'TAS_upper': (1000, 'kn'), + 'TAS_ref': (150, 'kn'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (150_000, 'lbm'), + 'mass_defect_ref': (150_000, 'lbm'), + 'distance_lower': (0, 'ft'), + 'distance_upper': (10.e3, 'ft'), + 'distance_ref': (3000, 'ft'), + 'distance_defect_ref': (3000, 'ft'), + }, 'initial_guesses': { 'times': ([0.0, 40.0], 's'), 'TAS': ([0.066, 143.1], 'kn'), @@ -47,28 +49,30 @@ } }, 'rotation': { - 'num_segments': 1, - 'order': 3, - 'fix_initial': False, - 'duration_bounds': ((1, 100), 's'), - 'duration_ref': (50.0, 's'), - 'TAS_lower': (0, 'kn'), - 'TAS_upper': (1000, 'kn'), - 'TAS_ref': (100, 'kn'), - 'TAS_ref0': (0, 'kn'), - 'mass_lower': (0, 'lbm'), - 'mass_upper': (None, 'lbm'), - 'mass_ref': (150_000, 'lbm'), - 'mass_defect_ref': (150_000, 'lbm'), - 'distance_lower': (0, 'ft'), - 'distance_upper': (10_000, 'ft'), - 'distance_ref': (5000, 'ft'), - 'distance_defect_ref': (5000, 'ft'), - 'angle_lower': (0., 'deg'), - 'angle_upper': (5., 'deg'), - 'angle_ref': (5., 'deg'), - 'angle_defect_ref': (5., 'deg'), - 'normal_ref': (10000, 'lbf'), + 'user_options': { + 'num_segments': 1, + 'order': 3, + 'fix_initial': False, + 'duration_bounds': ((1, 100), 's'), + 'duration_ref': (50.0, 's'), + 'TAS_lower': (0, 'kn'), + 'TAS_upper': (1000, 'kn'), + 'TAS_ref': (100, 'kn'), + 'TAS_ref0': (0, 'kn'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (150_000, 'lbm'), + 'mass_defect_ref': (150_000, 'lbm'), + 'distance_lower': (0, 'ft'), + 'distance_upper': (10_000, 'ft'), + 'distance_ref': (5000, 'ft'), + 'distance_defect_ref': (5000, 'ft'), + 'angle_lower': (0., 'rad'), + 'angle_upper': (5., 'rad'), + 'angle_ref': (5., 'rad'), + 'angle_defect_ref': (5., 'rad'), + 'normal_ref': (10000, 'lbf'), + }, 'initial_guesses': { 'times': ([40.0, 5.0], 's'), 'alpha': ([0.0, 2.5], 'deg'), @@ -101,8 +105,8 @@ 'alt_constraint_eq': (500, 'ft'), 'alt_constraint_ref': (500, 'ft'), 'alt_constraint_ref0': (0, 'ft'), - 'angle_lower': (-10, 'deg'), - 'angle_upper': (20, 'deg'), + 'angle_lower': (-10, 'rad'), + 'angle_upper': (20, 'rad'), 'angle_ref': (57.2958, 'deg'), 'angle_defect_ref': (57.2958, 'deg'), 'pitch_constraint_lower': (0., 'deg'), diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 799237fa3..268df097e 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -27,17 +27,13 @@ UnsteadySolvedODE from aviary.mission.gasp_based.phases.time_integration_traj import FlexibleTraj from aviary.mission.gasp_based.phases.time_integration_phases import SGMCruise -from aviary.mission.gasp_based.phases.accel_phase import get_accel -from aviary.mission.gasp_based.phases.ascent_phase import get_ascent -from aviary.mission.gasp_based.phases.climb_phase import get_climb +from aviary.mission.gasp_based.phases.new_groundroll_phase import GroundrollPhase +from aviary.mission.gasp_based.phases.new_rotation_phase import RotationPhase from aviary.mission.gasp_based.phases.new_climb_phase import ClimbPhase from aviary.mission.gasp_based.phases.new_accel_phase import AccelPhase from aviary.mission.gasp_based.phases.new_ascent_phase import AscentPhase from aviary.mission.gasp_based.phases.new_descent_phase import DescentPhase -from aviary.mission.gasp_based.phases.desc_phase import get_descent -from aviary.mission.gasp_based.phases.groundroll_phase import get_groundroll from aviary.mission.gasp_based.phases.landing_group import LandingSegment -from aviary.mission.gasp_based.phases.rotation_phase import get_rotation from aviary.mission.gasp_based.phases.taxi_group import TaxiSegment from aviary.mission.gasp_based.phases.v_rotate_comp import VRotateComp from aviary.mission.gasp_based.polynomial_fit import PolynomialFit @@ -606,23 +602,8 @@ def _get_2dof_phase(self, phase_name): phase.add_timeseries_output("time", units="s") else: - # Create a dictionary of phase functions - phase_functions = { - 'groundroll': get_groundroll, - 'rotation': get_rotation, - 'ascent': get_ascent, - 'accel': get_accel - } - - # Set the phase function based on the phase name - if 'climb' in phase_name or 'accel' in phase_name or 'ascent' in phase_name or 'desc' in phase_name: - phase_functions[phase_name] = get_climb - num_segments = phase_options['user_options']['num_segments'] - order = phase_options['user_options']['order'] - else: - num_segments = phase_options['num_segments'] - order = phase_options['order'] - + num_segments = phase_options['user_options']['num_segments'] + order = phase_options['user_options']['order'] # Create a Radau transcription scheme object with the specified num_segments and order transcription = dm.Radau( num_segments=num_segments, @@ -630,41 +611,6 @@ def _get_2dof_phase(self, phase_name): compressed=True, solve_segments=False) - # Get the phase function corresponding to the phase name - phase_func = phase_functions.get(phase_name) - - # Calculate the phase by calling the phase function - # with the transcription object and remaining phase options - trimmed_phase_options = {k: v for k, v in phase_options.items( - ) if k not in ['num_segments', 'order', 'initial_guesses', 'external_subsystems']} - - # define expected units for each phase option - expected_units = { - 'alt': 'ft', - 'mass': 'lbm', - 'distance': 'ft', - 'time': 's', - 'duration': 's', - 'initial': 's', - 'EAS': 'kn', - 'TAS': 'kn', - 'angle': 'deg', - 'pitch': 'deg', - 'normal': 'lbf', - 'final_alt': 'ft', - 'required_available_climb_rate': 'ft/min', - } - - if phase_name in ['accel', 'climb1', 'climb2', 'desc1', 'desc2']: - expected_units['distance'] = 'NM' - - # loop through all trimmed_phase_options and call wrapped_convert_units with the correct expected units - for key, value in trimmed_phase_options.items(): - for expected_key, expected_unit in expected_units.items(): - if key.startswith(expected_key): - trimmed_phase_options[key] = wrapped_convert_units( - value, expected_unit) - if 'climb' in phase_name: phase_object = ClimbPhase.from_phase_info( phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) @@ -681,12 +627,14 @@ def _get_2dof_phase(self, phase_name): phase_object = DescentPhase.from_phase_info( phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) phase = phase_object.build_phase(aviary_options=self.aviary_inputs) - - else: - phase = phase_func( - ode_args=self.ode_args, - transcription=transcription, - **trimmed_phase_options) + elif 'groundroll' in phase_name: + phase_object = GroundrollPhase.from_phase_info( + phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) + phase = phase_object.build_phase(aviary_options=self.aviary_inputs) + elif 'rotation' in phase_name: + phase_object = RotationPhase.from_phase_info( + phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) + phase = phase_object.build_phase(aviary_options=self.aviary_inputs) phase.add_control( Dynamic.Mission.THROTTLE, targets=Dynamic.Mission.THROTTLE, units='unitless', diff --git a/aviary/mission/gasp_based/phases/new_groundroll_phase.py b/aviary/mission/gasp_based/phases/new_groundroll_phase.py new file mode 100644 index 000000000..1665c03a2 --- /dev/null +++ b/aviary/mission/gasp_based/phases/new_groundroll_phase.py @@ -0,0 +1,183 @@ +from aviary.mission.flops_based.phases.phase_builder_base import ( + PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.variables import Dynamic +from aviary.mission.gasp_based.ode.groundroll_ode import GroundrollODE +from aviary.variable_info.variable_meta_data import _MetaData + + +class GroundrollPhase(PhaseBuilderBase): + default_name = 'groundroll_phase' + default_ode_class = GroundrollODE + + __slots__ = ('external_subsystems', 'meta_data') + + _meta_data_ = {} + _initial_guesses_meta_data_ = {} + + default_meta_data = _MetaData + + def __init__( + self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, core_subsystems=None, + external_subsystems=None, meta_data=None + ): + super().__init__( + name=name, subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, + core_subsystems=core_subsystems, + ) + + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + + self.meta_data = meta_data + + def build_phase(self, aviary_options: AviaryValues = None): + phase = super().build_phase(aviary_options) + + # Retrieve user options values + user_options = self.user_options + # Add the necessary get_val calls for each parameter, e.g., + fix_initial = user_options.get_val('fix_initial') + fix_initial_mass = user_options.get_val('fix_initial_mass') + connect_initial_mass = user_options.get_val('connect_initial_mass') + duration_bounds = user_options.get_val('duration_bounds', units='s') + duration_ref = user_options.get_val('duration_ref', units='s') + TAS_lower = user_options.get_val('TAS_lower', units='kn') + TAS_upper = user_options.get_val('TAS_upper', units='kn') + TAS_ref = user_options.get_val('TAS_ref', units='kn') + TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') + TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') + mass_lower = user_options.get_val('mass_lower', units='lbm') + mass_upper = user_options.get_val('mass_upper', units='lbm') + mass_ref = user_options.get_val('mass_ref', units='lbm') + mass_ref0 = user_options.get_val('mass_ref0', units='lbm') + mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') + distance_lower = user_options.get_val('distance_lower', units='ft') + distance_upper = user_options.get_val('distance_upper', units='ft') + distance_ref = user_options.get_val('distance_ref', units='ft') + distance_ref0 = user_options.get_val('distance_ref0', units='ft') + distance_defect_ref = user_options.get_val('distance_defect_ref', units='ft') + + # Set time options + phase.set_time_options( + fix_initial=fix_initial, + fix_duration=False, + units="s", + targets="t_curr", + duration_bounds=duration_bounds, + duration_ref=duration_ref, + ) + + # Add states + phase.add_state( + "TAS", + fix_initial=fix_initial, + fix_final=False, + lower=TAS_lower, + upper=TAS_upper, + units="kn", + rate_source="TAS_rate", + ref=TAS_ref, + defect_ref=TAS_defect_ref, + ref0=TAS_ref0, + ) + + phase.add_state( + Dynamic.Mission.MASS, + fix_initial=fix_initial_mass, + input_initial=connect_initial_mass, + fix_final=False, + lower=mass_lower, + upper=mass_upper, + units="lbm", + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + ref=mass_ref, + defect_ref=mass_defect_ref, + ref0=mass_ref0, + ) + + phase.add_state( + Dynamic.Mission.DISTANCE, + fix_initial=fix_initial, + fix_final=False, + lower=distance_lower, + upper=distance_upper, + units="ft", + rate_source="distance_rate", + ref=distance_ref, + defect_ref=distance_defect_ref, + ref0=distance_ref0, + ) + + phase.add_parameter("t_init_gear", units="s", + static_target=True, opt=False, val=100) + phase.add_parameter("t_init_flaps", units="s", + static_target=True, opt=False, val=100) + + # boundary/path constraints + controls + # the final TAS is constrained externally to define the transition to the rotation + # phase + + phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") + + phase.add_timeseries_output("normal_force") + phase.add_timeseries_output(Dynamic.Mission.MACH) + phase.add_timeseries_output("EAS", units="kn") + + phase.add_timeseries_output(Dynamic.Mission.LIFT) + phase.add_timeseries_output("CL") + phase.add_timeseries_output("CD") + phase.add_timeseries_output("fuselage_pitch", output_name="theta", units="deg") + + return phase + + +# Adding metadata for the GroundrollPhase +GroundrollPhase._add_meta_data('fix_initial', val=True) +GroundrollPhase._add_meta_data('fix_initial_mass', val=False) +GroundrollPhase._add_meta_data('connect_initial_mass', val=True) +GroundrollPhase._add_meta_data('duration_bounds', val=(1, 100), units='s') +GroundrollPhase._add_meta_data('duration_ref', val=1, units='s') +GroundrollPhase._add_meta_data('TAS_lower', val=0, units='kn') +GroundrollPhase._add_meta_data('TAS_upper', val=1000, units='kn') +GroundrollPhase._add_meta_data('TAS_ref', val=100, units='kn') +GroundrollPhase._add_meta_data('TAS_ref0', val=0, units='kn') +GroundrollPhase._add_meta_data('TAS_defect_ref', val=None, units='kn') +GroundrollPhase._add_meta_data('mass_lower', val=0, units='lbm') +GroundrollPhase._add_meta_data('mass_upper', val=200_000, units='lbm') +GroundrollPhase._add_meta_data('mass_ref', val=100_000, units='lbm') +GroundrollPhase._add_meta_data('mass_ref0', val=0, units='lbm') +GroundrollPhase._add_meta_data('mass_defect_ref', val=100, units='lbm') +GroundrollPhase._add_meta_data('distance_lower', val=0, units='ft') +GroundrollPhase._add_meta_data('distance_upper', val=4000, units='ft') +GroundrollPhase._add_meta_data('distance_ref', val=3000, units='ft') +GroundrollPhase._add_meta_data('distance_ref0', val=0, units='ft') +GroundrollPhase._add_meta_data('distance_defect_ref', val=3000, units='ft') +GroundrollPhase._add_meta_data('t_init_gear', val=100, units='s') +GroundrollPhase._add_meta_data('t_init_flaps', val=100, units='s') +GroundrollPhase._add_meta_data('num_segments', val=None, units='unitless') +GroundrollPhase._add_meta_data('order', val=None, units='unitless') + +# Adding initial guess metadata +GroundrollPhase._add_initial_guess_meta_data( + InitialGuessTime(), + desc='initial guess for time options') +GroundrollPhase._add_initial_guess_meta_data( + InitialGuessState('TAS'), + desc='initial guess for true airspeed state') +GroundrollPhase._add_initial_guess_meta_data( + InitialGuessState('mass'), + desc='initial guess for mass state') +GroundrollPhase._add_initial_guess_meta_data( + InitialGuessState('distance'), + desc='initial guess for distance state') +GroundrollPhase._add_initial_guess_meta_data( + InitialGuessControl('throttle'), + desc='initial guess for throttle') diff --git a/aviary/mission/gasp_based/phases/new_rotation_phase.py b/aviary/mission/gasp_based/phases/new_rotation_phase.py new file mode 100644 index 000000000..0b65efdb8 --- /dev/null +++ b/aviary/mission/gasp_based/phases/new_rotation_phase.py @@ -0,0 +1,218 @@ +import numpy as np + +from aviary.mission.flops_based.phases.phase_builder_base import ( + PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.variables import Dynamic +from aviary.mission.gasp_based.ode.rotation_ode import RotationODE +from aviary.variable_info.variable_meta_data import _MetaData + + +class RotationPhase(PhaseBuilderBase): + default_name = 'rotation_phase' + default_ode_class = RotationODE + + __slots__ = ('external_subsystems', 'meta_data') + + _meta_data_ = {} + _initial_guesses_meta_data_ = {} + + default_meta_data = _MetaData + + def __init__( + self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, core_subsystems=None, + external_subsystems=None, meta_data=None + ): + super().__init__( + name=name, subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, + core_subsystems=core_subsystems, + ) + + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + + self.meta_data = meta_data + + def build_phase(self, aviary_options: AviaryValues = None): + phase = super().build_phase(aviary_options) + + # Retrieve user options values + user_options = self.user_options + fix_initial = user_options.get_val('fix_initial') + initial_ref = user_options.get_val('initial_ref', units='s') + duration_bounds = user_options.get_val('duration_bounds', units='s') + duration_ref = user_options.get_val('duration_ref', units='s') + angle_lower = user_options.get_val('angle_lower', units='rad') + angle_upper = user_options.get_val('angle_upper', units='rad') + angle_ref = user_options.get_val('angle_ref', units='rad') + angle_ref0 = user_options.get_val('angle_ref0', units='rad') + angle_defect_ref = user_options.get_val('angle_defect_ref', units='rad') + TAS_lower = user_options.get_val('TAS_lower', units='kn') + TAS_upper = user_options.get_val('TAS_upper', units='kn') + TAS_ref = user_options.get_val('TAS_ref', units='kn') + TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') + TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') + mass_lower = user_options.get_val('mass_lower', units='lbm') + mass_upper = user_options.get_val('mass_upper', units='lbm') + mass_ref = user_options.get_val('mass_ref', units='lbm') + mass_ref0 = user_options.get_val('mass_ref0', units='lbm') + mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') + distance_lower = user_options.get_val('distance_lower', units='ft') + distance_upper = user_options.get_val('distance_upper', units='ft') + distance_ref = user_options.get_val('distance_ref', units='ft') + distance_ref0 = user_options.get_val('distance_ref0', units='ft') + distance_defect_ref = user_options.get_val('distance_defect_ref', units='ft') + normal_ref = user_options.get_val('normal_ref', units='lbf') + normal_ref0 = user_options.get_val('normal_ref0', units='lbf') + + # Set time options + phase.set_time_options( + fix_initial=fix_initial, + fix_duration=False, + units="s", + targets="t_curr", + initial_ref=initial_ref, + duration_bounds=duration_bounds, + duration_ref=duration_ref, + ) + + # Add states + phase.add_state( + "alpha", + fix_initial=True, + fix_final=False, + lower=angle_lower, + upper=angle_upper, + units="rad", + rate_source="alpha_rate", + ref=angle_ref, + ref0=angle_ref0, + defect_ref=angle_defect_ref, + ) + + phase.add_state( + "TAS", + fix_initial=fix_initial, + fix_final=False, + lower=TAS_lower, + upper=TAS_upper, + units="kn", + rate_source="TAS_rate", + ref=TAS_ref, + ref0=TAS_ref0, + defect_ref=TAS_defect_ref, + ) + + phase.add_state( + Dynamic.Mission.MASS, + fix_initial=fix_initial, + fix_final=False, + lower=mass_lower, + upper=mass_upper, + units="lbm", + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + ref=mass_ref, + ref0=mass_ref0, + defect_ref=mass_defect_ref, + ) + + phase.add_state( + Dynamic.Mission.DISTANCE, + fix_initial=fix_initial, + fix_final=False, + lower=distance_lower, + upper=distance_upper, + units="ft", + rate_source="distance_rate", + ref=distance_ref, + ref0=distance_ref0, + defect_ref=distance_defect_ref, + ) + + # Add parameters + phase.add_parameter("t_init_gear", units="s", + static_target=True, opt=False, val=100) + phase.add_parameter("t_init_flaps", units="s", + static_target=True, opt=False, val=100) + + # Add boundary constraints + phase.add_boundary_constraint( + "normal_force", + loc="final", + equals=0, + units="lbf", + ref=normal_ref, + ref0=normal_ref0, + ) + + # Add timeseries outputs + phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") + phase.add_timeseries_output("normal_force") + phase.add_timeseries_output(Dynamic.Mission.MACH) + phase.add_timeseries_output("EAS", units="kn") + phase.add_timeseries_output(Dynamic.Mission.LIFT) + phase.add_timeseries_output("CL") + phase.add_timeseries_output("CD") + phase.add_timeseries_output("fuselage_pitch", output_name="theta", units="deg") + + return phase + + +# Adding metadata for the RotationPhase +RotationPhase._add_meta_data('fix_initial', val=False) +RotationPhase._add_meta_data('initial_ref', val=1, units='s') +RotationPhase._add_meta_data('duration_bounds', val=(1, 100), units='s') +RotationPhase._add_meta_data('duration_ref', val=1, units='s') +RotationPhase._add_meta_data('angle_lower', val=0.0, units='rad') # rad +RotationPhase._add_meta_data('angle_upper', val=25 * np.pi / 180, units='rad') # rad +RotationPhase._add_meta_data('angle_ref', val=1, units='rad') +RotationPhase._add_meta_data('angle_ref0', val=0, units='rad') +RotationPhase._add_meta_data('angle_defect_ref', val=0.01, units='rad') +RotationPhase._add_meta_data('TAS_lower', val=0, units='kn') +RotationPhase._add_meta_data('TAS_upper', val=1000, units='kn') +RotationPhase._add_meta_data('TAS_ref', val=100, units='kn') +RotationPhase._add_meta_data('TAS_ref0', val=0, units='kn') +RotationPhase._add_meta_data('TAS_defect_ref', val=None, units='kn') +RotationPhase._add_meta_data('mass_lower', val=0, units='lbm') +RotationPhase._add_meta_data('mass_upper', val=190_000, units='lbm') +RotationPhase._add_meta_data('mass_ref', val=100_000, units='lbm') +RotationPhase._add_meta_data('mass_ref0', val=0, units='lbm') +RotationPhase._add_meta_data('mass_defect_ref', val=None, units='lbm') +RotationPhase._add_meta_data('distance_lower', val=0, units='ft') +RotationPhase._add_meta_data('distance_upper', val=10.e3, units='ft') +RotationPhase._add_meta_data('distance_ref', val=3000, units='ft') +RotationPhase._add_meta_data('distance_ref0', val=0, units='ft') +RotationPhase._add_meta_data('distance_defect_ref', val=3000, units='ft') +RotationPhase._add_meta_data('normal_ref', val=1, units='lbf') +RotationPhase._add_meta_data('normal_ref0', val=0, units='lbf') +RotationPhase._add_meta_data('t_init_gear', val=100, units='s') +RotationPhase._add_meta_data('t_init_flaps', val=100, units='s') +RotationPhase._add_meta_data('num_segments', val=None, units='unitless') +RotationPhase._add_meta_data('order', val=None, units='unitless') + +# Adding initial guess metadata +RotationPhase._add_initial_guess_meta_data( + InitialGuessTime(), + desc='initial guess for time options') +RotationPhase._add_initial_guess_meta_data( + InitialGuessState('alpha'), + desc='initial guess for angle of attack state') +RotationPhase._add_initial_guess_meta_data( + InitialGuessState('TAS'), + desc='initial guess for true airspeed state') +RotationPhase._add_initial_guess_meta_data( + InitialGuessState('mass'), + desc='initial guess for mass state') +RotationPhase._add_initial_guess_meta_data( + InitialGuessState('distance'), + desc='initial guess for distance state') +RotationPhase._add_initial_guess_meta_data( + InitialGuessControl('throttle'), + desc='initial guess for throttle') From 75eedf7c4545381f7e3c6c69a16bbf1340e51364 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 17 Jan 2024 15:10:19 -0600 Subject: [PATCH 089/188] All tests and benches pass --- aviary/interface/default_phase_info/two_dof.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/interface/default_phase_info/two_dof.py b/aviary/interface/default_phase_info/two_dof.py index a4ade5db0..2cec8b98e 100644 --- a/aviary/interface/default_phase_info/two_dof.py +++ b/aviary/interface/default_phase_info/two_dof.py @@ -344,10 +344,10 @@ def phase_info_parameterization(phase_info, aviary_inputs): range_scale = range_cruise / old_range_cruise # Altitude - old_alt_cruise = phase_info['climb2']['final_alt'][0] + old_alt_cruise = phase_info['climb2']['user_options']['final_alt'][0] if alt_cruise != old_alt_cruise: - phase_info['climb2']['final_alt'] = (alt_cruise, 'ft') + phase_info['climb2']['user_options']['final_alt'] = (alt_cruise, 'ft') phase_info['climb2']['initial_guesses']['altitude'] = ([10.e3, alt_cruise], 'ft') phase_info['cruise']['initial_guesses']['altitude'] = (alt_cruise, 'ft') phase_info['desc1']['initial_guesses']['altitude'] = ([alt_cruise, 10.e3], 'ft') From 65c706a669a675a908812b24298dce8d4991df12 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 17 Jan 2024 15:12:17 -0600 Subject: [PATCH 090/188] Renaming all phase files for GASP --- .../mission/gasp_based/phases/accel_phase.py | 306 ++-- .../mission/gasp_based/phases/ascent_phase.py | 447 +++--- .../mission/gasp_based/phases/climb_phase.py | 386 +++-- .../mission/gasp_based/phases/desc_phase.py | 338 +++-- .../gasp_based/phases/groundroll_phase.py | 283 ++-- .../gasp_based/phases/new_accel_phase.py | 208 --- .../gasp_based/phases/new_ascent_phase.py | 288 ---- .../gasp_based/phases/new_climb_phase.py | 255 ---- .../gasp_based/phases/new_descent_phase.py | 213 --- .../gasp_based/phases/new_groundroll_phase.py | 183 --- .../gasp_based/phases/new_rotation_phase.py | 218 --- .../gasp_based/phases/rotation_phase.py | 340 +++-- .../gasp_based/phases/run_phases/__init__.py | 0 .../gasp_based/phases/run_phases/run_accel.py | 96 -- .../phases/run_phases/run_ascent.py | 123 -- .../gasp_based/phases/run_phases/run_climb.py | 277 ---- .../run_phases/run_climb_test_FLOPS_prop.py | 297 ---- .../run_phases/run_conventional_problem.py | 1255 ----------------- .../gasp_based/phases/run_phases/run_desc1.py | 330 ----- .../gasp_based/phases/run_phases/run_desc2.py | 328 ----- .../phases/run_phases/run_groundroll.py | 136 -- .../phases/run_phases/run_rotation.py | 53 - .../phases/run_phases/run_takeoff.py | 196 --- 23 files changed, 1340 insertions(+), 5216 deletions(-) delete mode 100644 aviary/mission/gasp_based/phases/new_accel_phase.py delete mode 100644 aviary/mission/gasp_based/phases/new_ascent_phase.py delete mode 100644 aviary/mission/gasp_based/phases/new_climb_phase.py delete mode 100644 aviary/mission/gasp_based/phases/new_descent_phase.py delete mode 100644 aviary/mission/gasp_based/phases/new_groundroll_phase.py delete mode 100644 aviary/mission/gasp_based/phases/new_rotation_phase.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/__init__.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_accel.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_ascent.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_climb.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_conventional_problem.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_desc1.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_desc2.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_groundroll.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_rotation.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_takeoff.py diff --git a/aviary/mission/gasp_based/phases/accel_phase.py b/aviary/mission/gasp_based/phases/accel_phase.py index ed938768a..bff6bac20 100644 --- a/aviary/mission/gasp_based/phases/accel_phase.py +++ b/aviary/mission/gasp_based/phases/accel_phase.py @@ -1,104 +1,208 @@ -import dymos as dm - -from aviary.mission.gasp_based.ode.accel_ode import AccelODE +from aviary.mission.flops_based.phases.phase_builder_base import ( + PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic +from aviary.mission.gasp_based.ode.accel_ode import AccelODE +from aviary.variable_info.variable_meta_data import _MetaData + + +class AccelPhase(PhaseBuilderBase): + """ + A phase builder for an acceleration phase in a mission simulation. + + This class extends the PhaseBuilderBase class, providing specific implementations for + the acceleration phase of a flight mission. + + Attributes + ---------- + Inherits all attributes from PhaseBuilderBase. + + Methods + ------- + Inherits all methods from PhaseBuilderBase. + Additional method overrides and new methods specific to the acceleration phase are included. + """ + default_name = 'accel_phase' + default_ode_class = AccelODE + + __slots__ = ('external_subsystems', 'meta_data') + + _meta_data_ = {} + _initial_guesses_meta_data_ = {} + + default_meta_data = _MetaData + + def __init__( + self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, core_subsystems=None, + external_subsystems=None, meta_data=None + ): + super().__init__( + name=name, subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, + core_subsystems=core_subsystems, + ) + + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + + self.meta_data = meta_data + + def build_phase(self, aviary_options: AviaryValues = None): + """ + Return a new acceleration phase for analysis using these constraints. + + Parameters + ---------- + aviary_options : AviaryValues + Collection of Aircraft/Mission specific options + + Returns + ------- + dymos.Phase + """ + phase = super().build_phase(aviary_options) + user_options = self.user_options + + # Extracting and setting options + fix_initial = user_options.get_val('fix_initial') + EAS_constraint_eq = user_options.get_val('EAS_constraint_eq', units='kn') + time_initial_bounds = user_options.get_val('time_initial_bounds', units='s') + duration_bounds = user_options.get_val('duration_bounds', units='s') + duration_ref = user_options.get_val('duration_ref', units='s') + TAS_lower = user_options.get_val('TAS_lower', units='kn') + TAS_upper = user_options.get_val('TAS_upper', units='kn') + TAS_ref = user_options.get_val('TAS_ref', units='kn') + TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') + TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') + mass_lower = user_options.get_val('mass_lower', units='lbm') + mass_upper = user_options.get_val('mass_upper', units='lbm') + mass_ref = user_options.get_val('mass_ref', units='lbm') + mass_ref0 = user_options.get_val('mass_ref0', units='lbm') + mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') + distance_lower = user_options.get_val('distance_lower', units='NM') + distance_upper = user_options.get_val('distance_upper', units='NM') + distance_ref = user_options.get_val('distance_ref', units='NM') + distance_ref0 = user_options.get_val('distance_ref0', units='NM') + distance_defect_ref = user_options.get_val('distance_defect_ref', units='NM') + alt = user_options.get_val('alt', units='ft') + + phase.set_time_options( + fix_initial=fix_initial, + initial_bounds=time_initial_bounds, + duration_bounds=duration_bounds, + units="s", + duration_ref=duration_ref, + ) + + # States + phase.add_state( + "TAS", + fix_initial=fix_initial, + fix_final=False, + lower=TAS_lower, + upper=TAS_upper, + units="kn", + rate_source="TAS_rate", + targets="TAS", + ref=TAS_ref, + ref0=TAS_ref0, + defect_ref=TAS_defect_ref, + ) + + phase.add_state( + Dynamic.Mission.MASS, + fix_initial=fix_initial, + fix_final=False, + lower=mass_lower, + upper=mass_upper, + units="lbm", + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, + ref=mass_ref, + ref0=mass_ref0, + defect_ref=mass_defect_ref, + ) + + phase.add_state( + Dynamic.Mission.DISTANCE, + fix_initial=fix_initial, + fix_final=False, + lower=distance_lower, + upper=distance_upper, + units="NM", + rate_source="distance_rate", + ref=distance_ref, + ref0=distance_ref0, + defect_ref=distance_defect_ref, + ) + + # Boundary Constraints + phase.add_boundary_constraint( + "EAS", loc="final", equals=EAS_constraint_eq, units="kn", ref=EAS_constraint_eq + ) + + phase.add_parameter(Dynamic.Mission.ALTITUDE, opt=False, units="ft", val=alt) + + # Timeseries Outputs + phase.add_timeseries_output("EAS", output_name="EAS", units="kn") + phase.add_timeseries_output( + Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") + phase.add_timeseries_output("alpha", output_name="alpha", units="deg") + phase.add_timeseries_output("aero.CL", output_name="CL", units="unitless") + phase.add_timeseries_output( + Dynamic.Mission.THRUST_TOTAL, output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") + phase.add_timeseries_output("aero.CD", output_name="CD", units="unitless") + + return phase + + +# Adding metadata for the AccelPhase +AccelPhase._add_meta_data('fix_initial', val=False) +AccelPhase._add_meta_data('EAS_constraint_eq', val=250, units='kn') +AccelPhase._add_meta_data('time_initial_bounds', val=(0, 0), units='s') +AccelPhase._add_meta_data('duration_bounds', val=(0, 0), units='s') +AccelPhase._add_meta_data('duration_ref', val=1, units='s') +AccelPhase._add_meta_data('TAS_lower', val=0, units='kn') +AccelPhase._add_meta_data('TAS_upper', val=0, units='kn') +AccelPhase._add_meta_data('TAS_ref', val=1, units='kn') +AccelPhase._add_meta_data('TAS_ref0', val=0, units='kn') +AccelPhase._add_meta_data('TAS_defect_ref', val=None, units='kn') +AccelPhase._add_meta_data('mass_lower', val=0, units='lbm') +AccelPhase._add_meta_data('mass_upper', val=0, units='lbm') +AccelPhase._add_meta_data('mass_ref', val=1, units='lbm') +AccelPhase._add_meta_data('mass_ref0', val=0, units='lbm') +AccelPhase._add_meta_data('mass_defect_ref', val=None, units='lbm') +AccelPhase._add_meta_data('distance_lower', val=0, units='NM') +AccelPhase._add_meta_data('distance_upper', val=0, units='NM') +AccelPhase._add_meta_data('distance_ref', val=1, units='NM') +AccelPhase._add_meta_data('distance_ref0', val=0, units='NM') +AccelPhase._add_meta_data('distance_defect_ref', val=None, units='NM') +AccelPhase._add_meta_data('alt', val=500, units='ft') +AccelPhase._add_meta_data('num_segments', val=None, units='unitless') +AccelPhase._add_meta_data('order', val=None, units='unitless') + +AccelPhase._add_initial_guess_meta_data( + InitialGuessTime(), + desc='initial guess for initial time and duration specified as a tuple') + +AccelPhase._add_initial_guess_meta_data( + InitialGuessState('TAS'), + desc='initial guess for true airspeed') + +AccelPhase._add_initial_guess_meta_data( + InitialGuessState('mass'), + desc='initial guess for mass') +AccelPhase._add_initial_guess_meta_data( + InitialGuessState('distance'), + desc='initial guess for horizontal distance traveled') -def get_accel( - ode_args=None, - transcription=None, - fix_initial=False, - alt=500, - EAS_constraint_eq=250, - time_initial_bounds=(0, 0), - duration_bounds=(0, 0), - duration_ref=1, - TAS_lower=0, - TAS_upper=0, - TAS_ref=1, - TAS_ref0=0, - TAS_defect_ref=None, - mass_lower=0, - mass_upper=0, - mass_ref=1, - mass_ref0=0, - mass_defect_ref=None, - distance_lower=0, - distance_upper=0, - distance_ref=1, - distance_ref0=0, - distance_defect_ref=None, -): - accel = dm.Phase( - ode_class=AccelODE, - transcription=transcription, - ode_init_kwargs=ode_args, - ) - - accel.set_time_options( - fix_initial=fix_initial, - initial_bounds=time_initial_bounds, - duration_bounds=duration_bounds, - units="s", - duration_ref=duration_ref, - ) - - accel.add_state( - "TAS", - fix_initial=fix_initial, - fix_final=False, - lower=TAS_lower, - upper=TAS_upper, - units="kn", - rate_source="TAS_rate", - targets="TAS", - ref=TAS_ref, - ref0=TAS_ref0, - defect_ref=TAS_defect_ref, - ) - - accel.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - ref=mass_ref, - ref0=mass_ref0, - defect_ref=mass_defect_ref, - ) - - accel.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="NM", - rate_source="distance_rate", - ref=distance_ref, - ref0=distance_ref0, - defect_ref=distance_defect_ref, - ) - - accel.add_boundary_constraint( - "EAS", loc="final", equals=EAS_constraint_eq, units="kn", ref=EAS_constraint_eq - ) - - accel.add_parameter(Dynamic.Mission.ALTITUDE, opt=False, units="ft", val=alt) - - accel.add_timeseries_output("EAS", output_name="EAS", units="kn") - accel.add_timeseries_output( - Dynamic.Mission.MACH, - output_name=Dynamic.Mission.MACH, - units="unitless") - accel.add_timeseries_output("alpha", output_name="alpha", units="deg") - accel.add_timeseries_output("aero.CL", output_name="CL", units="unitless") - accel.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") - accel.add_timeseries_output("aero.CD", output_name="CD", units="unitless") - - return accel +AccelPhase._add_initial_guess_meta_data( + InitialGuessControl('throttle'), + desc='initial guess for throttle') diff --git a/aviary/mission/gasp_based/phases/ascent_phase.py b/aviary/mission/gasp_based/phases/ascent_phase.py index 6b9ed6747..467fcdb1f 100644 --- a/aviary/mission/gasp_based/phases/ascent_phase.py +++ b/aviary/mission/gasp_based/phases/ascent_phase.py @@ -1,167 +1,288 @@ -import dymos as dm +from aviary.mission.flops_based.phases.phase_builder_base import ( + PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.variables import Dynamic +from aviary.mission.gasp_based.ode.ascent_ode import AscentODE +from aviary.variable_info.variable_meta_data import _MetaData + import numpy as np -from aviary.mission.gasp_based.ode.ascent_ode import AscentODE -from aviary.variable_info.variables import Dynamic +class AscentPhase(PhaseBuilderBase): + default_name = 'ascent_phase' + default_ode_class = AscentODE + + __slots__ = ('external_subsystems', 'meta_data') + + _meta_data_ = {} + _initial_guesses_meta_data_ = {} + + default_meta_data = _MetaData + + def __init__( + self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, core_subsystems=None, + external_subsystems=None, meta_data=None + ): + super().__init__( + name=name, subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, + core_subsystems=core_subsystems, + ) + + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + + self.meta_data = meta_data + + def build_phase(self, aviary_options: AviaryValues = None): + phase = super().build_phase(aviary_options) + + # Retrieve user options values + user_options = self.user_options + angle_lower = user_options.get_val('angle_lower', units='rad') + angle_upper = user_options.get_val('angle_upper', units='rad') + angle_ref = user_options.get_val('angle_ref', units='rad') + angle_ref0 = user_options.get_val('angle_ref0', units='rad') + angle_defect_ref = user_options.get_val('angle_defect_ref', units='rad') + alt_lower = user_options.get_val('alt_lower', units='ft') + alt_upper = user_options.get_val('alt_upper', units='ft') + alt_ref = user_options.get_val('alt_ref', units='ft') + alt_ref0 = user_options.get_val('alt_ref0', units='ft') + alt_defect_ref = user_options.get_val('alt_defect_ref', units='ft') + alt_constraint_eq = user_options.get_val('alt_constraint_eq', units='ft') + alt_constraint_ref = user_options.get_val('alt_constraint_ref', units='ft') + alt_constraint_ref0 = user_options.get_val('alt_constraint_ref0', units='ft') + TAS_lower = user_options.get_val('TAS_lower', units='kn') + TAS_upper = user_options.get_val('TAS_upper', units='kn') + TAS_ref = user_options.get_val('TAS_ref', units='kn') + TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') + TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') + mass_lower = user_options.get_val('mass_lower', units='lbm') + mass_upper = user_options.get_val('mass_upper', units='lbm') + mass_ref = user_options.get_val('mass_ref', units='lbm') + mass_ref0 = user_options.get_val('mass_ref0', units='lbm') + mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') + distance_lower = user_options.get_val('distance_lower', units='ft') + distance_upper = user_options.get_val('distance_upper', units='ft') + distance_ref = user_options.get_val('distance_ref', units='ft') + distance_ref0 = user_options.get_val('distance_ref0', units='ft') + distance_defect_ref = user_options.get_val('distance_defect_ref', units='ft') + pitch_constraint_lower = user_options.get_val( + 'pitch_constraint_lower', units='deg') + pitch_constraint_upper = user_options.get_val( + 'pitch_constraint_upper', units='deg') + pitch_constraint_ref = user_options.get_val('pitch_constraint_ref', units='deg') + alpha_constraint_lower = user_options.get_val( + 'alpha_constraint_lower', units='rad') + alpha_constraint_upper = user_options.get_val( + 'alpha_constraint_upper', units='rad') + alpha_constraint_ref = user_options.get_val('alpha_constraint_ref', units='rad') + + phase.set_time_options( + units="s", + targets="t_curr", + input_initial=True, + input_duration=True, + ) + + phase.add_state( + Dynamic.Mission.FLIGHT_PATH_ANGLE, + fix_initial=True, + fix_final=False, + lower=angle_lower, + upper=angle_upper, + units="rad", + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + ref=angle_ref, + defect_ref=angle_defect_ref, + ref0=angle_ref0, + ) + + phase.add_state( + Dynamic.Mission.ALTITUDE, + fix_initial=True, + fix_final=False, + lower=alt_lower, + upper=alt_upper, + units="ft", + rate_source=Dynamic.Mission.ALTITUDE_RATE, + ref=alt_ref, + defect_ref=alt_defect_ref, + ref0=alt_ref0, + ) + + phase.add_state( + "TAS", + fix_initial=user_options.get_val('fix_initial'), + fix_final=False, + lower=TAS_lower, + upper=TAS_upper, + units="kn", + rate_source="TAS_rate", + ref=TAS_ref, + defect_ref=TAS_defect_ref, + ref0=TAS_ref0, + ) + + phase.add_state( + Dynamic.Mission.MASS, + fix_initial=user_options.get_val('fix_initial'), + fix_final=False, + lower=mass_lower, + upper=mass_upper, + units="lbm", + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + ref=mass_ref, + defect_ref=mass_defect_ref, + ref0=mass_ref0, + ) + + phase.add_state( + Dynamic.Mission.DISTANCE, + fix_initial=user_options.get_val('fix_initial'), + fix_final=False, + lower=distance_lower, + upper=distance_upper, + units="ft", + rate_source="distance_rate", + ref=distance_ref, + defect_ref=distance_defect_ref, + ref0=distance_ref0, + ) + + phase.add_boundary_constraint( + Dynamic.Mission.ALTITUDE, + loc="final", + equals=alt_constraint_eq, + units="ft", + ref=alt_constraint_ref, + ref0=alt_constraint_ref0, + ) + + phase.add_path_constraint( + "load_factor", + upper=1.10, + lower=0.0 + ) + + phase.add_path_constraint( + "fuselage_pitch", + "theta", + lower=pitch_constraint_lower, + upper=pitch_constraint_upper, + units="deg", + ref=pitch_constraint_ref, + ) + + phase.add_control( + "alpha", + val=0, + lower=alpha_constraint_lower, + upper=alpha_constraint_upper, + units="rad", + ref=alpha_constraint_ref, + opt=True, + ) + + phase.add_parameter("t_init_gear", units="s", + static_target=True, opt=False, val=38.25) + + phase.add_parameter("t_init_flaps", units="s", + static_target=True, opt=False, val=48.21) + + phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") + phase.add_timeseries_output("normal_force") + phase.add_timeseries_output(Dynamic.Mission.MACH) + phase.add_timeseries_output("EAS", units="kn") + phase.add_timeseries_output(Dynamic.Mission.LIFT) + phase.add_timeseries_output("CL") + phase.add_timeseries_output("CD") + + return phase + + +# Adding metadata for the AscentPhase +AscentPhase._add_meta_data('fix_initial', val=False) +AscentPhase._add_meta_data('angle_lower', val=-15 * np.pi / 180, units='rad') +AscentPhase._add_meta_data('angle_upper', val=25 * np.pi / 180, units='rad') +AscentPhase._add_meta_data('angle_ref', val=np.deg2rad(1), units='rad') +AscentPhase._add_meta_data('angle_ref0', val=0, units='rad') +AscentPhase._add_meta_data('angle_defect_ref', val=0.01, units='rad') +AscentPhase._add_meta_data('alt_lower', val=0, units='ft') +AscentPhase._add_meta_data('alt_upper', val=700, units='ft') +AscentPhase._add_meta_data('alt_ref', val=100, units='ft') +AscentPhase._add_meta_data('alt_ref0', val=0, units='ft') +AscentPhase._add_meta_data('alt_defect_ref', val=100, units='ft') +AscentPhase._add_meta_data('alt_constraint_eq', val=500, units='ft') +AscentPhase._add_meta_data('alt_constraint_ref', val=100, units='ft') +AscentPhase._add_meta_data('alt_constraint_ref0', val=0, units='ft') +AscentPhase._add_meta_data('TAS_lower', val=0, units='kn') +AscentPhase._add_meta_data('TAS_upper', val=1000, units='kn') +AscentPhase._add_meta_data('TAS_ref', val=1e2, units='kn') +AscentPhase._add_meta_data('TAS_ref0', val=0, units='kn') +AscentPhase._add_meta_data('TAS_defect_ref', val=None, units='kn') +AscentPhase._add_meta_data('mass_lower', val=0, units='lbm') +AscentPhase._add_meta_data('mass_upper', val=190_000, units='lbm') +AscentPhase._add_meta_data('mass_ref', val=100_000, units='lbm') +AscentPhase._add_meta_data('mass_ref0', val=0, units='lbm') +AscentPhase._add_meta_data('mass_defect_ref', val=1e2, units='lbm') +AscentPhase._add_meta_data('distance_lower', val=0, units='ft') +AscentPhase._add_meta_data('distance_upper', val=10.e3, units='ft') +AscentPhase._add_meta_data('distance_ref', val=3000, units='ft') +AscentPhase._add_meta_data('distance_ref0', val=0, units='ft') +AscentPhase._add_meta_data('distance_defect_ref', val=3000, units='ft') +AscentPhase._add_meta_data('pitch_constraint_lower', val=0, units='deg') +AscentPhase._add_meta_data('pitch_constraint_upper', val=15, units='deg') +AscentPhase._add_meta_data('pitch_constraint_ref', val=1, units='deg') +AscentPhase._add_meta_data('alpha_constraint_lower', val=np.deg2rad(-30), units='rad') +AscentPhase._add_meta_data('alpha_constraint_upper', val=np.deg2rad(30), units='rad') +AscentPhase._add_meta_data('alpha_constraint_ref', val=np.deg2rad(5), units='rad') +AscentPhase._add_meta_data('num_segments', val=None, units='unitless') +AscentPhase._add_meta_data('order', val=None, units='unitless') + +# Adding initial guess metadata +AscentPhase._add_initial_guess_meta_data( + InitialGuessTime(), + desc='initial guess for time options') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessState('flight_path_angle'), + desc='initial guess for flight path angle state') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessState('altitude'), + desc='initial guess for altitude state') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessState('TAS'), + desc='initial guess for true airspeed state') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessState('mass'), + desc='initial guess for mass state') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessState('distance'), + desc='initial guess for distance state') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessControl('alpha'), + desc='initial guess for angle of attack control') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessControl('tau_gear'), + desc='when the gear is retracted') + +AscentPhase._add_initial_guess_meta_data( + InitialGuessControl('tau_flaps'), + desc='when the flaps are retracted') -def get_ascent( - ode_args=None, - transcription=None, - fix_initial=False, - angle_lower=-15 * np.pi / 180, - angle_upper=25 * np.pi / 180, - angle_ref=np.deg2rad(1), - angle_ref0=0, - angle_defect_ref=0.01, - alt_lower=0, - alt_upper=700, - alt_ref=100, - alt_ref0=0, - alt_defect_ref=100, - alt_constraint_eq=500, - alt_constraint_ref=100, - alt_constraint_ref0=0, - TAS_lower=0, - TAS_upper=1000, - TAS_ref=1e2, - TAS_ref0=0, - TAS_defect_ref=None, - mass_lower=0, - mass_upper=190_000, - mass_ref=100_000, - mass_ref0=0, - mass_defect_ref=1e2, - distance_lower=0, - distance_upper=10.e3, - distance_ref=3000, - distance_ref0=0, - distance_defect_ref=3000, - pitch_constraint_lower=0, - pitch_constraint_upper=15, - pitch_constraint_ref=1, - alpha_constraint_lower=np.deg2rad(-30), - alpha_constraint_upper=np.deg2rad(30), - alpha_constraint_ref=np.deg2rad(5), -): - phase = dm.Phase( - ode_class=AscentODE, - ode_init_kwargs=ode_args, - transcription=transcription, - ) - - phase.set_time_options( - units="s", - targets="t_curr", - input_initial=True, - input_duration=True, - ) - - phase.add_state( - Dynamic.Mission.FLIGHT_PATH_ANGLE, - fix_initial=True, - fix_final=False, - lower=angle_lower, - upper=angle_upper, - units="rad", - rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, - ref=angle_ref, - defect_ref=angle_defect_ref, - ref0=angle_ref0, - ) - - phase.add_state( - Dynamic.Mission.ALTITUDE, - fix_initial=True, - fix_final=False, - lower=alt_lower, - upper=alt_upper, - units="ft", - rate_source=Dynamic.Mission.ALTITUDE_RATE, - ref=alt_ref, - defect_ref=alt_defect_ref, - ref0=alt_ref0, - ) - - phase.add_state( - "TAS", - fix_initial=fix_initial, - fix_final=False, - lower=TAS_lower, - upper=TAS_upper, - units="kn", - rate_source="TAS_rate", - ref=TAS_ref, - defect_ref=TAS_defect_ref, - ref0=TAS_ref0, - ) - - phase.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - ref=mass_ref, - defect_ref=mass_defect_ref, - ref0=mass_ref0, - ) - - phase.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="ft", - rate_source="distance_rate", - ref=distance_ref, - defect_ref=distance_defect_ref, - ref0=distance_ref0, - ) - - # boundary/path constraints + controls - phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, - loc="final", - equals=alt_constraint_eq, - units="ft", - ref=alt_constraint_ref, - ref0=alt_constraint_ref0, - ) - phase.add_path_constraint("load_factor", upper=1.10, lower=0.0) - phase.add_path_constraint( - "fuselage_pitch", - "theta", - lower=pitch_constraint_lower, - upper=pitch_constraint_upper, - units="deg", - ref=pitch_constraint_ref, - ) - - phase.add_control( - "alpha", - val=0, - lower=alpha_constraint_lower, - upper=alpha_constraint_upper, - units="rad", - ref=alpha_constraint_ref, - opt=True, - ) - phase.add_parameter("t_init_gear", units="s", - static_target=True, opt=False, val=38.25) - phase.add_parameter("t_init_flaps", units="s", - static_target=True, opt=False, val=48.21) - phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") - - phase.add_timeseries_output("normal_force") - phase.add_timeseries_output(Dynamic.Mission.MACH) - phase.add_timeseries_output("EAS", units="kn") - - phase.add_timeseries_output(Dynamic.Mission.LIFT) - phase.add_timeseries_output("CL") - phase.add_timeseries_output("CD") - - return phase +AscentPhase._add_initial_guess_meta_data( + InitialGuessControl('throttle'), + desc='initial guess for throttle') diff --git a/aviary/mission/gasp_based/phases/climb_phase.py b/aviary/mission/gasp_based/phases/climb_phase.py index c4791dbf1..0f517b9a2 100644 --- a/aviary/mission/gasp_based/phases/climb_phase.py +++ b/aviary/mission/gasp_based/phases/climb_phase.py @@ -1,141 +1,255 @@ -import dymos as dm - +from aviary.mission.flops_based.phases.phase_builder_base import ( + PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.variables import Dynamic from aviary.mission.gasp_based.ode.climb_ode import ClimbODE -from aviary.variable_info.variables import Mission, Dynamic -from aviary.interface.default_phase_info.two_dof import default_mission_subsystems - - -def get_climb( - ode_args=None, - transcription=None, - fix_initial=False, - EAS_target=0, - mach_cruise=0, - target_mach=False, - final_alt=0, - required_available_climb_rate=None, - time_initial_bounds=(0, 0), - duration_bounds=(0, 0), - duration_ref=1, - alt_lower=0, - alt_upper=0, - alt_ref=1, - alt_ref0=0, - alt_defect_ref=None, - mass_lower=0, - mass_upper=0, - mass_ref=1, - mass_ref0=0, - mass_defect_ref=None, - distance_lower=0, - distance_upper=0, - distance_ref=1, - distance_ref0=0, - distance_defect_ref=None, -): - - ode_init_kwargs = dict( - EAS_target=EAS_target, - mach_cruise=mach_cruise, - core_subsystems=default_mission_subsystems - ) - if ode_args: - ode_init_kwargs.update(ode_args) - - climb = dm.Phase( - ode_class=ClimbODE, - transcription=transcription, - ode_init_kwargs=ode_init_kwargs, - ) - - climb.set_time_options( - fix_initial=fix_initial, - initial_bounds=time_initial_bounds, - duration_bounds=duration_bounds, - duration_ref=duration_ref, - units="s", - ) - - climb.add_state( - Dynamic.Mission.ALTITUDE, - fix_initial=fix_initial, - fix_final=False, - lower=alt_lower, - upper=alt_upper, - units="ft", - rate_source=Dynamic.Mission.ALTITUDE_RATE, - targets=Dynamic.Mission.ALTITUDE, - ref=alt_ref, - ref0=alt_ref0, - defect_ref=alt_defect_ref, - ) - - climb.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - ref=mass_ref, - ref0=mass_ref0, - defect_ref=mass_defect_ref, - ) - - climb.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="NM", - rate_source="distance_rate", - ref=distance_ref, - ref0=distance_ref0, - defect_ref=distance_defect_ref, - ) - - climb.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, - loc="final", - equals=final_alt, - units="ft", - ref=final_alt) - if required_available_climb_rate: - climb.add_boundary_constraint( - Dynamic.Mission.ALTITUDE_RATE, - loc="final", - lower=required_available_climb_rate, - units="ft/min", - ref=1, +from aviary.variable_info.variable_meta_data import _MetaData + + +class ClimbPhase(PhaseBuilderBase): + """ + A phase builder for a climb phase in a mission simulation. + + This class extends the PhaseBuilderBase class, providing specific implementations for + the climb phase of a flight mission. + + Attributes + ---------- + Inherits all attributes from PhaseBuilderBase. + + Methods + ------- + Inherits all methods from PhaseBuilderBase. + Additional method overrides and new methods specific to the climb phase are included. + """ + default_name = 'climb_phase' + default_ode_class = ClimbODE + + __slots__ = ('external_subsystems', 'meta_data') + + # region : derived type customization points + _meta_data_ = {} + + _initial_guesses_meta_data_ = {} + + default_meta_data = _MetaData + + def __init__( + self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, core_subsystems=None, + external_subsystems=None, meta_data=None + ): + super().__init__( + name=name, subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, + core_subsystems=core_subsystems, + ) + + # TODO: support external_subsystems and meta_data in the base class + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + + self.meta_data = meta_data + + def build_phase(self, aviary_options: AviaryValues = None): + """ + Return a new climb phase for analysis using these constraints. + + If ode_class is None, ClimbODE is used as the default. + + Parameters + ---------- + aviary_options : AviaryValues + Collection of Aircraft/Mission specific options + + Returns + ------- + dymos.Phase + """ + phase = super().build_phase(aviary_options) + + # Custom configurations for the climb phase + user_options = self.user_options + + fix_initial = user_options.get_val('fix_initial') + mach_cruise = user_options.get_val('mach_cruise') + target_mach = user_options.get_val('target_mach') + final_alt = user_options.get_val('final_alt', units='ft') + required_available_climb_rate = user_options.get_val( + 'required_available_climb_rate', units='ft/min') + time_initial_bounds = user_options.get_val('time_initial_bounds', units='s') + duration_bounds = user_options.get_val('duration_bounds', units='s') + duration_ref = user_options.get_val('duration_ref', units='s') + alt_lower = user_options.get_val('alt_lower', units='ft') + alt_upper = user_options.get_val('alt_upper', units='ft') + alt_ref = user_options.get_val('alt_ref', units='ft') + alt_ref0 = user_options.get_val('alt_ref0', units='ft') + alt_defect_ref = user_options.get_val('alt_defect_ref', units='ft') + mass_lower = user_options.get_val('mass_lower', units='lbm') + mass_upper = user_options.get_val('mass_upper', units='lbm') + mass_ref = user_options.get_val('mass_ref', units='lbm') + mass_ref0 = user_options.get_val('mass_ref0', units='lbm') + mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') + distance_lower = user_options.get_val('distance_lower', units='NM') + distance_upper = user_options.get_val('distance_upper', units='NM') + distance_ref = user_options.get_val('distance_ref', units='NM') + distance_ref0 = user_options.get_val('distance_ref0', units='NM') + distance_defect_ref = user_options.get_val('distance_defect_ref', units='NM') + + phase.set_time_options( + fix_initial=fix_initial, + initial_bounds=time_initial_bounds, + duration_bounds=duration_bounds, + duration_ref=duration_ref, + units="s", ) - if target_mach is True: - climb.add_boundary_constraint( - Dynamic.Mission.MACH, loc="final", equals=mach_cruise, units="unitless" + # States + phase.add_state( + Dynamic.Mission.ALTITUDE, + fix_initial=fix_initial, + fix_final=False, + lower=alt_lower, + upper=alt_upper, + units="ft", + rate_source=Dynamic.Mission.ALTITUDE_RATE, + targets=Dynamic.Mission.ALTITUDE, + ref=alt_ref, + ref0=alt_ref0, + defect_ref=alt_defect_ref, ) - climb.add_timeseries_output( - Dynamic.Mission.MACH, - output_name=Dynamic.Mission.MACH, - units="unitless") - climb.add_timeseries_output("EAS", output_name="EAS", units="kn") - climb.add_timeseries_output( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units="lbm/s" - ) - climb.add_timeseries_output("theta", output_name="theta", units="deg") - climb.add_timeseries_output("alpha", output_name="alpha", units="deg") - climb.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, - output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") - climb.add_timeseries_output( - "TAS_violation", output_name="TAS_violation", units="kn" - ) - climb.add_timeseries_output("TAS", output_name="TAS", units="kn") - climb.add_timeseries_output("aero.CL", output_name="CL", units="unitless") - climb.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") - climb.add_timeseries_output("aero.CD", output_name="CD", units="unitless") - - return climb + phase.add_state( + Dynamic.Mission.MASS, + fix_initial=fix_initial, + fix_final=False, + lower=mass_lower, + upper=mass_upper, + units="lbm", + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, + ref=mass_ref, + ref0=mass_ref0, + defect_ref=mass_defect_ref, + ) + + phase.add_state( + Dynamic.Mission.DISTANCE, + fix_initial=fix_initial, + fix_final=False, + lower=distance_lower, + upper=distance_upper, + units="NM", + rate_source="distance_rate", + ref=distance_ref, + ref0=distance_ref0, + defect_ref=distance_defect_ref, + ) + + # Boundary Constraints + phase.add_boundary_constraint( + Dynamic.Mission.ALTITUDE, + loc="final", + equals=final_alt, + units="ft", + ref=final_alt, + ) + + if required_available_climb_rate is not None: + # TODO: this should be altitude rate max + phase.add_boundary_constraint( + Dynamic.Mission.ALTITUDE_RATE, + loc="final", + lower=required_available_climb_rate, + units="ft/min", + ref=1, + ) + + if target_mach: + phase.add_boundary_constraint( + Dynamic.Mission.MACH, loc="final", equals=mach_cruise, + ) + + # Timeseries Outputs + phase.add_timeseries_output( + Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") + phase.add_timeseries_output("EAS", output_name="EAS", units="kn") + phase.add_timeseries_output( + Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units="lbm/s") + phase.add_timeseries_output("theta", output_name="theta", units="deg") + phase.add_timeseries_output("alpha", output_name="alpha", units="deg") + phase.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, + output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") + phase.add_timeseries_output( + "TAS_violation", output_name="TAS_violation", units="kn") + phase.add_timeseries_output("TAS", output_name="TAS", units="kn") + phase.add_timeseries_output("aero.CL", output_name="CL", units="unitless") + phase.add_timeseries_output( + Dynamic.Mission.THRUST_TOTAL, output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") + phase.add_timeseries_output("aero.CD", output_name="CD", units="unitless") + + return phase + + def _extra_ode_init_kwargs(self): + """ + Return extra kwargs required for initializing the ODE. + """ + # TODO: support external_subsystems and meta_data in the base class + return { + 'EAS_target': self.user_options.get_val('EAS_target', units='kn'), + 'mach_cruise': self.user_options.get_val('mach_cruise'), + } + + +# Adding metadata for the ClimbPhase +ClimbPhase._add_meta_data('fix_initial', val=False) +ClimbPhase._add_meta_data('EAS_target', val=0) +ClimbPhase._add_meta_data('mach_cruise', val=0) +ClimbPhase._add_meta_data('target_mach', val=False) +ClimbPhase._add_meta_data('final_alt', val=0) +ClimbPhase._add_meta_data('required_available_climb_rate', val=None, units='ft/min') +ClimbPhase._add_meta_data('time_initial_bounds', val=(0, 0), units='s') +ClimbPhase._add_meta_data('duration_bounds', val=(0, 0), units='s') +ClimbPhase._add_meta_data('duration_ref', val=1, units='s') +ClimbPhase._add_meta_data('alt_lower', val=0, units='ft') +ClimbPhase._add_meta_data('alt_upper', val=0, units='ft') +ClimbPhase._add_meta_data('alt_ref', val=1, units='ft') +ClimbPhase._add_meta_data('alt_ref0', val=0, units='ft') +ClimbPhase._add_meta_data('alt_defect_ref', val=None, units='ft') +ClimbPhase._add_meta_data('mass_lower', val=0, units='lbm') +ClimbPhase._add_meta_data('mass_upper', val=0, units='lbm') +ClimbPhase._add_meta_data('mass_ref', val=1, units='lbm') +ClimbPhase._add_meta_data('mass_ref0', val=0, units='lbm') +ClimbPhase._add_meta_data('mass_defect_ref', val=None, units='lbm') +ClimbPhase._add_meta_data('distance_lower', val=0, units='NM') +ClimbPhase._add_meta_data('distance_upper', val=0, units='NM') +ClimbPhase._add_meta_data('distance_ref', val=1, units='NM') +ClimbPhase._add_meta_data('distance_ref0', val=0, units='NM') +ClimbPhase._add_meta_data('distance_defect_ref', val=None, units='NM') +ClimbPhase._add_meta_data('num_segments', val=None, units='unitless') +ClimbPhase._add_meta_data('order', val=None, units='unitless') + +ClimbPhase._add_initial_guess_meta_data( + InitialGuessTime(), + desc='initial guess for initial time and duration specified as a tuple') + +ClimbPhase._add_initial_guess_meta_data( + InitialGuessState('distance'), + desc='initial guess for horizontal distance traveled') + +ClimbPhase._add_initial_guess_meta_data( + InitialGuessState('altitude'), + desc='initial guess for vertical distances') + +ClimbPhase._add_initial_guess_meta_data( + InitialGuessState('mass'), + desc='initial guess for mass') + +ClimbPhase._add_initial_guess_meta_data( + InitialGuessControl('throttle'), + desc='initial guess for throttle') diff --git a/aviary/mission/gasp_based/phases/desc_phase.py b/aviary/mission/gasp_based/phases/desc_phase.py index 6f2eab9aa..42af7f5bb 100644 --- a/aviary/mission/gasp_based/phases/desc_phase.py +++ b/aviary/mission/gasp_based/phases/desc_phase.py @@ -1,135 +1,213 @@ -import dymos as dm - -from aviary.mission.gasp_based.ode.descent_ode import DescentODE -from aviary.variable_info.enums import SpeedType +from aviary.mission.flops_based.phases.phase_builder_base import ( + PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic +from aviary.variable_info.enums import SpeedType +from aviary.mission.gasp_based.ode.descent_ode import DescentODE +from aviary.variable_info.variable_meta_data import _MetaData + + +class DescentPhase(PhaseBuilderBase): + default_name = 'descent_phase' + default_ode_class = DescentODE + + __slots__ = ('external_subsystems', 'meta_data') + + _meta_data_ = {} + _initial_guesses_meta_data_ = {} + + default_meta_data = _MetaData + + def __init__( + self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, core_subsystems=None, + external_subsystems=None, meta_data=None + ): + super().__init__( + name=name, subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, + core_subsystems=core_subsystems, + ) + + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + self.meta_data = meta_data -def get_descent( - ode_args=None, - transcription=None, - fix_initial=False, - input_initial=False, - EAS_limit=0, - mach_cruise=0, - input_speed_type=SpeedType.MACH, - final_alt=0, - time_initial_bounds=(0, 0), - time_initial_ref=1, - duration_bounds=(0, 0), - duration_ref=1, - alt_lower=0, - alt_upper=0, - alt_ref=1, - alt_ref0=0, - alt_defect_ref=None, - alt_constraint_ref=None, - mass_lower=0, - mass_upper=0, - mass_ref=1, - mass_ref0=0, - mass_defect_ref=None, - distance_lower=0, - distance_upper=0, - distance_ref=1, - distance_ref0=0, - distance_defect_ref=None, -): - ode_init_kwargs = dict( - EAS_limit=EAS_limit, - input_speed_type=input_speed_type, - mach_cruise=mach_cruise, - ) - if ode_args: - ode_init_kwargs.update(ode_args) - - desc = dm.Phase( - ode_class=DescentODE, - transcription=transcription, - ode_init_kwargs=ode_init_kwargs, - ) - - desc.set_time_options( - initial_bounds=time_initial_bounds, - duration_bounds=duration_bounds, - fix_initial=fix_initial, - input_initial=input_initial, - units="s", - duration_ref=duration_ref, - initial_ref=time_initial_ref, - ) - - desc.add_state( - Dynamic.Mission.ALTITUDE, - fix_initial=True, - fix_final=False, - lower=alt_lower, - upper=alt_upper, - units="ft", - rate_source=Dynamic.Mission.ALTITUDE_RATE, - targets=Dynamic.Mission.ALTITUDE, - ref=alt_ref, - ref0=alt_ref0, - defect_ref=alt_defect_ref, - ) - - if fix_initial and input_initial: - raise ValueError( - "ERROR in desc_phase: fix_initial and input_initial are both True" + def build_phase(self, aviary_options: AviaryValues = None): + phase = super().build_phase(aviary_options) + + # Retrieve user options values + user_options = self.user_options + time_initial_bounds = user_options.get_val('time_initial_bounds', units='s') + duration_bounds = user_options.get_val('duration_bounds', units='s') + fix_initial = user_options.get_val('fix_initial') + input_initial = user_options.get_val('input_initial') + duration_ref = user_options.get_val('duration_ref', units='s') + time_initial_ref = user_options.get_val('time_initial_ref', units='s') + alt_lower = user_options.get_val('alt_lower', units='ft') + alt_upper = user_options.get_val('alt_upper', units='ft') + alt_ref = user_options.get_val('alt_ref', units='ft') + alt_ref0 = user_options.get_val('alt_ref0', units='ft') + alt_defect_ref = user_options.get_val('alt_defect_ref', units='ft') + final_alt = user_options.get_val('final_alt', units='ft') + alt_constraint_ref = user_options.get_val('alt_constraint_ref', units='ft') + mass_lower = user_options.get_val('mass_lower', units='lbm') + mass_upper = user_options.get_val('mass_upper', units='lbm') + mass_ref = user_options.get_val('mass_ref', units='lbm') + mass_ref0 = user_options.get_val('mass_ref0', units='lbm') + mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') + distance_lower = user_options.get_val('distance_lower', units='NM') + distance_upper = user_options.get_val('distance_upper', units='NM') + distance_ref = user_options.get_val('distance_ref', units='NM') + distance_ref0 = user_options.get_val('distance_ref0', units='NM') + distance_defect_ref = user_options.get_val('distance_defect_ref', units='NM') + input_speed_type = user_options.get_val('input_speed_type') + EAS_limit = user_options.get_val('EAS_limit', units='kn') + + # Time options + phase.set_time_options( + initial_bounds=time_initial_bounds, + duration_bounds=duration_bounds, + fix_initial=fix_initial, + input_initial=input_initial, + units="s", + duration_ref=duration_ref, + initial_ref=time_initial_ref, + ) + + # Add states + phase.add_state( + Dynamic.Mission.ALTITUDE, + fix_initial=True, + fix_final=False, + lower=alt_lower, + upper=alt_upper, + units="ft", + rate_source=Dynamic.Mission.ALTITUDE_RATE, + targets=Dynamic.Mission.ALTITUDE, + ref=alt_ref, + ref0=alt_ref0, + defect_ref=alt_defect_ref, + ) + + phase.add_state( + Dynamic.Mission.MASS, + fix_initial=fix_initial, + input_initial=input_initial, + fix_final=False, + lower=mass_lower, + upper=mass_upper, + units="lbm", + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, + ref=mass_ref, + ref0=mass_ref0, + defect_ref=mass_defect_ref, + ) + + phase.add_state( + Dynamic.Mission.DISTANCE, + fix_initial=fix_initial, + input_initial=input_initial, + fix_final=False, + lower=distance_lower, + upper=distance_upper, + units="NM", + rate_source="distance_rate", + ref=distance_ref, + ref0=distance_ref0, + defect_ref=distance_defect_ref, ) - desc.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial, - input_initial=input_initial, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - ref=mass_ref, - ref0=mass_ref0, - defect_ref=mass_defect_ref, - ) - - desc.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - input_initial=input_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="NM", - rate_source="distance_rate", - ref=distance_ref, - ref0=distance_ref0, - defect_ref=distance_defect_ref, - ) - - desc.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, - loc="final", - equals=final_alt, - units="ft", - ref=alt_constraint_ref) - - if input_speed_type is SpeedType.EAS: - desc.add_parameter("EAS", opt=False, units="kn", val=EAS_limit) - - desc.add_timeseries_output( - Dynamic.Mission.MACH, - output_name=Dynamic.Mission.MACH, - units="unitless") - desc.add_timeseries_output("EAS", output_name="EAS", units="kn") - desc.add_timeseries_output("TAS", output_name="TAS", units="kn") - desc.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, - output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") - desc.add_timeseries_output("alpha", output_name="alpha", units="deg") - desc.add_timeseries_output("theta", output_name="theta", units="deg") - desc.add_timeseries_output("aero.CL", output_name="CL", units="unitless") - desc.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") - desc.add_timeseries_output("aero.CD", output_name="CD", units="unitless") - - return desc + # Add boundary constraint + phase.add_boundary_constraint( + Dynamic.Mission.ALTITUDE, + loc="final", + equals=final_alt, + units="ft", + ref=alt_constraint_ref) + + # Add parameter if necessary + if input_speed_type == SpeedType.EAS: + phase.add_parameter("EAS", opt=False, units="kn", val=EAS_limit) + + # Add timeseries outputs + phase.add_timeseries_output( + Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") + phase.add_timeseries_output("EAS", output_name="EAS", units="kn") + phase.add_timeseries_output("TAS", output_name="TAS", units="kn") + phase.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, + output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") + phase.add_timeseries_output("alpha", output_name="alpha", units="deg") + phase.add_timeseries_output("theta", output_name="theta", units="deg") + phase.add_timeseries_output("aero.CL", output_name="CL", units="unitless") + phase.add_timeseries_output( + Dynamic.Mission.THRUST_TOTAL, output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") + phase.add_timeseries_output("aero.CD", output_name="CD", units="unitless") + + return phase + + def _extra_ode_init_kwargs(self): + """ + Return extra kwargs required for initializing the ODE. + """ + # TODO: support external_subsystems and meta_data in the base class + return { + 'input_speed_type': self.user_options.get_val('input_speed_type'), + 'mach_cruise': self.user_options.get_val('mach_cruise'), + 'EAS_limit': self.user_options.get_val('EAS_limit', 'kn'), + } + + +# Adding metadata for the DescentPhase +DescentPhase._add_meta_data('fix_initial', val=False) +DescentPhase._add_meta_data('input_initial', val=False) +DescentPhase._add_meta_data('EAS_limit', val=0, units='kn') +DescentPhase._add_meta_data('mach_cruise', val=0) +DescentPhase._add_meta_data('input_speed_type', val=SpeedType.MACH) +DescentPhase._add_meta_data('final_alt', val=0, units='ft') +DescentPhase._add_meta_data('time_initial_bounds', val=(0, 0), units='s') +DescentPhase._add_meta_data('time_initial_ref', val=1, units='s') +DescentPhase._add_meta_data('duration_bounds', val=(0, 0), units='s') +DescentPhase._add_meta_data('duration_ref', val=1, units='s') +DescentPhase._add_meta_data('alt_lower', val=0, units='ft') +DescentPhase._add_meta_data('alt_upper', val=0, units='ft') +DescentPhase._add_meta_data('alt_ref', val=1, units='ft') +DescentPhase._add_meta_data('alt_ref0', val=0, units='ft') +DescentPhase._add_meta_data('alt_defect_ref', val=None, units='ft') +DescentPhase._add_meta_data('alt_constraint_ref', val=None, units='ft') +DescentPhase._add_meta_data('mass_lower', val=0, units='lbm') +DescentPhase._add_meta_data('mass_upper', val=0, units='lbm') +DescentPhase._add_meta_data('mass_ref', val=1, units='lbm') +DescentPhase._add_meta_data('mass_ref0', val=0, units='lbm') +DescentPhase._add_meta_data('mass_defect_ref', val=None, units='lbm') +DescentPhase._add_meta_data('distance_lower', val=0, units='NM') +DescentPhase._add_meta_data('distance_upper', val=0, units='NM') +DescentPhase._add_meta_data('distance_ref', val=1, units='NM') +DescentPhase._add_meta_data('distance_ref0', val=0, units='NM') +DescentPhase._add_meta_data('distance_defect_ref', val=None, units='NM') +DescentPhase._add_meta_data('num_segments', val=None, units='unitless') +DescentPhase._add_meta_data('order', val=None, units='unitless') + +# Adding initial guess metadata +DescentPhase._add_initial_guess_meta_data( + InitialGuessTime(), + desc='initial guess for time options') +DescentPhase._add_initial_guess_meta_data( + InitialGuessState('altitude'), + desc='initial guess for altitude state') +DescentPhase._add_initial_guess_meta_data( + InitialGuessState('mass'), + desc='initial guess for mass state') +DescentPhase._add_initial_guess_meta_data( + InitialGuessState('distance'), + desc='initial guess for distance state') +DescentPhase._add_initial_guess_meta_data( + InitialGuessControl('throttle'), + desc='initial guess for throttle') diff --git a/aviary/mission/gasp_based/phases/groundroll_phase.py b/aviary/mission/gasp_based/phases/groundroll_phase.py index aa5a61df2..1665c03a2 100644 --- a/aviary/mission/gasp_based/phases/groundroll_phase.py +++ b/aviary/mission/gasp_based/phases/groundroll_phase.py @@ -1,106 +1,183 @@ -import dymos as dm - -from aviary.mission.gasp_based.ode.groundroll_ode import GroundrollODE +from aviary.mission.flops_based.phases.phase_builder_base import ( + PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic +from aviary.mission.gasp_based.ode.groundroll_ode import GroundrollODE +from aviary.variable_info.variable_meta_data import _MetaData + + +class GroundrollPhase(PhaseBuilderBase): + default_name = 'groundroll_phase' + default_ode_class = GroundrollODE + + __slots__ = ('external_subsystems', 'meta_data') + + _meta_data_ = {} + _initial_guesses_meta_data_ = {} + + default_meta_data = _MetaData + + def __init__( + self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, core_subsystems=None, + external_subsystems=None, meta_data=None + ): + super().__init__( + name=name, subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, + core_subsystems=core_subsystems, + ) + + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + + self.meta_data = meta_data + + def build_phase(self, aviary_options: AviaryValues = None): + phase = super().build_phase(aviary_options) + + # Retrieve user options values + user_options = self.user_options + # Add the necessary get_val calls for each parameter, e.g., + fix_initial = user_options.get_val('fix_initial') + fix_initial_mass = user_options.get_val('fix_initial_mass') + connect_initial_mass = user_options.get_val('connect_initial_mass') + duration_bounds = user_options.get_val('duration_bounds', units='s') + duration_ref = user_options.get_val('duration_ref', units='s') + TAS_lower = user_options.get_val('TAS_lower', units='kn') + TAS_upper = user_options.get_val('TAS_upper', units='kn') + TAS_ref = user_options.get_val('TAS_ref', units='kn') + TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') + TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') + mass_lower = user_options.get_val('mass_lower', units='lbm') + mass_upper = user_options.get_val('mass_upper', units='lbm') + mass_ref = user_options.get_val('mass_ref', units='lbm') + mass_ref0 = user_options.get_val('mass_ref0', units='lbm') + mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') + distance_lower = user_options.get_val('distance_lower', units='ft') + distance_upper = user_options.get_val('distance_upper', units='ft') + distance_ref = user_options.get_val('distance_ref', units='ft') + distance_ref0 = user_options.get_val('distance_ref0', units='ft') + distance_defect_ref = user_options.get_val('distance_defect_ref', units='ft') + + # Set time options + phase.set_time_options( + fix_initial=fix_initial, + fix_duration=False, + units="s", + targets="t_curr", + duration_bounds=duration_bounds, + duration_ref=duration_ref, + ) + + # Add states + phase.add_state( + "TAS", + fix_initial=fix_initial, + fix_final=False, + lower=TAS_lower, + upper=TAS_upper, + units="kn", + rate_source="TAS_rate", + ref=TAS_ref, + defect_ref=TAS_defect_ref, + ref0=TAS_ref0, + ) + + phase.add_state( + Dynamic.Mission.MASS, + fix_initial=fix_initial_mass, + input_initial=connect_initial_mass, + fix_final=False, + lower=mass_lower, + upper=mass_upper, + units="lbm", + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + ref=mass_ref, + defect_ref=mass_defect_ref, + ref0=mass_ref0, + ) + + phase.add_state( + Dynamic.Mission.DISTANCE, + fix_initial=fix_initial, + fix_final=False, + lower=distance_lower, + upper=distance_upper, + units="ft", + rate_source="distance_rate", + ref=distance_ref, + defect_ref=distance_defect_ref, + ref0=distance_ref0, + ) + + phase.add_parameter("t_init_gear", units="s", + static_target=True, opt=False, val=100) + phase.add_parameter("t_init_flaps", units="s", + static_target=True, opt=False, val=100) + + # boundary/path constraints + controls + # the final TAS is constrained externally to define the transition to the rotation + # phase + + phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") + + phase.add_timeseries_output("normal_force") + phase.add_timeseries_output(Dynamic.Mission.MACH) + phase.add_timeseries_output("EAS", units="kn") + + phase.add_timeseries_output(Dynamic.Mission.LIFT) + phase.add_timeseries_output("CL") + phase.add_timeseries_output("CD") + phase.add_timeseries_output("fuselage_pitch", output_name="theta", units="deg") + + return phase + +# Adding metadata for the GroundrollPhase +GroundrollPhase._add_meta_data('fix_initial', val=True) +GroundrollPhase._add_meta_data('fix_initial_mass', val=False) +GroundrollPhase._add_meta_data('connect_initial_mass', val=True) +GroundrollPhase._add_meta_data('duration_bounds', val=(1, 100), units='s') +GroundrollPhase._add_meta_data('duration_ref', val=1, units='s') +GroundrollPhase._add_meta_data('TAS_lower', val=0, units='kn') +GroundrollPhase._add_meta_data('TAS_upper', val=1000, units='kn') +GroundrollPhase._add_meta_data('TAS_ref', val=100, units='kn') +GroundrollPhase._add_meta_data('TAS_ref0', val=0, units='kn') +GroundrollPhase._add_meta_data('TAS_defect_ref', val=None, units='kn') +GroundrollPhase._add_meta_data('mass_lower', val=0, units='lbm') +GroundrollPhase._add_meta_data('mass_upper', val=200_000, units='lbm') +GroundrollPhase._add_meta_data('mass_ref', val=100_000, units='lbm') +GroundrollPhase._add_meta_data('mass_ref0', val=0, units='lbm') +GroundrollPhase._add_meta_data('mass_defect_ref', val=100, units='lbm') +GroundrollPhase._add_meta_data('distance_lower', val=0, units='ft') +GroundrollPhase._add_meta_data('distance_upper', val=4000, units='ft') +GroundrollPhase._add_meta_data('distance_ref', val=3000, units='ft') +GroundrollPhase._add_meta_data('distance_ref0', val=0, units='ft') +GroundrollPhase._add_meta_data('distance_defect_ref', val=3000, units='ft') +GroundrollPhase._add_meta_data('t_init_gear', val=100, units='s') +GroundrollPhase._add_meta_data('t_init_flaps', val=100, units='s') +GroundrollPhase._add_meta_data('num_segments', val=None, units='unitless') +GroundrollPhase._add_meta_data('order', val=None, units='unitless') -def get_groundroll( - ode_args=None, - transcription=None, - fix_initial=True, - fix_initial_mass=False, - connect_initial_mass=True, - duration_bounds=(1, 100), - duration_ref=1, - TAS_lower=0, - TAS_upper=1000, - TAS_ref=100, - TAS_ref0=0, - TAS_defect_ref=None, - mass_lower=0, - mass_upper=200_000, - mass_ref=100_000, - mass_ref0=0, - mass_defect_ref=100, - distance_lower=0, - distance_upper=4000, - distance_ref=3000, - distance_ref0=0, - distance_defect_ref=3000, -): - phase = dm.Phase( - ode_class=GroundrollODE, - ode_init_kwargs=ode_args, - transcription=transcription, - ) - - phase.set_time_options( - fix_initial=fix_initial, - fix_duration=False, - units="s", - targets="t_curr", - duration_bounds=duration_bounds, - duration_ref=duration_ref, - ) - - phase.add_state( - "TAS", - fix_initial=fix_initial, - fix_final=False, - lower=TAS_lower, - upper=TAS_upper, - units="kn", - rate_source="TAS_rate", - ref=TAS_ref, - defect_ref=TAS_defect_ref, - ref0=TAS_ref0, - ) - - phase.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial_mass, - input_initial=connect_initial_mass, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - ref=mass_ref, - defect_ref=mass_defect_ref, - ref0=mass_ref0, - ) - - phase.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="ft", - rate_source="distance_rate", - ref=distance_ref, - defect_ref=distance_defect_ref, - ref0=distance_ref0, - ) - - phase.add_parameter("t_init_gear", units="s", - static_target=True, opt=False, val=100) - phase.add_parameter("t_init_flaps", units="s", - static_target=True, opt=False, val=100) - - # boundary/path constraints + controls - # the final TAS is constrained externally to define the transition to the rotation - # phase - - phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") - - phase.add_timeseries_output("normal_force") - phase.add_timeseries_output(Dynamic.Mission.MACH) - phase.add_timeseries_output("EAS", units="kn") - - phase.add_timeseries_output(Dynamic.Mission.LIFT) - phase.add_timeseries_output("CL") - phase.add_timeseries_output("CD") - phase.add_timeseries_output("fuselage_pitch", output_name="theta", units="deg") - - return phase +# Adding initial guess metadata +GroundrollPhase._add_initial_guess_meta_data( + InitialGuessTime(), + desc='initial guess for time options') +GroundrollPhase._add_initial_guess_meta_data( + InitialGuessState('TAS'), + desc='initial guess for true airspeed state') +GroundrollPhase._add_initial_guess_meta_data( + InitialGuessState('mass'), + desc='initial guess for mass state') +GroundrollPhase._add_initial_guess_meta_data( + InitialGuessState('distance'), + desc='initial guess for distance state') +GroundrollPhase._add_initial_guess_meta_data( + InitialGuessControl('throttle'), + desc='initial guess for throttle') diff --git a/aviary/mission/gasp_based/phases/new_accel_phase.py b/aviary/mission/gasp_based/phases/new_accel_phase.py deleted file mode 100644 index bff6bac20..000000000 --- a/aviary/mission/gasp_based/phases/new_accel_phase.py +++ /dev/null @@ -1,208 +0,0 @@ -from aviary.mission.flops_based.phases.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.variables import Dynamic -from aviary.mission.gasp_based.ode.accel_ode import AccelODE -from aviary.variable_info.variable_meta_data import _MetaData - - -class AccelPhase(PhaseBuilderBase): - """ - A phase builder for an acceleration phase in a mission simulation. - - This class extends the PhaseBuilderBase class, providing specific implementations for - the acceleration phase of a flight mission. - - Attributes - ---------- - Inherits all attributes from PhaseBuilderBase. - - Methods - ------- - Inherits all methods from PhaseBuilderBase. - Additional method overrides and new methods specific to the acceleration phase are included. - """ - default_name = 'accel_phase' - default_ode_class = AccelODE - - __slots__ = ('external_subsystems', 'meta_data') - - _meta_data_ = {} - _initial_guesses_meta_data_ = {} - - default_meta_data = _MetaData - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, subsystem_options=subsystem_options, user_options=user_options, - initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, - core_subsystems=core_subsystems, - ) - - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - - def build_phase(self, aviary_options: AviaryValues = None): - """ - Return a new acceleration phase for analysis using these constraints. - - Parameters - ---------- - aviary_options : AviaryValues - Collection of Aircraft/Mission specific options - - Returns - ------- - dymos.Phase - """ - phase = super().build_phase(aviary_options) - user_options = self.user_options - - # Extracting and setting options - fix_initial = user_options.get_val('fix_initial') - EAS_constraint_eq = user_options.get_val('EAS_constraint_eq', units='kn') - time_initial_bounds = user_options.get_val('time_initial_bounds', units='s') - duration_bounds = user_options.get_val('duration_bounds', units='s') - duration_ref = user_options.get_val('duration_ref', units='s') - TAS_lower = user_options.get_val('TAS_lower', units='kn') - TAS_upper = user_options.get_val('TAS_upper', units='kn') - TAS_ref = user_options.get_val('TAS_ref', units='kn') - TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') - TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') - mass_lower = user_options.get_val('mass_lower', units='lbm') - mass_upper = user_options.get_val('mass_upper', units='lbm') - mass_ref = user_options.get_val('mass_ref', units='lbm') - mass_ref0 = user_options.get_val('mass_ref0', units='lbm') - mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') - distance_lower = user_options.get_val('distance_lower', units='NM') - distance_upper = user_options.get_val('distance_upper', units='NM') - distance_ref = user_options.get_val('distance_ref', units='NM') - distance_ref0 = user_options.get_val('distance_ref0', units='NM') - distance_defect_ref = user_options.get_val('distance_defect_ref', units='NM') - alt = user_options.get_val('alt', units='ft') - - phase.set_time_options( - fix_initial=fix_initial, - initial_bounds=time_initial_bounds, - duration_bounds=duration_bounds, - units="s", - duration_ref=duration_ref, - ) - - # States - phase.add_state( - "TAS", - fix_initial=fix_initial, - fix_final=False, - lower=TAS_lower, - upper=TAS_upper, - units="kn", - rate_source="TAS_rate", - targets="TAS", - ref=TAS_ref, - ref0=TAS_ref0, - defect_ref=TAS_defect_ref, - ) - - phase.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - ref=mass_ref, - ref0=mass_ref0, - defect_ref=mass_defect_ref, - ) - - phase.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="NM", - rate_source="distance_rate", - ref=distance_ref, - ref0=distance_ref0, - defect_ref=distance_defect_ref, - ) - - # Boundary Constraints - phase.add_boundary_constraint( - "EAS", loc="final", equals=EAS_constraint_eq, units="kn", ref=EAS_constraint_eq - ) - - phase.add_parameter(Dynamic.Mission.ALTITUDE, opt=False, units="ft", val=alt) - - # Timeseries Outputs - phase.add_timeseries_output("EAS", output_name="EAS", units="kn") - phase.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") - phase.add_timeseries_output("alpha", output_name="alpha", units="deg") - phase.add_timeseries_output("aero.CL", output_name="CL", units="unitless") - phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") - phase.add_timeseries_output("aero.CD", output_name="CD", units="unitless") - - return phase - - -# Adding metadata for the AccelPhase -AccelPhase._add_meta_data('fix_initial', val=False) -AccelPhase._add_meta_data('EAS_constraint_eq', val=250, units='kn') -AccelPhase._add_meta_data('time_initial_bounds', val=(0, 0), units='s') -AccelPhase._add_meta_data('duration_bounds', val=(0, 0), units='s') -AccelPhase._add_meta_data('duration_ref', val=1, units='s') -AccelPhase._add_meta_data('TAS_lower', val=0, units='kn') -AccelPhase._add_meta_data('TAS_upper', val=0, units='kn') -AccelPhase._add_meta_data('TAS_ref', val=1, units='kn') -AccelPhase._add_meta_data('TAS_ref0', val=0, units='kn') -AccelPhase._add_meta_data('TAS_defect_ref', val=None, units='kn') -AccelPhase._add_meta_data('mass_lower', val=0, units='lbm') -AccelPhase._add_meta_data('mass_upper', val=0, units='lbm') -AccelPhase._add_meta_data('mass_ref', val=1, units='lbm') -AccelPhase._add_meta_data('mass_ref0', val=0, units='lbm') -AccelPhase._add_meta_data('mass_defect_ref', val=None, units='lbm') -AccelPhase._add_meta_data('distance_lower', val=0, units='NM') -AccelPhase._add_meta_data('distance_upper', val=0, units='NM') -AccelPhase._add_meta_data('distance_ref', val=1, units='NM') -AccelPhase._add_meta_data('distance_ref0', val=0, units='NM') -AccelPhase._add_meta_data('distance_defect_ref', val=None, units='NM') -AccelPhase._add_meta_data('alt', val=500, units='ft') -AccelPhase._add_meta_data('num_segments', val=None, units='unitless') -AccelPhase._add_meta_data('order', val=None, units='unitless') - -AccelPhase._add_initial_guess_meta_data( - InitialGuessTime(), - desc='initial guess for initial time and duration specified as a tuple') - -AccelPhase._add_initial_guess_meta_data( - InitialGuessState('TAS'), - desc='initial guess for true airspeed') - -AccelPhase._add_initial_guess_meta_data( - InitialGuessState('mass'), - desc='initial guess for mass') - -AccelPhase._add_initial_guess_meta_data( - InitialGuessState('distance'), - desc='initial guess for horizontal distance traveled') - -AccelPhase._add_initial_guess_meta_data( - InitialGuessControl('throttle'), - desc='initial guess for throttle') diff --git a/aviary/mission/gasp_based/phases/new_ascent_phase.py b/aviary/mission/gasp_based/phases/new_ascent_phase.py deleted file mode 100644 index 467fcdb1f..000000000 --- a/aviary/mission/gasp_based/phases/new_ascent_phase.py +++ /dev/null @@ -1,288 +0,0 @@ -from aviary.mission.flops_based.phases.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.variables import Dynamic -from aviary.mission.gasp_based.ode.ascent_ode import AscentODE -from aviary.variable_info.variable_meta_data import _MetaData - -import numpy as np - - -class AscentPhase(PhaseBuilderBase): - default_name = 'ascent_phase' - default_ode_class = AscentODE - - __slots__ = ('external_subsystems', 'meta_data') - - _meta_data_ = {} - _initial_guesses_meta_data_ = {} - - default_meta_data = _MetaData - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, subsystem_options=subsystem_options, user_options=user_options, - initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, - core_subsystems=core_subsystems, - ) - - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - - def build_phase(self, aviary_options: AviaryValues = None): - phase = super().build_phase(aviary_options) - - # Retrieve user options values - user_options = self.user_options - angle_lower = user_options.get_val('angle_lower', units='rad') - angle_upper = user_options.get_val('angle_upper', units='rad') - angle_ref = user_options.get_val('angle_ref', units='rad') - angle_ref0 = user_options.get_val('angle_ref0', units='rad') - angle_defect_ref = user_options.get_val('angle_defect_ref', units='rad') - alt_lower = user_options.get_val('alt_lower', units='ft') - alt_upper = user_options.get_val('alt_upper', units='ft') - alt_ref = user_options.get_val('alt_ref', units='ft') - alt_ref0 = user_options.get_val('alt_ref0', units='ft') - alt_defect_ref = user_options.get_val('alt_defect_ref', units='ft') - alt_constraint_eq = user_options.get_val('alt_constraint_eq', units='ft') - alt_constraint_ref = user_options.get_val('alt_constraint_ref', units='ft') - alt_constraint_ref0 = user_options.get_val('alt_constraint_ref0', units='ft') - TAS_lower = user_options.get_val('TAS_lower', units='kn') - TAS_upper = user_options.get_val('TAS_upper', units='kn') - TAS_ref = user_options.get_val('TAS_ref', units='kn') - TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') - TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') - mass_lower = user_options.get_val('mass_lower', units='lbm') - mass_upper = user_options.get_val('mass_upper', units='lbm') - mass_ref = user_options.get_val('mass_ref', units='lbm') - mass_ref0 = user_options.get_val('mass_ref0', units='lbm') - mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') - distance_lower = user_options.get_val('distance_lower', units='ft') - distance_upper = user_options.get_val('distance_upper', units='ft') - distance_ref = user_options.get_val('distance_ref', units='ft') - distance_ref0 = user_options.get_val('distance_ref0', units='ft') - distance_defect_ref = user_options.get_val('distance_defect_ref', units='ft') - pitch_constraint_lower = user_options.get_val( - 'pitch_constraint_lower', units='deg') - pitch_constraint_upper = user_options.get_val( - 'pitch_constraint_upper', units='deg') - pitch_constraint_ref = user_options.get_val('pitch_constraint_ref', units='deg') - alpha_constraint_lower = user_options.get_val( - 'alpha_constraint_lower', units='rad') - alpha_constraint_upper = user_options.get_val( - 'alpha_constraint_upper', units='rad') - alpha_constraint_ref = user_options.get_val('alpha_constraint_ref', units='rad') - - phase.set_time_options( - units="s", - targets="t_curr", - input_initial=True, - input_duration=True, - ) - - phase.add_state( - Dynamic.Mission.FLIGHT_PATH_ANGLE, - fix_initial=True, - fix_final=False, - lower=angle_lower, - upper=angle_upper, - units="rad", - rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, - ref=angle_ref, - defect_ref=angle_defect_ref, - ref0=angle_ref0, - ) - - phase.add_state( - Dynamic.Mission.ALTITUDE, - fix_initial=True, - fix_final=False, - lower=alt_lower, - upper=alt_upper, - units="ft", - rate_source=Dynamic.Mission.ALTITUDE_RATE, - ref=alt_ref, - defect_ref=alt_defect_ref, - ref0=alt_ref0, - ) - - phase.add_state( - "TAS", - fix_initial=user_options.get_val('fix_initial'), - fix_final=False, - lower=TAS_lower, - upper=TAS_upper, - units="kn", - rate_source="TAS_rate", - ref=TAS_ref, - defect_ref=TAS_defect_ref, - ref0=TAS_ref0, - ) - - phase.add_state( - Dynamic.Mission.MASS, - fix_initial=user_options.get_val('fix_initial'), - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - ref=mass_ref, - defect_ref=mass_defect_ref, - ref0=mass_ref0, - ) - - phase.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=user_options.get_val('fix_initial'), - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="ft", - rate_source="distance_rate", - ref=distance_ref, - defect_ref=distance_defect_ref, - ref0=distance_ref0, - ) - - phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, - loc="final", - equals=alt_constraint_eq, - units="ft", - ref=alt_constraint_ref, - ref0=alt_constraint_ref0, - ) - - phase.add_path_constraint( - "load_factor", - upper=1.10, - lower=0.0 - ) - - phase.add_path_constraint( - "fuselage_pitch", - "theta", - lower=pitch_constraint_lower, - upper=pitch_constraint_upper, - units="deg", - ref=pitch_constraint_ref, - ) - - phase.add_control( - "alpha", - val=0, - lower=alpha_constraint_lower, - upper=alpha_constraint_upper, - units="rad", - ref=alpha_constraint_ref, - opt=True, - ) - - phase.add_parameter("t_init_gear", units="s", - static_target=True, opt=False, val=38.25) - - phase.add_parameter("t_init_flaps", units="s", - static_target=True, opt=False, val=48.21) - - phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") - phase.add_timeseries_output("normal_force") - phase.add_timeseries_output(Dynamic.Mission.MACH) - phase.add_timeseries_output("EAS", units="kn") - phase.add_timeseries_output(Dynamic.Mission.LIFT) - phase.add_timeseries_output("CL") - phase.add_timeseries_output("CD") - - return phase - - -# Adding metadata for the AscentPhase -AscentPhase._add_meta_data('fix_initial', val=False) -AscentPhase._add_meta_data('angle_lower', val=-15 * np.pi / 180, units='rad') -AscentPhase._add_meta_data('angle_upper', val=25 * np.pi / 180, units='rad') -AscentPhase._add_meta_data('angle_ref', val=np.deg2rad(1), units='rad') -AscentPhase._add_meta_data('angle_ref0', val=0, units='rad') -AscentPhase._add_meta_data('angle_defect_ref', val=0.01, units='rad') -AscentPhase._add_meta_data('alt_lower', val=0, units='ft') -AscentPhase._add_meta_data('alt_upper', val=700, units='ft') -AscentPhase._add_meta_data('alt_ref', val=100, units='ft') -AscentPhase._add_meta_data('alt_ref0', val=0, units='ft') -AscentPhase._add_meta_data('alt_defect_ref', val=100, units='ft') -AscentPhase._add_meta_data('alt_constraint_eq', val=500, units='ft') -AscentPhase._add_meta_data('alt_constraint_ref', val=100, units='ft') -AscentPhase._add_meta_data('alt_constraint_ref0', val=0, units='ft') -AscentPhase._add_meta_data('TAS_lower', val=0, units='kn') -AscentPhase._add_meta_data('TAS_upper', val=1000, units='kn') -AscentPhase._add_meta_data('TAS_ref', val=1e2, units='kn') -AscentPhase._add_meta_data('TAS_ref0', val=0, units='kn') -AscentPhase._add_meta_data('TAS_defect_ref', val=None, units='kn') -AscentPhase._add_meta_data('mass_lower', val=0, units='lbm') -AscentPhase._add_meta_data('mass_upper', val=190_000, units='lbm') -AscentPhase._add_meta_data('mass_ref', val=100_000, units='lbm') -AscentPhase._add_meta_data('mass_ref0', val=0, units='lbm') -AscentPhase._add_meta_data('mass_defect_ref', val=1e2, units='lbm') -AscentPhase._add_meta_data('distance_lower', val=0, units='ft') -AscentPhase._add_meta_data('distance_upper', val=10.e3, units='ft') -AscentPhase._add_meta_data('distance_ref', val=3000, units='ft') -AscentPhase._add_meta_data('distance_ref0', val=0, units='ft') -AscentPhase._add_meta_data('distance_defect_ref', val=3000, units='ft') -AscentPhase._add_meta_data('pitch_constraint_lower', val=0, units='deg') -AscentPhase._add_meta_data('pitch_constraint_upper', val=15, units='deg') -AscentPhase._add_meta_data('pitch_constraint_ref', val=1, units='deg') -AscentPhase._add_meta_data('alpha_constraint_lower', val=np.deg2rad(-30), units='rad') -AscentPhase._add_meta_data('alpha_constraint_upper', val=np.deg2rad(30), units='rad') -AscentPhase._add_meta_data('alpha_constraint_ref', val=np.deg2rad(5), units='rad') -AscentPhase._add_meta_data('num_segments', val=None, units='unitless') -AscentPhase._add_meta_data('order', val=None, units='unitless') - -# Adding initial guess metadata -AscentPhase._add_initial_guess_meta_data( - InitialGuessTime(), - desc='initial guess for time options') - -AscentPhase._add_initial_guess_meta_data( - InitialGuessState('flight_path_angle'), - desc='initial guess for flight path angle state') - -AscentPhase._add_initial_guess_meta_data( - InitialGuessState('altitude'), - desc='initial guess for altitude state') - -AscentPhase._add_initial_guess_meta_data( - InitialGuessState('TAS'), - desc='initial guess for true airspeed state') - -AscentPhase._add_initial_guess_meta_data( - InitialGuessState('mass'), - desc='initial guess for mass state') - -AscentPhase._add_initial_guess_meta_data( - InitialGuessState('distance'), - desc='initial guess for distance state') - -AscentPhase._add_initial_guess_meta_data( - InitialGuessControl('alpha'), - desc='initial guess for angle of attack control') - -AscentPhase._add_initial_guess_meta_data( - InitialGuessControl('tau_gear'), - desc='when the gear is retracted') - -AscentPhase._add_initial_guess_meta_data( - InitialGuessControl('tau_flaps'), - desc='when the flaps are retracted') - -AscentPhase._add_initial_guess_meta_data( - InitialGuessControl('throttle'), - desc='initial guess for throttle') diff --git a/aviary/mission/gasp_based/phases/new_climb_phase.py b/aviary/mission/gasp_based/phases/new_climb_phase.py deleted file mode 100644 index 0f517b9a2..000000000 --- a/aviary/mission/gasp_based/phases/new_climb_phase.py +++ /dev/null @@ -1,255 +0,0 @@ -from aviary.mission.flops_based.phases.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.variables import Dynamic -from aviary.mission.gasp_based.ode.climb_ode import ClimbODE -from aviary.variable_info.variable_meta_data import _MetaData - - -class ClimbPhase(PhaseBuilderBase): - """ - A phase builder for a climb phase in a mission simulation. - - This class extends the PhaseBuilderBase class, providing specific implementations for - the climb phase of a flight mission. - - Attributes - ---------- - Inherits all attributes from PhaseBuilderBase. - - Methods - ------- - Inherits all methods from PhaseBuilderBase. - Additional method overrides and new methods specific to the climb phase are included. - """ - default_name = 'climb_phase' - default_ode_class = ClimbODE - - __slots__ = ('external_subsystems', 'meta_data') - - # region : derived type customization points - _meta_data_ = {} - - _initial_guesses_meta_data_ = {} - - default_meta_data = _MetaData - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, subsystem_options=subsystem_options, user_options=user_options, - initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, - core_subsystems=core_subsystems, - ) - - # TODO: support external_subsystems and meta_data in the base class - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - - def build_phase(self, aviary_options: AviaryValues = None): - """ - Return a new climb phase for analysis using these constraints. - - If ode_class is None, ClimbODE is used as the default. - - Parameters - ---------- - aviary_options : AviaryValues - Collection of Aircraft/Mission specific options - - Returns - ------- - dymos.Phase - """ - phase = super().build_phase(aviary_options) - - # Custom configurations for the climb phase - user_options = self.user_options - - fix_initial = user_options.get_val('fix_initial') - mach_cruise = user_options.get_val('mach_cruise') - target_mach = user_options.get_val('target_mach') - final_alt = user_options.get_val('final_alt', units='ft') - required_available_climb_rate = user_options.get_val( - 'required_available_climb_rate', units='ft/min') - time_initial_bounds = user_options.get_val('time_initial_bounds', units='s') - duration_bounds = user_options.get_val('duration_bounds', units='s') - duration_ref = user_options.get_val('duration_ref', units='s') - alt_lower = user_options.get_val('alt_lower', units='ft') - alt_upper = user_options.get_val('alt_upper', units='ft') - alt_ref = user_options.get_val('alt_ref', units='ft') - alt_ref0 = user_options.get_val('alt_ref0', units='ft') - alt_defect_ref = user_options.get_val('alt_defect_ref', units='ft') - mass_lower = user_options.get_val('mass_lower', units='lbm') - mass_upper = user_options.get_val('mass_upper', units='lbm') - mass_ref = user_options.get_val('mass_ref', units='lbm') - mass_ref0 = user_options.get_val('mass_ref0', units='lbm') - mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') - distance_lower = user_options.get_val('distance_lower', units='NM') - distance_upper = user_options.get_val('distance_upper', units='NM') - distance_ref = user_options.get_val('distance_ref', units='NM') - distance_ref0 = user_options.get_val('distance_ref0', units='NM') - distance_defect_ref = user_options.get_val('distance_defect_ref', units='NM') - - phase.set_time_options( - fix_initial=fix_initial, - initial_bounds=time_initial_bounds, - duration_bounds=duration_bounds, - duration_ref=duration_ref, - units="s", - ) - - # States - phase.add_state( - Dynamic.Mission.ALTITUDE, - fix_initial=fix_initial, - fix_final=False, - lower=alt_lower, - upper=alt_upper, - units="ft", - rate_source=Dynamic.Mission.ALTITUDE_RATE, - targets=Dynamic.Mission.ALTITUDE, - ref=alt_ref, - ref0=alt_ref0, - defect_ref=alt_defect_ref, - ) - - phase.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - ref=mass_ref, - ref0=mass_ref0, - defect_ref=mass_defect_ref, - ) - - phase.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="NM", - rate_source="distance_rate", - ref=distance_ref, - ref0=distance_ref0, - defect_ref=distance_defect_ref, - ) - - # Boundary Constraints - phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, - loc="final", - equals=final_alt, - units="ft", - ref=final_alt, - ) - - if required_available_climb_rate is not None: - # TODO: this should be altitude rate max - phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE_RATE, - loc="final", - lower=required_available_climb_rate, - units="ft/min", - ref=1, - ) - - if target_mach: - phase.add_boundary_constraint( - Dynamic.Mission.MACH, loc="final", equals=mach_cruise, - ) - - # Timeseries Outputs - phase.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") - phase.add_timeseries_output("EAS", output_name="EAS", units="kn") - phase.add_timeseries_output( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units="lbm/s") - phase.add_timeseries_output("theta", output_name="theta", units="deg") - phase.add_timeseries_output("alpha", output_name="alpha", units="deg") - phase.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, - output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") - phase.add_timeseries_output( - "TAS_violation", output_name="TAS_violation", units="kn") - phase.add_timeseries_output("TAS", output_name="TAS", units="kn") - phase.add_timeseries_output("aero.CL", output_name="CL", units="unitless") - phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") - phase.add_timeseries_output("aero.CD", output_name="CD", units="unitless") - - return phase - - def _extra_ode_init_kwargs(self): - """ - Return extra kwargs required for initializing the ODE. - """ - # TODO: support external_subsystems and meta_data in the base class - return { - 'EAS_target': self.user_options.get_val('EAS_target', units='kn'), - 'mach_cruise': self.user_options.get_val('mach_cruise'), - } - - -# Adding metadata for the ClimbPhase -ClimbPhase._add_meta_data('fix_initial', val=False) -ClimbPhase._add_meta_data('EAS_target', val=0) -ClimbPhase._add_meta_data('mach_cruise', val=0) -ClimbPhase._add_meta_data('target_mach', val=False) -ClimbPhase._add_meta_data('final_alt', val=0) -ClimbPhase._add_meta_data('required_available_climb_rate', val=None, units='ft/min') -ClimbPhase._add_meta_data('time_initial_bounds', val=(0, 0), units='s') -ClimbPhase._add_meta_data('duration_bounds', val=(0, 0), units='s') -ClimbPhase._add_meta_data('duration_ref', val=1, units='s') -ClimbPhase._add_meta_data('alt_lower', val=0, units='ft') -ClimbPhase._add_meta_data('alt_upper', val=0, units='ft') -ClimbPhase._add_meta_data('alt_ref', val=1, units='ft') -ClimbPhase._add_meta_data('alt_ref0', val=0, units='ft') -ClimbPhase._add_meta_data('alt_defect_ref', val=None, units='ft') -ClimbPhase._add_meta_data('mass_lower', val=0, units='lbm') -ClimbPhase._add_meta_data('mass_upper', val=0, units='lbm') -ClimbPhase._add_meta_data('mass_ref', val=1, units='lbm') -ClimbPhase._add_meta_data('mass_ref0', val=0, units='lbm') -ClimbPhase._add_meta_data('mass_defect_ref', val=None, units='lbm') -ClimbPhase._add_meta_data('distance_lower', val=0, units='NM') -ClimbPhase._add_meta_data('distance_upper', val=0, units='NM') -ClimbPhase._add_meta_data('distance_ref', val=1, units='NM') -ClimbPhase._add_meta_data('distance_ref0', val=0, units='NM') -ClimbPhase._add_meta_data('distance_defect_ref', val=None, units='NM') -ClimbPhase._add_meta_data('num_segments', val=None, units='unitless') -ClimbPhase._add_meta_data('order', val=None, units='unitless') - -ClimbPhase._add_initial_guess_meta_data( - InitialGuessTime(), - desc='initial guess for initial time and duration specified as a tuple') - -ClimbPhase._add_initial_guess_meta_data( - InitialGuessState('distance'), - desc='initial guess for horizontal distance traveled') - -ClimbPhase._add_initial_guess_meta_data( - InitialGuessState('altitude'), - desc='initial guess for vertical distances') - -ClimbPhase._add_initial_guess_meta_data( - InitialGuessState('mass'), - desc='initial guess for mass') - -ClimbPhase._add_initial_guess_meta_data( - InitialGuessControl('throttle'), - desc='initial guess for throttle') diff --git a/aviary/mission/gasp_based/phases/new_descent_phase.py b/aviary/mission/gasp_based/phases/new_descent_phase.py deleted file mode 100644 index 42af7f5bb..000000000 --- a/aviary/mission/gasp_based/phases/new_descent_phase.py +++ /dev/null @@ -1,213 +0,0 @@ -from aviary.mission.flops_based.phases.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.variables import Dynamic -from aviary.variable_info.enums import SpeedType -from aviary.mission.gasp_based.ode.descent_ode import DescentODE -from aviary.variable_info.variable_meta_data import _MetaData - - -class DescentPhase(PhaseBuilderBase): - default_name = 'descent_phase' - default_ode_class = DescentODE - - __slots__ = ('external_subsystems', 'meta_data') - - _meta_data_ = {} - _initial_guesses_meta_data_ = {} - - default_meta_data = _MetaData - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, subsystem_options=subsystem_options, user_options=user_options, - initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, - core_subsystems=core_subsystems, - ) - - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - - def build_phase(self, aviary_options: AviaryValues = None): - phase = super().build_phase(aviary_options) - - # Retrieve user options values - user_options = self.user_options - time_initial_bounds = user_options.get_val('time_initial_bounds', units='s') - duration_bounds = user_options.get_val('duration_bounds', units='s') - fix_initial = user_options.get_val('fix_initial') - input_initial = user_options.get_val('input_initial') - duration_ref = user_options.get_val('duration_ref', units='s') - time_initial_ref = user_options.get_val('time_initial_ref', units='s') - alt_lower = user_options.get_val('alt_lower', units='ft') - alt_upper = user_options.get_val('alt_upper', units='ft') - alt_ref = user_options.get_val('alt_ref', units='ft') - alt_ref0 = user_options.get_val('alt_ref0', units='ft') - alt_defect_ref = user_options.get_val('alt_defect_ref', units='ft') - final_alt = user_options.get_val('final_alt', units='ft') - alt_constraint_ref = user_options.get_val('alt_constraint_ref', units='ft') - mass_lower = user_options.get_val('mass_lower', units='lbm') - mass_upper = user_options.get_val('mass_upper', units='lbm') - mass_ref = user_options.get_val('mass_ref', units='lbm') - mass_ref0 = user_options.get_val('mass_ref0', units='lbm') - mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') - distance_lower = user_options.get_val('distance_lower', units='NM') - distance_upper = user_options.get_val('distance_upper', units='NM') - distance_ref = user_options.get_val('distance_ref', units='NM') - distance_ref0 = user_options.get_val('distance_ref0', units='NM') - distance_defect_ref = user_options.get_val('distance_defect_ref', units='NM') - input_speed_type = user_options.get_val('input_speed_type') - EAS_limit = user_options.get_val('EAS_limit', units='kn') - - # Time options - phase.set_time_options( - initial_bounds=time_initial_bounds, - duration_bounds=duration_bounds, - fix_initial=fix_initial, - input_initial=input_initial, - units="s", - duration_ref=duration_ref, - initial_ref=time_initial_ref, - ) - - # Add states - phase.add_state( - Dynamic.Mission.ALTITUDE, - fix_initial=True, - fix_final=False, - lower=alt_lower, - upper=alt_upper, - units="ft", - rate_source=Dynamic.Mission.ALTITUDE_RATE, - targets=Dynamic.Mission.ALTITUDE, - ref=alt_ref, - ref0=alt_ref0, - defect_ref=alt_defect_ref, - ) - - phase.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial, - input_initial=input_initial, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - ref=mass_ref, - ref0=mass_ref0, - defect_ref=mass_defect_ref, - ) - - phase.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - input_initial=input_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="NM", - rate_source="distance_rate", - ref=distance_ref, - ref0=distance_ref0, - defect_ref=distance_defect_ref, - ) - - # Add boundary constraint - phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, - loc="final", - equals=final_alt, - units="ft", - ref=alt_constraint_ref) - - # Add parameter if necessary - if input_speed_type == SpeedType.EAS: - phase.add_parameter("EAS", opt=False, units="kn", val=EAS_limit) - - # Add timeseries outputs - phase.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") - phase.add_timeseries_output("EAS", output_name="EAS", units="kn") - phase.add_timeseries_output("TAS", output_name="TAS", units="kn") - phase.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, - output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") - phase.add_timeseries_output("alpha", output_name="alpha", units="deg") - phase.add_timeseries_output("theta", output_name="theta", units="deg") - phase.add_timeseries_output("aero.CL", output_name="CL", units="unitless") - phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") - phase.add_timeseries_output("aero.CD", output_name="CD", units="unitless") - - return phase - - def _extra_ode_init_kwargs(self): - """ - Return extra kwargs required for initializing the ODE. - """ - # TODO: support external_subsystems and meta_data in the base class - return { - 'input_speed_type': self.user_options.get_val('input_speed_type'), - 'mach_cruise': self.user_options.get_val('mach_cruise'), - 'EAS_limit': self.user_options.get_val('EAS_limit', 'kn'), - } - - -# Adding metadata for the DescentPhase -DescentPhase._add_meta_data('fix_initial', val=False) -DescentPhase._add_meta_data('input_initial', val=False) -DescentPhase._add_meta_data('EAS_limit', val=0, units='kn') -DescentPhase._add_meta_data('mach_cruise', val=0) -DescentPhase._add_meta_data('input_speed_type', val=SpeedType.MACH) -DescentPhase._add_meta_data('final_alt', val=0, units='ft') -DescentPhase._add_meta_data('time_initial_bounds', val=(0, 0), units='s') -DescentPhase._add_meta_data('time_initial_ref', val=1, units='s') -DescentPhase._add_meta_data('duration_bounds', val=(0, 0), units='s') -DescentPhase._add_meta_data('duration_ref', val=1, units='s') -DescentPhase._add_meta_data('alt_lower', val=0, units='ft') -DescentPhase._add_meta_data('alt_upper', val=0, units='ft') -DescentPhase._add_meta_data('alt_ref', val=1, units='ft') -DescentPhase._add_meta_data('alt_ref0', val=0, units='ft') -DescentPhase._add_meta_data('alt_defect_ref', val=None, units='ft') -DescentPhase._add_meta_data('alt_constraint_ref', val=None, units='ft') -DescentPhase._add_meta_data('mass_lower', val=0, units='lbm') -DescentPhase._add_meta_data('mass_upper', val=0, units='lbm') -DescentPhase._add_meta_data('mass_ref', val=1, units='lbm') -DescentPhase._add_meta_data('mass_ref0', val=0, units='lbm') -DescentPhase._add_meta_data('mass_defect_ref', val=None, units='lbm') -DescentPhase._add_meta_data('distance_lower', val=0, units='NM') -DescentPhase._add_meta_data('distance_upper', val=0, units='NM') -DescentPhase._add_meta_data('distance_ref', val=1, units='NM') -DescentPhase._add_meta_data('distance_ref0', val=0, units='NM') -DescentPhase._add_meta_data('distance_defect_ref', val=None, units='NM') -DescentPhase._add_meta_data('num_segments', val=None, units='unitless') -DescentPhase._add_meta_data('order', val=None, units='unitless') - -# Adding initial guess metadata -DescentPhase._add_initial_guess_meta_data( - InitialGuessTime(), - desc='initial guess for time options') -DescentPhase._add_initial_guess_meta_data( - InitialGuessState('altitude'), - desc='initial guess for altitude state') -DescentPhase._add_initial_guess_meta_data( - InitialGuessState('mass'), - desc='initial guess for mass state') -DescentPhase._add_initial_guess_meta_data( - InitialGuessState('distance'), - desc='initial guess for distance state') -DescentPhase._add_initial_guess_meta_data( - InitialGuessControl('throttle'), - desc='initial guess for throttle') diff --git a/aviary/mission/gasp_based/phases/new_groundroll_phase.py b/aviary/mission/gasp_based/phases/new_groundroll_phase.py deleted file mode 100644 index 1665c03a2..000000000 --- a/aviary/mission/gasp_based/phases/new_groundroll_phase.py +++ /dev/null @@ -1,183 +0,0 @@ -from aviary.mission.flops_based.phases.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.variables import Dynamic -from aviary.mission.gasp_based.ode.groundroll_ode import GroundrollODE -from aviary.variable_info.variable_meta_data import _MetaData - - -class GroundrollPhase(PhaseBuilderBase): - default_name = 'groundroll_phase' - default_ode_class = GroundrollODE - - __slots__ = ('external_subsystems', 'meta_data') - - _meta_data_ = {} - _initial_guesses_meta_data_ = {} - - default_meta_data = _MetaData - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, subsystem_options=subsystem_options, user_options=user_options, - initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, - core_subsystems=core_subsystems, - ) - - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - - def build_phase(self, aviary_options: AviaryValues = None): - phase = super().build_phase(aviary_options) - - # Retrieve user options values - user_options = self.user_options - # Add the necessary get_val calls for each parameter, e.g., - fix_initial = user_options.get_val('fix_initial') - fix_initial_mass = user_options.get_val('fix_initial_mass') - connect_initial_mass = user_options.get_val('connect_initial_mass') - duration_bounds = user_options.get_val('duration_bounds', units='s') - duration_ref = user_options.get_val('duration_ref', units='s') - TAS_lower = user_options.get_val('TAS_lower', units='kn') - TAS_upper = user_options.get_val('TAS_upper', units='kn') - TAS_ref = user_options.get_val('TAS_ref', units='kn') - TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') - TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') - mass_lower = user_options.get_val('mass_lower', units='lbm') - mass_upper = user_options.get_val('mass_upper', units='lbm') - mass_ref = user_options.get_val('mass_ref', units='lbm') - mass_ref0 = user_options.get_val('mass_ref0', units='lbm') - mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') - distance_lower = user_options.get_val('distance_lower', units='ft') - distance_upper = user_options.get_val('distance_upper', units='ft') - distance_ref = user_options.get_val('distance_ref', units='ft') - distance_ref0 = user_options.get_val('distance_ref0', units='ft') - distance_defect_ref = user_options.get_val('distance_defect_ref', units='ft') - - # Set time options - phase.set_time_options( - fix_initial=fix_initial, - fix_duration=False, - units="s", - targets="t_curr", - duration_bounds=duration_bounds, - duration_ref=duration_ref, - ) - - # Add states - phase.add_state( - "TAS", - fix_initial=fix_initial, - fix_final=False, - lower=TAS_lower, - upper=TAS_upper, - units="kn", - rate_source="TAS_rate", - ref=TAS_ref, - defect_ref=TAS_defect_ref, - ref0=TAS_ref0, - ) - - phase.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial_mass, - input_initial=connect_initial_mass, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - ref=mass_ref, - defect_ref=mass_defect_ref, - ref0=mass_ref0, - ) - - phase.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="ft", - rate_source="distance_rate", - ref=distance_ref, - defect_ref=distance_defect_ref, - ref0=distance_ref0, - ) - - phase.add_parameter("t_init_gear", units="s", - static_target=True, opt=False, val=100) - phase.add_parameter("t_init_flaps", units="s", - static_target=True, opt=False, val=100) - - # boundary/path constraints + controls - # the final TAS is constrained externally to define the transition to the rotation - # phase - - phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") - - phase.add_timeseries_output("normal_force") - phase.add_timeseries_output(Dynamic.Mission.MACH) - phase.add_timeseries_output("EAS", units="kn") - - phase.add_timeseries_output(Dynamic.Mission.LIFT) - phase.add_timeseries_output("CL") - phase.add_timeseries_output("CD") - phase.add_timeseries_output("fuselage_pitch", output_name="theta", units="deg") - - return phase - - -# Adding metadata for the GroundrollPhase -GroundrollPhase._add_meta_data('fix_initial', val=True) -GroundrollPhase._add_meta_data('fix_initial_mass', val=False) -GroundrollPhase._add_meta_data('connect_initial_mass', val=True) -GroundrollPhase._add_meta_data('duration_bounds', val=(1, 100), units='s') -GroundrollPhase._add_meta_data('duration_ref', val=1, units='s') -GroundrollPhase._add_meta_data('TAS_lower', val=0, units='kn') -GroundrollPhase._add_meta_data('TAS_upper', val=1000, units='kn') -GroundrollPhase._add_meta_data('TAS_ref', val=100, units='kn') -GroundrollPhase._add_meta_data('TAS_ref0', val=0, units='kn') -GroundrollPhase._add_meta_data('TAS_defect_ref', val=None, units='kn') -GroundrollPhase._add_meta_data('mass_lower', val=0, units='lbm') -GroundrollPhase._add_meta_data('mass_upper', val=200_000, units='lbm') -GroundrollPhase._add_meta_data('mass_ref', val=100_000, units='lbm') -GroundrollPhase._add_meta_data('mass_ref0', val=0, units='lbm') -GroundrollPhase._add_meta_data('mass_defect_ref', val=100, units='lbm') -GroundrollPhase._add_meta_data('distance_lower', val=0, units='ft') -GroundrollPhase._add_meta_data('distance_upper', val=4000, units='ft') -GroundrollPhase._add_meta_data('distance_ref', val=3000, units='ft') -GroundrollPhase._add_meta_data('distance_ref0', val=0, units='ft') -GroundrollPhase._add_meta_data('distance_defect_ref', val=3000, units='ft') -GroundrollPhase._add_meta_data('t_init_gear', val=100, units='s') -GroundrollPhase._add_meta_data('t_init_flaps', val=100, units='s') -GroundrollPhase._add_meta_data('num_segments', val=None, units='unitless') -GroundrollPhase._add_meta_data('order', val=None, units='unitless') - -# Adding initial guess metadata -GroundrollPhase._add_initial_guess_meta_data( - InitialGuessTime(), - desc='initial guess for time options') -GroundrollPhase._add_initial_guess_meta_data( - InitialGuessState('TAS'), - desc='initial guess for true airspeed state') -GroundrollPhase._add_initial_guess_meta_data( - InitialGuessState('mass'), - desc='initial guess for mass state') -GroundrollPhase._add_initial_guess_meta_data( - InitialGuessState('distance'), - desc='initial guess for distance state') -GroundrollPhase._add_initial_guess_meta_data( - InitialGuessControl('throttle'), - desc='initial guess for throttle') diff --git a/aviary/mission/gasp_based/phases/new_rotation_phase.py b/aviary/mission/gasp_based/phases/new_rotation_phase.py deleted file mode 100644 index 0b65efdb8..000000000 --- a/aviary/mission/gasp_based/phases/new_rotation_phase.py +++ /dev/null @@ -1,218 +0,0 @@ -import numpy as np - -from aviary.mission.flops_based.phases.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.variables import Dynamic -from aviary.mission.gasp_based.ode.rotation_ode import RotationODE -from aviary.variable_info.variable_meta_data import _MetaData - - -class RotationPhase(PhaseBuilderBase): - default_name = 'rotation_phase' - default_ode_class = RotationODE - - __slots__ = ('external_subsystems', 'meta_data') - - _meta_data_ = {} - _initial_guesses_meta_data_ = {} - - default_meta_data = _MetaData - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, subsystem_options=subsystem_options, user_options=user_options, - initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, - core_subsystems=core_subsystems, - ) - - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - - def build_phase(self, aviary_options: AviaryValues = None): - phase = super().build_phase(aviary_options) - - # Retrieve user options values - user_options = self.user_options - fix_initial = user_options.get_val('fix_initial') - initial_ref = user_options.get_val('initial_ref', units='s') - duration_bounds = user_options.get_val('duration_bounds', units='s') - duration_ref = user_options.get_val('duration_ref', units='s') - angle_lower = user_options.get_val('angle_lower', units='rad') - angle_upper = user_options.get_val('angle_upper', units='rad') - angle_ref = user_options.get_val('angle_ref', units='rad') - angle_ref0 = user_options.get_val('angle_ref0', units='rad') - angle_defect_ref = user_options.get_val('angle_defect_ref', units='rad') - TAS_lower = user_options.get_val('TAS_lower', units='kn') - TAS_upper = user_options.get_val('TAS_upper', units='kn') - TAS_ref = user_options.get_val('TAS_ref', units='kn') - TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') - TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') - mass_lower = user_options.get_val('mass_lower', units='lbm') - mass_upper = user_options.get_val('mass_upper', units='lbm') - mass_ref = user_options.get_val('mass_ref', units='lbm') - mass_ref0 = user_options.get_val('mass_ref0', units='lbm') - mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') - distance_lower = user_options.get_val('distance_lower', units='ft') - distance_upper = user_options.get_val('distance_upper', units='ft') - distance_ref = user_options.get_val('distance_ref', units='ft') - distance_ref0 = user_options.get_val('distance_ref0', units='ft') - distance_defect_ref = user_options.get_val('distance_defect_ref', units='ft') - normal_ref = user_options.get_val('normal_ref', units='lbf') - normal_ref0 = user_options.get_val('normal_ref0', units='lbf') - - # Set time options - phase.set_time_options( - fix_initial=fix_initial, - fix_duration=False, - units="s", - targets="t_curr", - initial_ref=initial_ref, - duration_bounds=duration_bounds, - duration_ref=duration_ref, - ) - - # Add states - phase.add_state( - "alpha", - fix_initial=True, - fix_final=False, - lower=angle_lower, - upper=angle_upper, - units="rad", - rate_source="alpha_rate", - ref=angle_ref, - ref0=angle_ref0, - defect_ref=angle_defect_ref, - ) - - phase.add_state( - "TAS", - fix_initial=fix_initial, - fix_final=False, - lower=TAS_lower, - upper=TAS_upper, - units="kn", - rate_source="TAS_rate", - ref=TAS_ref, - ref0=TAS_ref0, - defect_ref=TAS_defect_ref, - ) - - phase.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - ref=mass_ref, - ref0=mass_ref0, - defect_ref=mass_defect_ref, - ) - - phase.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="ft", - rate_source="distance_rate", - ref=distance_ref, - ref0=distance_ref0, - defect_ref=distance_defect_ref, - ) - - # Add parameters - phase.add_parameter("t_init_gear", units="s", - static_target=True, opt=False, val=100) - phase.add_parameter("t_init_flaps", units="s", - static_target=True, opt=False, val=100) - - # Add boundary constraints - phase.add_boundary_constraint( - "normal_force", - loc="final", - equals=0, - units="lbf", - ref=normal_ref, - ref0=normal_ref0, - ) - - # Add timeseries outputs - phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") - phase.add_timeseries_output("normal_force") - phase.add_timeseries_output(Dynamic.Mission.MACH) - phase.add_timeseries_output("EAS", units="kn") - phase.add_timeseries_output(Dynamic.Mission.LIFT) - phase.add_timeseries_output("CL") - phase.add_timeseries_output("CD") - phase.add_timeseries_output("fuselage_pitch", output_name="theta", units="deg") - - return phase - - -# Adding metadata for the RotationPhase -RotationPhase._add_meta_data('fix_initial', val=False) -RotationPhase._add_meta_data('initial_ref', val=1, units='s') -RotationPhase._add_meta_data('duration_bounds', val=(1, 100), units='s') -RotationPhase._add_meta_data('duration_ref', val=1, units='s') -RotationPhase._add_meta_data('angle_lower', val=0.0, units='rad') # rad -RotationPhase._add_meta_data('angle_upper', val=25 * np.pi / 180, units='rad') # rad -RotationPhase._add_meta_data('angle_ref', val=1, units='rad') -RotationPhase._add_meta_data('angle_ref0', val=0, units='rad') -RotationPhase._add_meta_data('angle_defect_ref', val=0.01, units='rad') -RotationPhase._add_meta_data('TAS_lower', val=0, units='kn') -RotationPhase._add_meta_data('TAS_upper', val=1000, units='kn') -RotationPhase._add_meta_data('TAS_ref', val=100, units='kn') -RotationPhase._add_meta_data('TAS_ref0', val=0, units='kn') -RotationPhase._add_meta_data('TAS_defect_ref', val=None, units='kn') -RotationPhase._add_meta_data('mass_lower', val=0, units='lbm') -RotationPhase._add_meta_data('mass_upper', val=190_000, units='lbm') -RotationPhase._add_meta_data('mass_ref', val=100_000, units='lbm') -RotationPhase._add_meta_data('mass_ref0', val=0, units='lbm') -RotationPhase._add_meta_data('mass_defect_ref', val=None, units='lbm') -RotationPhase._add_meta_data('distance_lower', val=0, units='ft') -RotationPhase._add_meta_data('distance_upper', val=10.e3, units='ft') -RotationPhase._add_meta_data('distance_ref', val=3000, units='ft') -RotationPhase._add_meta_data('distance_ref0', val=0, units='ft') -RotationPhase._add_meta_data('distance_defect_ref', val=3000, units='ft') -RotationPhase._add_meta_data('normal_ref', val=1, units='lbf') -RotationPhase._add_meta_data('normal_ref0', val=0, units='lbf') -RotationPhase._add_meta_data('t_init_gear', val=100, units='s') -RotationPhase._add_meta_data('t_init_flaps', val=100, units='s') -RotationPhase._add_meta_data('num_segments', val=None, units='unitless') -RotationPhase._add_meta_data('order', val=None, units='unitless') - -# Adding initial guess metadata -RotationPhase._add_initial_guess_meta_data( - InitialGuessTime(), - desc='initial guess for time options') -RotationPhase._add_initial_guess_meta_data( - InitialGuessState('alpha'), - desc='initial guess for angle of attack state') -RotationPhase._add_initial_guess_meta_data( - InitialGuessState('TAS'), - desc='initial guess for true airspeed state') -RotationPhase._add_initial_guess_meta_data( - InitialGuessState('mass'), - desc='initial guess for mass state') -RotationPhase._add_initial_guess_meta_data( - InitialGuessState('distance'), - desc='initial guess for distance state') -RotationPhase._add_initial_guess_meta_data( - InitialGuessControl('throttle'), - desc='initial guess for throttle') diff --git a/aviary/mission/gasp_based/phases/rotation_phase.py b/aviary/mission/gasp_based/phases/rotation_phase.py index a0c4441db..0b65efdb8 100644 --- a/aviary/mission/gasp_based/phases/rotation_phase.py +++ b/aviary/mission/gasp_based/phases/rotation_phase.py @@ -1,132 +1,218 @@ -import dymos as dm import numpy as np -from aviary.mission.gasp_based.ode.rotation_ode import RotationODE +from aviary.mission.flops_based.phases.phase_builder_base import ( + PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic +from aviary.mission.gasp_based.ode.rotation_ode import RotationODE +from aviary.variable_info.variable_meta_data import _MetaData + + +class RotationPhase(PhaseBuilderBase): + default_name = 'rotation_phase' + default_ode_class = RotationODE + + __slots__ = ('external_subsystems', 'meta_data') + + _meta_data_ = {} + _initial_guesses_meta_data_ = {} + + default_meta_data = _MetaData + + def __init__( + self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, core_subsystems=None, + external_subsystems=None, meta_data=None + ): + super().__init__( + name=name, subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, + core_subsystems=core_subsystems, + ) + + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + + self.meta_data = meta_data + + def build_phase(self, aviary_options: AviaryValues = None): + phase = super().build_phase(aviary_options) + + # Retrieve user options values + user_options = self.user_options + fix_initial = user_options.get_val('fix_initial') + initial_ref = user_options.get_val('initial_ref', units='s') + duration_bounds = user_options.get_val('duration_bounds', units='s') + duration_ref = user_options.get_val('duration_ref', units='s') + angle_lower = user_options.get_val('angle_lower', units='rad') + angle_upper = user_options.get_val('angle_upper', units='rad') + angle_ref = user_options.get_val('angle_ref', units='rad') + angle_ref0 = user_options.get_val('angle_ref0', units='rad') + angle_defect_ref = user_options.get_val('angle_defect_ref', units='rad') + TAS_lower = user_options.get_val('TAS_lower', units='kn') + TAS_upper = user_options.get_val('TAS_upper', units='kn') + TAS_ref = user_options.get_val('TAS_ref', units='kn') + TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') + TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') + mass_lower = user_options.get_val('mass_lower', units='lbm') + mass_upper = user_options.get_val('mass_upper', units='lbm') + mass_ref = user_options.get_val('mass_ref', units='lbm') + mass_ref0 = user_options.get_val('mass_ref0', units='lbm') + mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') + distance_lower = user_options.get_val('distance_lower', units='ft') + distance_upper = user_options.get_val('distance_upper', units='ft') + distance_ref = user_options.get_val('distance_ref', units='ft') + distance_ref0 = user_options.get_val('distance_ref0', units='ft') + distance_defect_ref = user_options.get_val('distance_defect_ref', units='ft') + normal_ref = user_options.get_val('normal_ref', units='lbf') + normal_ref0 = user_options.get_val('normal_ref0', units='lbf') + + # Set time options + phase.set_time_options( + fix_initial=fix_initial, + fix_duration=False, + units="s", + targets="t_curr", + initial_ref=initial_ref, + duration_bounds=duration_bounds, + duration_ref=duration_ref, + ) + + # Add states + phase.add_state( + "alpha", + fix_initial=True, + fix_final=False, + lower=angle_lower, + upper=angle_upper, + units="rad", + rate_source="alpha_rate", + ref=angle_ref, + ref0=angle_ref0, + defect_ref=angle_defect_ref, + ) + + phase.add_state( + "TAS", + fix_initial=fix_initial, + fix_final=False, + lower=TAS_lower, + upper=TAS_upper, + units="kn", + rate_source="TAS_rate", + ref=TAS_ref, + ref0=TAS_ref0, + defect_ref=TAS_defect_ref, + ) + + phase.add_state( + Dynamic.Mission.MASS, + fix_initial=fix_initial, + fix_final=False, + lower=mass_lower, + upper=mass_upper, + units="lbm", + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + ref=mass_ref, + ref0=mass_ref0, + defect_ref=mass_defect_ref, + ) + + phase.add_state( + Dynamic.Mission.DISTANCE, + fix_initial=fix_initial, + fix_final=False, + lower=distance_lower, + upper=distance_upper, + units="ft", + rate_source="distance_rate", + ref=distance_ref, + ref0=distance_ref0, + defect_ref=distance_defect_ref, + ) + + # Add parameters + phase.add_parameter("t_init_gear", units="s", + static_target=True, opt=False, val=100) + phase.add_parameter("t_init_flaps", units="s", + static_target=True, opt=False, val=100) + + # Add boundary constraints + phase.add_boundary_constraint( + "normal_force", + loc="final", + equals=0, + units="lbf", + ref=normal_ref, + ref0=normal_ref0, + ) + + # Add timeseries outputs + phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") + phase.add_timeseries_output("normal_force") + phase.add_timeseries_output(Dynamic.Mission.MACH) + phase.add_timeseries_output("EAS", units="kn") + phase.add_timeseries_output(Dynamic.Mission.LIFT) + phase.add_timeseries_output("CL") + phase.add_timeseries_output("CD") + phase.add_timeseries_output("fuselage_pitch", output_name="theta", units="deg") + + return phase + +# Adding metadata for the RotationPhase +RotationPhase._add_meta_data('fix_initial', val=False) +RotationPhase._add_meta_data('initial_ref', val=1, units='s') +RotationPhase._add_meta_data('duration_bounds', val=(1, 100), units='s') +RotationPhase._add_meta_data('duration_ref', val=1, units='s') +RotationPhase._add_meta_data('angle_lower', val=0.0, units='rad') # rad +RotationPhase._add_meta_data('angle_upper', val=25 * np.pi / 180, units='rad') # rad +RotationPhase._add_meta_data('angle_ref', val=1, units='rad') +RotationPhase._add_meta_data('angle_ref0', val=0, units='rad') +RotationPhase._add_meta_data('angle_defect_ref', val=0.01, units='rad') +RotationPhase._add_meta_data('TAS_lower', val=0, units='kn') +RotationPhase._add_meta_data('TAS_upper', val=1000, units='kn') +RotationPhase._add_meta_data('TAS_ref', val=100, units='kn') +RotationPhase._add_meta_data('TAS_ref0', val=0, units='kn') +RotationPhase._add_meta_data('TAS_defect_ref', val=None, units='kn') +RotationPhase._add_meta_data('mass_lower', val=0, units='lbm') +RotationPhase._add_meta_data('mass_upper', val=190_000, units='lbm') +RotationPhase._add_meta_data('mass_ref', val=100_000, units='lbm') +RotationPhase._add_meta_data('mass_ref0', val=0, units='lbm') +RotationPhase._add_meta_data('mass_defect_ref', val=None, units='lbm') +RotationPhase._add_meta_data('distance_lower', val=0, units='ft') +RotationPhase._add_meta_data('distance_upper', val=10.e3, units='ft') +RotationPhase._add_meta_data('distance_ref', val=3000, units='ft') +RotationPhase._add_meta_data('distance_ref0', val=0, units='ft') +RotationPhase._add_meta_data('distance_defect_ref', val=3000, units='ft') +RotationPhase._add_meta_data('normal_ref', val=1, units='lbf') +RotationPhase._add_meta_data('normal_ref0', val=0, units='lbf') +RotationPhase._add_meta_data('t_init_gear', val=100, units='s') +RotationPhase._add_meta_data('t_init_flaps', val=100, units='s') +RotationPhase._add_meta_data('num_segments', val=None, units='unitless') +RotationPhase._add_meta_data('order', val=None, units='unitless') -def get_rotation( - ode_args=None, - transcription=None, - fix_initial=False, - initial_ref=1, - duration_bounds=(1, 100), - duration_ref=1, - angle_lower=0.0, # rad - angle_upper=25 * np.pi / 180, # rad - angle_ref=1, - angle_ref0=0, - angle_defect_ref=0.01, - TAS_lower=0, - TAS_upper=1000, - TAS_ref=100, - TAS_ref0=0, - TAS_defect_ref=None, - mass_lower=0, - mass_upper=190_000, - mass_ref=100_000, - mass_ref0=0, - mass_defect_ref=None, - distance_lower=0, - distance_upper=10.e3, - distance_ref=3000, - distance_ref0=0, - distance_defect_ref=3000, - normal_ref=1, - normal_ref0=0, -): - phase = dm.Phase( - ode_class=RotationODE, - ode_init_kwargs=ode_args, - transcription=transcription, - ) - - phase.set_time_options( - fix_initial=fix_initial, - fix_duration=False, - units="s", - targets="t_curr", - initial_ref=initial_ref, - duration_bounds=duration_bounds, - duration_ref=duration_ref, - ) - - phase.add_state( - "alpha", - fix_initial=True, - fix_final=False, - lower=angle_lower, - upper=angle_upper, - units="rad", - rate_source="alpha_rate", - ref=angle_ref, - ref0=angle_ref0, - defect_ref=angle_defect_ref, - ) - - phase.add_state( - "TAS", - fix_initial=fix_initial, - fix_final=False, - lower=TAS_lower, - upper=TAS_upper, - units="kn", - rate_source="TAS_rate", - ref=TAS_ref, - ref0=TAS_ref0, - defect_ref=TAS_defect_ref, - ) - - phase.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - ref=mass_ref, - ref0=mass_ref0, - defect_ref=mass_defect_ref, - ) - - phase.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="ft", - rate_source="distance_rate", - ref=distance_ref, - ref0=distance_ref0, - defect_ref=distance_defect_ref, - ) - - phase.add_parameter("t_init_gear", units="s", - static_target=True, opt=False, val=100) - phase.add_parameter("t_init_flaps", units="s", - static_target=True, opt=False, val=100) - - # boundary/path constraints + controls - phase.add_boundary_constraint( - "normal_force", - loc="final", - equals=0, - units="lbf", - ref=normal_ref, - ref0=normal_ref0, - ) - - phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") - - phase.add_timeseries_output("normal_force") - phase.add_timeseries_output(Dynamic.Mission.MACH) - phase.add_timeseries_output("EAS", units="kn") - - phase.add_timeseries_output(Dynamic.Mission.LIFT) - phase.add_timeseries_output("CL") - phase.add_timeseries_output("CD") - phase.add_timeseries_output("fuselage_pitch", output_name="theta", units="deg") - - return phase +# Adding initial guess metadata +RotationPhase._add_initial_guess_meta_data( + InitialGuessTime(), + desc='initial guess for time options') +RotationPhase._add_initial_guess_meta_data( + InitialGuessState('alpha'), + desc='initial guess for angle of attack state') +RotationPhase._add_initial_guess_meta_data( + InitialGuessState('TAS'), + desc='initial guess for true airspeed state') +RotationPhase._add_initial_guess_meta_data( + InitialGuessState('mass'), + desc='initial guess for mass state') +RotationPhase._add_initial_guess_meta_data( + InitialGuessState('distance'), + desc='initial guess for distance state') +RotationPhase._add_initial_guess_meta_data( + InitialGuessControl('throttle'), + desc='initial guess for throttle') diff --git a/aviary/mission/gasp_based/phases/run_phases/__init__.py b/aviary/mission/gasp_based/phases/run_phases/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/aviary/mission/gasp_based/phases/run_phases/run_accel.py b/aviary/mission/gasp_based/phases/run_phases/run_accel.py deleted file mode 100644 index ce26a879e..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_accel.py +++ /dev/null @@ -1,96 +0,0 @@ -import dymos as dm -import matplotlib.pyplot as plt -import openmdao.api as om -import numpy as np - -from aviary.mission.gasp_based.phases.accel_phase import get_accel -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 packaging import version - - -def run_accel(): - # Column-wise data from CSV - time_GASP = np.array([0.182, 0.188]) - distance_GASP = np.array([0.00, 1.57]) - weight_GASP = np.array([174974., 174878.]) - TAS_GASP = np.array([185., 252.]) - EAS_GASP = np.array([184., 250.]) - - time_GASP = time_GASP * 3600 - time_GASP = time_GASP - time_GASP[0] - - prob = om.Problem(model=om.Group()) - - prob.driver = om.pyOptSparseDriver() - prob.driver.options["optimizer"] = "SNOPT" - prob.driver.opt_settings["Major iterations limit"] = 100 - prob.driver.opt_settings["Major optimality tolerance"] = 5.0e-3 - prob.driver.opt_settings["Major feasibility tolerance"] = 1e-6 - prob.driver.opt_settings["iSumm"] = 6 - prob.driver.declare_coloring() - - transcription = dm.Radau(num_segments=15, order=4, compressed=False) - - ode_args = dict( - aviary_options=get_option_defaults(), - core_subsystems=default_mission_subsystems, - ) - - accel = get_accel( - ode_args=ode_args, - transcription=transcription, - alt=500, - EAS_constraint_eq=250, - fix_initial=True, - time_initial_bounds=(0, 0), - duration_bounds=(0, 36_000), - duration_ref=1000, - TAS_lower=0, - TAS_upper=1000, - TAS_ref=250, - TAS_ref0=150, - mass_lower=0, - mass_upper=None, - mass_ref=175_500, - distance_lower=0, - distance_upper=150, - distance_ref=1, - distance_defect_ref=1, - ) # min GASP time is 18 seconds, max is 25.2 - - accel.add_parameter( - Aircraft.Wing.AREA, opt=False, units="ft**2", val=1370.0, static_target=True - ) - - prob.model.add_subsystem(name='accel', subsys=accel) - accel.add_timeseries_output("EAS", output_name="EAS", units="kn") - accel.add_timeseries_output("TAS", output_name="TAS", units="kn") - accel.add_timeseries_output("mass", output_name="mass", units="lbm") - accel.add_timeseries_output("distance", output_name="distance", units="NM") - accel.timeseries_options['use_prefix'] = True - - accel.add_objective("time", loc="final") - prob.model.linear_solver.options["iprint"] = 0 - prob.model.nonlinear_solver.options["iprint"] = 0 - - prob.model.options["assembled_jac_type"] = "csc" - prob.model.linear_solver = om.DirectSolver(assemble_jac=True) - - prob.set_solver_print(level=0) - - prob.setup() - prob.set_val("accel.states:mass", accel.interp("mass", ys=[174974, 174878])) - prob.set_val("accel.states:TAS", accel.interp("TAS", ys=[185, 252])) - prob.set_val("accel.states:distance", accel.interp( - Dynamic.Mission.DISTANCE, ys=[0, 1.57])) - prob.set_val("accel.t_duration", 1000) - prob.set_val("accel.t_initial", 0) - - dm.run_problem(problem=prob, simulate=True) - print() - print("Done Running Model, Now Simulating") - print() - - return prob diff --git a/aviary/mission/gasp_based/phases/run_phases/run_ascent.py b/aviary/mission/gasp_based/phases/run_phases/run_ascent.py deleted file mode 100644 index fdd3c0384..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_ascent.py +++ /dev/null @@ -1,123 +0,0 @@ -import dymos as dm -import openmdao.api as om - -from aviary.mission.gasp_based.phases.ascent_phase import get_ascent -from aviary.mission.gasp_based.polynomial_fit import PolynomialFit -from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Aircraft, Dynamic, Mission -from aviary.interface.default_phase_info.height_energy import default_mission_subsystems - - -def run_ascent(make_plots=False): - - solve_segments = False # changed from "forward" because got a singular matrix error - ascent_trans = dm.Radau( - num_segments=2, order=5, compressed=True, solve_segments=solve_segments - ) - ascent = get_ascent( - fix_initial=True, - transcription=ascent_trans, - TAS_ref=1, - alt_ref=1, - alt_defect_ref=1, - ode_args=get_option_defaults(), - core_subsystems=default_mission_subsystems - ) - - p = om.Problem() - traj = p.model.add_subsystem("traj", dm.Trajectory()) - traj.add_phase("ascent", ascent) - - p.model.promotes( - "traj", - inputs=[ - ("ascent.parameters:t_init_gear", "t_init_gear"), - ("ascent.parameters:t_init_flaps", "t_init_flaps"), - ( - "ascent.parameters:" + Mission.Design.GROSS_MASS, - Mission.Design.GROSS_MASS, - ), - ("ascent.t_duration", "t_duration"), - ], - ) - - ascent_tx = ascent.options["transcription"] - ascent_num_nodes = ascent_tx.grid_data.num_nodes - - p.model.add_subsystem( - "h_fit", - PolynomialFit(N_cp=ascent_num_nodes), - promotes_inputs=["t_init_gear", "t_init_flaps"], - ) - p.model.connect("traj.ascent.timeseries.time", "h_fit.time_cp") - p.model.connect("traj.ascent.timeseries.states:altitude", "h_fit.h_cp") - - # TODO: re-parameterize time to be 0-1 (i.e. add a component that offsets by t_initial/t_duration) - p.model.add_design_var("t_init_gear", lower=32.0, upper=45.0, units="s", ref=5.0) - p.model.add_constraint("h_fit.h_init_gear", equals=50.0, units="ft", ref=50.0) - - p.model.add_design_var("t_init_flaps", lower=45.0, upper=100.0, units="s", ref=50.0) - p.model.add_constraint("h_fit.h_init_flaps", equals=400.0, units="ft", ref=400.0) - - p.model.add_design_var("t_duration", lower=5, upper=100, units="s") - p.model.set_input_defaults("t_duration", val=25, units="s") - - p.driver = om.pyOptSparseDriver() - p.driver.options["optimizer"] = "SNOPT" - p.driver.opt_settings["iSumm"] = 6 - # p.driver.options['debug_print'] = ['desvars'] - p.driver.declare_coloring() - - # p.model.add_objective("traj.ascent.timeseries.states:mass", index=-1, ref=1.4e5, ref0=1.3e5) - ascent.add_objective("time", loc="final") - p.set_solver_print(level=-1) - - ascent.add_parameter( - Aircraft.Wing.AREA, - opt=False, - units="ft**2", - val=1370, - static_target=True, - targets=[Aircraft.Wing.AREA], - ) - p.model.set_input_defaults(Mission.Design.GROSS_MASS, val=174000, units="lbm") - p.setup() - - p.set_val( - "traj.ascent.states:altitude", - ascent.interp(Dynamic.Mission.ALTITUDE, ys=[0, 100, 500], xs=[0, 1, 10]), - units="ft", - ) - p.set_val("traj.ascent.states:flight_path_angle", 0.2, units="rad") - - p.set_val( - "traj.ascent.states:TAS", ascent.interp("TAS", [153.3196491, 500]), units="kn" - ) - p.set_val( - "traj.ascent.states:mass", - ascent.interp("mass", [174963.74211336, 174000]), - units="lbm", - ) - p.set_val( - "traj.ascent.states:distance", - ascent.interp(Dynamic.Mission.DISTANCE, [4330.83393029, 5000]), - units="ft", - ) - p.set_val("traj.ascent.t_initial", 31.2) - # p.set_val("traj.ascent.t_duration", 10.0) - - p.set_val("t_init_gear", 40.0) # initial guess - p.set_val("t_init_flaps", 47.5) # initial guess - - p.set_val( - "traj.ascent.controls:alpha", - ascent.interpolate(ys=[1, 1], nodes="control_input"), - units="deg", - ) - - dm.run_problem(p, simulate=True, make_plots=make_plots) - - print("t_init_gear (s)", p.get_val("t_init_gear", units="s")) - print("t_init_flaps (s)", p.get_val("t_init_flaps", units="s")) - - return p diff --git a/aviary/mission/gasp_based/phases/run_phases/run_climb.py b/aviary/mission/gasp_based/phases/run_phases/run_climb.py deleted file mode 100644 index 90d3a5376..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_climb.py +++ /dev/null @@ -1,277 +0,0 @@ -import argparse -import os - -import dymos as dm -import matplotlib.pyplot as plt -import openmdao.api as om -import pandas as pd - -from aviary.mission.gasp_based.ode.params import ParamPort -from aviary.mission.gasp_based.phases.climb_phase import get_climb -from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Dynamic - -thisdir = os.path.dirname(__file__) -def_outdir = os.path.join(thisdir, "output") - -gaspdata_dir = os.path.join(thisdir, "..", "..", "problem", - "large_single_aisle_validation_data") - -theta_max = 15 -TAS_violation_max = 0 -use_surrogate = True - -ode_args = {} - -# name: (gaspname, path, units) -varinfo = { - "time": ("TIME", "time", "s"), - Dynamic.Mission.ALTITUDE: ("ALT", "states:altitude", "ft"), - "mass": ("MASS", "states:mass", "lbm"), - Dynamic.Mission.DISTANCE: ("RANGE", "states:distance", "NM"), - Dynamic.Mission.MACH: ("MACH", Dynamic.Mission.MACH, None), - "EAS": ("EAS", "EAS", "kn"), - "alpha": ("ALPHA", "alpha", "deg"), - Dynamic.Mission.FLIGHT_PATH_ANGLE: ("GAMMA", Dynamic.Mission.FLIGHT_PATH_ANGLE, "deg"), - "theta": ("FUSANGLE", "theta", "deg"), - "TAS_violation": (None, "TAS_violation", "kn"), - "CL": ("CL", "CL", None), - "CD": ("CD", "CD", None), - Dynamic.Mission.THRUST_TOTAL: ("THRUST", Dynamic.Mission.THRUST_TOTAL, "lbf"), -} - - -def setup_climb1(): - prob = om.Problem(model=om.Group(), name="main") - setup_driver(prob) - - ode_args["aviary_options"] = get_option_defaults() - - transcription = dm.Radau(num_segments=1, order=5, compressed=False) - climb1 = get_climb( - ode_args=ode_args, - transcription=transcription, - fix_initial=True, - alt_lower=0, - alt_upper=11000, - mass_lower=0, - mass_upper=200_000, - distance_lower=0, - distance_upper=300, - time_initial_bounds=(0, 0), - duration_bounds=(1.1, 36_000), - EAS_target=250, - mach_cruise=0.8, - target_mach=False, - final_alt=10000, - alt_ref=10000, - mass_ref=200000, - distance_ref=300, - ) - prob.model.add_subsystem(name="climb1", subsys=climb1) - - # add all params and promote them to prob.model level - ParamPort.promote_params(prob.model, phases=["climb1"]) - ParamPort.set_default_vals(prob.model) - - climb1.add_objective("time", loc="final") - - prob.model.options["assembled_jac_type"] = "csc" - prob.model.linear_solver = om.LinearRunOnce() - - prob.setup() - - prob.set_val("climb1.controls:throttle", - climb1.interp("throttle", ys=[1.0, 1.0])) - prob.set_val("climb1.states:mass", climb1.interp("mass", ys=[174878, 174219])) - prob.set_val( - "climb1.timeseries:altitude", climb1.interp( - Dynamic.Mission.ALTITUDE, ys=[ - 500, 10000])) - prob.set_val("climb1.states:distance", climb1.interp( - Dynamic.Mission.DISTANCE, ys=[2, 15])) - prob.set_val("climb1.t_duration", 1000) - prob.set_val("climb1.t_initial", 0) - - return prob - - -def setup_climb2(): - prob = om.Problem(model=om.Group(), name="main") - - setup_driver(prob) - - ode_args["aviary_options"] = get_option_defaults() - - transcription = dm.Radau(num_segments=3, order=3, compressed=False) - climb2 = get_climb( - ode_args=ode_args, - transcription=transcription, - fix_initial=True, - alt_lower=9000, - alt_upper=60000, - mass_lower=0, - mass_upper=200_000, - distance_lower=0, - distance_upper=300, - time_initial_bounds=(0, 0), - duration_bounds=(2, 36_000), - EAS_target=270, - mach_cruise=0.8, - target_mach=True, - final_alt=37500, - alt_ref=40000, - mass_ref=200000, - distance_ref=300, - required_available_climb_rate=300, - ) - prob.model.add_subsystem(name="climb2", subsys=climb2) - - # fixed initial mass, so max final mass is equivalent to min fuel burn - climb2.add_objective("mass", loc="final", ref=-1) - - # add all params and promote them to prob.model level - ParamPort.promote_params(prob.model, phases=["climb2"]) - ParamPort.set_default_vals(prob.model) - - prob.model.options["assembled_jac_type"] = "csc" - prob.model.linear_solver = om.LinearRunOnce() - - prob.setup() - prob.set_val("climb2.states:mass", climb2.interp("mass", ys=[174219, 171481])) - prob.set_val("climb2.controls:throttle", - climb2.interp("throttle", ys=[1.0, 1.0])) - prob.set_val( - "climb2.states:altitude", climb2.interp( - Dynamic.Mission.ALTITUDE, ys=[ - 10000, 37500])) - prob.set_val("climb2.states:distance", climb2.interp( - Dynamic.Mission.DISTANCE, ys=[15, 154])) - prob.set_val("climb2.t_duration", 1500) - prob.set_val("climb2.t_initial", 0) - - return prob - - -def setup_driver(prob): - prob.driver = om.pyOptSparseDriver() - prob.driver.options["optimizer"] = "SNOPT" - prob.driver.opt_settings["Major iterations limit"] = 100 - prob.driver.opt_settings["Major optimality tolerance"] = 5.0e-3 - prob.driver.opt_settings["Major feasibility tolerance"] = 1e-6 - prob.driver.opt_settings["iSumm"] = 6 - prob.driver.declare_coloring() - prob.set_solver_print(level=0) - - -def make_recorder_filepaths(phasename, outdir): - return ( - os.path.join(outdir, f"{phasename}_prob.sql"), - os.path.join(outdir, f"{phasename}_sim.sql"), - ) - - -def run_phase(phasename, prob, outdir=def_outdir): - os.makedirs(outdir, exist_ok=True) - prob_rec_fp = make_recorder_filepaths(phasename, outdir)[0] - - recorder = om.SqliteRecorder(prob_rec_fp) - prob.driver.add_recorder(recorder) - prob.driver.recording_options["includes"] = ["*timeseries*"] - prob.add_recorder(recorder) - - print("\nRunning driver...\n") - prob.run_driver() - - prob.record("final") - prob.cleanup() - - return prob - - -def sim_phase(phasename, prob, outdir=def_outdir): - os.makedirs(outdir, exist_ok=True) - sim_rec_fp = make_recorder_filepaths(phasename, outdir)[1] - - print("\nSimulating...\n") - sys = getattr(prob.model, phasename) - prob.set_solver_print(level=-1) - sys.rhs_all.prop.set_solver_print(level=-1, depth=1e99) - simprob = sys.simulate(atol=1e-6, rtol=1e-6, record_file=sim_rec_fp) - - return simprob - - -def load_phase(phasename, outdir=def_outdir): - for fp in make_recorder_filepaths(phasename, outdir): - cr = om.CaseReader(fp) - yield cr.get_case("final") - - -def load_phase_nosim(phasename, outdir=def_outdir): - fp = make_recorder_filepaths(phasename, outdir)[0] - cr = om.CaseReader(fp) - return cr.get_case("final") - - -def gen_plots(phasename, probdata, simdata, plot_dir, show=False): - gaspdata = pd.read_csv(os.path.join(gaspdata_dir, f"{phasename}_data.csv")) - # gasp data in hours, convert to seconds, reference to 0 - gaspdata["TIME"] = 3600 * (gaspdata["TIME"] - gaspdata["TIME"][0]) - - def gen_plot(title, varnames): - fig, axs = plt.subplots(len(varnames), 1, sharex=True) - fig.suptitle(title) - - if len(varnames) == 1: - axs = [axs] - - gaspname, path, units = varinfo["time"] - path = f"{phasename}.timeseries.{path}" - t_solved = probdata.get_val(path, units=units) - if simdata: - t_sim = simdata.get_val(path, units=units) - t_gasp = gaspdata[gaspname] - - for ax, varname in zip(axs, varnames): - gaspname, path, units = varinfo[varname] - path = f"{phasename}.timeseries.{path}" - ax.plot(t_solved, probdata.get_val(path, units=units), "bo", label="opt") - if simdata: - ax.plot(t_sim, simdata.get_val(path, units=units), "b--", label="sim") - if gaspname is not None: - ax.plot(t_gasp, gaspdata[gaspname], "k-", label="GASP") - ylabel = f"{varname}" - if units: - ylabel += f" ({units})" - ax.set_ylabel(ylabel) - - axs[0].legend() - axs[-1].set_xlabel("time (s)") - - plt.tight_layout() - - return fig - - gen_plot("States", [Dynamic.Mission.ALTITUDE, "mass", Dynamic.Mission.DISTANCE]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_states.pdf")) - - gen_plot("Speeds", [Dynamic.Mission.MACH, "EAS"]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_speeds.pdf")) - - gen_plot("Angles", ["alpha", Dynamic.Mission.FLIGHT_PATH_ANGLE]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_angles.pdf")) - - fig = gen_plot("Constraints", ["TAS_violation", "theta"]) - fig.axes[0].axhline(theta_max, color="r", linestyle=":") - fig.axes[1].axhline(TAS_violation_max, color="r", linestyle=":") - plt.savefig(os.path.join(plot_dir, f"{phasename}_constraints.pdf")) - - gen_plot("Aero", ["CL", "CD"]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_aero.pdf")) - - gen_plot("Thrust", [Dynamic.Mission.THRUST_TOTAL]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_thrust.pdf")) - - if show: - plt.show() diff --git a/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py b/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py deleted file mode 100644 index d9197c50b..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py +++ /dev/null @@ -1,297 +0,0 @@ -import os - -import dymos as dm -import matplotlib.pyplot as plt -import openmdao.api as om -import pandas as pd - -from aviary.mission.gasp_based.ode.params import ParamPort -from aviary.mission.gasp_based.phases.climb_phase import get_climb -from aviary.subsystems.propulsion.engine_deck import EngineDeck -from aviary.variable_info.options import get_option_defaults -from aviary.utils.preprocessors import preprocess_propulsion -from aviary.utils.functions import get_path -from aviary.variable_info.variables import Dynamic - -thisdir = os.path.dirname(__file__) -def_outdir = os.path.join(thisdir, "output") - -gaspdata_dir = os.path.join(thisdir, "..", "..", "problem", - "large_single_aisle_validation_data") - -theta_max = 15 -TAS_violation_max = 0 -use_surrogate = False - -ode_args = {} - -# name: (gaspname, path, units) -varinfo = { - "time": ("TIME", "time", "s"), - Dynamic.Mission.ALTITUDE: ("ALT", "states:altitude", "ft"), - "mass": ("MASS", "states:mass", "lbm"), - Dynamic.Mission.DISTANCE: ("RANGE", "states:distance", "NM"), - Dynamic.Mission.MACH: ("MACH", Dynamic.Mission.MACH, None), - "EAS": ("EAS", "EAS", "kn"), - "alpha": ("ALPHA", "alpha", "deg"), - Dynamic.Mission.FLIGHT_PATH_ANGLE: ("GAMMA", Dynamic.Mission.FLIGHT_PATH_ANGLE, "deg"), - "theta": ("FUSANGLE", "theta", "deg"), - "TAS_violation": (None, "TAS_violation", "kn"), - "CL": ("CL", "CL", None), - "CD": ("CD", "CD", None), - Dynamic.Mission.THRUST_TOTAL: ("THRUST", Dynamic.Mission.THRUST_TOTAL, "lbf"), -} - - -def setup_climb1(): - prob = om.Problem(model=om.Group(), name="main") - setup_driver(prob) - - filename = 'models/engines/turbofan_28k.deck' - filename = get_path(filename) - option_defaults = get_option_defaults() - engine = EngineDeck(name='engine', - options=option_defaults - ) - preprocess_propulsion(option_defaults, [engine]) - - ode_args["aviary_options"] = option_defaults - - transcription = dm.Radau(num_segments=1, order=5, compressed=False) - climb1 = get_climb( - ode_args=ode_args, - transcription=transcription, - fix_initial=True, - alt_lower=0, - alt_upper=11000, - mass_lower=0, - mass_upper=200_000, - mass_ref=175.e3, - mass_ref0=174.e3, - distance_lower=0, - distance_upper=300, - time_initial_bounds=(0, 0), - duration_bounds=(1.1, 36_000), - duration_ref=1000., - EAS_target=250, - mach_cruise=0.8, - target_mach=False, - final_alt=10.e3, - alt_ref=10.e3, - distance_ref=300, - ) - prob.model.add_subsystem(name="climb1", subsys=climb1) - - # add all params and promote them to prob.model level - # TODO: paramport - ParamPort.promote_params(prob.model, phases=["climb1"]) - ParamPort.set_default_vals(prob.model) - - climb1.add_objective("time", loc="final", ref=1000.) - # climb1.add_design_var("rhs_all.throttle", lower=0., upper=1.) - - prob.model.options["assembled_jac_type"] = "csc" - prob.model.linear_solver = om.LinearRunOnce() - - prob.setup() - - prob.set_val("climb1.states:mass", climb1.interp("mass", ys=[174878, 174219])) - prob.set_val( - "climb1.states:altitude", climb1.interp( - Dynamic.Mission.ALTITUDE, ys=[ - 500, 10000])) - # prob.set_val( - # "climb1.rhs_all.throttle", climb1.interp( - # Dynamic.Mission.ALTITUDE, ys=[ - # 0.40, 1.0])) - prob.set_val("climb1.states:distance", climb1.interp( - Dynamic.Mission.DISTANCE, ys=[2, 15])) - prob.set_val("climb1.t_duration", 1000) - prob.set_val("climb1.t_initial", 0) - - return prob - - -def setup_climb2(): - prob = om.Problem(model=om.Group(), name="main") - - setup_driver(prob) - - ode_args["aviary_options"] = get_option_defaults() - - transcription = dm.Radau(num_segments=3, order=3, compressed=False) - climb2 = get_climb( - ode_args=ode_args, - transcription=transcription, - fix_initial=True, - alt_lower=9000, - alt_upper=60000, - mass_lower=0, - mass_upper=200_000, - distance_lower=0, - distance_upper=300, - time_initial_bounds=(0, 0), - duration_bounds=(2, 36_000), - EAS_target=270, - mach_cruise=0.8, - target_mach=True, - final_alt=37500, - alt_ref=40000, - mass_ref=200000, - distance_ref=300, - required_available_climb_rate=300, - ) - prob.model.add_subsystem(name="climb2", subsys=climb2) - - # fixed initial mass, so max final mass is equivalent to min fuel burn - climb2.add_objective("mass", loc="final", ref=-1) - - # add all params and promote them to prob.model level - ParamPort.promote_params(prob.model, phases=["climb2"]) - ParamPort.set_default_vals(prob.model) - - prob.model.options["assembled_jac_type"] = "csc" - prob.model.linear_solver = om.LinearRunOnce() - - prob.setup() - prob.set_val("climb2.states:mass", climb2.interp("mass", ys=[174219, 171481])) - prob.set_val( - "climb2.states:altitude", climb2.interp( - Dynamic.Mission.ALTITUDE, ys=[ - 10000, 37500])) - prob.set_val("climb2.states:distance", climb2.interp( - Dynamic.Mission.DISTANCE, ys=[15, 154])) - prob.set_val("climb2.t_duration", 1500) - prob.set_val("climb2.t_initial", 0) - - return prob - - -def setup_driver(prob): - prob.driver = om.pyOptSparseDriver() - prob.driver.options["optimizer"] = "SNOPT" - prob.driver.opt_settings["Major iterations limit"] = 50 - prob.driver.opt_settings["Major optimality tolerance"] = 5.0e-3 - prob.driver.opt_settings["Major feasibility tolerance"] = 1e-6 - prob.driver.opt_settings["iSumm"] = 6 - prob.driver.declare_coloring() - prob.set_solver_print(level=0) - - -def make_recorder_filepaths(phasename, outdir): - return ( - os.path.join(outdir, f"{phasename}_prob.sql"), - os.path.join(outdir, f"{phasename}_sim.sql"), - ) - - -def run_phase(phasename, prob, outdir=def_outdir): - os.makedirs(outdir, exist_ok=True) - prob_rec_fp = make_recorder_filepaths(phasename, outdir)[0] - - recorder = om.SqliteRecorder(prob_rec_fp) - prob.driver.add_recorder(recorder) - prob.driver.recording_options["includes"] = ["*timeseries*"] - prob.add_recorder(recorder) - - print("\nRunning driver...\n") - prob.run_driver() - - prob.record("final") - prob.cleanup() - - return prob - - -def sim_phase(phasename, prob, outdir=def_outdir): - os.makedirs(outdir, exist_ok=True) - sim_rec_fp = make_recorder_filepaths(phasename, outdir)[1] - - print("\nSimulating...\n") - sys = getattr(prob.model, phasename) - prob.set_solver_print(level=-1) - sys.rhs_all.prop.set_solver_print(level=-1, depth=1e99) - simprob = sys.simulate(atol=1e-6, rtol=1e-6, record_file=sim_rec_fp) - - return simprob - - -def load_phase(phasename, outdir=def_outdir): - for fp in make_recorder_filepaths(phasename, outdir): - cr = om.CaseReader(fp) - yield cr.get_case("final") - - -def load_phase_nosim(phasename, outdir=def_outdir): - fp = make_recorder_filepaths(phasename, outdir)[0] - cr = om.CaseReader(fp) - return cr.get_case("final") - - -def gen_plots(phasename, probdata, simdata, plot_dir, show=False): - gaspdata = pd.read_csv(os.path.join(gaspdata_dir, f"{phasename}_data.csv")) - # gasp data in hours, convert to seconds, reference to 0 - gaspdata["TIME"] = 3600 * (gaspdata["TIME"] - gaspdata["TIME"][0]) - - def gen_plot(title, varnames): - fig, axs = plt.subplots(len(varnames), 1, sharex=True) - fig.suptitle(title) - - if len(varnames) == 1: - axs = [axs] - - gaspname, path, units = varinfo["time"] - path = f"{phasename}.timeseries.{path}" - t_solved = probdata.get_val(path, units=units) - if simdata: - t_sim = simdata.get_val(path, units=units) - t_gasp = gaspdata[gaspname] - - for ax, varname in zip(axs, varnames): - gaspname, path, units = varinfo[varname] - path = f"{phasename}.timeseries.{path}" - ax.plot(t_solved, probdata.get_val(path, units=units), "bo", label="opt") - if simdata: - ax.plot(t_sim, simdata.get_val(path, units=units), "b--", label="sim") - if gaspname is not None: - ax.plot(t_gasp, gaspdata[gaspname], "k-", label="GASP") - ylabel = f"{varname}" - if units: - ylabel += f" ({units})" - ax.set_ylabel(ylabel) - - axs[0].legend() - axs[-1].set_xlabel("time (s)") - - plt.tight_layout() - - return fig - - gen_plot("States", [Dynamic.Mission.ALTITUDE, "mass", Dynamic.Mission.DISTANCE]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_states.pdf")) - - gen_plot("Speeds", [Dynamic.Mission.MACH, "EAS"]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_speeds.pdf")) - - gen_plot("Angles", ["alpha", Dynamic.Mission.FLIGHT_PATH_ANGLE]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_angles.pdf")) - - fig = gen_plot("Constraints", ["TAS_violation", "theta"]) - fig.axes[0].axhline(theta_max, color="r", linestyle=":") - fig.axes[1].axhline(TAS_violation_max, color="r", linestyle=":") - plt.savefig(os.path.join(plot_dir, f"{phasename}_constraints.pdf")) - - gen_plot("Aero", ["CL", "CD"]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_aero.pdf")) - - gen_plot("Thrust", [Dynamic.Mission.THRUST_TOTAL]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_thrust.pdf")) - - if show: - plt.show() - - -if __name__ == "__main__": - climb1 = setup_climb1() - setup_driver(climb1) - run_phase('climb1', climb1) diff --git a/aviary/mission/gasp_based/phases/run_phases/run_conventional_problem.py b/aviary/mission/gasp_based/phases/run_phases/run_conventional_problem.py deleted file mode 100644 index 603c5bc95..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_conventional_problem.py +++ /dev/null @@ -1,1255 +0,0 @@ -import os - -import dymos as dm -import numpy as np -import openmdao.api as om -from packaging import version - -if version.parse(dm.__version__) <= version.parse("1.6.1"): - updated_dymos = False -else: - updated_dymos = True - -from aviary.constants import RHO_SEA_LEVEL_ENGLISH -from aviary.mission.gasp_based.ode.breguet_cruise_ode import \ - BreguetCruiseODESolution -from aviary.mission.gasp_based.ode.flight_path_ode import FlightPathODE -from aviary.mission.gasp_based.ode.params import ParamPort -from aviary.mission.gasp_based.phases.v_rotate_comp import VRotateComp -from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Aircraft, Dynamic - -TARGET_RANGE = 3000 -CRUISE_ALT = 37500. - - -def run_conventional_problem(make_plots=True, optimizer="IPOPT"): - - options = get_option_defaults() - - ode_args = dict( - aviary_options=options - ) - - # - # GROUNDROLL TO VROTATE - # - # Note: - # VRotate is computed in a post-trajectory analysis, and the difference between computed Vrot and - # the final speed in the groundroll phase and enforced downstream of the trajectory. - # - groundroll_trans = dm.Radau( - num_segments=5, order=3, compressed=True, solve_segments=False - ) - - groundroll = dm.Phase( - ode_class=FlightPathODE, - ode_init_kwargs=dict(ode_args, ground_roll=True), - transcription=groundroll_trans, - ) - - groundroll.set_time_options( - fix_initial=True, - fix_duration=False, - units="s", - targets="t_curr", - duration_bounds=(20, 100), - duration_ref=1) - - groundroll.set_state_options( - "TAS", - fix_initial=True, - fix_final=False, - lower=1.0E-6, - upper=1000, - ref=1, - defect_ref=1) - - groundroll.set_state_options( - "mass", - fix_initial=True, - fix_final=False, - lower=1, - upper=195_000, - ref=1000, - defect_ref=1000) - - groundroll.set_state_options( - Dynamic.Mission.DISTANCE, - fix_initial=True, - fix_final=False, - lower=0, - upper=100_000, - ref=1, - defect_ref=1) - - groundroll.add_parameter(Dynamic.Mission.ALTITUDE, opt=False, - static_target=False, val=0.0, units='ft') - groundroll.add_parameter( - Dynamic.Mission.FLIGHT_PATH_ANGLE, opt=False, static_target=False, val=0.0, units='rad') - groundroll.add_parameter("t_init_gear", units="s", - static_target=True, opt=False, val=50) - groundroll.add_parameter("t_init_flaps", units="s", - static_target=True, opt=False, val=50) - - # - # ROTATION TO TAKEOFF - # - - rotation_trans = dm.Radau( - num_segments=5, order=3, compressed=True, solve_segments=False - ) - - rotation = dm.Phase( - ode_class=FlightPathODE, - # Use the standard ode_args and update it for ground_roll dynamics - ode_init_kwargs=dict(ode_args, ground_roll=True), - transcription=rotation_trans, - ) - - rotation.set_time_options( - fix_initial=False, - fix_duration=False, - units="s", - targets="t_curr", - duration_bounds=(1, 100), - duration_ref=1.0, - ) - - rotation.add_parameter(Dynamic.Mission.ALTITUDE, opt=False, - static_target=False, val=0.0, units='ft') - rotation.add_parameter(Dynamic.Mission.FLIGHT_PATH_ANGLE, - opt=False, static_target=False, val=0.0, units='rad') - rotation.add_parameter('alpha_rate', opt=False, - static_target=True, val=3.33, units='deg/s') - rotation.add_parameter("t_init_gear", units="s", - static_target=True, opt=False, val=50) - rotation.add_parameter("t_init_flaps", units="s", - static_target=True, opt=False, val=50) - - # State alpha is not defined in the ODE, taken from the parameter "alpha_rate" - rotation.add_state( - "alpha", - units="rad", - rate_source="alpha_rate", - fix_initial=False, - fix_final=False, - lower=0.0, - upper=np.radians(25), - ref=1.0) - - rotation.set_state_options( - "TAS", - fix_initial=False, - fix_final=False, - lower=1.0, - upper=1000.0, - ref=100.0, - defect_ref=100.0) - - rotation.set_state_options( - "mass", - fix_initial=False, - fix_final=False, - lower=1.0, - upper=190_000.0, - ref=1000.0, - defect_ref=1000.0,) - - rotation.set_state_options( - Dynamic.Mission.DISTANCE, - fix_initial=False, - fix_final=False, - lower=0, - upper=10.e3, - ref=100, - defect_ref=100) - - # boundary/path constraints + controls - rotation.add_boundary_constraint( - "normal_force", loc="final", equals=0, units="lbf", ref=1000.0) - - rotation.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") - rotation.add_timeseries_output("normal_force") - rotation.add_timeseries_output(Dynamic.Mission.MACH) - rotation.add_timeseries_output("EAS", units="kn") - rotation.add_timeseries_output(Dynamic.Mission.LIFT) - rotation.add_timeseries_output("CL") - rotation.add_timeseries_output("CD") - rotation.add_timeseries_output("fuselage_pitch", output_name="theta", units="deg") - - # - # ASCENT TO GEAR RETRACTION - # - ascent0_tx = dm.Radau(num_segments=3, order=3, compressed=True, solve_segments=False) - ascent_to_gear_retract = dm.Phase( - ode_class=FlightPathODE, ode_init_kwargs=ode_args, transcription=ascent0_tx) - - ascent_to_gear_retract.set_time_options( - units="s", - targets="t_curr", - fix_initial=False, - fix_duration=False, - initial_bounds=(10, 50), - duration_bounds=(1, 50)) - - # Rate sources and units of states are set with tags in AscentEOM - ascent_to_gear_retract.set_state_options( - Dynamic.Mission.FLIGHT_PATH_ANGLE, - fix_initial=False, - fix_final=False, - lower=0, - upper=0.5, - ref=1.0, - defect_ref=100.0) - - ascent_to_gear_retract.set_state_options( - Dynamic.Mission.ALTITUDE, - fix_initial=False, - fix_final=False, - lower=0, - upper=500, - ref=100, - defect_ref=10000) - - ascent_to_gear_retract.set_state_options( - "TAS", - fix_initial=False, - fix_final=False, - lower=1, - upper=1000, - ref=100, - defect_ref=1000) - - ascent_to_gear_retract.set_state_options( - "mass", - fix_initial=False, - fix_final=False, - lower=1, - upper=None, - ref=175_000, - defect_ref=175_000) - - ascent_to_gear_retract.set_state_options( - Dynamic.Mission.DISTANCE, - fix_initial=False, - fix_final=False, - lower=0, - upper=15_000, - ref=5280, - defect_ref=5280) - - # Targets are not needed when there is a top-level ODE input with the same - # name as the parameter, state, or control - ascent_to_gear_retract.add_parameter( - "t_init_gear", units="s", static_target=True, opt=False, val=50) - ascent_to_gear_retract.add_parameter( - "t_init_flaps", units="s", static_target=True, opt=False, val=50) - - # Using Radau, we need to apply rate continuity if desired for controls even when the transcription is compressed. - # The final value of a control in a segment is interpolated, not a design variable. - # Note we specify units as radians here, since alpha inputs in the ODE are - # in degrees. - if updated_dymos: - ascent_to_gear_retract.add_control("alpha", - continuity_scaler=1.0E-2, - units="rad", - val=0.0, # continuity=True, rate_continuity=False, - opt=True, - lower=np.radians(-30), - upper=np.radians(30), - ref=0.01) - else: - ascent_to_gear_retract.add_control("alpha", - units="rad", - val=0.0, # continuity=True, rate_continuity=False, - opt=True, - lower=np.radians(-30), - upper=np.radians(30), - ref=0.01) - - # boundary/path constraints + controls - # Final altitude can be a linear constraint, since the final value of - # altitude is a design variable. - ascent_to_gear_retract.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, - loc="final", - equals=50, - units="ft", - ref=1.0, - ref0=0.0, - linear=False) - - # Load factor can be treated as a linear constraint as long as i_wing is - # not a design variable. - ascent_to_gear_retract.add_path_constraint( - "load_factor", - lower=0.0, - upper=1.10, - scaler=1.0E-6 / 0.001, - linear=False) - - ascent_to_gear_retract.add_path_constraint( - "fuselage_pitch", - constraint_name="theta", - lower=0, - upper=15, - units="deg", - scaler=1.0E-6 / 0.001, - linear=False) - - # - # ASCENT TO FLAP RETRACTION - # - ascent1_tx = dm.Radau(num_segments=5, order=3, - compressed=True, solve_segments=False) - ascent_to_flap_retract = dm.Phase( - ode_class=FlightPathODE, ode_init_kwargs=ode_args, transcription=ascent1_tx) - - ascent_to_flap_retract.set_time_options(units="s", targets="t_curr", - fix_initial=False, fix_duration=False, - initial_bounds=(1, 500), - duration_bounds=(0.5, 100)) - - # Rate sources and units of states are set with tags in AscentEOM - ascent_to_flap_retract.set_state_options( - Dynamic.Mission.FLIGHT_PATH_ANGLE, - fix_initial=False, - fix_final=False, - lower=-0.2618, - upper=0.43633, - ref=0.43633, - defect_ref=0.43633) - - ascent_to_flap_retract.set_state_options( - Dynamic.Mission.ALTITUDE, - fix_initial=False, - fix_final=False, - lower=0, - upper=500, - ref=100, - defect_ref=100) - - ascent_to_flap_retract.set_state_options( - "TAS", - fix_initial=False, - fix_final=False, - lower=1, - upper=1000, - ref=100, - defect_ref=100) - - ascent_to_flap_retract.set_state_options( - "mass", - fix_initial=False, - fix_final=False, - lower=1, - upper=None, - ref=175_000, - defect_ref=175_000) - - ascent_to_flap_retract.set_state_options( - Dynamic.Mission.DISTANCE, - fix_initial=False, - fix_final=False, - lower=0, - upper=50_000, - ref=5280, - defect_ref=5280) - - # Targets are not needed when there is a top-level ODE input with the same - # name as the parameter, state, or control - ascent_to_flap_retract.add_parameter( - "t_init_gear", units="s", static_target=True, opt=False, val=100) - ascent_to_flap_retract.add_parameter( - "t_init_flaps", units="s", static_target=True, opt=False, val=100) - - # Using Radau, we need to apply rate continuity if desired for controls even when the transcription is compressed. - # The final value of a control in a segment is interpolated, not a design variable. - # Note we specify units as radians here, since alpha inputs in the ODE are - # in degrees. - if updated_dymos: - ascent_to_flap_retract.add_control("alpha", - continuity_scaler=1.0E-2, - units="rad", - val=0.0, - continuity=True, - rate_continuity=False, - opt=True, - lower=np.radians(-14), - upper=np.radians(14), - ref=0.01) - else: - ascent_to_flap_retract.add_control("alpha", - units="rad", - val=0.0, - continuity=True, - rate_continuity=False, - opt=True, - lower=np.radians(-14), - upper=np.radians(14), - ref=0.01) - - # boundary/path constraints + controls - # Final altitude can be a linear constraint, since the final value of - # altitude is a design variable. - ascent_to_flap_retract.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, - loc="final", - equals=400, - units="ft", - ref=1.0, - ref0=0.0, - linear=False, - ) - - # Load factor can be treated as a linear constraint as long as i_wing is - # not a design variable. - ascent_to_flap_retract.add_path_constraint( - "load_factor", - lower=0.0, - upper=1.10, - scaler=1.0E-6 / 0.001, - linear=False) - - ascent_to_flap_retract.add_path_constraint( - "fuselage_pitch", - constraint_name="theta", - lower=0, - upper=15, - units="deg", - scaler=1.0E-6 / 0.001, - linear=False) - - # - # ASCENT TO CLEAN AERO CONFIG - # - ascent2_tx = dm.Radau(num_segments=3, order=3, compressed=True, solve_segments=False) - ascent_to_clean_aero = dm.Phase( - ode_class=FlightPathODE, ode_init_kwargs=ode_args, transcription=ascent2_tx) - - ascent_to_clean_aero.set_time_options(units="s", targets="t_curr", - fix_initial=False, fix_duration=False, - initial_bounds=(1, 500), - duration_bounds=(0.5, 100)) - - # Rate sources and units of states are set with tags in AscentEOM - ascent_to_clean_aero.set_state_options( - Dynamic.Mission.FLIGHT_PATH_ANGLE, - fix_initial=False, - fix_final=False, - lower=-0.2618, - upper=0.43633, - ref=0.43633, - defect_ref=0.43633) - - ascent_to_clean_aero.set_state_options( - Dynamic.Mission.ALTITUDE, - fix_initial=False, - fix_final=False, - lower=0, - upper=500, - ref=100, - defect_ref=100) - - ascent_to_clean_aero.set_state_options( - "TAS", - fix_initial=False, - fix_final=False, - lower=0, - upper=1000, - ref=100, - defect_ref=100) - - ascent_to_clean_aero.set_state_options( - "mass", - fix_initial=False, - fix_final=False, - lower=1, - upper=None, - ref=175_000, - defect_ref=175_000) - - ascent_to_clean_aero.set_state_options( - Dynamic.Mission.DISTANCE, - fix_initial=False, - fix_final=False, - lower=0, - upper=30.e3, - ref=5_280, - defect_ref=5_280) - - # Targets are not needed when there is a top-level ODE input with the same - # name as the parameter, state, or control - ascent_to_clean_aero.add_parameter( - "t_init_gear", units="s", static_target=True, opt=False) - ascent_to_clean_aero.add_parameter( - "t_init_flaps", units="s", static_target=True, opt=False) - - # Using Radau, we need to apply rate continuity if desired for controls even when the transcription is compressed. - # The final value of a control in a segment is interpolated, not a design variable. - # Note we specify units as radians here, since alpha inputs in the ODE are - # in degrees. - ascent_to_clean_aero.add_polynomial_control( - "alpha", order=1, - units="rad", - val=0.0, # continuity=True, rate_continuity=True, - opt=True, - lower=np.radians(-14), - upper=np.radians(14), - ref=0.01) - - # boundary/path constraints + controls - # Final altitude can be a linear constraint, since the final value of - # altitude is a design variable. - ascent_to_clean_aero.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, - loc="final", - equals=500, - units="ft", - ref=1.0, - ref0=0.0, - linear=False) - - # Ensure flaps are fully retracted - # Note setting equals=0.0 here will result in a failure of the optimization, since flap_factor approaches - # zero asymptotically. - ascent_to_clean_aero.add_boundary_constraint( - "flap_factor", - loc="final", - upper=1.0E-3, - ref=1.0, - ref0=0.0, - linear=False) - - # Load factor can be treated as a linear constraint as long as i_wing is - # not a design variable. - ascent_to_clean_aero.add_path_constraint( - "load_factor", - lower=0.0, - upper=1.10, - scaler=1.0E-6 / 0.001, - linear=False) - - ascent_to_clean_aero.add_path_constraint( - "fuselage_pitch", - constraint_name="theta", - lower=0, - upper=15, - units="deg", - scaler=1.0E-6 / 0.001, - linear=False) - - # - # ACCEL CONFIG - # - accel2_tx = dm.Radau(num_segments=5, order=3, compressed=True, solve_segments=False) - accel_ode_args = ode_args.deepcopy() - accel = dm.Phase(ode_class=FlightPathODE, - ode_init_kwargs=accel_ode_args, transcription=accel2_tx) - - accel.set_time_options(units="s", targets="t_curr", - fix_initial=False, fix_duration=False, - initial_bounds=(1, 500), - duration_bounds=(0.5, 10)) - - # Rate sources and units of states are set with tags in AscentEOM - accel.set_state_options( - Dynamic.Mission.FLIGHT_PATH_ANGLE, - fix_initial=False, - fix_final=False, - lower=0.0, - ref=1.0e1, - defect_ref=1.0e1) - - accel.set_state_options( - Dynamic.Mission.ALTITUDE, - fix_initial=False, - fix_final=False, - units="ft", - ref0=495, - ref=520e1, - defect_ref=500e1, - lower=495, - upper=520) - - accel.set_state_options( - "TAS", - fix_initial=False, - fix_final=False, - lower=1, - upper=1000, - units="kn", - ref=250e1, - defect_ref=250e1) - - accel.set_state_options( - "mass", - fix_initial=False, - fix_final=False, - lower=1, - upper=500_000, - ref=175_000e1, - defect_ref=175_000e1) - - accel.set_state_options( - Dynamic.Mission.DISTANCE, - fix_initial=False, - lower=0, - upper=None, - units="ft", - ref=1000e1, - defect_ref=1000e1) - - # Using Radau, we need to apply rate continuity if desired for controls even when the transcription is compressed. - # The final value of a control in a segment is interpolated, not a design variable. - # Note we specify units as radians here, since alpha inputs in the ODE are - # in degrees. - accel.add_polynomial_control("alpha", - order=2, - opt=True, - units="rad", - val=0.0, - lower=np.radians(-8), - upper=np.radians(8)) - - # boundary/path constraints + controls - # Final altitude can be a linear constraint, since the final value of - # altitude is a design variable. - accel.add_boundary_constraint("EAS", loc="final", equals=250., ref=250, units="kn") - - accel.add_parameter("t_init_gear", units="s", - static_target=True, opt=False, val=32.3) - accel.add_parameter("t_init_flaps", units="s", - static_target=True, opt=False, val=44.0) - - climb_ode_args = ode_args.deepcopy() - climb_ode_args['clean'] = True - transcription = dm.Radau(num_segments=11, order=3, compressed=True) - constant_quantity = 'EAS' - constant_EAS_climb = dm.Phase( - ode_class=FlightPathODE, - ode_init_kwargs=climb_ode_args, - transcription=transcription) - - constant_EAS_climb.set_time_options( - fix_initial=False, initial_bounds=( - 0, 1000), duration_bounds=( - 20, 1000), units="s", duration_ref=100) - - constant_EAS_climb.set_state_options( - "TAS", - fix_initial=False, - fix_final=False, - lower=1, - upper=1000, - units="kn", - ref=250, - defect_ref=250) - - constant_EAS_climb.set_state_options( - "mass", - fix_initial=False, - fix_final=False, - lower=1, - upper=None, - units="lbm", - ref=200000, - defect_ref=200000) - - constant_EAS_climb.set_state_options( - Dynamic.Mission.DISTANCE, - fix_initial=False, - fix_final=False, - lower=0, - upper=None, - units="ft", - ref=10000, - defect_ref=10000) - - if constant_quantity == 'EAS': - constant_EAS_climb.set_state_options( - Dynamic.Mission.ALTITUDE, - fix_initial=False, - fix_final=False, - lower=400, - upper=20000, - units="ft", - ref=20.e3, - defect_ref=20.e3) - else: - constant_EAS_climb.set_state_options( - Dynamic.Mission.ALTITUDE, - fix_initial=False, - fix_final=False, - lower=9000, - upper=50000, - units="ft", - ref=40000, - defect_ref=40000) - - constant_EAS_climb.set_state_options( - Dynamic.Mission.FLIGHT_PATH_ANGLE, - fix_initial=False, - fix_final=False, - units="rad", - lower=0.0, - ref=1.0, - defect_ref=1.0) - - constant_EAS_climb.add_control("alpha", opt=True, units="rad", val=0.0, - lower=np.radians(-14), upper=np.radians(14), ref=0.01, - rate_continuity=True, rate2_continuity=False) - - if updated_dymos: - constant_EAS_climb.add_control("alpha", - continuity_scaler=1.0E-2, - rate_continuity=False, - rate2_continuity=False, - opt=True, - units="rad", - val=0.0, - lower=np.radians(-14), - upper=np.radians(14), - ref=0.01) - else: - constant_EAS_climb.add_control("alpha", - rate_continuity=False, - rate2_continuity=False, - opt=True, - units="rad", - val=0.0, - lower=np.radians(-14), - upper=np.radians(14), - ref=0.01) - - # constant_EAS_climb.add_polynomial_control("alpha", order=1, opt=True, units="rad", lower=-np.radians(14), upper=np.radians(14), ref=0.01) - - if constant_quantity == 'EAS': - constant_EAS_climb.add_path_constraint( - "EAS", lower=249.9, upper=250.1, ref=350., units="kn") - # constant_EAS_climb.add_path_constraint("EAS", equals=350., ref=350., units="kn") - constant_EAS_climb.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc="final", equals=10.e3, ref=10.e3, units="ft") - else: - constant_EAS_climb.add_path_constraint( - Dynamic.Mission.MACH, lower=0.799, upper=0.801, ref=1.e3) - constant_EAS_climb.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc="final", equals=37.5e3, ref=10.e3, units="ft") - - constant_EAS_climb.add_timeseries_output("EAS", output_name="EAS", units="kn") - constant_EAS_climb.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") - constant_EAS_climb.add_timeseries_output("alpha", output_name="alpha", units="deg") - constant_EAS_climb.add_timeseries_output("CL", output_name="CL", units="unitless") - constant_EAS_climb.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, - units="lbf") - constant_EAS_climb.add_timeseries_output("CD", output_name="CD", units="unitless") - - # - # CLIMB 2 (constrained EAS) - # - climb_ode_args = ode_args.deepcopy() - climb_ode_args['clean'] = True - transcription = dm.Radau(num_segments=5, order=3, compressed=True) - climb_to_mach = dm.Phase(ode_class=FlightPathODE, - ode_init_kwargs=climb_ode_args, transcription=transcription) - - climb_to_mach.set_time_options( - units="s", fix_initial=False, - initial_bounds=(1, 1.e3), - duration_bounds=(10., 1.e3)) - - # Rate sources and units of states are set with tags in AscentEOM - climb_to_mach.set_state_options( - "TAS", - fix_initial=False, - fix_final=False, - lower=1, - upper=1000, - units="kn", - ref=250, - defect_ref=250) - - climb_to_mach.set_state_options( - "mass", - fix_initial=False, - fix_final=False, - lower=1, - upper=None, - units="lbm", - ref=200000, - defect_ref=200000) - - climb_to_mach.set_state_options( - Dynamic.Mission.DISTANCE, - fix_initial=False, - fix_final=False, - lower=0, - upper=None, - units="ft", - ref=10000, - defect_ref=10000) - - climb_to_mach.set_state_options( - Dynamic.Mission.ALTITUDE, - fix_initial=False, - fix_final=False, - lower=9.e3, - upper=40.e3, - units="ft", - ref=20.e3, - defect_ref=40000) - - climb_to_mach.set_state_options( - Dynamic.Mission.FLIGHT_PATH_ANGLE, - fix_initial=False, - fix_final=False, - units="rad", - ref=1.0, - defect_ref=1.0) - - climb_to_mach.set_state_options( - Dynamic.Mission.DISTANCE, - fix_initial=False, - lower=0, - upper=None, - units="ft", - ref=1000, - defect_ref=1000) - - # Using Radau, we need to apply rate continuity if desired for controls even when the transcription is compressed. - # The final value of a control in a segment is interpolated, not a design variable. - # Note we specify units as radians here, since alpha inputs in the ODE are in degrees. - # climb_to_mach.add_polynomial_control("alpha", order=5, opt=True, units="rad", val=0.0, lower=np.radians(-14), upper=np.radians(14)) - if updated_dymos: - climb_to_mach.add_control("alpha", - continuity_scaler=1.0E-2, - rate_continuity=False, - rate2_continuity=False, - opt=True, - units="rad", - val=0.0, - lower=np.radians(-14), - upper=np.radians(14), - ref=0.01) - else: - climb_to_mach.add_control("alpha", - rate_continuity=False, - rate2_continuity=False, - opt=True, - units="rad", - val=0.0, - lower=np.radians(-14), - upper=np.radians(14), - ref=0.01) - - # boundary/path constraints + controls - climb_to_mach.add_path_constraint( - "EAS", lower=270., upper=270., ref=270., units='kn') - climb_to_mach.add_boundary_constraint(Dynamic.Mission.MACH, equals=0.8, loc="final") - - # - # CLIMB 3 (constant Mach) - # - climb_ode_args = ode_args.deepcopy() - climb_ode_args['clean'] = True - transcription = dm.Radau(num_segments=5, order=3, compressed=True) - climb_to_cruise = dm.Phase( - ode_class=FlightPathODE, - ode_init_kwargs=climb_ode_args, - transcription=transcription) - - climb_to_cruise.set_time_options( - units="s", fix_initial=False, - initial_bounds=(400, 1.5e3), - duration_bounds=(10., 1.e3)) - - # Rate sources and units of states are set with tags in AscentEOM - climb_to_cruise.set_state_options( - "TAS", - fix_initial=False, - fix_final=False, - lower=1, - upper=1000, - units="kn", - ref=250, - defect_ref=250) - - climb_to_cruise.set_state_options( - "mass", - fix_initial=False, - fix_final=False, - lower=1, - upper=None, - units="lbm", - ref=200000, - defect_ref=200000) - - climb_to_cruise.set_state_options( - Dynamic.Mission.DISTANCE, - fix_initial=False, - fix_final=False, - lower=0, - upper=None, - units="ft", - ref=10000, - defect_ref=10000) - - climb_to_cruise.set_state_options( - Dynamic.Mission.ALTITUDE, - fix_initial=False, - fix_final=False, - lower=15.e3, - upper=40.e3, - units="ft", - ref=20.e3, - defect_ref=40000) - - climb_to_cruise.set_state_options( - Dynamic.Mission.FLIGHT_PATH_ANGLE, - fix_initial=False, - fix_final=False, - units="rad", - lower=0, - ref=1.0, - defect_ref=1.0) - - climb_to_cruise.set_state_options( - Dynamic.Mission.DISTANCE, - fix_initial=False, - lower=0, - upper=None, - units="ft", - ref=1000, - defect_ref=1000) - - # Using Radau, we need to apply rate continuity if desired for controls even when the transcription is compressed. - # The final value of a control in a segment is interpolated, not a design variable. - # Note we specify units as radians here, since alpha inputs in the ODE are in degrees. - # climb_to_cruise.add_polynomial_control("alpha", order=5, opt=True, units="rad", val=0.0, lower=np.radians(-14), upper=np.radians(14)) - if updated_dymos: - climb_to_cruise.add_control("alpha", - continuity_scaler=1.0E-2, - rate_continuity=False, - rate2_continuity=False, - opt=True, - units="rad", - val=0.0, - lower=np.radians(-14), - upper=np.radians(14), - ref=0.01) - else: - climb_to_cruise.add_control("alpha", - rate_continuity=False, - rate2_continuity=False, - opt=True, - units="rad", - val=0.0, - lower=np.radians(-14), - upper=np.radians(14), - ref=0.01) - - # boundary/path constraints + controls - climb_to_cruise.add_path_constraint(Dynamic.Mission.MACH, equals=0.8, ref=1.) - climb_to_cruise.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc="final", equals=37.5e3, ref=30.e3, units="ft") - - # - # CRUISE: Analytic Breguet Range Phase - # - cruise_ode_args = ode_args.deepcopy() - cruise = dm.AnalyticPhase( - ode_class=BreguetCruiseODESolution, - ode_init_kwargs=cruise_ode_args, - num_nodes=20 - ) - - # Time here is really the independent variable through which we are integrating. - # In the case of the Breguet Range ODE, it's mass. - # We rely on mass being monotonically non-increasing across the phase. - cruise.set_time_options( - name='mass', - fix_initial=False, - fix_duration=False, - units="lbm", - targets="mass", - initial_bounds=(10.e3, 500_000), - initial_ref=100_000, - duration_bounds=(-50000, -10), - duration_ref=10000, - ) - - cruise.add_parameter(Dynamic.Mission.ALTITUDE, opt=False, val=CRUISE_ALT, units='ft') - cruise.add_parameter(Dynamic.Mission.MACH, opt=False, val=0.8) - cruise.add_parameter("wing_area", opt=False, val=1370, units="ft**2") - cruise.add_parameter("initial_distance", opt=False, val=0.0, - units="NM", static_target=True) - cruise.add_parameter("initial_time", opt=False, val=0.0, - units="s", static_target=True) - - cruise.add_timeseries_output("time", units="s") - - cruise.add_boundary_constraint( - Dynamic.Mission.DISTANCE, loc="final", equals=TARGET_RANGE, ref=TARGET_RANGE, units="NM") - - # - # PROBLEM DEFINITION - # - p = om.Problem() - traj = p.model.add_subsystem("traj", dm.Trajectory()) - traj.add_phase("groundroll", groundroll) - traj.add_phase("rotation", rotation) - traj.add_phase("ascent_to_gear_retract", ascent_to_gear_retract) - traj.add_phase("ascent_to_flap_retract", ascent_to_flap_retract) - traj.add_phase("ascent_to_clean_aero", ascent_to_clean_aero) - traj.add_phase(Dynamic.Mission.VELOCITY_RATE, accel) - traj.add_phase("constant_EAS_climb", constant_EAS_climb) - traj.add_phase("climb_to_mach", climb_to_mach) - traj.add_phase("climb_to_cruise", climb_to_cruise) - traj.add_phase("cruise", cruise) - - traj.add_linkage_constraint(phase_a='ascent_to_gear_retract', - phase_b='ascent_to_flap_retract', - var_a='time', - var_b='t_init_gear', - loc_a='final', - loc_b='initial', - connected=True) - - traj.add_linkage_constraint(phase_a='ascent_to_gear_retract', - phase_b='ascent_to_clean_aero', - var_a='time', - var_b='t_init_gear', - loc_a='final', - loc_b='initial', - connected=True) - - traj.add_linkage_constraint(phase_a='ascent_to_gear_retract', - phase_b=Dynamic.Mission.VELOCITY_RATE, - var_a='time', - var_b='t_init_gear', - loc_a='final', - loc_b='initial', - connected=True) - - traj.add_linkage_constraint(phase_a='ascent_to_flap_retract', - phase_b='ascent_to_clean_aero', - var_a='time', - var_b='t_init_flaps', - loc_a='final', - loc_b='initial', - connected=True) - - traj.add_linkage_constraint(phase_a='ascent_to_flap_retract', - phase_b=Dynamic.Mission.VELOCITY_RATE, - var_a='time', - var_b='t_init_flaps', - loc_a='final', - loc_b='initial', - connected=True) - - traj.add_linkage_constraint(phase_a='climb_to_cruise', - phase_b='cruise', - var_a='time', - var_b='initial_time', - loc_a='final', - loc_b='initial', - connected=True) - - traj.add_linkage_constraint(phase_a='climb_to_cruise', - phase_b='cruise', - var_a=Dynamic.Mission.DISTANCE, - var_b='initial_distance', - loc_a='final', - loc_b='initial', - connected=True) - - traj.add_linkage_constraint(phase_a='climb_to_cruise', - phase_b='cruise', - var_a=Dynamic.Mission.MACH, - var_b=Dynamic.Mission.MACH, - loc_a='final', - loc_b='initial', - connected=True) - - traj.add_linkage_constraint(phase_a='climb_to_cruise', - phase_b='cruise', - var_a=Dynamic.Mission.ALTITUDE, - var_b=Dynamic.Mission.ALTITUDE, - loc_a='final', - loc_b='initial', - connected=True) - - traj.add_linkage_constraint(phase_a='climb_to_cruise', - phase_b='cruise', - var_a='mass', - var_b='mass', - loc_a='final', - loc_b='initial', - connected=False) - - # 2. Continuity for rotation to first ascent phase. Altitude and flight - # path angle are not states on the ground. - traj.link_phases(['groundroll', 'rotation'], - vars=['time', 'TAS', 'mass', Dynamic.Mission.DISTANCE]) - - # Continuity for rotation to first ascent phase. Altitude and flight path - # angle are not states on the ground. - traj.link_phases(['rotation', 'ascent_to_gear_retract'], vars=[ - 'time', 'TAS', 'mass', Dynamic.Mission.DISTANCE, 'alpha', Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.ALTITUDE]) - - # 3. Enforce value continuity between all phases in ascent for time, - # states, and alpha control - traj.link_phases(['ascent_to_gear_retract', - 'ascent_to_flap_retract', - 'ascent_to_clean_aero', - Dynamic.Mission.VELOCITY_RATE], - vars=['time', - Dynamic.Mission.FLIGHT_PATH_ANGLE, - Dynamic.Mission.ALTITUDE, - 'TAS', - Dynamic.Mission.MASS, - Dynamic.Mission.DISTANCE, - 'alpha']) - - traj.link_phases([Dynamic.Mission.VELOCITY_RATE, - 'constant_EAS_climb', - 'climb_to_mach', - 'climb_to_cruise'], - vars=['time', - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MASS, - Dynamic.Mission.DISTANCE]) - - # Post trajectory analyses - p.model.add_subsystem("vrot_comp", VRotateComp()) - p.model.connect('traj.groundroll.states:mass', - 'vrot_comp.mass', src_indices=om.slicer[0, ...]) - - vrot_eq_comp = p.model.add_subsystem("vrot_eq_comp", om.EQConstraintComp()) - vrot_eq_comp.add_eq_output( - "v_rotate_error", - eq_units="kn", - lhs_name="v_rot_computed", - rhs_name="groundroll_v_final", - add_constraint=True) - - p.model.connect('vrot_comp.Vrot', 'vrot_eq_comp.v_rot_computed') - p.model.connect('traj.groundroll.states:TAS', - 'vrot_eq_comp.groundroll_v_final', src_indices=om.slicer[-1, ...]) - - for phase_name, phase in traj._phases.items(): - if "clean" in phase.options["ode_init_kwargs"] and not phase.options["ode_init_kwargs"]["clean"]: - phase.add_timeseries_output('gear_factor') - phase.add_timeseries_output('flap_factor') - phase.add_timeseries_output('normal_force') - phase.add_timeseries_output('fuselage_pitch') - # Add alpha to the timeseries as 'alpha' regardless of whether it is a - # control or polynomial control. - phase.add_timeseries_output('alpha', units='deg') - phase.add_timeseries_output(Dynamic.Mission.ALTITUDE, units='ft') - phase.add_timeseries_output(Dynamic.Mission.MACH) - phase.add_timeseries_output('EAS', units="kn") - phase.add_timeseries_output('TAS', units="kn") - phase.add_timeseries_output('mass', units="lbm") - phase.add_timeseries_output(Dynamic.Mission.DISTANCE, units="NM") - - # Setup the solvers - # We're roughtly twice as fast per iteration with a direct solver at the phase level. - for phase_name, phase in traj._phases.items(): - phase.linear_solver = om.DirectSolver(iprint=0, assemble_jac=True) - p.driver = om.pyOptSparseDriver() - - if optimizer == "SNOPT": - p.driver.options["optimizer"] = "SNOPT" - p.driver.opt_settings["iSumm"] = 6 - p.driver.opt_settings['Major step limit'] = 0.5 - p.driver.opt_settings['Major iterations limit'] = 100 - p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-5 - p.driver.opt_settings['Major optimality tolerance'] = 1.0E-5 - p.driver.opt_settings['Hessian updates'] = 5 - elif optimizer == "IPOPT": - p.driver.options['optimizer'] = 'IPOPT' - p.driver.opt_settings['tol'] = 1.0E-4 - # p.driver.opt_settings['dual_inf_tol'] = 1.0E-4 - p.driver.opt_settings['acceptable_tol'] = 5.0E-4 - p.driver.opt_settings['mu_init'] = 1e-5 - p.driver.opt_settings['max_iter'] = 100 - p.driver.opt_settings['print_level'] = 5 - # for faster convergence - p.driver.opt_settings['nlp_scaling_method'] = 'gradient-based' - p.driver.opt_settings['nlp_scaling_max_gradient'] = 1000.0 - - # p.driver.opt_settings['nlp_scaling_method'] = 'none' - p.driver.opt_settings['alpha_for_y'] = 'safer-min-dual-infeas' - p.driver.opt_settings['bound_mult_init_method'] = 'mu-based' - p.driver.opt_settings['limited_memory_update_type'] = 'bfgs' - p.driver.opt_settings['mu_strategy'] = 'monotone' - # p.driver.opt_settings['mu_strategy'] = 'adaptive' - # p.driver.opt_settings['grad_f_constant'] = "yes" - - # Uncomment declare_coloring when the coloring needs to be reset (number - # of nodes have changed, constraints changed, or underlying models have - # changed) - p.driver.declare_coloring(tol=1.0E-12, num_full_jacs=1) - - obj_comp = om.ExecComp("obj = -final_mass / 175191 + final_time / 10", - final_mass={"units": "lbm"}, - final_time={"units": "h"}) - p.model.add_subsystem("obj_comp", obj_comp) - - p.model.connect("traj.cruise.timeseries.mass", - "obj_comp.final_mass", src_indices=[-1]) - p.model.connect("traj.cruise.timeseries.time", - "obj_comp.final_time", src_indices=[-1]) - - p.model.add_objective("obj_comp.obj", ref=1.0) - - p.setup() - - # SET INPUTS FOR POST TRAJECTORY ANALYSES - # TODO: paramport - params = ParamPort.param_data - p.set_val('vrot_comp.' + Aircraft.Wing.AREA, - params[Aircraft.Wing.AREA]["val"], - units=params[Aircraft.Wing.AREA]["units"]) - p.set_val("vrot_comp.dV1", val=10, units="kn") - p.set_val("vrot_comp.dVR", val=5, units="kn") - p.set_val("vrot_comp.rho", val=RHO_SEA_LEVEL_ENGLISH, units="slug/ft**3") - p.set_val("vrot_comp.CL_max", val=2.1886, units="unitless") - - # SET TIME INITIAL GUESS - p.set_val("traj.cruise.t_initial", 171481, units="lbm") # Initial mass in cruise - p.set_val("traj.cruise.t_duration", -10000, units="lbm") # Mass of fuel consumed - - p.set_val("traj.cruise.parameters:altitude", val=37500.0, units="ft") - p.set_val("traj.cruise.parameters:mach", val=0.8, units="unitless") - p.set_val("traj.cruise.parameters:wing_area", val=1370, units="ft**2") - p.set_val("traj.cruise.parameters:initial_distance", val=175.0, units="NM") - p.set_val("traj.cruise.parameters:initial_time", val=1600.0, units="s") - - # RUN THE DRIVER AND EXPLICITLY SIMULATE THE CONTROL SOLUTION - this_dir = os.path.dirname(os.path.realpath(__file__)) - restart_file = this_dir + os.sep + "dymos_solution_IPOPT.db" - dm.run_problem(p, run_driver=True, simulate=False, make_plots=make_plots, - restart=restart_file, - simulation_record_file=f'dymos_simulation_{optimizer}.db', - solution_record_file=f'dymos_solution_{optimizer}.db') - - print("t_init_gear (s)", p.get_val( - "traj.ascent_to_gear_retract.timeseries.time", units="s")[-1, ...]) - print("t_init_flaps (s)", p.get_val( - "traj.ascent_to_flap_retract.timeseries.time", units="s")[-1, ...]) - print("initial cruise time (s)", p.get_val( - "traj.cruise.parameter_vals:initial_time", units="s")) - print("cruise time (s)", p.get_val( - "traj.cruise.timeseries.time", units="s")[-1, ...]) - print("cruise range (NM)", p.get_val( - "traj.cruise.timeseries.distance", units="NM")[-1, ...]) - print("cruise equivalent airspeed", p.get_val( - "traj.cruise.timeseries.EAS", units="kn")[0, ...]) - - return p diff --git a/aviary/mission/gasp_based/phases/run_phases/run_desc1.py b/aviary/mission/gasp_based/phases/run_phases/run_desc1.py deleted file mode 100644 index 9b18c15ea..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_desc1.py +++ /dev/null @@ -1,330 +0,0 @@ -# separated ODE into 2 balances and removed top level solver - -import dymos as dm -import matplotlib.pyplot as plt -import numpy as np -import openmdao.api as om -import pandas as pd - -from aviary.mission.gasp_based.ode.descent_ode import DescentODE -from aviary.mission.gasp_based.phases.desc_phase import get_descent -from aviary.variable_info.enums import SpeedType -from aviary.variable_info.variables import Aircraft, Dynamic - - -def run_desc1(make_plots=False): - - theta_max_val = 15 - plot_over_alt = False - - prob = om.Problem(model=om.Group()) - - prob.driver = om.pyOptSparseDriver() - prob.driver.options["optimizer"] = "SNOPT" - prob.driver.opt_settings["Major iterations limit"] = 100 - prob.driver.opt_settings["Major optimality tolerance"] = 5.0e-3 - prob.driver.opt_settings["Major feasibility tolerance"] = 1e-6 - prob.driver.opt_settings["iSumm"] = 6 - prob.driver.declare_coloring() - - transcription = dm.Radau(num_segments=20, order=4, compressed=False) - desc1 = get_descent( - ODE=DescentODE, - fix_initial=True, - input_initial=False, - alt_lb=1000, - alt_ub=60000, - mass_lb=0, - mass_ub=200000, - distance_lb=2000, - distance_ub=3000, - time_lb=(0, 0), - time_ub=(2, 36000), - EAS_limit=350, - mach_cruise=0.8, - transcription=transcription, - final_alt=10000, - input_speed_type=SpeedType.MACH, - ) - - desc1.add_parameter( - Dynamic.Mission.THROTTLE, opt=False, units="unitless", val=0.0, static_target=False - ) - - desc1.add_parameter( - Aircraft.Wing.AREA, opt=False, units="ft**2", val=1370.0, static_target=True - ) - - prob.model.add_subsystem(name="desc1", subsys=desc1) - desc1.add_timeseries_output( - Dynamic.Mission.MACH, - output_name=Dynamic.Mission.MACH, - units="unitless") - desc1.add_timeseries_output("EAS", output_name="EAS", units="kn") - desc1.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") - desc1.add_timeseries_output("aero.CD", output_name="CD", units="unitless") - desc1.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, - output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") - desc1.add_timeseries_output("alpha", output_name="alpha", units="deg") - desc1.add_timeseries_output("aero.CL", output_name="CL", units="unitless") - desc1.add_timeseries_output( - "required_lift", output_name="required_lift", units="lbf" - ) - desc1.add_timeseries_output("theta", output_name="theta", units="deg") - - desc1.add_objective("time", loc="final") - prob.model.linear_solver.options["iprint"] = 0 - prob.model.nonlinear_solver.options["iprint"] = 0 - - prob.model.options["assembled_jac_type"] = "csc" - # prob.model.linear_solver = om.DirectSolver(assemble_jac=True) - # prob.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=True) - # prob.model.nonlinear_solver.options["err_on_non_converge"] = True - - prob.setup() - prob.model.nonlinear_solver.options["iprint"] = 1 - prob.set_val("desc1.states:mass", desc1.interp("mass", ys=[147664, 147541.5])) - prob.set_val( - "desc1.states:altitude", desc1.interp( - Dynamic.Mission.ALTITUDE, ys=[ - 37500, 10000])) - prob.set_val("desc1.states:distance", desc1.interp( - Dynamic.Mission.DISTANCE, ys=[2490, 2563.5])) - prob.set_val("desc1.t_duration", 350) - prob.set_val("desc1.t_initial", 0) - - prob.set_solver_print(level=0) - prob.run_driver() - - if make_plots == True: - print() - print("Done Running Model, Now Simulating") - print() - - simout4 = desc1.simulate(atol=1e-6, rtol=1e-6) - simout4.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=True) - simout4.model.options["assembled_jac_type"] = "csc" - simout4.model.linear_solver = om.DirectSolver(assemble_jac=True) - simout4.model.nonlinear_solver.options["err_on_non_converge"] = True - t_solved = prob.get_val("desc1.timeseries.time") - t_simulate = simout4.get_val("desc1.timeseries.time") - - alt_solved = prob.get_val("desc1.timeseries.states:altitude", units="ft") - alt_simulate = simout4.get_val("desc1.timeseries.states:altitude", units="ft") - - mass_solved = prob.get_val("desc1.timeseries.states:mass", units="lbm") - mass_simulate = simout4.get_val("desc1.timeseries.states:mass", units="lbm") - - distance_solved = prob.get_val("desc1.timeseries.states:distance", units="NM") - distance_simulate = simout4.get_val( - "desc1.timeseries.states:distance", units="NM" - ) - - mach_solved = prob.get_val("desc1.timeseries.mach", units="unitless") - mach_simulate = simout4.get_val("desc1.timeseries.mach", units="unitless") - - EAS_solved = prob.get_val("desc1.timeseries.EAS", units="kn") - EAS_simulate = simout4.get_val("desc1.timeseries.EAS", units="kn") - - EAS_solved = prob.get_val("desc1.timeseries.EAS", units="kn") - EAS_simulate = simout4.get_val("desc1.timeseries.EAS", units="kn") - - gamma_solved = prob.get_val("desc1.timeseries.flight_path_angle", units="deg") - gamma_simulate = simout4.get_val( - "desc1.timeseries.flight_path_angle", units="deg") - - thrust_solved = prob.get_val("desc1.timeseries.thrust", units="unitless") - thrust_simulate = simout4.get_val("desc1.timeseries.thrust", units="unitless") - - CD_solved = prob.get_val("desc1.timeseries.CD", units="unitless") - CD_simulate = simout4.get_val("desc1.timeseries.CD", units="unitless") - - alpha_solved = prob.get_val("desc1.timeseries.alpha", units="deg") - alpha_simulate = simout4.get_val("desc1.timeseries.alpha", units="deg") - - CL_solved = prob.get_val("desc1.timeseries.CL", units="unitless") - CL_simulate = simout4.get_val("desc1.timeseries.CL", units="unitless") - - theta_solved = prob.get_val("desc1.timeseries.theta", units="deg") - theta_simulate = simout4.get_val("desc1.timeseries.theta", units="deg") - theta_max = np.ones(np.shape(theta_simulate)) * theta_max_val - - fig, ax = plt.subplots(3, 1, sharex=True) - fig.suptitle("State Values") - - if plot_over_alt is False: - l1 = ax[0].plot(t_solved, alt_solved, "bo") - l2 = ax[0].plot(t_simulate, alt_simulate, "b-") - - ax[1].plot(t_solved, mass_solved, "bo") - ax[1].plot(t_simulate, mass_simulate, "b-") - - ax[2].plot(t_solved, distance_solved, "bo") - ax[2].plot(t_simulate, distance_simulate, "b-") - - ax[0].set_xlabel("time (s)") - ax[1].set_xlabel("time (s)") - ax[2].set_xlabel("time (s)") - ax[0].set_ylabel("alt (ft)") - - plt_name = "plots/desc1_states_time.pdf" - - else: - l1 = ax[0].plot(alt_solved, t_solved, "bo") - l2 = ax[0].plot(alt_simulate, t_simulate, "b-") - - ax[1].plot(alt_solved, mass_solved, "bo") - ax[1].plot(alt_simulate, mass_simulate, "b-") - - ax[2].plot(alt_solved, distance_solved, "bo") - ax[2].plot(alt_simulate, distance_simulate, "b-") - - ax[0].set_xlabel("alt (ft)") - ax[1].set_xlabel("alt (ft)") - ax[2].set_xlabel("alt (ft)") - ax[0].set_ylabel("time (s)") - - plt_name = "plots/desc1_states_alt.pdf" - - ax[1].set_ylabel("mass (lbm)") - ax[2].set_ylabel("distance (NM)") - fig.legend([l1, l2, l3], labels=["Optimized", "Simulated"]) - plt.savefig(plt_name) - - fig2, ax2 = plt.subplots(2, 1, sharex=True) - fig2.suptitle("Speed Values") - - if plot_over_alt is False: - a1 = ax2[0].plot(t_solved, mach_solved, "ro") - a2 = ax2[0].plot(t_simulate, mach_simulate, "r-") - - ax2[1].plot(t_solved, EAS_solved, "ro") - ax2[1].plot(t_simulate, EAS_simulate, "r-") - - ax2[0].set_xlabel("time (s)") - ax2[1].set_xlabel("time (s)") - - plt_name = "plots/desc1_speeds_time.pdf" - - else: - a1 = ax2[0].plot(alt_solved, mach_solved, "ro") - a2 = ax2[0].plot(alt_simulate, mach_simulate, "r-") - - ax2[1].plot(alt_solved, EAS_solved, "ro") - ax2[1].plot(alt_simulate, EAS_simulate, "r-") - - ax2[0].set_xlabel("alt (ft)") - ax2[1].set_xlabel("alt (ft)") - - plt_name = "plots/desc1_speeds_alt.pdf" - - ax2[0].set_ylabel(Dynamic.Mission.MACH) - ax2[1].set_ylabel("EAS (knots)") - fig2.legend([a1, a2], labels=["Optimized", "Simulated"]) - plt.savefig(plt_name) - - fig3, ax3 = plt.subplots(3, 1, sharex=True) - fig3.suptitle("Force Values") - - if plot_over_alt is False: - c1 = ax3[0].plot(t_solved, thrust_solved, "ro") - c2 = ax3[0].plot(t_simulate, thrust_simulate, "r-") - - ax3[1].plot(t_solved, CD_solved, "ro") - ax3[1].plot(t_simulate, CD_simulate, "r-") - - ax3[2].plot(t_solved, CL_solved, "ro") - ax3[2].plot(t_simulate, CL_simulate, "r-") - - ax3[0].set_xlabel("time (s)") - ax3[1].set_xlabel("time (s)") - ax3[2].set_xlabel("time (s)") - - plt_name = "plots/desc1_forces_time.pdf" - - else: - c1 = ax3[0].plot(alt_solved, thrust_solved, "ro") - c2 = ax3[0].plot(alt_simulate, thrust_simulate, "r-") - - ax3[1].plot(alt_solved, CD_solved, "ro") - ax3[1].plot(alt_simulate, CD_simulate, "r-") - - ax3[2].plot(alt_solved, CL_solved, "ro") - ax3[2].plot(alt_simulate, CL_simulate, "r-") - - ax3[0].set_xlabel("alt (ft)") - ax3[1].set_xlabel("alt (ft)") - ax3[2].set_xlabel("alt (ft)") - - plt_name = "plots/desc1_forces_alt.pdf" - - ax3[0].set_ylabel("thrust (lbf)") - ax3[1].set_ylabel("CD") - ax3[2].set_ylabel("CL") - fig3.legend([c1, c2], labels=["Optimized", "Simulated"]) - plt.savefig(plt_name) - - fig4, ax4 = plt.subplots(3, 1, sharex=True) - fig4.suptitle("Angle Values") - - if plot_over_alt is False: - - ax4[0].plot(t_solved, alpha_solved, "go") - ax4[0].plot(t_simulate, alpha_simulate, "g-") - - ax4[1].plot(t_solved, gamma_solved, "go") - ax4[1].plot(t_simulate, gamma_simulate, "g-") - - d1 = ax4[2].plot(t_solved, theta_solved, "go") - d2 = ax4[2].plot(t_simulate, theta_simulate, "g-") - d3 = ax4[2].plot(t_simulate, theta_max, "r-") - - ax4[0].set_xlabel("time (s)") - ax4[1].set_xlabel("time (s)") - ax4[1].set_xlabel("time (s)") - - plt_name = "plots/desc1_angles_time.pdf" - - else: - - ax4[0].plot(alt_solved, alpha_solved, "go") - ax4[0].plot(alt_simulate, alpha_simulate, "g-") - - ax4[1].plot(alt_solved, gamma_solved, "go") - ax4[1].plot(alt_simulate, gamma_simulate, "g-") - - d1 = ax4[2].plot(alt_solved, theta_solved, "go") - d2 = ax4[2].plot(alt_simulate, theta_simulate, "g-") - d3 = ax4[2].plot(alt_simulate, theta_max, "r-") - - ax4[0].set_xlabel("alt (ft)") - ax4[1].set_xlabel("alt (ft)") - ax4[2].set_xlabel("alt (ft)") - - plt_name = "plots/desc1_angles_alt.pdf" - - ax4[0].set_ylabel("alpha (deg)") - ax4[1].set_ylabel("gamma (deg)") - ax4[2].set_ylabel("theta (deg)") - fig4.legend( - [d1, d2, d3], labels=["Optimized", "Simulated", "maximum"] - ) - plt.savefig(plt_name) - - fig5, ax5 = plt.subplots(2, 1, sharex=True) - fig5.suptitle("Alpha Values") - - f1 = ax5[0].plot(alpha_solved, CL_solved, "ro") - - ax5[1].plot(alpha_solved, CD_solved, "ro") - - ax5[0].set_xlabel("alpha (deg)") - ax5[1].set_xlabel("alpha (deg)") - - ax5[0].set_ylabel("CL") - ax5[1].set_ylabel("CD") - fig5.legend([f1, f2], labels=["Optimized"]) - plt.savefig("plots/desc1_alphas.pdf") - - return prob diff --git a/aviary/mission/gasp_based/phases/run_phases/run_desc2.py b/aviary/mission/gasp_based/phases/run_phases/run_desc2.py deleted file mode 100644 index d7d30deb3..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_desc2.py +++ /dev/null @@ -1,328 +0,0 @@ -import dymos as dm -import matplotlib.pyplot as plt -import numpy as np -import openmdao.api as om -import pandas as pd - -from aviary.mission.gasp_based.ode.descent_ode import DescentODE -from aviary.mission.gasp_based.phases.desc_phase import get_descent -from aviary.variable_info.enums import SpeedType -from aviary.variable_info.variables import Aircraft, Dynamic - - -def run_desc2(): - theta_max_val = 15 - plot_over_alt = False - - prob = om.Problem(model=om.Group()) - - prob.driver = om.pyOptSparseDriver() - prob.driver.options["optimizer"] = "SNOPT" - prob.driver.opt_settings["Major iterations limit"] = 100 - prob.driver.opt_settings["Major optimality tolerance"] = 5.0e-3 - prob.driver.opt_settings["Major feasibility tolerance"] = 1e-6 - prob.driver.opt_settings["iSumm"] = 6 - prob.driver.declare_coloring() - - transcription = dm.Radau(num_segments=15, order=4, compressed=False) - desc2 = get_descent( - DescentODE, - fix_initial=True, - input_initial=False, - alt_lb=1000, - alt_ub=60000, - mass_lb=0, - mass_ub=200000, - distance_lb=2000, - distance_ub=3000, - time_lb=(0, 0), - time_ub=(2, 36000), - EAS_limit=250, - mach_cruise=0.8, - transcription=transcription, - final_alt=1000, - input_speed_type=SpeedType.EAS, - ) - - desc2.add_parameter( - Dynamic.Mission.THROTTLE, - opt=False, - units="unitless", - val=0.0, - static_target=False) - - desc2.add_parameter( - Aircraft.Wing.AREA, opt=False, units="ft**2", val=1370.0, static_target=True - ) - - prob.model.add_subsystem(name="desc2", subsys=desc2) - desc2.add_timeseries_output( - Dynamic.Mission.MACH, - output_name=Dynamic.Mission.MACH, - units="unitless") - desc2.add_timeseries_output("EAS", output_name="EAS", units="kn") - desc2.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, - units="lbf") - desc2.add_timeseries_output("aero.CD", output_name="CD", units="unitless") - desc2.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, - output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") - desc2.add_timeseries_output("alpha", output_name="alpha", units="deg") - desc2.add_timeseries_output("aero.CL", output_name="CL", units="unitless") - desc2.add_timeseries_output( - "required_lift", output_name="required_lift", units="lbf" - ) - desc2.add_timeseries_output("theta", output_name="theta", units="deg") - desc2.add_timeseries_output("TAS", output_name="TAS", units="kn") - - desc2.add_objective("time", loc="final") - prob.model.linear_solver.options["iprint"] = 0 - prob.model.nonlinear_solver.options["iprint"] = 0 - - prob.model.options["assembled_jac_type"] = "csc" - prob.model.linear_solver = om.DirectSolver(assemble_jac=True) - - prob.setup() - prob.set_val("desc2.states:mass", desc2.interp("mass", ys=[147541.5, 147390])) - prob.set_val( - "desc2.states:altitude", desc2.interp( - Dynamic.Mission.ALTITUDE, ys=[ - 10000, 1000])) - prob.set_val("desc2.states:distance", desc2.interp( - Dynamic.Mission.DISTANCE, ys=[2563.5, 2598])) - prob.set_val("desc2.t_duration", 500) - prob.set_val("desc2.t_initial", 0) - - prob.set_solver_print(level=0) - prob.run_driver() - print() - print("Done Running Model, Now Simulating") - print() - - simout5 = desc2.simulate(atol=1e-6, rtol=1e-6) - - if make_plots == True: - - ## make plots ## - - t_solved = prob.get_val("desc2.timeseries.time") - t_simulate = simout5.get_val("desc2.timeseries.time") - - alt_solved = prob.get_val("desc2.timeseries.states:altitude", units="ft") - alt_simulate = simout5.get_val("desc2.timeseries.states:altitude", units="ft") - - mass_solved = prob.get_val("desc2.timeseries.states:mass", units="lbm") - mass_simulate = simout5.get_val("desc2.timeseries.states:mass", units="lbm") - - distance_solved = prob.get_val("desc2.timeseries.states:distance", units="NM") - distance_simulate = simout5.get_val( - "desc2.timeseries.states:distance", units="NM" - ) - - mach_solved = prob.get_val("desc2.timeseries.mach", units="unitless") - mach_simulate = simout5.get_val("desc2.timeseries.mach", units="unitless") - - TAS_solved = prob.get_val("desc2.timeseries.TAS", units="kn") - TAS_simulate = simout5.get_val("desc2.timeseries.TAS", units="kn") - - gamma_solved = prob.get_val("desc2.timeseries.flight_path_angle", units="deg") - gamma_simulate = simout5.get_val( - "desc2.timeseries.flight_path_angle", units="deg") - - thrust_solved = prob.get_val("desc2.timeseries.thrust", units="unitless") - thrust_simulate = simout5.get_val("desc2.timeseries.thrust", units="unitless") - - CD_solved = prob.get_val("desc2.timeseries.CD", units="unitless") - CD_simulate = simout5.get_val("desc2.timeseries.CD", units="unitless") - - alpha_solved = prob.get_val("desc2.timeseries.alpha", units="deg") - alpha_simulate = simout5.get_val("desc2.timeseries.alpha", units="deg") - - CL_solved = prob.get_val("desc2.timeseries.CL", units="unitless") - CL_simulate = simout5.get_val("desc2.timeseries.CL", units="unitless") - - theta_solved = prob.get_val("desc2.timeseries.theta", units="deg") - theta_simulate = simout5.get_val("desc2.timeseries.theta", units="deg") - theta_max = np.ones(np.shape(theta_simulate)) * theta_max_val - - fig, ax = plt.subplots(3, 1, sharex=True) - fig.suptitle("State Values") - - if plot_over_alt is False: - l1 = ax[0].plot(t_solved, alt_solved, "go") - l2 = ax[0].plot(t_simulate, alt_simulate, "g-") - - ax[1].plot(t_solved, mass_solved, "go") - ax[1].plot(t_simulate, mass_simulate, "g-") - - ax[2].plot(t_solved, distance_solved, "go") - ax[2].plot(t_simulate, distance_simulate, "g-") - - ax[0].set_xlabel("time (s)") - ax[1].set_xlabel("time (s)") - ax[2].set_xlabel("time (s)") - ax[0].set_ylabel("alt (ft)") - - plt_name = "plots/desc2_states_time.pdf" - - else: - l1 = ax[0].plot(alt_solved, t_solved, "go") - l2 = ax[0].plot(alt_simulate, t_simulate, "g-") - - ax[1].plot(alt_solved, mass_solved, "go") - ax[1].plot(alt_simulate, mass_simulate, "g-") - - ax[2].plot(alt_solved, distance_solved, "go") - ax[2].plot(alt_simulate, distance_simulate, "g-") - - ax[0].set_xlabel("alt (ft)") - ax[1].set_xlabel("alt (ft)") - ax[2].set_xlabel("alt (ft)") - ax[0].set_ylabel("time (s)") - - plt_name = "plots/desc2_states_alt.pdf" - - ax[1].set_ylabel("mass (lbm)") - ax[2].set_ylabel("distance (NM)") - fig.legend([l1, l2], labels=["Optimized", "Simulated"]) - plt.savefig(plt_name) - - fig2, ax2 = plt.subplots(2, 1, sharex=True) - fig2.suptitle("Speed Values") - - if plot_over_alt is False: - a1 = ax2[0].plot(t_solved, mach_solved, "ro") - a2 = ax2[0].plot(t_simulate, mach_simulate, "r-") - - ax2[1].plot(t_solved, TAS_solved, "ro") - ax2[1].plot(t_simulate, TAS_simulate, "r-") - - ax2[0].set_xlabel("time (s)") - ax2[1].set_xlabel("time (s)") - - plt_name = "plots/desc2_speeds_time.pdf" - - else: - a1 = ax2[0].plot(alt_solved, mach_solved, "ro") - a2 = ax2[0].plot(alt_simulate, mach_simulate, "r-") - - ax2[1].plot(alt_solved, TAS_solved, "ro") - ax2[1].plot(alt_simulate, TAS_simulate, "r-") - - ax2[0].set_xlabel("alt (ft)") - ax2[1].set_xlabel("alt (ft)") - - plt_name = "plots/desc2_speeds_alt.pdf" - - ax2[0].set_ylabel(Dynamic.Mission.MACH) - ax2[1].set_ylabel("TAS (knots)") - fig2.legend([a1, a2], labels=["Optimized", "Simulated"]) - plt.savefig(plt_name) - - fig3, ax3 = plt.subplots(3, 1, sharex=True) - fig3.suptitle("Force Values") - - if plot_over_alt is False: - - d1 = ax3[0].plot(t_solved, thrust_solved, "bo") - d2 = ax3[0].plot(t_simulate, thrust_simulate, "b-") - - ax3[1].plot(t_solved, CD_solved, "bo") - ax3[1].plot(t_simulate, CD_simulate, "b-") - - ax3[2].plot(t_solved, CL_solved, "bo") - ax3[2].plot(t_simulate, CL_simulate, "b-") - - ax3[0].set_xlabel("time (s)") - ax3[1].set_xlabel("time (s)") - ax3[2].set_xlabel("time (s)") - - plt_name = "plots/desc2_forces_time.pdf" - - else: - - d1 = ax3[0].plot(alt_solved, thrust_solved, "bo") - d2 = ax3[0].plot(alt_simulate, thrust_simulate, "b-") - - ax3[1].plot(alt_solved, CD_solved, "bo") - ax3[1].plot(alt_simulate, CD_simulate, "b-") - - ax3[2].plot(alt_solved, CL_solved, "bo") - ax3[2].plot(alt_simulate, CL_simulate, "b-") - - ax3[0].set_xlabel("alt (ft)") - ax3[1].set_xlabel("alt (ft)") - ax3[2].set_xlabel("alt (ft)") - - plt_name = "plots/desc2_forces_alt.pdf" - - ax3[0].set_ylabel("thrust (lbf)") - ax3[1].set_ylabel("CD") - ax3[2].set_ylabel("CL") - fig3.legend([d1, d2], labels=["Optimized", "Simulated"]) - plt.savefig(plt_name) - - fig4, ax4 = plt.subplots(3, 1, sharex=True) - fig4.suptitle("Angle Values") - - if plot_over_alt is False: - - ax4[0].plot(t_solved, alpha_solved, "go") - ax4[0].plot(t_simulate, alpha_simulate, "g-") - - ax4[1].plot(t_solved, gamma_solved, "go") - ax4[1].plot(t_simulate, gamma_simulate, "g-") - - c1 = ax4[2].plot(t_solved, theta_solved, "go") - c2 = ax4[2].plot(t_simulate, theta_simulate, "g-") - c3 = ax4[2].plot(t_simulate, theta_max, "r-") - - ax4[0].set_xlabel("time (s)") - ax4[1].set_xlabel("time (s)") - ax4[1].set_xlabel("time (s)") - - plt_name = "plots/desc2_angles_time.pdf" - - else: - - ax4[0].plot(alt_solved, alpha_solved, "go") - ax4[0].plot(alt_simulate, alpha_simulate, "g-") - - ax4[1].plot(alt_solved, gamma_solved, "go") - ax4[1].plot(alt_simulate, gamma_simulate, "g-") - - c1 = ax4[2].plot(alt_solved, theta_solved, "go") - c2 = ax4[2].plot(alt_simulate, theta_simulate, "g-") - c3 = ax4[2].plot(alt_simulate, theta_max, "r-") - - ax4[0].set_xlabel("alt (ft)") - ax4[1].set_xlabel("alt (ft)") - ax4[2].set_xlabel("alt (ft)") - - plt_name = "plots/desc2_angles_alt.pdf" - - ax4[0].set_ylabel("alpha (deg)") - ax4[1].set_ylabel("gamma (deg)") - ax4[2].set_ylabel("theta (deg)") - fig4.legend( - [c1, c2, c3], labels=["Optimized", "Simulated", "maximum"] - ) - plt.savefig(plt_name) - - fig5, ax5 = plt.subplots(2, 1, sharex=True) - fig5.suptitle("Alpha Values") - - f1 = ax5[0].plot(alpha_solved, CL_solved, "ro") - - ax5[1].plot(alpha_solved, CD_solved, "ro") - - ax5[0].set_xlabel("alpha (deg)") - ax5[1].set_xlabel("alpha (deg)") - - ax5[0].set_ylabel("CL") - ax5[1].set_ylabel("CD") - fig5.legend([f1, f2], labels=["Optimized"]) - plt.savefig("plots/desc2_alphas.pdf") - - return prob diff --git a/aviary/mission/gasp_based/phases/run_phases/run_groundroll.py b/aviary/mission/gasp_based/phases/run_phases/run_groundroll.py deleted file mode 100644 index 3f57333d4..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_groundroll.py +++ /dev/null @@ -1,136 +0,0 @@ -import dymos as dm -import openmdao.api as om - -from aviary.constants import GRAV_ENGLISH_LBM, RHO_SEA_LEVEL_ENGLISH -from aviary.mission.gasp_based.phases.groundroll_phase import get_groundroll -from aviary.variable_info.variables import Aircraft, Mission -from aviary.variable_info.options import get_option_defaults - - -def run_groundroll(): - num_segments = 5 - transcription = dm.Radau( - num_segments=num_segments, order=3, compressed=True, solve_segments=False - ) - - ode_args = dict( - aviary_options=get_option_defaults() - ) - - groundroll = get_groundroll( - fix_initial=True, - fix_initial_mass=True, - connect_initial_mass=False, - ode_args=ode_args, - transcription=transcription, - ) - - p = om.Problem() - - # calculate speed at which to initiate rotation - p.model.add_subsystem( - "vrot", - om.ExecComp( - "Vrot = ((2 * mass * g) / (rho * wing_area * CLmax))**0.5 + dV1 + dVR", - Vrot={"units": "ft/s"}, - mass={"units": "lbm"}, - g={"units": "lbf/lbm", "val": GRAV_ENGLISH_LBM}, - rho={"units": "slug/ft**3", "val": RHO_SEA_LEVEL_ENGLISH}, - wing_area={"units": "ft**2"}, - dV1={ - "units": "ft/s", - "desc": "Increment of engine failure decision speed above stall", - }, - dVR={ - "units": "ft/s", - "desc": "Increment of takeoff rotation speed above engine failure " - "decision speed", - }, - ), - promotes_inputs=[ - ("wing_area", Aircraft.Wing.AREA), - "mass", - "dV1", - "dVR", - ("CLmax", Mission.Takeoff.LIFT_COEFFICIENT_MAX), - ], - promotes_outputs=[("Vrot", Mission.Takeoff.ROTATION_VELOCITY)] - ) - - traj = p.model.add_subsystem("traj", dm.Trajectory()) - traj.add_phase("groundroll", groundroll) - - p.model.add_subsystem( - "groundroll_boundary", - om.EQConstraintComp( - "TAS", - eq_units="ft/s", - normalize=True, - add_constraint=True, - ), - ) - p.model.connect(Mission.Takeoff.ROTATION_VELOCITY, "groundroll_boundary.rhs:TAS") - p.model.connect("traj.groundroll.states:TAS", "groundroll_boundary.lhs:TAS", - src_indices=[-1], - flat_src_indices=True, - ) - - groundroll.add_objective('time', ref=1.0) - - p.driver = om.pyOptSparseDriver() - p.driver.declare_coloring() - p.driver.options["print_results"] = p.comm.rank == 0 - - optimizer = 'IPOPT' - print_opt_iters = True - - p.driver.options["optimizer"] = optimizer - - if optimizer == "SNOPT": - p.driver.opt_settings["Major optimality tolerance"] = 3e-4 - p.driver.opt_settings["Major feasibility tolerance"] = 1e-6 - p.driver.opt_settings["Function precision"] = 1e-6 - p.driver.opt_settings["Linesearch tolerance"] = 0.99 - if print_opt_iters: - p.driver.opt_settings["iSumm"] = 6 - p.driver.opt_settings["Major iterations limit"] = 75 - elif optimizer == "IPOPT": - p.driver.opt_settings["max_iter"] = 500 - p.driver.opt_settings["tol"] = 1e-5 - if print_opt_iters: - p.driver.opt_settings["print_level"] = 5 - p.driver.opt_settings[ - "nlp_scaling_method" - ] = "gradient-based" # for faster convergence - p.driver.opt_settings["alpha_for_y"] = "safer-min-dual-infeas" - p.driver.opt_settings["mu_strategy"] = "monotone" - p.driver.opt_settings["bound_mult_init_method"] = "mu-based" - - p.set_solver_print(level=-1) - - p.setup() - - p.set_val("traj.groundroll.states:TAS", 0, units="kn") - p.set_val( - "traj.groundroll.states:mass", - groundroll.interp("mass", [175100, 174000]), - units="lbm", - ) - p.set_val('mass', 175100, units='lbm') - p.set_val("dV1", 10, units="kn") - p.set_val("dVR", 5, units="kn") - p.set_val(Aircraft.Wing.AREA, units="ft**2", val=1370) - p.set_val(Mission.Takeoff.LIFT_COEFFICIENT_MAX, 2.1886) - - p.set_val( - "traj.groundroll.states:distance", - groundroll.interp("distance", [0, 1000]), - units="ft", - ) - - p.set_val("traj.groundroll.t_duration", 27.7) - - p.run_driver() - # simout = traj.simulate(atol=1e-6, rtol=1e-6) - - return p diff --git a/aviary/mission/gasp_based/phases/run_phases/run_rotation.py b/aviary/mission/gasp_based/phases/run_phases/run_rotation.py deleted file mode 100644 index ce2fb8130..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_rotation.py +++ /dev/null @@ -1,53 +0,0 @@ -import dymos as dm -import openmdao.api as om - -from aviary.mission.gasp_based.phases.rotation_phase import get_rotation -from aviary.variable_info.options import get_option_defaults - - -def run_rotation(make_plots=False): - rotation_trans = dm.Radau( - num_segments=1, order=3, compressed=True, solve_segments=False - ) - rotation = get_rotation( - ode_args=get_option_defaults(), - fix_initial=True, - connect_initial_mass=False, - transcription=rotation_trans, - ) - - p = om.Problem() - traj = p.model.add_subsystem("traj", dm.Trajectory()) - traj.add_phase("rotation", rotation) - - p.driver = om.pyOptSparseDriver() - p.driver.options["optimizer"] = "SNOPT" - p.driver.opt_settings["iSumm"] = 6 - p.driver.declare_coloring() - - p.model.add_objective( - "traj.rotation.timeseries.states:mass", index=-1, ref=1.4e5, ref0=1.3e5 - ) - p.set_solver_print(level=-1) - - p.setup() - - p.set_val( - "traj.rotation.states:alpha", rotation.interp("alpha", [0, 2.5]), units="deg" - ) - p.set_val("traj.rotation.states:TAS", 143, units="kn") - p.set_val( - "traj.rotation.states:mass", - rotation.interp("mass", [174975.12776915, 174000]), - units="lbm", - ) - p.set_val( - "traj.rotation.states:distance", - rotation.interp("distance", [3680.37217765, 4000]), - units="ft", - ) - p.set_val("traj.rotation.t_duration", 50.0) - - dm.run_problem(p, simulate=True, make_plots=make_plots) - - return p diff --git a/aviary/mission/gasp_based/phases/run_phases/run_takeoff.py b/aviary/mission/gasp_based/phases/run_phases/run_takeoff.py deleted file mode 100644 index 1b859eb1c..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_takeoff.py +++ /dev/null @@ -1,196 +0,0 @@ -import dymos as dm -import openmdao.api as om - -from aviary.mission.gasp_based.phases.ascent_phase import get_ascent -from aviary.mission.gasp_based.phases.groundroll_phase import get_groundroll -from aviary.mission.gasp_based.phases.rotation_phase import get_rotation -from aviary.mission.gasp_based.polynomial_fit import PolynomialFit -from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Dynamic, Mission - - -def run_takeoff(make_plots=False): - option_defaults = get_option_defaults() - groundroll_trans = dm.Radau( - num_segments=1, order=3, compressed=True, solve_segments=False - ) - groundroll = get_groundroll( - ode_args=option_defaults, - fix_initial=True, - connect_initial_mass=False, - transcription=groundroll_trans, - ) - - p = om.Problem() - - p.model.add_subsystem( - "event_xform", - om.ExecComp( - ["t_init_gear=m*tau_gear+b", "t_init_flaps=m*tau_flaps+b"], units="s" - ), - promotes_inputs=[ - "tau_gear", - "tau_flaps", - ("m", Mission.Takeoff.ASCENT_DURATION), - ("b", "ascent:t_initial"), - ], - promotes_outputs=["t_init_gear", "t_init_flaps"], - ) - - p.model.add_design_var("ascent:t_initial", lower=0, upper=100) - p.model.add_design_var(Mission.Takeoff.ASCENT_DURATION, lower=1, upper=1000) - - traj = p.model.add_subsystem("traj", dm.Trajectory()) - traj.add_phase("groundroll", groundroll) - - rotation_trans = dm.Radau( - num_segments=1, order=3, compressed=True, solve_segments=False - ) - rotation = get_rotation( - ode_args=option_defaults, - fix_initial=False, - connect_initial_mass=False, - transcription=rotation_trans, - ) - traj.add_phase("rotation", rotation) - traj.link_phases(["groundroll", "rotation"], ["time", "TAS", "mass", "distance"]) - - ascent_trans = dm.Radau( - num_segments=2, order=5, compressed=True, solve_segments=False - ) - ascent = get_ascent( - ode_args=option_defaults, - fix_initial=False, - connect_initial_mass=False, - transcription=ascent_trans, - ) - traj.add_phase("ascent", ascent) - traj.link_phases( - ["rotation", "ascent"], ["time", "TAS", "mass", "distance", "alpha"] - ) - p.model.promotes( - "traj", - inputs=[ - ("ascent.parameters:t_init_gear", "t_init_gear"), - ("ascent.parameters:t_init_flaps", "t_init_flaps"), - ("ascent.t_initial", "ascent:t_initial"), - ("ascent.t_duration", Mission.Takeoff.ASCENT_DURATION), - ], - ) - - p.model.promotes( - "traj", - inputs=[ - ( - "groundroll.parameters:" + Mission.Design.GROSS_MASS, - Mission.Design.GROSS_MASS, - ), - ( - "rotation.parameters:" + Mission.Design.GROSS_MASS, - Mission.Design.GROSS_MASS, - ), - ( - "ascent.parameters:" + Mission.Design.GROSS_MASS, - Mission.Design.GROSS_MASS, - ), - ], - ) - p.model.set_input_defaults(Mission.Design.GROSS_MASS, 175400, units="lbm") - - p.model.set_input_defaults("ascent:t_initial", val=10.0) - p.model.set_input_defaults(Mission.Takeoff.ASCENT_DURATION, val=30.0) - - ascent_tx = ascent.options["transcription"] - ascent_num_nodes = ascent_tx.grid_data.num_nodes - p.model.add_subsystem( - "h_fit", - PolynomialFit(N_cp=ascent_num_nodes), - promotes_inputs=["t_init_gear", "t_init_flaps"], - ) - p.model.connect("traj.ascent.timeseries.time", "h_fit.time_cp") - p.model.connect("traj.ascent.timeseries.states:altitude", "h_fit.h_cp") - - # TODO: re-parameterize time to be 0-1 (i.e. add a component that offsets by t_initial/t_duration) - p.model.add_design_var("tau_gear", lower=0.01, upper=0.75, units="s", ref=1) - p.model.add_constraint("h_fit.h_init_gear", equals=50.0, units="ft", ref=50.0) - - p.model.add_design_var("tau_flaps", lower=0.3, upper=1.0, units="s", ref=1) - p.model.add_constraint("h_fit.h_init_flaps", equals=400.0, units="ft", ref=400.0) - - p.model.add_objective( - "traj.ascent.timeseries.states:mass", index=-1, ref0=-1.747e5, ref=-1.749e5 - ) - - p.driver = om.pyOptSparseDriver() - p.driver.options["optimizer"] = "SNOPT" - p.driver.opt_settings["Major feasibility tolerance"] = 1.0e-7 - p.driver.opt_settings["Major optimality tolerance"] = 1.0e-2 - p.driver.opt_settings["Function precision"] = 1e-6 - p.driver.opt_settings["Linesearch tolerance"] = 0.95 - p.driver.opt_settings["iSumm"] = 6 - p.driver.declare_coloring() - - p.model.linear_solver = om.DirectSolver() - - p.setup() - - p.set_val("traj.groundroll.states:TAS", 0, units="kn") - p.set_val( - "traj.groundroll.states:mass", - groundroll.interp("mass", [175100, 174000]), - units="lbm", - ) - p.set_val( - "traj.groundroll.states:distance", - groundroll.interp("distance", [0, 1000]), - units="ft", - ) - p.set_val("traj.groundroll.t_duration", 50.0) - - p.set_val( - "traj.rotation.states:alpha", rotation.interp("alpha", [0, 2.5]), units="deg" - ) - p.set_val("traj.rotation.states:TAS", 143, units="kn") - p.set_val( - "traj.rotation.states:mass", - rotation.interp("mass", [174975.12776915, 174000]), - units="lbm", - ) - p.set_val( - "traj.rotation.states:distance", - rotation.interp("distance", [3680.37217765, 4000]), - units="ft", - ) - p.set_val("traj.rotation.t_duration", 50.0) - - p.set_val( - "traj.ascent.states:altitude", - ascent.interp(Dynamic.Mission.ALTITUDE, ys=[0, 100, 500], xs=[0, 1, 10]), - units="ft", - ) - p.set_val("traj.ascent.states:flight_path_angle", 0.0, units="rad") - p.set_val( - "traj.ascent.states:TAS", ascent.interp("TAS", [153.3196491, 500]), units="kn" - ) - p.set_val( - "traj.ascent.states:mass", - ascent.interp("mass", [174963.74211336, 174000]), - units="lbm", - ) - p.set_val( - "traj.ascent.states:distance", - ascent.interp("distance", [4330.83393029, 5000]), - units="ft", - ) - p.set_val("traj.ascent.t_initial", 31.2) - p.set_val("traj.ascent.t_duration", 10.0) - - # event trigger times - p.set_val("tau_gear", 0.2) # initial guess - p.set_val("tau_flaps", 0.5) # initial guess - - p.set_solver_print(level=-1) - - dm.run_problem(p, simulate=True, make_plots=make_plots) - - return p From ccbdc74f53a3fe1bf3a0c3372081dfcf4577c5de Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 17 Jan 2024 15:18:15 -0600 Subject: [PATCH 091/188] Renaming desc phase --- aviary/interface/methods_for_level2.py | 12 ++++++------ .../phases/{desc_phase.py => descent_phase.py} | 0 2 files changed, 6 insertions(+), 6 deletions(-) rename aviary/mission/gasp_based/phases/{desc_phase.py => descent_phase.py} (100%) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 268df097e..695257ecd 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -27,12 +27,12 @@ UnsteadySolvedODE from aviary.mission.gasp_based.phases.time_integration_traj import FlexibleTraj from aviary.mission.gasp_based.phases.time_integration_phases import SGMCruise -from aviary.mission.gasp_based.phases.new_groundroll_phase import GroundrollPhase -from aviary.mission.gasp_based.phases.new_rotation_phase import RotationPhase -from aviary.mission.gasp_based.phases.new_climb_phase import ClimbPhase -from aviary.mission.gasp_based.phases.new_accel_phase import AccelPhase -from aviary.mission.gasp_based.phases.new_ascent_phase import AscentPhase -from aviary.mission.gasp_based.phases.new_descent_phase import DescentPhase +from aviary.mission.gasp_based.phases.groundroll_phase import GroundrollPhase +from aviary.mission.gasp_based.phases.rotation_phase import RotationPhase +from aviary.mission.gasp_based.phases.climb_phase import ClimbPhase +from aviary.mission.gasp_based.phases.accel_phase import AccelPhase +from aviary.mission.gasp_based.phases.ascent_phase import AscentPhase +from aviary.mission.gasp_based.phases.descent_phase import DescentPhase from aviary.mission.gasp_based.phases.landing_group import LandingSegment from aviary.mission.gasp_based.phases.taxi_group import TaxiSegment from aviary.mission.gasp_based.phases.v_rotate_comp import VRotateComp diff --git a/aviary/mission/gasp_based/phases/desc_phase.py b/aviary/mission/gasp_based/phases/descent_phase.py similarity index 100% rename from aviary/mission/gasp_based/phases/desc_phase.py rename to aviary/mission/gasp_based/phases/descent_phase.py From 5a0f64b52bd3fa9a8acb1757d370713a62b9834a Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 17 Jan 2024 15:26:46 -0600 Subject: [PATCH 092/188] updated --- aviary/api.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aviary/api.py b/aviary/api.py index 9bd1e7104..fd6eef768 100644 --- a/aviary/api.py +++ b/aviary/api.py @@ -112,12 +112,12 @@ from aviary.mission.flops_based.phases.detailed_takeoff_phases import TakeoffBrakeToAbort as DetailedTakeoffBrakeToAbortPhaseBuilder # Phase getters # TODO these should be going away in favor of phase builders -from aviary.mission.gasp_based.phases.accel_phase import get_accel as get_2DOF_acceleration_phase -from aviary.mission.gasp_based.phases.ascent_phase import get_ascent as get_2DOF_ascent_phase -from aviary.mission.gasp_based.phases.climb_phase import get_climb as get_2DOF_climb_phase -from aviary.mission.gasp_based.phases.desc_phase import get_descent as get_2DOF_descent_phase -from aviary.mission.gasp_based.phases.groundroll_phase import get_groundroll as get_2DOF_groundroll_phase -from aviary.mission.gasp_based.phases.rotation_phase import get_rotation as get_2DOF_rotation_phase +from aviary.mission.gasp_based.phases.accel_phase import AccelPhase as TwoDOFAccelerationPhase +from aviary.mission.gasp_based.phases.ascent_phase import AscentPhase as TwoDOFAscentPhase +from aviary.mission.gasp_based.phases.climb_phase import ClimbPhase as TwoDOFClimbPhase +from aviary.mission.gasp_based.phases.descent_phase import DescentPhase as TwoDOFDescentPhase +from aviary.mission.gasp_based.phases.groundroll_phase import GroundrollPhase as TwoDOFGroundrollPhase +from aviary.mission.gasp_based.phases.rotation_phase import RotationPhase as TwoDOFRotationPhase # Trajectory builders From 07267c0c9daa11426c084e6ac34154442bfc3303 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 17 Jan 2024 16:52:22 -0600 Subject: [PATCH 093/188] Added battery data for example --- .github/install_env_from_github.sh | 4 +--- .../onboarding_ext_subsystem.ipynb | 2 +- .../model/reg_thevenin_interp_group.py | 23 +++++++++++++------ setup.py | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/.github/install_env_from_github.sh b/.github/install_env_from_github.sh index fb5eb9cf9..a87cd103f 100755 --- a/.github/install_env_from_github.sh +++ b/.github/install_env_from_github.sh @@ -49,7 +49,7 @@ fi # pyoptsparse_line=$(grep ' pyoptsparse' $input_yaml | sed 's/^ //') # Remove specified packages and write to an intermediate file -grep -v -e 'aviary' -e 'om-aviary' -e 'build-pyoptsparse' -e 'pyoptsparse' -e 'boring-battery' -e 'networkx' -e ' - pip:' $input_yaml > $intermediate_yaml +grep -v -e 'aviary' -e 'om-aviary' -e 'build-pyoptsparse' -e 'pyoptsparse' -e 'networkx' -e ' - pip:' $input_yaml > $intermediate_yaml # Check for 'dev' versions of OpenMDAO and Dymos if grep -q -e 'openmdao.*dev' $intermediate_yaml; then @@ -99,8 +99,6 @@ conda activate $env_name # Check flags and install special packages if needed pip install -r $requirements_txt -pip install "boring_battery @ git+https://github.com/jcchin/boring.git" - if [ "$install_openmdao_from_git" = true ]; then pip install git+https://github.com/OpenMDAO/OpenMDAO.git fi diff --git a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb index 5b6ac3718..e9052b03b 100644 --- a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb +++ b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb @@ -755,7 +755,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.8" + "version": "3.8.17" } }, "nbformat": 4, diff --git a/aviary/examples/external_subsystems/battery/model/reg_thevenin_interp_group.py b/aviary/examples/external_subsystems/battery/model/reg_thevenin_interp_group.py index d9096214f..ed271a289 100644 --- a/aviary/examples/external_subsystems/battery/model/reg_thevenin_interp_group.py +++ b/aviary/examples/external_subsystems/battery/model/reg_thevenin_interp_group.py @@ -2,7 +2,16 @@ from openmdao.api import Group, MetaModelStructuredComp -from boring.src.model.maps.s18650_battery import battery + +# These battery values are entirely fabricated and not representative of any real battery. +# This model is used as an example of how to integrate external subsystems in Aviary. +T_bp = np.array([0., 60.]) +SOC_bp = np.linspace(0., 1., 32) + +tU_oc = np.vstack((np.linspace(2.8, 4.2, 32), np.linspace(2.7, 4.1, 32))) +tC_Th = np.ones((2, 32)) * 1000.0 +tR_Th = np.vstack((np.linspace(0.06, 0.03, 32), np.linspace(0.04, 0.02, 32))) +tR_0 = np.vstack((np.linspace(0.06, 0.03, 32), np.linspace(0.04, 0.02, 32))) class RegTheveninInterpGroup(Group): @@ -16,13 +25,13 @@ def setup(self): thevenin_interp_comp = MetaModelStructuredComp(method='slinear', vec_size=n, training_data_gradients=False, extrapolate=True) - thevenin_interp_comp.add_input('T_batt', 1.0, battery.T_bp, units='degC') - thevenin_interp_comp.add_input('SOC', 1.0, battery.SOC_bp, units=None) - thevenin_interp_comp.add_output('C_Th', 1.0, battery.tC_Th, units='F') + thevenin_interp_comp.add_input('T_batt', 1.0, T_bp, units='degC') + thevenin_interp_comp.add_input('SOC', 1.0, SOC_bp, units=None) + thevenin_interp_comp.add_output('C_Th', 1.0, tC_Th, units='F') # add R_th and R_0 to get total R - thevenin_interp_comp.add_output('R_Th', 1.0, battery.tR_Th, units='ohm') - thevenin_interp_comp.add_output('R_0', 1.0, battery.tR_0, units='ohm') - thevenin_interp_comp.add_output('U_oc', 1.0, battery.tU_oc, units='V') + thevenin_interp_comp.add_output('R_Th', 1.0, tR_Th, units='ohm') + thevenin_interp_comp.add_output('R_0', 1.0, tR_0, units='ohm') + thevenin_interp_comp.add_output('U_oc', 1.0, tU_oc, units='V') self.add_subsystem(name='interp_comp', subsys=thevenin_interp_comp, diff --git a/setup.py b/setup.py index 4412061a9..52eaa3235 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ pkgname = "aviary" extras_require = { "test": ["testflo", "pyxdsm", "pre-commit"], - "examples": ["openaerostruct", "ambiance", "boring_battery @ git+https://github.com/jcchin/boring.git"], + "examples": ["openaerostruct", "ambiance"], } all_packages = [] From 5bc9b4eea8898945ff3c3bf38f60cfd8e4613dac Mon Sep 17 00:00:00 2001 From: swryan Date: Thu, 18 Jan 2024 09:59:30 -0500 Subject: [PATCH 094/188] fix bug in subsytem tester --- aviary/subsystems/test/subsystem_tester.py | 5 ++++- setup.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/aviary/subsystems/test/subsystem_tester.py b/aviary/subsystems/test/subsystem_tester.py index 4a65edb0d..0f16f37db 100644 --- a/aviary/subsystems/test/subsystem_tester.py +++ b/aviary/subsystems/test/subsystem_tester.py @@ -23,7 +23,10 @@ def import_builder(path_to_builder: str, base_package='aviary.examples.external_ ''' try: package, method = path_to_builder.rsplit('.', 1) - module = import_module(package, base_package) + package_path, package_name = package.rsplit('.', 1) + module_path = '.'.join([path_to_builder, package_path]) if package_path \ + else path_to_builder + module = import_module(package_name, module_path) builder = getattr(module, method) except ImportError: builder = 'Skipping due to missing dependencies' diff --git a/setup.py b/setup.py index 4412061a9..35cb14eaa 100644 --- a/setup.py +++ b/setup.py @@ -65,7 +65,7 @@ "visualization/assets/*", "visualization/assets/aviary_vars/*" ], - 'aviary.docs': ['*.py', + f"{pkgname}.docs": ['*.py', 'tests/*.py', '*/*.md', '*/*.ipynb', From d840553ffa002a5db7dbc40675a67a522d2e8dd8 Mon Sep 17 00:00:00 2001 From: jkirk5 Date: Thu, 18 Jan 2024 10:42:18 -0500 Subject: [PATCH 095/188] small cleanups --- aviary/interface/methods_for_level2.py | 1 - aviary/utils/process_input_decks.py | 4 ---- 2 files changed, 5 deletions(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 3cb04126c..0b2a87cce 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -167,7 +167,6 @@ def load_inputs(self, aviary_inputs, phase_info=None, engine_builder=None): # 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) - # aviary_inputs = self.aviary_inputs # pull which methods will be used for subsystems and mission self.mission_method = mission_method = aviary_inputs.get_val( diff --git a/aviary/utils/process_input_decks.py b/aviary/utils/process_input_decks.py index 840d254f6..469a1224b 100644 --- a/aviary/utils/process_input_decks.py +++ b/aviary/utils/process_input_decks.py @@ -160,10 +160,6 @@ def update_GASP_options(aircraft_values: AviaryValues(), initial_guesses): GASP_defaults.update(aircraft_values) aircraft_values = GASP_defaults - for var in initial_guesses: - if var in aircraft_values: - initial_guesses[var], _ = aircraft_values.get_item(var) - # update the options that depend on variables update_dependent_options(aircraft_values, dependent_options) From 3d69eb2fa437f0ac1744498dc7ecce1c64cce48e Mon Sep 17 00:00:00 2001 From: swryan Date: Thu, 18 Jan 2024 10:59:12 -0500 Subject: [PATCH 096/188] fix indent in setup.py --- setup.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 35cb14eaa..822a255b5 100644 --- a/setup.py +++ b/setup.py @@ -65,12 +65,14 @@ "visualization/assets/*", "visualization/assets/aviary_vars/*" ], - f"{pkgname}.docs": ['*.py', - 'tests/*.py', - '*/*.md', - '*/*.ipynb', - '*/*/*.md', - '*/*/*.ipynb',], + f"{pkgname}.docs": [ + "*.py", + "tests/*.py", + "*/*.md", + "*/*.ipynb", + "*/*/*.md", + "*/*/*.ipynb", + ], f"{pkgname}.subsystems.aero.test.data": ["*.csv"], f"{pkgname}.subsystems.prop.test": ["*.csv"], }, From 10e436b45e9717dc45842db0614d349926c04faa Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Thu, 18 Jan 2024 11:21:28 -0500 Subject: [PATCH 097/188] successfully moved ClimbODE edits out of balance --- aviary/mission/gasp_based/ode/accel_ode.py | 25 +++++++++++ aviary/mission/gasp_based/ode/climb_ode.py | 49 +++++++++++----------- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/aviary/mission/gasp_based/ode/accel_ode.py b/aviary/mission/gasp_based/ode/accel_ode.py index eae09fe28..f47fc29e2 100644 --- a/aviary/mission/gasp_based/ode/accel_ode.py +++ b/aviary/mission/gasp_based/ode/accel_ode.py @@ -9,6 +9,8 @@ from aviary.subsystems.mass.mass_to_weight import MassToWeight from aviary.variable_info.enums import AnalysisScheme, SpeedType from aviary.variable_info.variables import Aircraft, Dynamic, Mission +from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate +from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate class AccelODE(BaseODE): @@ -93,6 +95,29 @@ def setup(self): + sgm_outputs, ) + # the last two subsystems will also be used for constraints + self.add_subsystem( + name='SPECIFIC_ENERGY_RATE_EXCESS', + subsys=SpecificEnergyRate(num_nodes=nn), + promotes_inputs=[(Dynamic.Mission.VELOCITY, "TAS"), Dynamic.Mission.MASS, + (Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.THRUST_MAX_TOTAL), + Dynamic.Mission.DRAG], + promotes_outputs=[(Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS)] + ) + + self.add_subsystem( + name='ALTITUDE_RATE_MAX', + subsys=AltitudeRate(num_nodes=nn), + promotes_inputs=[ + (Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS), + (Dynamic.Mission.VELOCITY_RATE, "TAS_rate"), + (Dynamic.Mission.VELOCITY, "TAS")], + promotes_outputs=[ + (Dynamic.Mission.ALTITUDE_RATE, + Dynamic.Mission.ALTITUDE_RATE_MAX)]) + ParamPort.set_default_vals(self) self.set_input_defaults(Dynamic.Mission.MASS, val=14e4 * np.ones(nn), units="lbm") diff --git a/aviary/mission/gasp_based/ode/climb_ode.py b/aviary/mission/gasp_based/ode/climb_ode.py index c85752ac4..f112ea38c 100644 --- a/aviary/mission/gasp_based/ode/climb_ode.py +++ b/aviary/mission/gasp_based/ode/climb_ode.py @@ -199,29 +199,6 @@ def setup(self): ], ) - # defalting to outside the balance to minimize calcs. - self.add_subsystem( - name='SPECIFIC_ENERGY_RATE_EXCESS', - subsys=SpecificEnergyRate(num_nodes=nn), - promotes_inputs=[(Dynamic.Mission.VELOCITY, "TAS"), Dynamic.Mission.MASS, - Dynamic.Mission.THRUST_MAX_TOTAL, Dynamic.Mission.DRAG], - promotes_outputs=[(Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS)] - ) - - # Note when TAS_rate = 0, SPECIFIC_ENERGY_RATE_EXCESS = ALTITUDE_RATE_MAX - self.add_subsystem( - name='ALTITUDE_RATE_MAX', - subsys=AltitudeRate(num_nodes=nn), - promotes_inputs=[ - (Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS), - (Dynamic.Mission.VELOCITY_RATE, "TAS_rate"), - (Dynamic.Mission.VELOCITY, "TAS")], - promotes_outputs=[ - (Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.ALTITUDE_RATE_MAX)]) - self.AddAlphaControl( alpha_group=lift_balance_group, alpha_mode=AlphaModes.REQUIRED_LIFT, @@ -243,9 +220,33 @@ def setup(self): + constraint_inputs, promotes_outputs=["theta", "TAS_violation"], ) + + # the last two subsystems will also be used for constraints + self.add_subsystem( + name='SPECIFIC_ENERGY_RATE_EXCESS', + subsys=SpecificEnergyRate(num_nodes=nn), + promotes_inputs=[(Dynamic.Mission.VELOCITY, "TAS"), Dynamic.Mission.MASS, + (Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.THRUST_MAX_TOTAL), + Dynamic.Mission.DRAG], + promotes_outputs=[(Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS)] + ) + + self.add_subsystem( + name='ALTITUDE_RATE_MAX', + subsys=AltitudeRate(num_nodes=nn), + promotes_inputs=[ + (Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS), + (Dynamic.Mission.VELOCITY_RATE, "TAS_rate"), + (Dynamic.Mission.VELOCITY, "TAS")], + promotes_outputs=[ + (Dynamic.Mission.ALTITUDE_RATE, + Dynamic.Mission.ALTITUDE_RATE_MAX)]) + if analysis_scheme is AnalysisScheme.COLLOCATION: self.set_order(['params', 'USatm', 'mach_balance_group'] + prop_groups + - ['lift_balance_group', 'constraints']) + ['lift_balance_group', 'constraints', 'SPECIFIC_ENERGY_RATE_EXCESS', 'ALTITUDE_RATE_MAX']) ParamPort.set_default_vals(self) self.set_input_defaults("CL_max", val=5 * np.ones(nn), units="unitless") From 281266d0db63a17d51b579cfe148e4c93ebca50f Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Thu, 18 Jan 2024 11:43:10 -0500 Subject: [PATCH 098/188] Commented out tmate --- .github/workflows/test_workflow.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 436b1947c..6927d7b51 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -213,8 +213,8 @@ jobs: python run_all.py cd ../.. - - name: Setup tmate session - uses: mxschmitt/action-tmate@v3 + # - name: Setup tmate session + # uses: mxschmitt/action-tmate@v3 - name: Run tests From 97688d687d86f2df1ab57d28c80fcb5e563c7e64 Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Thu, 18 Jan 2024 11:47:58 -0500 Subject: [PATCH 099/188] climb_start_range to climb_start_distance --- aviary/docs/getting_started/onboarding_level3.ipynb | 12 ++++++------ ..._of_the_same_mission_at_different_UI_levels.ipynb | 6 +++--- .../test_FLOPS_based_full_mission_N3CC.py | 6 +++--- ..._FLOPS_based_full_mission_large_single_aisle_1.py | 6 +++--- ..._FLOPS_based_full_mission_large_single_aisle_2.py | 6 +++--- .../benchmark_tests/test_FLOPS_based_sizing_N3CC.py | 6 +++--- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/aviary/docs/getting_started/onboarding_level3.ipynb b/aviary/docs/getting_started/onboarding_level3.ipynb index 6d8915358..249a167d1 100644 --- a/aviary/docs/getting_started/onboarding_level3.ipynb +++ b/aviary/docs/getting_started/onboarding_level3.ipynb @@ -340,14 +340,14 @@ " om.ExecComp(\n", " [\n", " \"takeoff_mass_con=takeoff_mass-climb_start_mass\",\n", - " \"takeoff_distance_con=takeoff_range-climb_start_range\",\n", + " \"takeoff_distance_con=takeoff_range-climb_start_distance\",\n", " \"takeoff_vel_con=takeoff_vel-climb_start_vel\",\n", " \"takeoff_alt_con=takeoff_alt-climb_start_alt\"\n", " ],\n", " takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'},\n", " climb_start_mass={'units': 'lbm'},\n", " takeoff_distance_con={'units': 'ft'}, takeoff_range={'units': 'ft'},\n", - " climb_start_range={'units': 'ft'},\n", + " climb_start_distance={'units': 'ft'},\n", " takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'},\n", " climb_start_vel={'units': 'm/s'},\n", " takeoff_alt_con={'units': 'ft'}, takeoff_alt={'units': 'ft'},\n", @@ -366,7 +366,7 @@ "prob.model.connect('traj.climb.states:mass',\n", " 'takeoff_constraints.climb_start_mass', src_indices=[0])\n", "prob.model.connect('traj.climb.states:distance',\n", - " 'takeoff_constraints.climb_start_range', src_indices=[0])\n", + " 'takeoff_constraints.climb_start_distance', src_indices=[0])\n", "prob.model.connect('traj.climb.states:velocity',\n", " 'takeoff_constraints.climb_start_vel', src_indices=[0])\n", "prob.model.connect('traj.climb.states:altitude',\n", @@ -695,14 +695,14 @@ " om.ExecComp(\n", " [\n", " \"takeoff_mass_con=takeoff_mass-climb_start_mass\",\n", - " \"takeoff_distance_con=takeoff_range-climb_start_range\",\n", + " \"takeoff_distance_con=takeoff_range-climb_start_distance\",\n", " \"takeoff_vel_con=takeoff_vel-climb_start_vel\",\n", " \"takeoff_alt_con=takeoff_alt-climb_start_alt\"\n", " ],\n", " takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'},\n", " climb_start_mass={'units': 'lbm'},\n", " takeoff_distance_con={'units': 'ft'}, takeoff_range={'units': 'ft'},\n", - " climb_start_range={'units': 'ft'},\n", + " climb_start_distance={'units': 'ft'},\n", " takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'},\n", " climb_start_vel={'units': 'm/s'},\n", " takeoff_alt_con={'units': 'ft'}, takeoff_alt={'units': 'ft'},\n", @@ -977,7 +977,7 @@ " prob.model.connect('traj.climb.states:mass',\n", " 'takeoff_constraints.climb_start_mass', src_indices=[0])\n", " prob.model.connect('traj.climb.states:distance',\n", - " 'takeoff_constraints.climb_start_range', src_indices=[0])\n", + " 'takeoff_constraints.climb_start_distance', src_indices=[0])\n", " prob.model.connect('traj.climb.states:velocity',\n", " 'takeoff_constraints.climb_start_vel', src_indices=[0])\n", " prob.model.connect('traj.climb.states:altitude',\n", 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 1cbe7da34..711c18eec 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 @@ -448,14 +448,14 @@ " om.ExecComp(\n", " [\n", " \"takeoff_mass_con=takeoff_mass-climb_start_mass\",\n", - " \"takeoff_distance_con=takeoff_range-climb_start_range\",\n", + " \"takeoff_distance_con=takeoff_range-climb_start_distance\",\n", " \"takeoff_vel_con=takeoff_vel-climb_start_vel\",\n", " \"takeoff_alt_con=takeoff_alt-climb_start_alt\"\n", " ],\n", " takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'},\n", " climb_start_mass={'units': 'lbm'},\n", " takeoff_distance_con={'units': 'ft'}, takeoff_range={'units': 'ft'},\n", - " climb_start_range={'units': 'ft'},\n", + " climb_start_distance={'units': 'ft'},\n", " takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'},\n", " climb_start_vel={'units': 'm/s'},\n", " takeoff_alt_con={'units': 'ft'}, takeoff_alt={'units': 'ft'},\n", @@ -474,7 +474,7 @@ "prob.model.connect('traj.climb.states:mass',\n", " 'takeoff_constraints.climb_start_mass', src_indices=[0])\n", "prob.model.connect('traj.climb.states:distance',\n", - " 'takeoff_constraints.climb_start_range', src_indices=[0])\n", + " 'takeoff_constraints.climb_start_distance', src_indices=[0])\n", "prob.model.connect('traj.climb.states:velocity',\n", " 'takeoff_constraints.climb_start_vel', src_indices=[0])\n", "prob.model.connect('traj.climb.states:altitude',\n", diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py index 4ae6d3e1d..8698766b9 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_N3CC.py @@ -268,14 +268,14 @@ def run_trajectory(driver: Driver, sim=True): om.ExecComp( [ "takeoff_mass_con=takeoff_mass-climb_start_mass", - "takeoff_range_con=takeoff_range-climb_start_range", + "takeoff_range_con=takeoff_range-climb_start_distance", "takeoff_vel_con=takeoff_vel-climb_start_vel", "takeoff_alt_con=takeoff_alt-climb_start_alt" ], takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'}, climb_start_mass={'units': 'lbm'}, takeoff_range_con={'units': 'ft'}, takeoff_range={'units': 'ft'}, - climb_start_range={'units': 'ft'}, + climb_start_distance={'units': 'ft'}, takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'}, climb_start_vel={'units': 'm/s'}, takeoff_alt_con={'units': 'ft'}, takeoff_alt={'units': 'ft'}, @@ -294,7 +294,7 @@ def run_trajectory(driver: Driver, sim=True): prob.model.connect('traj.climb.states:mass', 'takeoff_constraints.climb_start_mass', src_indices=[0]) prob.model.connect('traj.climb.states:distance', - 'takeoff_constraints.climb_start_range', src_indices=[0]) + 'takeoff_constraints.climb_start_distance', src_indices=[0]) prob.model.connect('traj.climb.states:velocity', 'takeoff_constraints.climb_start_vel', src_indices=[0]) prob.model.connect('traj.climb.states:altitude', diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py index a5b6cca94..376c50158 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_1.py @@ -274,14 +274,14 @@ def run_trajectory(sim=True): om.ExecComp( [ "takeoff_mass_con=takeoff_mass-climb_start_mass", - "takeoff_range_con=takeoff_range-climb_start_range", + "takeoff_range_con=takeoff_range-climb_start_distance", "takeoff_vel_con=takeoff_vel-climb_start_vel", "takeoff_alt_con=takeoff_alt-climb_start_alt" ], takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'}, climb_start_mass={'units': 'lbm'}, takeoff_range_con={'units': 'ft'}, takeoff_range={'units': 'ft'}, - climb_start_range={'units': 'ft'}, + climb_start_distance={'units': 'ft'}, takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'}, climb_start_vel={'units': 'm/s'}, takeoff_alt_con={'units': 'ft'}, takeoff_alt={'units': 'ft'}, @@ -300,7 +300,7 @@ def run_trajectory(sim=True): prob.model.connect('traj.climb.states:mass', 'takeoff_constraints.climb_start_mass', src_indices=[0]) prob.model.connect('traj.climb.states:distance', - 'takeoff_constraints.climb_start_range', src_indices=[0]) + 'takeoff_constraints.climb_start_distance', src_indices=[0]) prob.model.connect('traj.climb.states:velocity', 'takeoff_constraints.climb_start_vel', src_indices=[0]) prob.model.connect('traj.climb.states:altitude', diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py index 76566f394..84ed5bbc7 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_full_mission_large_single_aisle_2.py @@ -268,14 +268,14 @@ def run_trajectory(sim=True): om.ExecComp( [ "takeoff_mass_con=takeoff_mass-climb_start_mass", - "takeoff_range_con=takeoff_range-climb_start_range", + "takeoff_range_con=takeoff_range-climb_start_distance", "takeoff_vel_con=takeoff_vel-climb_start_vel", "takeoff_alt_con=takeoff_alt-climb_start_alt" ], takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'}, climb_start_mass={'units': 'lbm'}, takeoff_range_con={'units': 'ft'}, takeoff_range={'units': 'ft'}, - climb_start_range={'units': 'ft'}, + climb_start_distance={'units': 'ft'}, takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'}, climb_start_vel={'units': 'm/s'}, takeoff_alt_con={'units': 'ft'}, takeoff_alt={'units': 'ft'}, @@ -294,7 +294,7 @@ def run_trajectory(sim=True): prob.model.connect('traj.climb.states:mass', 'takeoff_constraints.climb_start_mass', src_indices=[0]) prob.model.connect('traj.climb.states:distance', - 'takeoff_constraints.climb_start_range', src_indices=[0]) + 'takeoff_constraints.climb_start_distance', src_indices=[0]) prob.model.connect('traj.climb.states:velocity', 'takeoff_constraints.climb_start_vel', src_indices=[0]) prob.model.connect('traj.climb.states:altitude', 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 4d05ca9f4..4e248b306 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 @@ -307,14 +307,14 @@ def run_trajectory(sim=True): om.ExecComp( [ "takeoff_mass_con=takeoff_mass-climb_start_mass", - "takeoff_range_con=takeoff_range-climb_start_range", + "takeoff_range_con=takeoff_range-climb_start_distance", "takeoff_vel_con=takeoff_vel-climb_start_vel", "takeoff_alt_con=takeoff_alt-climb_start_alt" ], takeoff_mass_con={'units': 'lbm'}, takeoff_mass={'units': 'lbm'}, climb_start_mass={'units': 'lbm'}, takeoff_range_con={'units': 'ft'}, takeoff_range={'units': 'ft'}, - climb_start_range={'units': 'ft'}, + climb_start_distance={'units': 'ft'}, takeoff_vel_con={'units': 'm/s'}, takeoff_vel={'units': 'm/s'}, climb_start_vel={'units': 'm/s'}, takeoff_alt_con={'units': 'ft'}, takeoff_alt={'units': 'ft'}, @@ -333,7 +333,7 @@ def run_trajectory(sim=True): prob.model.connect('traj.climb.states:mass', 'takeoff_constraints.climb_start_mass', src_indices=[0]) prob.model.connect('traj.climb.states:distance', - 'takeoff_constraints.climb_start_range', src_indices=[0]) + 'takeoff_constraints.climb_start_distance', src_indices=[0]) prob.model.connect('traj.climb.states:velocity', 'takeoff_constraints.climb_start_vel', src_indices=[0]) prob.model.connect('traj.climb.states:altitude', From 579c5135114a12f1b9bc82320c76fd4c0336e8b0 Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Thu, 18 Jan 2024 12:02:10 -0500 Subject: [PATCH 100/188] changed max_range to distance_max --- ...S_based_detailed_takeoff_and_landing.ipynb | 12 +- .../phases/detailed_landing_phases.py | 52 ++++----- .../phases/detailed_takeoff_phases.py | 108 +++++++++--------- aviary/models/N3CC/N3CC_data.py | 46 ++++---- .../test_FLOPS_balanced_field_length.py | 4 +- .../test_FLOPS_detailed_landing.py | 4 +- .../test_FLOPS_detailed_takeoff.py | 4 +- 7 files changed, 115 insertions(+), 115 deletions(-) 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 e13abbf88..97de4a087 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 @@ -138,7 +138,7 @@ "\n", "takeoff_brake_release_user_options.set_val('max_duration', val=60.0, units='s')\n", "takeoff_brake_release_user_options.set_val('duration_ref', val=60.0, units='s')\n", - "takeoff_brake_release_user_options.set_val('max_range', val=7500.0, units='ft')\n", + "takeoff_brake_release_user_options.set_val('distance_max', val=7500.0, units='ft')\n", "takeoff_brake_release_user_options.set_val('max_velocity', val=167.85, units='kn')\n", "\n", "takeoff_brake_release_initial_guesses = av.AviaryValues()\n", @@ -295,11 +295,11 @@ "takeoff_trajectory_builder.build_trajectory(\n", " aviary_options=aviary_options, model=takeoff.model, traj=traj)\n", "\n", - "max_range, units = takeoff_liftoff_user_options.get_item('max_range')\n", + "distance_max, units = takeoff_liftoff_user_options.get_item('distance_max')\n", "liftoff = takeoff_trajectory_builder.get_phase('takeoff_liftoff')\n", "\n", "liftoff.add_objective(\n", - " Dynamic.Mission.DISTANCE, loc='final', ref=max_range, units=units)\n", + " Dynamic.Mission.DISTANCE, loc='final', ref=distance_max, units=units)\n", "\n", "# Insert a constraint for a fake decision speed, until abort is added.\n", "takeoff.model.add_constraint(\n", @@ -431,7 +431,7 @@ "landing_approach_to_mic_p3_user_options.set_val('max_duration', val=50., units='s')\n", "landing_approach_to_mic_p3_user_options.set_val('duration_ref', val=50., units='s')\n", "landing_approach_to_mic_p3_user_options.set_val('initial_ref', val=50.0, units='s')\n", - "landing_approach_to_mic_p3_user_options.set_val('max_range', val=10000., units='ft')\n", + "landing_approach_to_mic_p3_user_options.set_val('distance_max', val=10000., units='ft')\n", "landing_approach_to_mic_p3_user_options.set_val('max_velocity', val=140., units='kn')\n", "landing_approach_to_mic_p3_user_options.set_val('altitude_ref', val=800., units='ft')\n", "\n", @@ -548,10 +548,10 @@ "landing_trajectory_builder.build_trajectory(\n", " aviary_options=aviary_options, model=landing.model, traj=traj)\n", "\n", - "max_range, units = landing_fullstop_user_options.get_item('max_range')\n", + "distance_max, units = landing_fullstop_user_options.get_item('distance_max')\n", "fullstop = landing_trajectory_builder.get_phase('landing_fullstop')\n", "\n", - "fullstop.add_objective(Dynamic.Mission.DISTANCE, loc='final', ref=max_range, units=units)\n", + "fullstop.add_objective(Dynamic.Mission.DISTANCE, loc='final', ref=distance_max, units=units)\n", "\n", "landing.model.add_subsystem(\n", " 'input_sink',\n", diff --git a/aviary/mission/flops_based/phases/detailed_landing_phases.py b/aviary/mission/flops_based/phases/detailed_landing_phases.py index ee46b4a1e..c569ef794 100644 --- a/aviary/mission/flops_based/phases/detailed_landing_phases.py +++ b/aviary/mission/flops_based/phases/detailed_landing_phases.py @@ -61,7 +61,7 @@ class LandingApproachToMicP3(PhaseBuilderBase): - max_duration (100.0, 's') - duration_ref (1.0, 's') - initial_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') - altitude_ref (1.0, 'ft') - lower_angle_of_attack (-10.0, 'deg') @@ -145,12 +145,12 @@ def build_phase(self, aviary_options: AviaryValues = None): duration_ref=duration_ref, initial_ref=initial_ref, units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( Dynamic.Mission.DISTANCE, fix_initial=False, fix_final=False, - upper=0, ref=max_range, - defect_ref=max_range, units=units, + upper=0, ref=distance_max, + defect_ref=distance_max, units=units, rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') @@ -239,7 +239,7 @@ def _extra_ode_init_kwargs(self): LandingApproachToMicP3._add_meta_data('initial_ref', val=10.0, units='s') -LandingApproachToMicP3._add_meta_data('max_range', val=1000., units='ft') +LandingApproachToMicP3._add_meta_data('distance_max', val=1000., units='ft') LandingApproachToMicP3._add_meta_data('max_velocity', val=100., units='ft/s') @@ -284,7 +284,7 @@ class LandingMicP3ToObstacle(LandingApproachToMicP3): - max_duration (100.0, 's') - duration_ref (1.0, 's') - initial_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') - altitude_ref (1.0, 'ft') - lower_angle_of_attack (-10.0, 'deg') @@ -384,7 +384,7 @@ class LandingObstacleToFlare(PhaseBuilderBase): supported options: - max_duration (100.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') - altitude_ref (1.0, 'ft') @@ -461,11 +461,11 @@ def build_phase(self, aviary_options: AviaryValues = None): fix_initial=True, duration_bounds=(1, max_duration), units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=True, lower=0, ref=max_range, - defect_ref=max_range, units=units, + Dynamic.Mission.DISTANCE, fix_initial=True, lower=0, ref=distance_max, + defect_ref=distance_max, units=units, rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') @@ -545,7 +545,7 @@ def _extra_ode_init_kwargs(self): LandingObstacleToFlare._add_meta_data('max_duration', val=100., units='s') -LandingObstacleToFlare._add_meta_data('max_range', val=1000., units='ft') +LandingObstacleToFlare._add_meta_data('distance_max', val=1000., units='ft') LandingObstacleToFlare._add_meta_data('max_velocity', val=100., units='ft/s') @@ -581,7 +581,7 @@ class LandingFlareToTouchdown(PhaseBuilderBase): - max_duration (100.0, 's') - duration_ref (1.0, 's') - initial_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') - altitude_ref (1.0, 'ft') - lower_angle_of_attack (-10.0, 'deg') @@ -664,11 +664,11 @@ def build_phase(self, aviary_options: AviaryValues = None): duration_ref=duration_ref, initial_ref=initial_ref, units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, - defect_ref=max_range, units=units, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=distance_max, + defect_ref=distance_max, units=units, rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') @@ -764,7 +764,7 @@ def _extra_ode_init_kwargs(self): LandingFlareToTouchdown._add_meta_data('initial_ref', val=10.0, units='s') -LandingFlareToTouchdown._add_meta_data('max_range', val=1000., units='ft') +LandingFlareToTouchdown._add_meta_data('distance_max', val=1000., units='ft') LandingFlareToTouchdown._add_meta_data('max_velocity', val=100., units='ft/s') @@ -805,7 +805,7 @@ class LandingTouchdownToNoseDown(PhaseBuilderBase): - max_duration (5.0, 's') - duration_ref (1.0, 's') - initial_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') - max_angle_of_attack (10.0, 'deg') @@ -883,11 +883,11 @@ def build_phase(self, aviary_options=None): duration_ref=duration_ref, initial_ref=initial_ref, units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, - defect_ref=max_range, units=units, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=distance_max, + defect_ref=distance_max, units=units, rate_source=Dynamic.Mission.DISTANCE_RATE) max_velocity, units = user_options.get_item('max_velocity') @@ -952,7 +952,7 @@ def _extra_ode_init_kwargs(self): LandingTouchdownToNoseDown._add_meta_data('initial_ref', val=10.0, units='s') -LandingTouchdownToNoseDown._add_meta_data('max_range', val=1000.0, units='ft') +LandingTouchdownToNoseDown._add_meta_data('distance_max', val=1000.0, units='ft') LandingTouchdownToNoseDown._add_meta_data('max_velocity', val=100.0, units='ft/s') @@ -981,7 +981,7 @@ class LandingNoseDownToStop(PhaseBuilderBase): supported options: - max_duration - duration_ref - - max_range + - distance_max - max_velocity initial_guesses : AviaryValues () @@ -1058,12 +1058,12 @@ def build_phase(self, aviary_options=None): duration_ref=duration_ref, initial_ref=initial_ref, units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( Dynamic.Mission.DISTANCE, fix_initial=False, fix_final=False, - lower=0, ref=max_range, - defect_ref=max_range, units=units, + lower=0, ref=distance_max, + defect_ref=distance_max, units=units, rate_source=Dynamic.Mission.DISTANCE_RATE) max_velocity, units = user_options.get_item('max_velocity') @@ -1124,7 +1124,7 @@ def _extra_ode_init_kwargs(self): LandingNoseDownToStop._add_meta_data('initial_ref', val=10.0, units='s') -LandingNoseDownToStop._add_meta_data('max_range', val=1000.0, units='ft') +LandingNoseDownToStop._add_meta_data('distance_max', val=1000.0, units='ft') LandingNoseDownToStop._add_meta_data('max_velocity', val=100.0, units='ft/s') diff --git a/aviary/mission/flops_based/phases/detailed_takeoff_phases.py b/aviary/mission/flops_based/phases/detailed_takeoff_phases.py index e637c2a46..068157ae1 100644 --- a/aviary/mission/flops_based/phases/detailed_takeoff_phases.py +++ b/aviary/mission/flops_based/phases/detailed_takeoff_phases.py @@ -104,7 +104,7 @@ class TakeoffBrakeReleaseToDecisionSpeed(PhaseBuilderBase): supported options: - max_duration (1000.0, 's') - duration_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') initial_guesses : AviaryValues () @@ -179,11 +179,11 @@ def build_phase(self, aviary_options=None): fix_initial=True, duration_bounds=(1, max_duration), duration_ref=duration_ref, units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=True, lower=0, ref=max_range, - defect_ref=max_range, units=units, upper=max_range, + Dynamic.Mission.DISTANCE, fix_initial=True, lower=0, ref=distance_max, + defect_ref=distance_max, units=units, upper=distance_max, rate_source=Dynamic.Mission.DISTANCE_RATE) max_velocity, units = user_options.get_item('max_velocity') @@ -241,7 +241,7 @@ def _extra_ode_init_kwargs(self): TakeoffBrakeReleaseToDecisionSpeed._add_meta_data('duration_ref', val=10.0, units='s') -TakeoffBrakeReleaseToDecisionSpeed._add_meta_data('max_range', val=1000.0, units='ft') +TakeoffBrakeReleaseToDecisionSpeed._add_meta_data('distance_max', val=1000.0, units='ft') TakeoffBrakeReleaseToDecisionSpeed._add_meta_data( 'max_velocity', val=100.0, units='ft/s') @@ -271,7 +271,7 @@ class TakeoffDecisionSpeedToRotate(PhaseBuilderBase): - max_duration (1000.0, 's') - duration_ref (1.0, 's') - initial_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') initial_guesses : AviaryValues () @@ -349,11 +349,11 @@ def build_phase(self, aviary_options=None): duration_ref=duration_ref, initial_ref=initial_ref, units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, - defect_ref=max_range, units=units, upper=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=distance_max, + defect_ref=distance_max, units=units, upper=distance_max, rate_source=Dynamic.Mission.DISTANCE_RATE) max_velocity, units = user_options.get_item('max_velocity') @@ -419,7 +419,7 @@ def _extra_ode_init_kwargs(self): TakeoffDecisionSpeedToRotate._add_meta_data('initial_ref', val=10.0, units='s') -TakeoffDecisionSpeedToRotate._add_meta_data('max_range', val=1000.0, units='ft') +TakeoffDecisionSpeedToRotate._add_meta_data('distance_max', val=1000.0, units='ft') TakeoffDecisionSpeedToRotate._add_meta_data('max_velocity', val=100.0, units='ft/s') @@ -448,7 +448,7 @@ class TakeoffDecisionSpeedBrakeDelay(TakeoffDecisionSpeedToRotate): - max_duration (1000.0, 's') - duration_ref (1.0, 's') - initial_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') initial_guesses : AviaryValues () @@ -523,7 +523,7 @@ def build_phase(self, aviary_options=None): TakeoffDecisionSpeedBrakeDelay._add_meta_data('initial_ref', val=10.0, units='s') -TakeoffDecisionSpeedBrakeDelay._add_meta_data('max_range', val=1000.0, units='ft') +TakeoffDecisionSpeedBrakeDelay._add_meta_data('distance_max', val=1000.0, units='ft') TakeoffDecisionSpeedBrakeDelay._add_meta_data('max_velocity', val=100.0, units='ft/s') @@ -551,7 +551,7 @@ class TakeoffRotateToLiftoff(PhaseBuilderBase): - max_duration (5.0, 's') - duration_ref (1.0, 's') - initial_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') - max_angle_of_attack (10.0, 'deg') @@ -630,11 +630,11 @@ def build_phase(self, aviary_options=None): duration_ref=duration_ref, initial_ref=initial_ref, units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, - defect_ref=max_range, units=units, upper=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=distance_max, + defect_ref=distance_max, units=units, upper=distance_max, rate_source=Dynamic.Mission.DISTANCE_RATE) max_velocity, units = user_options.get_item('max_velocity') @@ -702,7 +702,7 @@ def _extra_ode_init_kwargs(self): TakeoffRotateToLiftoff._add_meta_data('initial_ref', val=10.0, units='s') -TakeoffRotateToLiftoff._add_meta_data('max_range', val=1000.0, units='ft') +TakeoffRotateToLiftoff._add_meta_data('distance_max', val=1000.0, units='ft') TakeoffRotateToLiftoff._add_meta_data('max_velocity', val=100.0, units='ft/s') @@ -733,7 +733,7 @@ class TakeoffLiftoffToObstacle(PhaseBuilderBase): - max_duration (100.0, 's') - duration_ref (1.0, 's') - initial_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') - altitude_ref (1.0, 'ft') - flight_path_angle_ref (5., 'deg') @@ -818,11 +818,11 @@ def build_phase(self, aviary_options: AviaryValues = None): duration_ref=duration_ref, initial_ref=initial_ref, units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, - defect_ref=max_range, units=units, upper=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=distance_max, + defect_ref=distance_max, units=units, upper=distance_max, rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') @@ -924,7 +924,7 @@ def _extra_ode_init_kwargs(self): TakeoffLiftoffToObstacle._add_meta_data('initial_ref', val=10.0, units='s') -TakeoffLiftoffToObstacle._add_meta_data('max_range', val=1000., units='ft') +TakeoffLiftoffToObstacle._add_meta_data('distance_max', val=1000., units='ft') TakeoffLiftoffToObstacle._add_meta_data('max_velocity', val=100., units='ft/s') @@ -968,7 +968,7 @@ class TakeoffObstacleToMicP2(PhaseBuilderBase): - max_duration (100.0, 's') - duration_ref (1.0, 's') - initial_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') - altitude_ref (1.0, 'ft') - flight_path_angle_ref (5., 'deg') @@ -1054,11 +1054,11 @@ def build_phase(self, aviary_options: AviaryValues = None): duration_ref=duration_ref, initial_ref=initial_ref, units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, - defect_ref=max_range, units=units, upper=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=distance_max, + defect_ref=distance_max, units=units, upper=distance_max, rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') @@ -1154,7 +1154,7 @@ def _extra_ode_init_kwargs(self): TakeoffObstacleToMicP2._add_meta_data('initial_ref', val=10.0, units='s') -TakeoffObstacleToMicP2._add_meta_data('max_range', val=1000., units='ft') +TakeoffObstacleToMicP2._add_meta_data('distance_max', val=1000., units='ft') TakeoffObstacleToMicP2._add_meta_data('max_velocity', val=100., units='ft/s') @@ -1200,7 +1200,7 @@ class TakeoffMicP2ToEngineCutback(PhaseBuilderBase): - max_duration (100.0, 's') - duration_ref (1.0, 's') - initial_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') - altitude_ref (1.0, 'ft') - flight_path_angle_ref (5., 'deg') @@ -1286,11 +1286,11 @@ def build_phase(self, aviary_options: AviaryValues = None): duration_ref=duration_ref, initial_ref=initial_ref, units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, - defect_ref=max_range, units=units, upper=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=distance_max, + defect_ref=distance_max, units=units, upper=distance_max, rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') @@ -1347,8 +1347,8 @@ def build_phase(self, aviary_options: AviaryValues = None): ) # start engine cutback phase at this range, where this phase ends - # TODO: what is the difference between max_range and final_range? - # - should final_range replace max_range? + # TODO: what is the difference between distance_max and final_range? + # - should final_range replace distance_max? # - is there any reason to support both in this phase? final_range, units = user_options.get_item('final_range') @@ -1386,7 +1386,7 @@ def _extra_ode_init_kwargs(self): TakeoffMicP2ToEngineCutback._add_meta_data('initial_ref', val=10.0, units='s') -TakeoffMicP2ToEngineCutback._add_meta_data('max_range', val=1000., units='ft') +TakeoffMicP2ToEngineCutback._add_meta_data('distance_max', val=1000., units='ft') TakeoffMicP2ToEngineCutback._add_meta_data('max_velocity', val=100., units='ft/s') @@ -1431,7 +1431,7 @@ class TakeoffEngineCutback(PhaseBuilderBase): supported options: - initial_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') - altitude_ref (1.0, 'ft') - flight_path_angle_ref (5., 'deg') @@ -1514,11 +1514,11 @@ def build_phase(self, aviary_options: AviaryValues = None): initial_ref=initial_ref, units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, - defect_ref=max_range, units=units, upper=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=distance_max, + defect_ref=distance_max, units=units, upper=distance_max, rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') @@ -1600,7 +1600,7 @@ def _extra_ode_init_kwargs(self): TakeoffEngineCutback._add_meta_data('initial_ref', val=10.0, units='s') -TakeoffEngineCutback._add_meta_data('max_range', val=1000., units='ft') +TakeoffEngineCutback._add_meta_data('distance_max', val=1000., units='ft') TakeoffEngineCutback._add_meta_data('max_velocity', val=100., units='ft/s') @@ -1644,7 +1644,7 @@ class TakeoffEngineCutbackToMicP1(PhaseBuilderBase): - max_duration (100.0, 's') - duration_ref (1.0, 's') - initial_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') - altitude_ref (1.0, 'ft') - flight_path_angle_ref (5., 'deg') @@ -1730,11 +1730,11 @@ def build_phase(self, aviary_options: AviaryValues = None): duration_ref=duration_ref, initial_ref=initial_ref, units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, - defect_ref=max_range, units=units, upper=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=distance_max, + defect_ref=distance_max, units=units, upper=distance_max, rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') @@ -1826,7 +1826,7 @@ def _extra_ode_init_kwargs(self): TakeoffEngineCutbackToMicP1._add_meta_data('initial_ref', val=10.0, units='s') -TakeoffEngineCutbackToMicP1._add_meta_data('max_range', val=1000., units='ft') +TakeoffEngineCutbackToMicP1._add_meta_data('distance_max', val=1000., units='ft') TakeoffEngineCutbackToMicP1._add_meta_data('max_velocity', val=100., units='ft/s') @@ -1873,7 +1873,7 @@ class TakeoffMicP1ToClimb(PhaseBuilderBase): - max_duration (100.0, 's') - duration_ref (1.0, 's') - initial_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') - altitude_ref (1.0, 'ft') - flight_path_angle_ref (5., 'deg') @@ -1959,11 +1959,11 @@ def build_phase(self, aviary_options: AviaryValues = None): duration_ref=duration_ref, initial_ref=initial_ref, units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, - defect_ref=max_range, units=units, upper=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=distance_max, + defect_ref=distance_max, units=units, upper=distance_max, rate_source=Dynamic.Mission.DISTANCE_RATE) altitude_ref, units = user_options.get_item('altitude_ref') @@ -2055,7 +2055,7 @@ def _extra_ode_init_kwargs(self): TakeoffMicP1ToClimb._add_meta_data('initial_ref', val=10.0, units='s') -TakeoffMicP1ToClimb._add_meta_data('max_range', val=1000., units='ft') +TakeoffMicP1ToClimb._add_meta_data('distance_max', val=1000., units='ft') TakeoffMicP1ToClimb._add_meta_data('max_velocity', val=100., units='ft/s') @@ -2101,7 +2101,7 @@ class TakeoffBrakeToAbort(PhaseBuilderBase): - max_duration (1000.0, 's') - duration_ref (1.0, 's') - initial_ref (10.0, 's') - - max_range (1000.0, 'ft') + - distance_max (1000.0, 'ft') - max_velocity (100.0, 'ft/s') initial_guesses : AviaryValues () @@ -2179,11 +2179,11 @@ def build_phase(self, aviary_options=None): duration_ref=duration_ref, initial_ref=initial_ref, units=units) - max_range, units = user_options.get_item('max_range') + distance_max, units = user_options.get_item('distance_max') phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=max_range, - defect_ref=max_range, units=units, upper=max_range, + Dynamic.Mission.DISTANCE, fix_initial=False, lower=0, ref=distance_max, + defect_ref=distance_max, units=units, upper=distance_max, rate_source=Dynamic.Mission.DISTANCE_RATE) max_velocity, units = user_options.get_item('max_velocity') @@ -2234,7 +2234,7 @@ def _extra_ode_init_kwargs(self): TakeoffBrakeToAbort._add_meta_data('initial_ref', val=10.0, units='s') -TakeoffBrakeToAbort._add_meta_data('max_range', val=1000.0, units='ft') +TakeoffBrakeToAbort._add_meta_data('distance_max', val=1000.0, units='ft') TakeoffBrakeToAbort._add_meta_data('max_velocity', val=100.0, units='ft/s') diff --git a/aviary/models/N3CC/N3CC_data.py b/aviary/models/N3CC/N3CC_data.py index c8cce58c9..764d4d43f 100644 --- a/aviary/models/N3CC/N3CC_data.py +++ b/aviary/models/N3CC/N3CC_data.py @@ -480,7 +480,7 @@ takeoff_brake_release_user_options.set_val('max_duration', val=60.0, units='s') takeoff_brake_release_user_options.set_val('duration_ref', val=60.0, units='s') -takeoff_brake_release_user_options.set_val('max_range', val=7500.0, units='ft') +takeoff_brake_release_user_options.set_val('distance_max', val=7500.0, units='ft') takeoff_brake_release_user_options.set_val('max_velocity', val=167.85, units='kn') takeoff_brake_release_initial_guesses = AviaryValues() @@ -513,7 +513,7 @@ takeoff_decision_speed_user_options.set_val('max_duration', val=60.0, units='s') takeoff_decision_speed_user_options.set_val('duration_ref', val=60.0, units='s') takeoff_decision_speed_user_options.set_val('initial_ref', val=35.0, units='s') -takeoff_decision_speed_user_options.set_val('max_range', val=7500.0, units='ft') +takeoff_decision_speed_user_options.set_val('distance_max', val=7500.0, units='ft') takeoff_decision_speed_user_options.set_val('max_velocity', val=167.85, units='kn') takeoff_decision_speed_initial_guesses = AviaryValues() @@ -541,7 +541,7 @@ takeoff_rotate_user_options.set_val('max_duration', val=60.0, units='s') takeoff_rotate_user_options.set_val('duration_ref', val=60.0, units='s') takeoff_rotate_user_options.set_val('initial_ref', val=38.0, units='s') -takeoff_rotate_user_options.set_val('max_range', val=7500.0, units='ft') +takeoff_rotate_user_options.set_val('distance_max', val=7500.0, units='ft') takeoff_rotate_user_options.set_val('max_velocity', val=167.85, units='kn') takeoff_rotate_user_options.set_val('max_angle_of_attack', val=10.0, units='deg') @@ -570,7 +570,7 @@ takeoff_liftoff_user_options.set_val('max_duration', val=12., units='s') takeoff_liftoff_user_options.set_val('duration_ref', val=12., units='s') takeoff_liftoff_user_options.set_val('initial_ref', val=39.0, units='s') -takeoff_liftoff_user_options.set_val('max_range', val=7500., units='ft') +takeoff_liftoff_user_options.set_val('distance_max', val=7500., units='ft') takeoff_liftoff_user_options.set_val('max_velocity', val=167.85, units='kn') takeoff_liftoff_user_options.set_val('altitude_ref', val=35., units='ft') takeoff_liftoff_user_options.set_val('flight_path_angle_ref', val=10., units='deg') @@ -606,7 +606,7 @@ takeoff_mic_p2_user_options.set_val('max_duration', val=25., units='s') takeoff_mic_p2_user_options.set_val('duration_ref', val=25., units='s') takeoff_mic_p2_user_options.set_val('initial_ref', val=50.0, units='s') -takeoff_mic_p2_user_options.set_val('max_range', val=12000., units='ft') +takeoff_mic_p2_user_options.set_val('distance_max', val=12000., units='ft') takeoff_mic_p2_user_options.set_val('max_velocity', val=167.85, units='kn') takeoff_mic_p2_user_options.set_val('altitude_ref', val=1500., units='ft') takeoff_mic_p2_user_options.set_val('mic_altitude', val=985., units='ft') @@ -651,7 +651,7 @@ takeoff_mic_p2_to_engine_cutback_user_options.set_val('initial_ref', val=65.0, units='s') takeoff_mic_p2_to_engine_cutback_user_options.set_val( - 'max_range', val=20000., units='ft') + 'distance_max', val=20000., units='ft') takeoff_mic_p2_to_engine_cutback_user_options.set_val( 'max_velocity', val=167.85, units='kn') @@ -717,7 +717,7 @@ cutback_duration = (1.0 - cutback_throttle) / cutback_rate takeoff_engine_cutback_user_options.set_val('initial_ref', val=95.0, units='s') -takeoff_engine_cutback_user_options.set_val('max_range', val=21000., units='ft') +takeoff_engine_cutback_user_options.set_val('distance_max', val=21000., units='ft') takeoff_engine_cutback_user_options.set_val('max_velocity', val=167.85, units='kn') takeoff_engine_cutback_user_options.set_val('altitude_ref', val=4000., units='ft') @@ -762,7 +762,7 @@ takeoff_engine_cutback_to_mic_p1_user_options.set_val('initial_ref', val=97.0, units='s') takeoff_engine_cutback_to_mic_p1_user_options.set_val( - 'max_range', val=22000., units='ft') + 'distance_max', val=22000., units='ft') takeoff_engine_cutback_to_mic_p1_user_options.set_val( 'max_velocity', val=167.85, units='kn') @@ -823,7 +823,7 @@ takeoff_mic_p1_to_climb_user_options.set_val('max_duration', val=40., units='s') takeoff_mic_p1_to_climb_user_options.set_val('duration_ref', val=40., units='s') takeoff_mic_p1_to_climb_user_options.set_val('initial_ref', val=100.0, units='s') -takeoff_mic_p1_to_climb_user_options.set_val('max_range', val=30000., units='ft') +takeoff_mic_p1_to_climb_user_options.set_val('distance_max', val=30000., units='ft') takeoff_mic_p1_to_climb_user_options.set_val('max_velocity', val=167.85, units='kn') takeoff_mic_p1_to_climb_user_options.set_val('altitude_ref', val=4000., units='ft') @@ -939,7 +939,7 @@ def _split_aviary_values(aviary_values, slicing): balanced_brake_release_user_options.set_val('max_duration', val=60.0, units='s') balanced_brake_release_user_options.set_val('duration_ref', val=60.0, units='s') -balanced_brake_release_user_options.set_val('max_range', val=7500.0, units='ft') +balanced_brake_release_user_options.set_val('distance_max', val=7500.0, units='ft') balanced_brake_release_user_options.set_val('max_velocity', val=167.85, units='kn') balanced_brake_release_initial_guesses = AviaryValues() @@ -966,7 +966,7 @@ def _split_aviary_values(aviary_values, slicing): balanced_decision_speed_user_options.set_val('max_duration', val=60.0, units='s') balanced_decision_speed_user_options.set_val('duration_ref', val=5.0, units='s') balanced_decision_speed_user_options.set_val('initial_ref', val=35.0, units='s') -balanced_decision_speed_user_options.set_val('max_range', val=7500.0, units='ft') +balanced_decision_speed_user_options.set_val('distance_max', val=7500.0, units='ft') balanced_decision_speed_user_options.set_val('max_velocity', val=167.85, units='kn') balanced_decision_speed_initial_guesses = AviaryValues() @@ -996,7 +996,7 @@ def _split_aviary_values(aviary_values, slicing): balanced_rotate_user_options.set_val('max_duration', val=20.0, units='s') balanced_rotate_user_options.set_val('duration_ref', val=5.0, units='s') balanced_rotate_user_options.set_val('initial_ref', val=35.0, units='s') -balanced_rotate_user_options.set_val('max_range', val=7500.0, units='ft') +balanced_rotate_user_options.set_val('distance_max', val=7500.0, units='ft') balanced_rotate_user_options.set_val('max_velocity', val=167.85, units='kn') balanced_rotate_user_options.set_val('max_angle_of_attack', val=8.117, units='deg') @@ -1024,7 +1024,7 @@ def _split_aviary_values(aviary_values, slicing): balanced_liftoff_user_options.set_val('max_duration', val=20., units='s') balanced_liftoff_user_options.set_val('duration_ref', val=20., units='s') balanced_liftoff_user_options.set_val('initial_ref', val=40.0, units='s') -balanced_liftoff_user_options.set_val('max_range', val=7500., units='ft') +balanced_liftoff_user_options.set_val('distance_max', val=7500., units='ft') balanced_liftoff_user_options.set_val('max_velocity', val=167.85, units='kn') balanced_liftoff_user_options.set_val('altitude_ref', val=35., units='ft') balanced_liftoff_user_options.set_val('flight_path_angle_ref', val=5., units='deg') @@ -1058,7 +1058,7 @@ def _split_aviary_values(aviary_values, slicing): balanced_delayed_brake_user_options.set_val('duration_ref', val=4.0, units='s') balanced_delayed_brake_user_options.set_val('initial_ref', val=35.0, units='s') -balanced_delayed_brake_user_options.set_val('max_range', val=7500.0, units='ft') +balanced_delayed_brake_user_options.set_val('distance_max', val=7500.0, units='ft') balanced_delayed_brake_user_options.set_val('max_velocity', val=167.85, units='kn') balanced_delayed_brake_initial_guesses = AviaryValues() @@ -1085,7 +1085,7 @@ def _split_aviary_values(aviary_values, slicing): balanced_abort_user_options.set_val('max_duration', val=60.0, units='s') balanced_abort_user_options.set_val('initial_ref', val=35.0, units='s') balanced_abort_user_options.set_val('duration_ref', val=60.0, units='s') -balanced_abort_user_options.set_val('max_range', val=7500.0, units='ft') +balanced_abort_user_options.set_val('distance_max', val=7500.0, units='ft') balanced_abort_user_options.set_val('max_velocity', val=167.85, units='kn') balanced_abort_initial_guesses = AviaryValues() @@ -1104,10 +1104,10 @@ def _split_aviary_values(aviary_values, slicing): user_options=balanced_abort_user_options, initial_guesses=balanced_abort_initial_guesses) -max_range = balanced_liftoff_user_options.get_val('max_range', 'ft') +distance_max = balanced_liftoff_user_options.get_val('distance_max', 'ft') balanced_trajectory_builder.set_brake_to_abort( - balanced_abort_builder, balanced_field_ref=max_range) + balanced_abort_builder, balanced_field_ref=distance_max) # endregion balanced field length # region - detailed landing @@ -1325,7 +1325,7 @@ def _split_aviary_values(aviary_values, slicing): landing_approach_to_mic_p3_user_options.set_val('max_duration', val=50., units='s') landing_approach_to_mic_p3_user_options.set_val('duration_ref', val=50., units='s') landing_approach_to_mic_p3_user_options.set_val('initial_ref', val=50.0, units='s') -landing_approach_to_mic_p3_user_options.set_val('max_range', val=10000., units='ft') +landing_approach_to_mic_p3_user_options.set_val('distance_max', val=10000., units='ft') landing_approach_to_mic_p3_user_options.set_val('max_velocity', val=140., units='kn') landing_approach_to_mic_p3_user_options.set_val('altitude_ref', val=800., units='ft') @@ -1376,7 +1376,7 @@ def _split_aviary_values(aviary_values, slicing): landing_mic_p3_to_obstacle_user_options.set_val('max_duration', val=50., units='s') landing_mic_p3_to_obstacle_user_options.set_val('duration_ref', val=50., units='s') landing_mic_p3_to_obstacle_user_options.set_val('initial_ref', val=50.0, units='s') -landing_mic_p3_to_obstacle_user_options.set_val('max_range', val=6000., units='ft') +landing_mic_p3_to_obstacle_user_options.set_val('distance_max', val=6000., units='ft') landing_mic_p3_to_obstacle_user_options.set_val('max_velocity', val=140., units='kn') landing_mic_p3_to_obstacle_user_options.set_val('altitude_ref', val=400., units='ft') @@ -1425,7 +1425,7 @@ def _split_aviary_values(aviary_values, slicing): landing_obstacle_user_options = AviaryValues() landing_obstacle_user_options.set_val('max_duration', val=5., units='s') -landing_obstacle_user_options.set_val('max_range', val=800., units='ft') +landing_obstacle_user_options.set_val('distance_max', val=800., units='ft') landing_obstacle_user_options.set_val('max_velocity', val=140., units='kn') landing_obstacle_user_options.set_val('altitude_ref', val=50., units='ft') @@ -1463,7 +1463,7 @@ def _split_aviary_values(aviary_values, slicing): landing_flare_user_options.set_val('max_duration', val=7., units='s') landing_flare_user_options.set_val('duration_ref', val=7., units='s') landing_flare_user_options.set_val('initial_ref', val=4., units='s') -landing_flare_user_options.set_val('max_range', val=1000., units='ft') +landing_flare_user_options.set_val('distance_max', val=1000., units='ft') landing_flare_user_options.set_val('max_velocity', val=140., units='kn') landing_flare_user_options.set_val('altitude_ref', val=15., units='ft') @@ -1503,7 +1503,7 @@ def _split_aviary_values(aviary_values, slicing): landing_touchdown_user_options.set_val('max_duration', val=10., units='s') landing_touchdown_user_options.set_val('duration_ref', val=10., units='s') landing_touchdown_user_options.set_val('initial_ref', val=6., units='s') -landing_touchdown_user_options.set_val('max_range', val=3000., units='ft') +landing_touchdown_user_options.set_val('distance_max', val=3000., units='ft') landing_touchdown_user_options.set_val('max_velocity', val=140., units='kn') landing_touchdown_user_options.set_val('max_angle_of_attack', val=8., units='deg') @@ -1536,7 +1536,7 @@ def _split_aviary_values(aviary_values, slicing): landing_fullstop_user_options.set_val('max_duration', val=30., units='s') landing_fullstop_user_options.set_val('duration_ref', val=30., units='s') landing_fullstop_user_options.set_val('initial_ref', val=14., units='s') -landing_fullstop_user_options.set_val('max_range', val=4400., units='ft') +landing_fullstop_user_options.set_val('distance_max', val=4400., units='ft') landing_fullstop_user_options.set_val('max_velocity', val=140., units='kn') landing_fullstop_initial_guesses = AviaryValues() 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 a3908a1da..f30f6d812 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 @@ -89,11 +89,11 @@ def _do_run(self, driver: Driver, optimizer, *args): takeoff_trajectory_builder.build_trajectory( aviary_options=aviary_options, model=takeoff.model, traj=traj) - max_range, units = takeoff_liftoff_user_options.get_item('max_range') + distance_max, units = takeoff_liftoff_user_options.get_item('distance_max') liftoff = takeoff_trajectory_builder.get_phase('balanced_liftoff') liftoff.add_objective( - Dynamic.Mission.DISTANCE, loc='final', ref=max_range, units=units) + Dynamic.Mission.DISTANCE, loc='final', ref=distance_max, units=units) takeoff.model.add_subsystem( 'input_sink', 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 3da1a98ba..bc4b16846 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py @@ -84,11 +84,11 @@ def _do_run(self, driver: Driver, optimizer, *args): landing_trajectory_builder.build_trajectory( aviary_options=aviary_options, model=landing.model, traj=traj) - max_range, units = landing_fullstop_user_options.get_item('max_range') + distance_max, units = landing_fullstop_user_options.get_item('distance_max') fullstop = landing_trajectory_builder.get_phase('landing_fullstop') fullstop.add_objective(Dynamic.Mission.DISTANCE, loc='final', - ref=max_range, units=units) + ref=distance_max, units=units) landing.model.add_subsystem( 'input_sink', 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 c16facd15..e0752de37 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py @@ -90,11 +90,11 @@ def _do_run(self, driver: Driver, optimizer, *args): takeoff_trajectory_builder.build_trajectory( aviary_options=aviary_options, model=takeoff.model, traj=traj) - max_range, units = takeoff_liftoff_user_options.get_item('max_range') + distance_max, units = takeoff_liftoff_user_options.get_item('distance_max') liftoff = takeoff_trajectory_builder.get_phase('takeoff_liftoff') liftoff.add_objective( - Dynamic.Mission.DISTANCE, loc='final', ref=max_range, units=units) + Dynamic.Mission.DISTANCE, loc='final', ref=distance_max, units=units) # Insert a constraint for a fake decision speed, until abort is added. takeoff.model.add_constraint( From 875ae0cd7b7451b4e97d432aca4d5fdc830e0a6b Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Thu, 18 Jan 2024 12:28:27 -0500 Subject: [PATCH 101/188] accel_ode upd and tests passing --- aviary/mission/gasp_based/ode/accel_ode.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aviary/mission/gasp_based/ode/accel_ode.py b/aviary/mission/gasp_based/ode/accel_ode.py index f47fc29e2..6a3418309 100644 --- a/aviary/mission/gasp_based/ode/accel_ode.py +++ b/aviary/mission/gasp_based/ode/accel_ode.py @@ -95,7 +95,6 @@ def setup(self): + sgm_outputs, ) - # the last two subsystems will also be used for constraints self.add_subsystem( name='SPECIFIC_ENERGY_RATE_EXCESS', subsys=SpecificEnergyRate(num_nodes=nn), @@ -123,3 +122,5 @@ def setup(self): np.ones(nn), units="lbm") self.set_input_defaults(Dynamic.Mission.ALTITUDE, val=500 * np.ones(nn), units="ft") + self.set_input_defaults("TAS", val=200*np.ones(nn), + units="m/s") # val here is nominal From 358fa6495752eb9290e87faa0aa53b6dea243243 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 18 Jan 2024 11:35:30 -0600 Subject: [PATCH 102/188] WIP --- .../interface/default_phase_info/two_dof.py | 4 + aviary/interface/methods_for_level2.py | 95 ++++++------------- aviary/interface/utils/check_phase_info.py | 14 ++- .../flops_based/phases/phase_builder_base.py | 32 +++++-- 4 files changed, 66 insertions(+), 79 deletions(-) diff --git a/aviary/interface/default_phase_info/two_dof.py b/aviary/interface/default_phase_info/two_dof.py index 2cec8b98e..2ff207e9a 100644 --- a/aviary/interface/default_phase_info/two_dof.py +++ b/aviary/interface/default_phase_info/two_dof.py @@ -221,6 +221,10 @@ } }, 'cruise': { + 'user_options': { + 'alt_cruise': (37.5e3, 'ft'), + 'mach_cruise': 0.8, + }, 'initial_guesses': { # [Initial mass, delta mass] for special cruise phase. 'mass': ([171481., -35000], 'lbm'), diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 695257ecd..8e944935d 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -30,6 +30,7 @@ from aviary.mission.gasp_based.phases.groundroll_phase import GroundrollPhase from aviary.mission.gasp_based.phases.rotation_phase import RotationPhase from aviary.mission.gasp_based.phases.climb_phase import ClimbPhase +from aviary.mission.gasp_based.phases.cruise_phase import CruisePhase from aviary.mission.gasp_based.phases.accel_phase import AccelPhase from aviary.mission.gasp_based.phases.ascent_phase import AscentPhase from aviary.mission.gasp_based.phases.descent_phase import DescentPhase @@ -565,43 +566,7 @@ def _get_2dof_phase(self, phase_name): default_mission_subsystems = [ subsystems['aerodynamics'], subsystems['propulsion']] - if 'cruise' in phase_name: - phase = dm.AnalyticPhase( - ode_class=BreguetCruiseODESolution, - ode_init_kwargs=self.ode_args, - num_nodes=5, - ) - - # Time here is really the independent variable through which we are integrating. - # In the case of the Breguet Range ODE, it's mass. - # We rely on mass being monotonically non-increasing across the phase. - phase.set_time_options( - name='mass', - fix_initial=False, - fix_duration=False, - units="lbm", - targets="mass", - initial_bounds=(10.e3, 500_000), - initial_ref=100_000, - duration_bounds=(-50000, -10), - duration_ref=50000, - ) - - phase.add_parameter(Dynamic.Mission.ALTITUDE, opt=False, - val=self.phase_info['climb2']['user_options']['final_alt'][0], units=self.phase_info['climb2']['user_options']['final_alt'][1]) - mach_cruise = self.phase_info['climb2']['user_options']['mach_cruise'] - if type(mach_cruise) is tuple: - mach_cruise = mach_cruise[0] - phase.add_parameter(Dynamic.Mission.MACH, opt=False, - val=mach_cruise) - phase.add_parameter("initial_distance", opt=False, val=0.0, - units="NM", static_target=True) - phase.add_parameter("initial_time", opt=False, val=0.0, - units="s", static_target=True) - - phase.add_timeseries_output("time", units="s") - - else: + if 'cruise' not in phase_name: num_segments = phase_options['user_options']['num_segments'] order = phase_options['user_options']['order'] # Create a Radau transcription scheme object with the specified num_segments and order @@ -610,36 +575,32 @@ def _get_2dof_phase(self, phase_name): order=order, compressed=True, solve_segments=False) - - if 'climb' in phase_name: - phase_object = ClimbPhase.from_phase_info( - phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) - phase = phase_object.build_phase(aviary_options=self.aviary_inputs) - elif 'accel' in phase_name: - phase_object = AccelPhase.from_phase_info( - phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) - phase = phase_object.build_phase(aviary_options=self.aviary_inputs) - elif 'ascent' in phase_name: - phase_object = AscentPhase.from_phase_info( - phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) - phase = phase_object.build_phase(aviary_options=self.aviary_inputs) - elif 'desc' in phase_name: - phase_object = DescentPhase.from_phase_info( - phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) - phase = phase_object.build_phase(aviary_options=self.aviary_inputs) - elif 'groundroll' in phase_name: - phase_object = GroundrollPhase.from_phase_info( - phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) - phase = phase_object.build_phase(aviary_options=self.aviary_inputs) - elif 'rotation' in phase_name: - phase_object = RotationPhase.from_phase_info( - phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) - phase = phase_object.build_phase(aviary_options=self.aviary_inputs) - - phase.add_control( - Dynamic.Mission.THROTTLE, targets=Dynamic.Mission.THROTTLE, units='unitless', - opt=False, lower=0.0, upper=1.0 - ) + else: + transcription = None + + if 'groundroll' in phase_name: + phase_builder = GroundrollPhase + elif 'rotation' in phase_name: + phase_builder = RotationPhase + elif 'accel' in phase_name: + phase_builder = AccelPhase + elif 'ascent' in phase_name: + phase_builder = AscentPhase + elif 'climb' in phase_name: + phase_builder = ClimbPhase + elif 'cruise' in phase_name: + phase_builder = CruisePhase + elif 'desc' in phase_name: + phase_builder = DescentPhase + + phase_object = phase_builder.from_phase_info( + phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) + phase = phase_object.build_phase(aviary_options=self.aviary_inputs) + + phase.add_control( + Dynamic.Mission.THROTTLE, targets=Dynamic.Mission.THROTTLE, units='unitless', + opt=False, lower=0.0, upper=1.0 + ) phase.timeseries_options['use_prefix'] = True diff --git a/aviary/interface/utils/check_phase_info.py b/aviary/interface/utils/check_phase_info.py index 68cda2e83..5d84a2505 100644 --- a/aviary/interface/utils/check_phase_info.py +++ b/aviary/interface/utils/check_phase_info.py @@ -179,7 +179,10 @@ def check_phase_info(phase_info, mission_method): 'distance_ref0': tuple, 'distance_defect_ref': tuple, }, - 'cruise': {'initial_guesses': dict, }, + 'cruise': { + 'mach_cruise': float, + 'alt_cruise': tuple, + }, 'desc1': { **common_descent, **common_duration, @@ -210,10 +213,11 @@ def check_phase_info(phase_info, mission_method): phase_keys[phase] = phase_keys_flops[phase] elif mission_method is TWO_DEGREES_OF_FREEDOM: for phase in phase_info: - if phase != 'pre_mission' and phase != 'post_mission' and phase != 'cruise': - phase_keys[phase] = {**common_keys, **phase_keys_gasp[phase]} - else: - phase_keys[phase] = phase_keys_gasp[phase] + if phase != 'pre_mission' and phase != 'post_mission': + if phase == 'cruise': + phase_keys[phase] = {**phase_keys_gasp[phase]} + else: + phase_keys[phase] = {**common_keys, **phase_keys_gasp[phase]} elif mission_method is SOLVED: return elif mission_method is SIMPLE: diff --git a/aviary/mission/flops_based/phases/phase_builder_base.py b/aviary/mission/flops_based/phases/phase_builder_base.py index 2ec5f8b0e..5f82d69f3 100644 --- a/aviary/mission/flops_based/phases/phase_builder_base.py +++ b/aviary/mission/flops_based/phases/phase_builder_base.py @@ -232,6 +232,14 @@ class attribute: derived type customization point; the default value class attribute: derived type customization point; the default value for ode_class used by build_phase + is_analytic_phase : bool (False) + class attribute: derived type customization point; if True, build_phase + will return an AnalyticPhase instead of a Phase + + num_nodes : int (5) + class attribute: derived type customization point; the default value + for num_nodes used by build_phase, only for AnalyticPhases + Methods ------- build_phase @@ -241,7 +249,8 @@ class attribute: derived type customization point; the default value ''' __slots__ = ( 'name', 'core_subsystems', 'subsystem_options', 'user_options', - 'initial_guesses', 'ode_class', 'transcription', 'aero_builder' + 'initial_guesses', 'ode_class', 'transcription', 'aero_builder', + 'is_analytic_phase', 'num_nodes', ) # region : derived type customization points @@ -256,7 +265,7 @@ class attribute: derived type customization point; the default value def __init__( self, name=None, core_subsystems=None, aero_builder=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, subsystem_options=None, + ode_class=None, transcription=None, subsystem_options=None, is_analytic_phase=False, num_nodes=5, ): if name is None: name = self.default_name @@ -288,6 +297,8 @@ def __init__( self.ode_class = ode_class self.transcription = transcription + self.is_analytic_phase = is_analytic_phase + self.num_nodes = num_nodes def build_phase(self, aviary_options=None): ''' @@ -314,7 +325,7 @@ def build_phase(self, aviary_options=None): transcription = self.transcription - if transcription is None: + if transcription is None and not self.is_analytic_phase: transcription = self.make_default_transcription() if aviary_options is None: @@ -334,10 +345,17 @@ def build_phase(self, aviary_options=None): kwargs['core_subsystems'] = self.core_subsystems - phase = dm.Phase( - ode_class=ode_class, transcription=transcription, - ode_init_kwargs=kwargs - ) + if self.is_analytic_phase: + phase = dm.AnalyticPhase( + ode_class=ode_class, + ode_init_kwargs=self.ode_args, + num_nodes=self.num_nodes, + ) + else: + phase = dm.Phase( + ode_class=ode_class, transcription=transcription, + ode_init_kwargs=kwargs + ) # overrides should add state, controls, etc. return phase From 8d3caa07d3e45a22753cb8477fdc54aac540bd7a Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Thu, 18 Jan 2024 12:42:08 -0500 Subject: [PATCH 103/188] ascent updated with altitude_rate_max output --- aviary/mission/gasp_based/ode/ascent_ode.py | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/aviary/mission/gasp_based/ode/ascent_ode.py b/aviary/mission/gasp_based/ode/ascent_ode.py index 51223c42d..a98dee62b 100644 --- a/aviary/mission/gasp_based/ode/ascent_ode.py +++ b/aviary/mission/gasp_based/ode/ascent_ode.py @@ -13,6 +13,8 @@ from aviary.subsystems.propulsion.propulsion_mission import PropulsionMission from aviary.variable_info.enums import AlphaModes from aviary.variable_info.variables import Aircraft, Dynamic, Mission +from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate +from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate class AscentODE(BaseODE): @@ -116,6 +118,28 @@ def setup(self): ], ) + self.add_subsystem( + name='SPECIFIC_ENERGY_RATE_EXCESS', + subsys=SpecificEnergyRate(num_nodes=nn), + promotes_inputs=[(Dynamic.Mission.VELOCITY, "TAS"), Dynamic.Mission.MASS, + (Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.THRUST_MAX_TOTAL), + Dynamic.Mission.DRAG], + promotes_outputs=[(Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS)] + ) + + self.add_subsystem( + name='ALTITUDE_RATE_MAX', + subsys=AltitudeRate(num_nodes=nn), + promotes_inputs=[ + (Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS), + (Dynamic.Mission.VELOCITY_RATE, "TAS_rate"), + (Dynamic.Mission.VELOCITY, "TAS")], + promotes_outputs=[ + (Dynamic.Mission.ALTITUDE_RATE, + Dynamic.Mission.ALTITUDE_RATE_MAX)]) + ParamPort.set_default_vals(self) self.set_input_defaults("t_init_flaps", val=47.5) self.set_input_defaults("t_init_gear", val=37.3) @@ -129,3 +153,5 @@ def setup(self): self.set_input_defaults('aero_ramps.gear_factor:final_val', val=0.) self.set_input_defaults('aero_ramps.flap_factor:initial_val', val=1.) self.set_input_defaults('aero_ramps.gear_factor:initial_val', val=1.) + self.set_input_defaults(Dynamic.Mission.MASS, val=np.ones( + nn), units='kg') # val here is nominal From a50f06e8db4519b7ba7b6e7176e755b4270f11a4 Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Thu, 18 Jan 2024 12:50:26 -0500 Subject: [PATCH 104/188] ALTITUDE_RATE_MAX calc added --- .../gasp_based/ode/breguet_cruise_ode.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/aviary/mission/gasp_based/ode/breguet_cruise_ode.py b/aviary/mission/gasp_based/ode/breguet_cruise_ode.py index 8097210ac..306b41f44 100644 --- a/aviary/mission/gasp_based/ode/breguet_cruise_ode.py +++ b/aviary/mission/gasp_based/ode/breguet_cruise_ode.py @@ -10,6 +10,8 @@ from aviary.subsystems.propulsion.propulsion_builder import PropulsionBuilderBase from aviary.variable_info.enums import SpeedType from aviary.variable_info.variables import Dynamic +from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate +from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate class BreguetCruiseODESolution(BaseODE): @@ -135,6 +137,28 @@ def setup(self): ("cruise_time", "time")], ) + self.add_subsystem( + name='SPECIFIC_ENERGY_RATE_EXCESS', + subsys=SpecificEnergyRate(num_nodes=nn), + promotes_inputs=[(Dynamic.Mission.VELOCITY, "TAS"), Dynamic.Mission.MASS, + (Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.THRUST_MAX_TOTAL), + Dynamic.Mission.DRAG], + promotes_outputs=[(Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS)] + ) + + self.add_subsystem( + name='ALTITUDE_RATE_MAX', + subsys=AltitudeRate(num_nodes=nn), + promotes_inputs=[ + (Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS), + (Dynamic.Mission.VELOCITY_RATE, "TAS_rate"), + (Dynamic.Mission.VELOCITY, "TAS")], + promotes_outputs=[ + (Dynamic.Mission.ALTITUDE_RATE, + Dynamic.Mission.ALTITUDE_RATE_MAX)]) + ParamPort.set_default_vals(self) self.set_input_defaults( Dynamic.Mission.ALTITUDE, From 2f1d14a431ca3a7eff82e4f1c03ccfe230ae0ea7 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 18 Jan 2024 11:59:19 -0600 Subject: [PATCH 105/188] fix for run all examples test --- aviary/examples/test/test_all_examples.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/aviary/examples/test/test_all_examples.py b/aviary/examples/test/test_all_examples.py index 8393a27c7..efab5eed4 100644 --- a/aviary/examples/test/test_all_examples.py +++ b/aviary/examples/test/test_all_examples.py @@ -85,12 +85,13 @@ def run_script(self, script_path): Exception Any exception other than ImportError or TimeoutExpired that occurs while running the script. """ - try: - subprocess.check_call(['python', script_path], timeout=10) - except subprocess.TimeoutExpired: - pass # Test passes if it runs longer than 10 seconds - except subprocess.CalledProcessError as e: - if 'ImportError' in str(e): + proc = subprocess.Popen(['python', script_path], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + proc.wait() + (stdout, stderr) = proc.communicate() + + if proc.returncode != 0: + if 'ImportError' in str(stderr): self.skipTest(f"Skipped {script_path.name} due to ImportError") else: raise From 4b63fd651898668ee083f039fd9ad7a084a4a6cd Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Thu, 18 Jan 2024 13:01:09 -0500 Subject: [PATCH 106/188] ALTITUDE_RATE_MAX added to descent_ode --- aviary/mission/gasp_based/ode/descent_ode.py | 34 ++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/aviary/mission/gasp_based/ode/descent_ode.py b/aviary/mission/gasp_based/ode/descent_ode.py index 3257fbb14..ed10777d6 100644 --- a/aviary/mission/gasp_based/ode/descent_ode.py +++ b/aviary/mission/gasp_based/ode/descent_ode.py @@ -19,6 +19,8 @@ from aviary.variable_info.variables import Dynamic from aviary.subsystems.aerodynamics.aerodynamics_builder import AerodynamicsBuilderBase from aviary.subsystems.propulsion.propulsion_builder import PropulsionBuilderBase +from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate +from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate class DescentODE(BaseODE): @@ -232,6 +234,29 @@ def setup(self): add_default_solver=False, num_nodes=nn) + # the last two subsystems will also be used for constraints + self.add_subsystem( + name='SPECIFIC_ENERGY_RATE_EXCESS', + subsys=SpecificEnergyRate(num_nodes=nn), + promotes_inputs=[(Dynamic.Mission.VELOCITY, "TAS"), Dynamic.Mission.MASS, + (Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.THRUST_MAX_TOTAL), + Dynamic.Mission.DRAG], + promotes_outputs=[(Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS)] + ) + + self.add_subsystem( + name='ALTITUDE_RATE_MAX', + subsys=AltitudeRate(num_nodes=nn), + promotes_inputs=[ + (Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS), + (Dynamic.Mission.VELOCITY_RATE, "TAS_rate"), + (Dynamic.Mission.VELOCITY, "TAS")], + promotes_outputs=[ + (Dynamic.Mission.ALTITUDE_RATE, + Dynamic.Mission.ALTITUDE_RATE_MAX)]) + if analysis_scheme is AnalysisScheme.COLLOCATION: fc_loc = ['fc'] if input_speed_type is SpeedType.MACH: @@ -239,8 +264,13 @@ def setup(self): fc_loc = ['mach_balance_group'] # TODO this assumes the name of propulsion subsystem, need to pull from # the subsystem itself - self.set_order(['params', 'USatm',]+fc_loc+prop_groups+['lift_balance_group', - 'constraints']) + self.set_order(['params', + 'USatm',] + + fc_loc+prop_groups + + ['lift_balance_group', + 'constraints', + 'SPECIFIC_ENERGY_RATE_EXCESS', + 'ALTITUDE_RATE_MAX']) ParamPort.set_default_vals(self) self.set_input_defaults(Dynamic.Mission.ALTITUDE, From b7e9c6d14ba88d1a0129ae996764cdb6037df143 Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Thu, 18 Jan 2024 13:36:44 -0500 Subject: [PATCH 107/188] moved altitude_rate.py and specific_energy_rate.py to non-flops-specific folder, upd flightpath.ode with ALTITUDE_RATE_MAX --- aviary/mission/flops_based/ode/mission_EOM.py | 4 ++-- .../flops_based/ode/simple_mission_EOM.py | 4 ++-- .../ode/test/test_altitude_rate.py | 2 +- .../ode/test/test_specific_energy_rate.py | 2 +- aviary/mission/gasp_based/ode/accel_ode.py | 4 ++-- aviary/mission/gasp_based/ode/ascent_ode.py | 4 ++-- .../gasp_based/ode/breguet_cruise_ode.py | 4 ++-- aviary/mission/gasp_based/ode/climb_ode.py | 4 ++-- aviary/mission/gasp_based/ode/descent_ode.py | 4 ++-- .../mission/gasp_based/ode/flight_path_ode.py | 24 +++++++++++++++++++ .../{flops_based => }/ode/altitude_rate.py | 0 .../ode/specific_energy_rate.py | 0 12 files changed, 40 insertions(+), 16 deletions(-) rename aviary/mission/{flops_based => }/ode/altitude_rate.py (100%) rename aviary/mission/{flops_based => }/ode/specific_energy_rate.py (100%) diff --git a/aviary/mission/flops_based/ode/mission_EOM.py b/aviary/mission/flops_based/ode/mission_EOM.py index 946a85468..8762aa428 100644 --- a/aviary/mission/flops_based/ode/mission_EOM.py +++ b/aviary/mission/flops_based/ode/mission_EOM.py @@ -1,8 +1,8 @@ import openmdao.api as om -from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate +from aviary.mission.ode.altitude_rate import AltitudeRate from aviary.mission.flops_based.ode.range_rate import RangeRate -from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate +from aviary.mission.ode.specific_energy_rate import SpecificEnergyRate from aviary.variable_info.variables import Dynamic diff --git a/aviary/mission/flops_based/ode/simple_mission_EOM.py b/aviary/mission/flops_based/ode/simple_mission_EOM.py index 8e3e25e1f..eaccaa98d 100644 --- a/aviary/mission/flops_based/ode/simple_mission_EOM.py +++ b/aviary/mission/flops_based/ode/simple_mission_EOM.py @@ -1,9 +1,9 @@ import openmdao.api as om from aviary.variable_info.variables import Dynamic -from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate +from aviary.mission.ode.altitude_rate import AltitudeRate from aviary.mission.flops_based.ode.range_rate import RangeRate -from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate +from aviary.mission.ode.specific_energy_rate import SpecificEnergyRate from aviary.mission.flops_based.ode.required_thrust import RequiredThrust diff --git a/aviary/mission/flops_based/ode/test/test_altitude_rate.py b/aviary/mission/flops_based/ode/test/test_altitude_rate.py index 5e6958b39..e6d33d548 100644 --- a/aviary/mission/flops_based/ode/test/test_altitude_rate.py +++ b/aviary/mission/flops_based/ode/test/test_altitude_rate.py @@ -2,7 +2,7 @@ import openmdao.api as om -from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate +from aviary.mission.ode.altitude_rate import AltitudeRate from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_data.flops_data.full_mission_test_data import \ data diff --git a/aviary/mission/flops_based/ode/test/test_specific_energy_rate.py b/aviary/mission/flops_based/ode/test/test_specific_energy_rate.py index 4c5afa7ec..19a2eca32 100644 --- a/aviary/mission/flops_based/ode/test/test_specific_energy_rate.py +++ b/aviary/mission/flops_based/ode/test/test_specific_energy_rate.py @@ -2,7 +2,7 @@ import openmdao.api as om -from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate +from aviary.mission.ode.specific_energy_rate import SpecificEnergyRate from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_data.flops_data.full_mission_test_data import \ data diff --git a/aviary/mission/gasp_based/ode/accel_ode.py b/aviary/mission/gasp_based/ode/accel_ode.py index 6a3418309..c38df7971 100644 --- a/aviary/mission/gasp_based/ode/accel_ode.py +++ b/aviary/mission/gasp_based/ode/accel_ode.py @@ -9,8 +9,8 @@ from aviary.subsystems.mass.mass_to_weight import MassToWeight from aviary.variable_info.enums import AnalysisScheme, SpeedType from aviary.variable_info.variables import Aircraft, Dynamic, Mission -from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate -from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate +from aviary.mission.ode.specific_energy_rate import SpecificEnergyRate +from aviary.mission.ode.altitude_rate import AltitudeRate class AccelODE(BaseODE): diff --git a/aviary/mission/gasp_based/ode/ascent_ode.py b/aviary/mission/gasp_based/ode/ascent_ode.py index a98dee62b..1176e62d5 100644 --- a/aviary/mission/gasp_based/ode/ascent_ode.py +++ b/aviary/mission/gasp_based/ode/ascent_ode.py @@ -13,8 +13,8 @@ from aviary.subsystems.propulsion.propulsion_mission import PropulsionMission from aviary.variable_info.enums import AlphaModes from aviary.variable_info.variables import Aircraft, Dynamic, Mission -from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate -from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate +from aviary.mission.ode.specific_energy_rate import SpecificEnergyRate +from aviary.mission.ode.altitude_rate import AltitudeRate class AscentODE(BaseODE): diff --git a/aviary/mission/gasp_based/ode/breguet_cruise_ode.py b/aviary/mission/gasp_based/ode/breguet_cruise_ode.py index 306b41f44..fc5f594c9 100644 --- a/aviary/mission/gasp_based/ode/breguet_cruise_ode.py +++ b/aviary/mission/gasp_based/ode/breguet_cruise_ode.py @@ -10,8 +10,8 @@ from aviary.subsystems.propulsion.propulsion_builder import PropulsionBuilderBase from aviary.variable_info.enums import SpeedType from aviary.variable_info.variables import Dynamic -from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate -from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate +from aviary.mission.ode.specific_energy_rate import SpecificEnergyRate +from aviary.mission.ode.altitude_rate import AltitudeRate class BreguetCruiseODESolution(BaseODE): diff --git a/aviary/mission/gasp_based/ode/climb_ode.py b/aviary/mission/gasp_based/ode/climb_ode.py index f112ea38c..c92d202e8 100644 --- a/aviary/mission/gasp_based/ode/climb_ode.py +++ b/aviary/mission/gasp_based/ode/climb_ode.py @@ -14,8 +14,8 @@ from aviary.subsystems.propulsion.propulsion_mission import PropulsionMission from aviary.variable_info.enums import AnalysisScheme, AlphaModes, SpeedType from aviary.variable_info.variables import Dynamic -from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate -from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate +from aviary.mission.ode.specific_energy_rate import SpecificEnergyRate +from aviary.mission.ode.altitude_rate import AltitudeRate class ClimbODE(BaseODE): diff --git a/aviary/mission/gasp_based/ode/descent_ode.py b/aviary/mission/gasp_based/ode/descent_ode.py index ed10777d6..9c11179a4 100644 --- a/aviary/mission/gasp_based/ode/descent_ode.py +++ b/aviary/mission/gasp_based/ode/descent_ode.py @@ -19,8 +19,8 @@ from aviary.variable_info.variables import Dynamic from aviary.subsystems.aerodynamics.aerodynamics_builder import AerodynamicsBuilderBase from aviary.subsystems.propulsion.propulsion_builder import PropulsionBuilderBase -from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate -from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate +from aviary.mission.ode.specific_energy_rate import SpecificEnergyRate +from aviary.mission.ode.altitude_rate import AltitudeRate class DescentODE(BaseODE): diff --git a/aviary/mission/gasp_based/ode/flight_path_ode.py b/aviary/mission/gasp_based/ode/flight_path_ode.py index 64542100b..112f280b3 100644 --- a/aviary/mission/gasp_based/ode/flight_path_ode.py +++ b/aviary/mission/gasp_based/ode/flight_path_ode.py @@ -13,6 +13,8 @@ from aviary.subsystems.propulsion.propulsion_mission import PropulsionMission from aviary.subsystems.propulsion.propulsion_builder import PropulsionBuilderBase from aviary.variable_info.variables import Aircraft, Dynamic, Mission +from aviary.mission.ode.specific_energy_rate import SpecificEnergyRate +from aviary.mission.ode.altitude_rate import AltitudeRate class FlightPathODE(BaseODE): @@ -209,6 +211,28 @@ def setup(self): self.promotes('eoms', outputs=[ Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE]) + self.add_subsystem( + name='SPECIFIC_ENERGY_RATE_EXCESS', + subsys=SpecificEnergyRate(num_nodes=nn), + promotes_inputs=[(Dynamic.Mission.VELOCITY, "TAS"), Dynamic.Mission.MASS, + (Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.THRUST_MAX_TOTAL), + Dynamic.Mission.DRAG], + promotes_outputs=[(Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS)] + ) + + self.add_subsystem( + name='ALTITUDE_RATE_MAX', + subsys=AltitudeRate(num_nodes=nn), + promotes_inputs=[ + (Dynamic.Mission.SPECIFIC_ENERGY_RATE, + Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS), + (Dynamic.Mission.VELOCITY_RATE, "TAS_rate"), + (Dynamic.Mission.VELOCITY, "TAS")], + promotes_outputs=[ + (Dynamic.Mission.ALTITUDE_RATE, + Dynamic.Mission.ALTITUDE_RATE_MAX)]) + # Example of how to use a print_comp debug_comp = [] if False: diff --git a/aviary/mission/flops_based/ode/altitude_rate.py b/aviary/mission/ode/altitude_rate.py similarity index 100% rename from aviary/mission/flops_based/ode/altitude_rate.py rename to aviary/mission/ode/altitude_rate.py diff --git a/aviary/mission/flops_based/ode/specific_energy_rate.py b/aviary/mission/ode/specific_energy_rate.py similarity index 100% rename from aviary/mission/flops_based/ode/specific_energy_rate.py rename to aviary/mission/ode/specific_energy_rate.py From 8c3f87ef5e1ad9da9c387128b3970143eb874e23 Mon Sep 17 00:00:00 2001 From: swryan Date: Thu, 18 Jan 2024 13:42:10 -0500 Subject: [PATCH 108/188] Update version for v0.9.2 release --- .bumpversion.cfg | 2 +- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- aviary/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index a5f4cc007..cfe80c61d 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.9.2-dev +current_version = 0.9.2 commit = False tag = False parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index b86321f76..b3b15494e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -21,7 +21,7 @@ body: attributes: label: Aviary Version description: What version of Aviary is being used. - placeholder: "0.9.2-dev" + placeholder: "0.9.2" validations: required: true - type: textarea diff --git a/aviary/__init__.py b/aviary/__init__.py index 99316d3f4..a2fecb457 100644 --- a/aviary/__init__.py +++ b/aviary/__init__.py @@ -1 +1 @@ -__version__ = "0.9.2-dev" +__version__ = "0.9.2" From 746a32c238fffac095ee0cc6b3300ab22c3148da Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Thu, 18 Jan 2024 14:03:45 -0500 Subject: [PATCH 109/188] init file added to new folder --- aviary/mission/ode/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 aviary/mission/ode/__init__.py diff --git a/aviary/mission/ode/__init__.py b/aviary/mission/ode/__init__.py new file mode 100644 index 000000000..e69de29bb From 9f6254da5526aaeaf4451b379ade180be4bfa5c9 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 18 Jan 2024 13:09:15 -0600 Subject: [PATCH 110/188] Added gasp cruise phase --- aviary/interface/methods_for_level2.py | 9 +- .../flops_based/phases/phase_builder_base.py | 2 +- .../mission/gasp_based/phases/cruise_phase.py | 138 ++++++++++++++++++ 3 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 aviary/mission/gasp_based/phases/cruise_phase.py diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 8e944935d..3ec0e599c 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -597,10 +597,11 @@ def _get_2dof_phase(self, phase_name): phase_name, phase_options, default_mission_subsystems, meta_data=self.meta_data, transcription=transcription) phase = phase_object.build_phase(aviary_options=self.aviary_inputs) - phase.add_control( - Dynamic.Mission.THROTTLE, targets=Dynamic.Mission.THROTTLE, units='unitless', - opt=False, lower=0.0, upper=1.0 - ) + if 'cruise' not in phase_name: + phase.add_control( + Dynamic.Mission.THROTTLE, targets=Dynamic.Mission.THROTTLE, units='unitless', + opt=False, lower=0.0, upper=1.0 + ) phase.timeseries_options['use_prefix'] = True diff --git a/aviary/mission/flops_based/phases/phase_builder_base.py b/aviary/mission/flops_based/phases/phase_builder_base.py index 5f82d69f3..507b1cf86 100644 --- a/aviary/mission/flops_based/phases/phase_builder_base.py +++ b/aviary/mission/flops_based/phases/phase_builder_base.py @@ -348,7 +348,7 @@ def build_phase(self, aviary_options=None): if self.is_analytic_phase: phase = dm.AnalyticPhase( ode_class=ode_class, - ode_init_kwargs=self.ode_args, + ode_init_kwargs=kwargs, num_nodes=self.num_nodes, ) else: diff --git a/aviary/mission/gasp_based/phases/cruise_phase.py b/aviary/mission/gasp_based/phases/cruise_phase.py new file mode 100644 index 000000000..4d26d6709 --- /dev/null +++ b/aviary/mission/gasp_based/phases/cruise_phase.py @@ -0,0 +1,138 @@ +from aviary.mission.flops_based.phases.phase_builder_base import ( + PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.variables import Dynamic +from aviary.mission.gasp_based.ode.breguet_cruise_ode import BreguetCruiseODESolution +from aviary.variable_info.variable_meta_data import _MetaData + + +class CruisePhase(PhaseBuilderBase): + """ + A phase builder for a climb phase in a mission simulation. + + This class extends the PhaseBuilderBase class, providing specific implementations for + the climb phase of a flight mission. + + Attributes + ---------- + Inherits all attributes from PhaseBuilderBase. + + Methods + ------- + Inherits all methods from PhaseBuilderBase. + Additional method overrides and new methods specific to the climb phase are included. + """ + default_name = 'cruise_phase' + default_ode_class = BreguetCruiseODESolution + + __slots__ = ('external_subsystems', 'meta_data') + + # region : derived type customization points + _meta_data_ = {} + + _initial_guesses_meta_data_ = {} + + default_meta_data = _MetaData + + def __init__( + self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, core_subsystems=None, + external_subsystems=None, meta_data=None + ): + super().__init__( + name=name, subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, + core_subsystems=core_subsystems, + ) + + # TODO: support external_subsystems and meta_data in the base class + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + + self.meta_data = meta_data + self.is_analytic_phase = True + + def build_phase(self, aviary_options: AviaryValues = None): + """ + Return a new climb phase for analysis using these constraints. + + If ode_class is None, ClimbODE is used as the default. + + Parameters + ---------- + aviary_options : AviaryValues + Collection of Aircraft/Mission specific options + + Returns + ------- + dymos.Phase + """ + phase = super().build_phase(aviary_options) + + # Custom configurations for the climb phase + user_options = self.user_options + + mach_cruise = user_options.get_val('mach_cruise') + alt_cruise, alt_units = user_options.get_item('alt_cruise') + + # Time here is really the independent variable through which we are integrating. + # In the case of the Breguet Range ODE, it's mass. + # We rely on mass being monotonically non-increasing across the phase. + phase.set_time_options( + name='mass', + fix_initial=False, + fix_duration=False, + units="lbm", + targets="mass", + initial_bounds=(10.e3, 500_000), + initial_ref=100_000, + duration_bounds=(-50000, -10), + duration_ref=50000, + ) + + phase.add_parameter(Dynamic.Mission.ALTITUDE, opt=False, + val=alt_cruise, units=alt_units) + phase.add_parameter(Dynamic.Mission.MACH, opt=False, + val=mach_cruise) + phase.add_parameter("initial_distance", opt=False, val=0.0, + units="NM", static_target=True) + phase.add_parameter("initial_time", opt=False, val=0.0, + units="s", static_target=True) + + phase.add_timeseries_output("time", units="s") + + return phase + + +# Adding metadata for the CruisePhase +CruisePhase._add_meta_data('alt_cruise', val=0) +CruisePhase._add_meta_data('mach_cruise', val=0) + +CruisePhase._add_initial_guess_meta_data( + InitialGuessTime(), + desc='initial guess for initial time and duration specified as a tuple') + +CruisePhase._add_initial_guess_meta_data( + InitialGuessState('mass'), + desc='initial guess for mass') + +CruisePhase._add_initial_guess_meta_data( + InitialGuessState('initial_distance'), + desc='initial guess for initial_distance') + +CruisePhase._add_initial_guess_meta_data( + InitialGuessState('initial_time'), + desc='initial guess for initial_time') + +CruisePhase._add_initial_guess_meta_data( + InitialGuessState('altitude'), + desc='initial guess for altitude') + +CruisePhase._add_initial_guess_meta_data( + InitialGuessState('mach'), + desc='initial guess for mach') From b34e83bb3f4d58d4f5971ffd977c5095c5250dff Mon Sep 17 00:00:00 2001 From: swryan Date: Thu, 18 Jan 2024 14:10:13 -0500 Subject: [PATCH 111/188] increment version to 0.9.3-dev --- .bumpversion.cfg | 2 +- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- aviary/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index cfe80c61d..cb0597e80 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.9.2 +current_version = 0.9.3-dev commit = False tag = False parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index b3b15494e..e3fa89790 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -21,7 +21,7 @@ body: attributes: label: Aviary Version description: What version of Aviary is being used. - placeholder: "0.9.2" + placeholder: "0.9.3-dev" validations: required: true - type: textarea diff --git a/aviary/__init__.py b/aviary/__init__.py index a2fecb457..b6cf24f58 100644 --- a/aviary/__init__.py +++ b/aviary/__init__.py @@ -1 +1 @@ -__version__ = "0.9.2" +__version__ = "0.9.3-dev" From 0e3ecec2fd9ca3fdafa5ca28a0de2967f1d0a60f Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Thu, 18 Jan 2024 14:26:50 -0500 Subject: [PATCH 112/188] tmate on --- .github/workflows/test_workflow.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 6927d7b51..436b1947c 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -213,8 +213,8 @@ jobs: python run_all.py cd ../.. - # - name: Setup tmate session - # uses: mxschmitt/action-tmate@v3 + - name: Setup tmate session + uses: mxschmitt/action-tmate@v3 - name: Run tests From 5af33650bc42a184f8295363bc88426967fe6d2b Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Thu, 18 Jan 2024 14:45:27 -0500 Subject: [PATCH 113/188] moved tests to correct subfolder --- aviary/mission/ode/test/__init__.py | 0 aviary/mission/{flops_based => }/ode/test/test_altitude_rate.py | 0 .../{flops_based => }/ode/test/test_specific_energy_rate.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 aviary/mission/ode/test/__init__.py rename aviary/mission/{flops_based => }/ode/test/test_altitude_rate.py (100%) rename aviary/mission/{flops_based => }/ode/test/test_specific_energy_rate.py (100%) diff --git a/aviary/mission/ode/test/__init__.py b/aviary/mission/ode/test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/aviary/mission/flops_based/ode/test/test_altitude_rate.py b/aviary/mission/ode/test/test_altitude_rate.py similarity index 100% rename from aviary/mission/flops_based/ode/test/test_altitude_rate.py rename to aviary/mission/ode/test/test_altitude_rate.py diff --git a/aviary/mission/flops_based/ode/test/test_specific_energy_rate.py b/aviary/mission/ode/test/test_specific_energy_rate.py similarity index 100% rename from aviary/mission/flops_based/ode/test/test_specific_energy_rate.py rename to aviary/mission/ode/test/test_specific_energy_rate.py From a58530ea5703d6206df1f61a36d0a24ff35e91e8 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 18 Jan 2024 15:38:14 -0600 Subject: [PATCH 114/188] Removed mentions of aero_builder --- .../mission/flops_based/phases/climb_phase.py | 3 - .../flops_based/phases/descent_phase.py | 3 - .../phases/detailed_landing_phases.py | 18 ---- .../phases/detailed_takeoff_phases.py | 33 ------- .../flops_based/phases/phase_builder_base.py | 12 +-- .../phases/benchmark/test_bench_accel.py | 3 +- .../mission/gasp_based/phases/cruise_phase.py | 2 +- .../gasp_based/phases/run_phases/run_accel.py | 98 +++++++++++++++++++ aviary/models/N3CC/N3CC_data.py | 10 -- 9 files changed, 104 insertions(+), 78 deletions(-) create mode 100644 aviary/mission/gasp_based/phases/run_phases/run_accel.py diff --git a/aviary/mission/flops_based/phases/climb_phase.py b/aviary/mission/flops_based/phases/climb_phase.py index 977240d90..ca5042410 100644 --- a/aviary/mission/flops_based/phases/climb_phase.py +++ b/aviary/mission/flops_based/phases/climb_phase.py @@ -14,9 +14,6 @@ class Climb(EnergyPhase): name : str ('climb') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags diff --git a/aviary/mission/flops_based/phases/descent_phase.py b/aviary/mission/flops_based/phases/descent_phase.py index 78ad93a90..b76164fc7 100644 --- a/aviary/mission/flops_based/phases/descent_phase.py +++ b/aviary/mission/flops_based/phases/descent_phase.py @@ -14,9 +14,6 @@ class Descent(EnergyPhase): name : str ('descent') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags diff --git a/aviary/mission/flops_based/phases/detailed_landing_phases.py b/aviary/mission/flops_based/phases/detailed_landing_phases.py index e71d350c5..34d4bb437 100644 --- a/aviary/mission/flops_based/phases/detailed_landing_phases.py +++ b/aviary/mission/flops_based/phases/detailed_landing_phases.py @@ -54,9 +54,6 @@ class LandingApproachToMicP3(PhaseBuilderBase): name : str ('landing_approach') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -277,9 +274,6 @@ class LandingMicP3ToObstacle(LandingApproachToMicP3): name : str ('landing_approach') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -379,9 +373,6 @@ class LandingObstacleToFlare(PhaseBuilderBase): name : str ('landing_obstacle') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -573,9 +564,6 @@ class LandingFlareToTouchdown(PhaseBuilderBase): name : str ('landing_flare') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -796,9 +784,6 @@ class LandingTouchdownToNoseDown(PhaseBuilderBase): name : str ('landing_touchdown') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -973,9 +958,6 @@ class LandingNoseDownToStop(PhaseBuilderBase): name : str ('landing_stop') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags diff --git a/aviary/mission/flops_based/phases/detailed_takeoff_phases.py b/aviary/mission/flops_based/phases/detailed_takeoff_phases.py index 742c774f8..947c8f276 100644 --- a/aviary/mission/flops_based/phases/detailed_takeoff_phases.py +++ b/aviary/mission/flops_based/phases/detailed_takeoff_phases.py @@ -98,9 +98,6 @@ class TakeoffBrakeReleaseToDecisionSpeed(PhaseBuilderBase): name : str ('takeoff_brake_release') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -264,9 +261,6 @@ class TakeoffDecisionSpeedToRotate(PhaseBuilderBase): name : str ('takeoff_decision_speed') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -441,9 +435,6 @@ class TakeoffDecisionSpeedBrakeDelay(TakeoffDecisionSpeedToRotate): name : str ('takeoff_decision_speed') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -544,9 +535,6 @@ class TakeoffRotateToLiftoff(PhaseBuilderBase): name : str ('takeoff_rotate') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -726,9 +714,6 @@ class TakeoffLiftoffToObstacle(PhaseBuilderBase): name : str ('takeoff_liftoff') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -961,9 +946,6 @@ class TakeoffObstacleToMicP2(PhaseBuilderBase): name : str ('takeoff_climb') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -1193,9 +1175,6 @@ class TakeoffMicP2ToEngineCutback(PhaseBuilderBase): name : str ('takeoff_climb') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -1426,9 +1405,6 @@ class TakeoffEngineCutback(PhaseBuilderBase): name : str ('takeoff_climb') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -1637,9 +1613,6 @@ class TakeoffEngineCutbackToMicP1(PhaseBuilderBase): name : str ('takeoff_climb') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -1866,9 +1839,6 @@ class TakeoffMicP1ToClimb(PhaseBuilderBase): name : str ('takeoff_climb') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -2094,9 +2064,6 @@ class TakeoffBrakeToAbort(PhaseBuilderBase): name : str ('takeoff_abort') object label - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags diff --git a/aviary/mission/flops_based/phases/phase_builder_base.py b/aviary/mission/flops_based/phases/phase_builder_base.py index 507b1cf86..a2d5a82db 100644 --- a/aviary/mission/flops_based/phases/phase_builder_base.py +++ b/aviary/mission/flops_based/phases/phase_builder_base.py @@ -20,7 +20,7 @@ PhaseBuilderBase : the interface for a phase builder ''' -from abc import ABC, abstractmethod +from abc import ABC from collections import namedtuple from collections.abc import Sequence @@ -205,9 +205,6 @@ class PhaseBuilderBase(ABC): core_subsystems : (None) list of SubsystemBuilderBase objects that will be added to the phase ODE - aero_builder (None) - utility for building and connecting a dynamic aerodynamics analysis component - user_options : AviaryValues () state/path constraint values and flags @@ -249,7 +246,7 @@ class attribute: derived type customization point; the default value ''' __slots__ = ( 'name', 'core_subsystems', 'subsystem_options', 'user_options', - 'initial_guesses', 'ode_class', 'transcription', 'aero_builder', + 'initial_guesses', 'ode_class', 'transcription', 'is_analytic_phase', 'num_nodes', ) @@ -264,7 +261,7 @@ class attribute: derived type customization point; the default value # endregion : derived type customization points def __init__( - self, name=None, core_subsystems=None, aero_builder=None, user_options=None, initial_guesses=None, + self, name=None, core_subsystems=None, user_options=None, initial_guesses=None, ode_class=None, transcription=None, subsystem_options=None, is_analytic_phase=False, num_nodes=5, ): if name is None: @@ -280,9 +277,6 @@ def __init__( if subsystem_options is None: subsystem_options = {} - if aero_builder is not None: - self.aero_builder = aero_builder - self.subsystem_options = subsystem_options self.user_options = user_options diff --git a/aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py b/aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py index ac1f1294e..e31ec51c4 100644 --- a/aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py +++ b/aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py @@ -29,4 +29,5 @@ def bench_test_accel(self): if __name__ == "__main__": - unittest.main() + test = AccelPhaseTestCase() + test.bench_test_accel() diff --git a/aviary/mission/gasp_based/phases/cruise_phase.py b/aviary/mission/gasp_based/phases/cruise_phase.py index 4d26d6709..8af76ceeb 100644 --- a/aviary/mission/gasp_based/phases/cruise_phase.py +++ b/aviary/mission/gasp_based/phases/cruise_phase.py @@ -1,5 +1,5 @@ from aviary.mission.flops_based.phases.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) + PhaseBuilderBase, InitialGuessState, InitialGuessTime) from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic from aviary.mission.gasp_based.ode.breguet_cruise_ode import BreguetCruiseODESolution diff --git a/aviary/mission/gasp_based/phases/run_phases/run_accel.py b/aviary/mission/gasp_based/phases/run_phases/run_accel.py new file mode 100644 index 000000000..1031e215e --- /dev/null +++ b/aviary/mission/gasp_based/phases/run_phases/run_accel.py @@ -0,0 +1,98 @@ +import dymos as dm +import matplotlib.pyplot as plt +import openmdao.api as om +import numpy as np + +from aviary.mission.gasp_based.phases.accel_phase import AccelPhase +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 + + +def run_accel(): + # Column-wise data from CSV + time_GASP = np.array([0.182, 0.188]) + distance_GASP = np.array([0.00, 1.57]) + weight_GASP = np.array([174974., 174878.]) + TAS_GASP = np.array([185., 252.]) + EAS_GASP = np.array([184., 250.]) + + time_GASP = time_GASP * 3600 + time_GASP = time_GASP - time_GASP[0] + + prob = om.Problem(model=om.Group()) + + prob.driver = om.pyOptSparseDriver() + prob.driver.options["optimizer"] = "SNOPT" + prob.driver.opt_settings["Major iterations limit"] = 100 + prob.driver.opt_settings["Major optimality tolerance"] = 5.0e-3 + prob.driver.opt_settings["Major feasibility tolerance"] = 1e-6 + prob.driver.opt_settings["iSumm"] = 6 + prob.driver.declare_coloring() + + transcription = dm.Radau(num_segments=15, order=4, compressed=False) + + aviary_options = get_option_defaults() + + phase_name = "accel" + phase_options = { + 'user_options': { + 'alt': (500, 'ft'), + 'EAS_constraint_eq': (250, 'kn'), + 'fix_initial': True, + 'time_initial_bounds': ((0, 0), 's'), + 'duration_bounds': ((0, 36_000), 's'), + 'duration_ref': (1000, 's'), + 'TAS_lower': (0, 'kn'), + 'TAS_upper': (1000, 'kn'), + 'TAS_ref': (250, 'kn'), + 'TAS_ref0': (150, 'kn'), + 'mass_lower': (0, 'lbm'), + 'mass_upper': (None, 'lbm'), + 'mass_ref': (175_500, 'lbm'), + 'distance_lower': (0, 'NM'), + 'distance_upper': (150, 'NM'), + 'distance_ref': (1, 'NM'), + 'distance_defect_ref': (1, 'NM'), + } + } + + phase_object = AccelPhase.from_phase_info( + phase_name, phase_options, default_mission_subsystems, transcription=transcription) + accel = phase_object.build_phase(aviary_options=aviary_options) + + accel.add_parameter( + Aircraft.Wing.AREA, opt=False, units="ft**2", val=1370.0, static_target=True + ) + + prob.model.add_subsystem(name='accel', subsys=accel) + accel.add_timeseries_output("EAS", output_name="EAS", units="kn") + accel.add_timeseries_output("TAS", output_name="TAS", units="kn") + accel.add_timeseries_output("mass", output_name="mass", units="lbm") + accel.add_timeseries_output(Dynamic.Mission.DISTANCE, + output_name=Dynamic.Mission.DISTANCE, units="NM") + accel.timeseries_options['use_prefix'] = True + + accel.add_objective("time", loc="final") + prob.model.linear_solver.options["iprint"] = 0 + prob.model.nonlinear_solver.options["iprint"] = 0 + + prob.model.options["assembled_jac_type"] = "csc" + prob.model.linear_solver = om.DirectSolver(assemble_jac=True) + + prob.set_solver_print(level=0) + + prob.setup() + prob.set_val("accel.states:mass", accel.interp("mass", ys=[174974, 174878])) + prob.set_val("accel.states:TAS", accel.interp("TAS", ys=[185, 252])) + prob.set_val("accel.states:distance", accel.interp( + Dynamic.Mission.DISTANCE, ys=[0, 1.57])) + prob.set_val("accel.t_duration", 1000) + prob.set_val("accel.t_initial", 0) + + dm.run_problem(problem=prob, simulate=True) + print() + print("Done Running Model, Now Simulating") + print() + + return prob diff --git a/aviary/models/N3CC/N3CC_data.py b/aviary/models/N3CC/N3CC_data.py index a163553ea..53946d525 100644 --- a/aviary/models/N3CC/N3CC_data.py +++ b/aviary/models/N3CC/N3CC_data.py @@ -1132,16 +1132,6 @@ def _split_aviary_values(aviary_values, slicing): 'spoiler_lift_coefficient': -0.81, 'spoiler_drag_coefficient': 0.085}} -# landing_aero_builder = TakeoffAero(**landing_aero_user_options) - -# fullstop_aero_user_options = dict(landing_aero_user_options) -# fullstop_aero_user_options['use_spoilers'] = True -# fullstop_aero_user_options['spoiler_lift_coefficient'] = -0.81 -# fullstop_aero_user_options['spoiler_drag_coefficient'] = 0.085 - -# fullstop_aero_builder = TakeoffAero(**fullstop_aero_user_options) -# endregion - landing aero - # VELOCITY TIME DISTANCE ALPHA ALTITUDE # KNOTS SEC. FEET DEG. FEET # 50. FOOT OBSTACLE 138.65 0.00 0.00 5.22 50.00 From f896008fe7c5a67d658403316b96473e08ed2cd0 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 18 Jan 2024 17:48:33 -0600 Subject: [PATCH 115/188] updating benchmarks --- .../aircraft_for_bench_FwFm_simple.csv | 159 ---------- .../aircraft_for_bench_GwFm_simple.csv | 273 ------------------ .../benchmark_tests/test_bench_FwFm.py | 26 +- .../benchmark_tests/test_bench_GwFm.py | 12 +- 4 files changed, 19 insertions(+), 451 deletions(-) delete mode 100644 aviary/models/test_aircraft/aircraft_for_bench_FwFm_simple.csv delete mode 100644 aviary/models/test_aircraft/aircraft_for_bench_GwFm_simple.csv diff --git a/aviary/models/test_aircraft/aircraft_for_bench_FwFm_simple.csv b/aviary/models/test_aircraft/aircraft_for_bench_FwFm_simple.csv deleted file mode 100644 index 2d4ea4703..000000000 --- a/aviary/models/test_aircraft/aircraft_for_bench_FwFm_simple.csv +++ /dev/null @@ -1,159 +0,0 @@ -aircraft:air_conditioning:mass_scaler,1.0,unitless -aircraft:anti_icing:mass_scaler,1.0,unitless -aircraft:apu:mass_scaler,1.1,unitless -aircraft:avionics:mass_scaler,1.2,unitless -aircraft:canard:area,0.0,ft**2 -aircraft:canard:aspect_ratio,0.0,unitless -aircraft:canard:thickness_to_chord,0.0,unitless -aircraft:crew_and_payload:baggage_mass_per_passenger,45.0,lbm -aircraft:crew_and_payload:cargo_container_mass_scaler,1.0,unitless -aircraft:crew_and_payload:flight_crew_mass_scaler,1.0,unitless -aircraft:crew_and_payload:mass_per_passenger,180.0,lbm -aircraft:crew_and_payload:misc_cargo,0.0,lbm -aircraft:crew_and_payload:non_flight_crew_mass_scaler,1.0,unitless -aircraft:crew_and_payload:num_business_class,0,unitless -aircraft:crew_and_payload:num_first_class,11,unitless -aircraft:crew_and_payload:num_flight_attendants,3,unitless -aircraft:crew_and_payload:num_flight_crew,2,unitless -aircraft:crew_and_payload:num_galley_crew,0,unitless -aircraft:crew_and_payload:num_non_flight_crew,3,unitless -aircraft:crew_and_payload:num_passengers,169,unitless -aircraft:crew_and_payload:num_tourist_class,158,unitless -aircraft:crew_and_payload:passenger_service_mass_scaler,1.0,unitless -aircraft:crew_and_payload:wing_cargo,0.0,lbm -aircraft:design:base_area,0.0,ft**2 -aircraft:design:empty_mass_margin_scaler,0.0,unitless -aircraft:design:lift_dependent_drag_coeff_factor,0.909839381134961,unitless -aircraft:design:touchdown_mass,152800.0,lbm -aircraft:design:reserves,3000.,unitless -aircraft:design:subsonic_drag_coeff_factor,1.0,unitless -aircraft:design:supersonic_drag_coeff_factor,1.0,unitless -aircraft:design:use_alt_mass,False,unitless -aircraft:design:zero_lift_drag_coeff_factor,0.930890028006548,unitless -aircraft:electrical:mass_scaler,1.25,unitless -aircraft:engine:additional_mass_fraction,0.,unitless -aircraft:engine:constant_fuel_consumption,0.,lbm/h -aircraft:engine:data_file,models/engines/turbofan_28k.deck,unitless -aircraft:engine:flight_idle_thrust_fraction,0.0,unitless -aircraft:engine:flight_idle_max_fraction,1.0,unitless -aircraft:engine:flight_idle_min_fraction,0.08,unitless -aircraft:engine:fuel_flow_scaler_constant_term,0.,unitless -aircraft:engine:fuel_flow_scaler_linear_term,0.,unitless -aircraft:engine:generate_flight_idle,True,unitless -aircraft:engine:geopotential_alt,False,unitless -aircraft:engine:ignore_negative_thrust,False,unitless -aircraft:engine:interpolation_method,slinear,unitless -aircraft:engine:mass_scaler,1.15,unitless -aircraft:engine:mass,7400,lbm -aircraft:engine:num_engines,2,unitless -aircraft:engine:num_fuselage_engines,0,unitless -aircraft:engine:num_wing_engines,2,unitless -aircraft:engine:reference_mass,7400,lbm -aircraft:engine:reference_sls_thrust,28928.1,lbf -aircraft:engine:scale_mass,True,unitless -aircraft:engine:scale_performance,True,unitless -aircraft:engine:scaled_sls_thrust,28928.1,lbf -aircraft:engine:subsonic_fuel_flow_scaler,1.,unitless -aircraft:engine:supersonic_fuel_flow_scaler,1.,unitless -aircraft:engine:thrust_reversers_mass_scaler,0.0,unitless -aircraft:engine:wing_locations,[0.26869218],unitless -aircraft:fins:area,0.0,ft**2 -aircraft:fins:mass_scaler,1.0,unitless -aircraft:fins:mass,0.0,lbm -aircraft:fins:num_fins,0,unitless -aircraft:fins:taper_ratio,10.0,unitless -aircraft:fuel:auxiliary_fuel_capacity,0.0,lbm -aircraft:fuel:density_ratio,1.0,unitless -aircraft:fuel:fuel_system_mass_scaler,1.0,unitless -aircraft:fuel:fuselage_fuel_capacity,0.0,lbm -aircraft:fuel:num_tanks,7,unitless -aircraft:fuel:total_capacity,45694.0,lbm -aircraft:fuel:unusable_fuel_mass_scaler,1.0,unitless -aircraft:furnishings:mass_scaler,1.1,unitless -aircraft:fuselage:length,128.0,ft -aircraft:fuselage:mass_scaler,1.05,unitless -aircraft:fuselage:max_height,13.17,ft -aircraft:fuselage:max_width,12.33,ft -aircraft:fuselage:military_cargo_floor,False,unitless -aircraft:fuselage:num_fuselages,1,unitless -aircraft:fuselage:passenger_compartment_length,85.5,ft -aircraft:fuselage:planform_area,1578.24,ft**2 -aircraft:fuselage:wetted_area_scaler,1.0,unitless -aircraft:fuselage:wetted_area,4158.62,ft**2 -aircraft:horizontal_tail:area,355.0,ft**2 -aircraft:horizontal_tail:aspect_ratio,6.0,unitless -aircraft:horizontal_tail:mass_scaler,1.2,unitless -aircraft:horizontal_tail:taper_ratio,0.22,unitless -aircraft:horizontal_tail:thickness_to_chord,0.125,unitless -aircraft:horizontal_tail:vertical_tail_fraction,0.0,unitless -aircraft:horizontal_tail:wetted_area_scaler,1.0,unitless -aircraft:horizontal_tail:wetted_area,592.65,ft**2 -aircraft:hydraulics:mass_scaler,1.0,unitless -aircraft:hydraulics:system_pressure,3000.0,lbf/ft**2 -aircraft:instruments:mass_scaler,1.25,unitless -aircraft:landing_gear:carrier_based,False,unitless -aircraft:landing_gear:main_gear_mass_scaler,1.1,unitless -aircraft:landing_gear:main_gear_oleo_length,102.0,inch -aircraft:landing_gear:nose_gear_mass_scaler,1.0,unitless -aircraft:landing_gear:nose_gear_oleo_length,67.0,inch -aircraft:nacelle:avg_diameter,7.94,ft -aircraft:nacelle:avg_length,12.3,ft -aircraft:nacelle:count_factor,2,unitless -aircraft:nacelle:mass_scaler,1.0,unitless -aircraft:nacelle:wetted_area_scaler,1.0,unitless -aircraft:paint:mass_per_unit_area,0.037,lbm/ft**2 -aircraft:propulsion:engine_oil_mass_scaler,1.0,unitless -aircraft:propulsion:misc_mass_scaler,1.0,unitless -aircraft:vertical_tail:area,284.0,ft**2 -aircraft:vertical_tail:aspect_ratio,1.75,unitless -aircraft:vertical_tail:mass_scaler,1.0,unitless -aircraft:vertical_tail:num_tails,1,unitless -aircraft:vertical_tail:taper_ratio,0.33,unitless -aircraft:vertical_tail:thickness_to_chord,0.1195,unitless -aircraft:vertical_tail:wetted_area_scaler,1.0,unitless -aircraft:vertical_tail:wetted_area,581.13,ft**2 -aircraft:wing:aeroelastic_tailoring_factor,0.0,unitless -aircraft:wing:airfoil_technology,1.92669766647637,unitless -aircraft:wing:area,1370.0,ft**2 -aircraft:wing:aspect_ratio,11.22091,unitless -aircraft:wing:bending_mass_scaler,1.0,unitless -aircraft:wing:chord_per_semispan,0.31,0.23,0.084,unitless -aircraft:wing:composite_fraction,0.2,unitless -aircraft:wing:control_surface_area,137,ft**2 -aircraft:wing:control_surface_area_ratio,0.1,unitless -aircraft:wing:glove_and_bat,134.0,ft**2 -aircraft:wing:input_station_dist,0.,0.2759,0.9367,unitless -aircraft:wing:load_distribution_control,2.0,unitless -aircraft:wing:load_fraction,1.0,unitless -aircraft:wing:load_path_sweep_dist,0.,22.,deg -aircraft:wing:mass_scaler,1.23,unitless -aircraft:wing:max_camber_at_70_semispan,0.0,unitless -aircraft:wing:misc_mass_scaler,1.0,unitless -aircraft:wing:num_integration_stations,50,unitless -aircraft:wing:shear_control_mass_scaler,1.0,unitless -aircraft:wing:span_efficiency_reduction,False,unitless -aircraft:wing:span,117.83,ft -aircraft:wing:strut_bracing_factor,0.0,unitless -aircraft:wing:surface_ctrl_mass_scaler,1.0,unitless -aircraft:wing:sweep,25.0,deg -aircraft:wing:taper_ratio,0.278,unitless -aircraft:wing:thickness_to_chord_dist,0.145,0.115,0.104,unitless -aircraft:wing:thickness_to_chord,0.13,unitless -aircraft:wing:ultimate_load_factor,3.75,unitless -aircraft:wing:var_sweep_mass_penalty,0.0,unitless -aircraft:wing:wetted_area_scaler,1.0,unitless -aircraft:wing:wetted_area,2396.56,ft**2 -mission:constraints:max_mach,0.785,unitless -mission:design:cruise_altitude,35000,ft -mission:design:gross_mass,175400.0,lbm -mission:design:range,3500,NM -mission:design:thrust_takeoff_per_eng,28928.1,lbf -mission:landing:lift_coefficient_max,2.0,unitless -mission:summary:cruise_mach,0.785,unitless -mission:summary:fuel_flow_scaler,1.0,unitless -mission:takeoff:fuel_simple,577,lbm -mission:takeoff:lift_coefficient_max,3.0,unitless -mission:takeoff:lift_over_drag,17.354,unitless -mission:takeoff:rolling_friction_coefficient,0.0175,unitless -settings:equations_of_motion,height_energy -settings:mass_method,FLOPS \ No newline at end of file diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm_simple.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm_simple.csv deleted file mode 100644 index 5c0d0b8a0..000000000 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm_simple.csv +++ /dev/null @@ -1,273 +0,0 @@ -aircraft:air_conditioning:mass_scaler,1.0,unitless -aircraft:anti_icing:mass_scaler,1.0,unitless -aircraft:apu:mass_scaler,1.1,unitless -aircraft:avionics:mass_scaler,1.2,unitless -aircraft:canard:area,0.0,ft**2 -aircraft:canard:aspect_ratio,0.0,unitless -aircraft:canard:thickness_to_chord,0.0,unitless -aircraft:controls:cockpit_control_mass_scaler,1,unitless -aircraft:controls:control_mass_increment,0,lbm -aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless -aircraft:controls:stability_augmentation_system_mass,0,lbm -aircraft:crew_and_payload:cargo_container_mass_scaler,1.0,unitless -aircraft:crew_and_payload:cargo_mass,10040,lbm -aircraft:crew_and_payload:flight_crew_mass_scaler,1.0,unitless -aircraft:crew_and_payload:mass_per_passenger,180.0,lbm -aircraft:crew_and_payload:misc_cargo,0.0,lbm -aircraft:crew_and_payload:non_flight_crew_mass_scaler,1.0,unitless -aircraft:crew_and_payload:num_business_class,0,unitless -aircraft:crew_and_payload:num_first_class,11,unitless -aircraft:crew_and_payload:num_flight_attendants,3,unitless -aircraft:crew_and_payload:num_flight_crew,2,unitless -aircraft:crew_and_payload:num_galley_crew,0,unitless -aircraft:crew_and_payload:num_non_flight_crew,3,unitless -aircraft:crew_and_payload:num_passengers,180,unitless -aircraft:crew_and_payload:num_tourist_class,158,unitless -aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm -aircraft:crew_and_payload:passenger_service_mass_scaler,1.0,unitless -aircraft:crew_and_payload:wing_cargo,0.0,lbm -aircraft:design:base_area,0.0,ft**2 -aircraft:design:cg_delta,0.25,unitless -aircraft:design:cockpit_control_mass_coefficient,16.5,unitless -aircraft:design:compute_htail_volume_coeff,False,unitless -aircraft:design:compute_vtail_volume_coeff,False,unitless -aircraft:design:drag_increment,0.00175,unitless -aircraft:design:empty_mass_margin_scaler,0.0,unitless -aircraft:design:equipment_mass_coefficients,928.0,0.0736,0.112,0.14,1959.0,1.65,551.0,11192.0,5.0,3.0,50.0,7.6,12.0,unitless -aircraft:design:lift_curve_slope,7.1765,1/rad -aircraft:design:lift_dependent_drag_coeff_factor,0.909839381134961,unitless -aircraft:design:touchdown_mass,152800.0,lbm -aircraft:design:max_structural_speed,402.5,mi/h -aircraft:design:part25_structural_category,3,unitless -aircraft:design:reserves,5000.,unitless -aircraft:design:smooth_mass_discontinuities,False,unitless -aircraft:design:static_margin,0.03,unitless -aircraft:design:structural_mass_increment,0,lbm -aircraft:design:subsonic_drag_coeff_factor,1.0,unitless -aircraft:design:supercritical_drag_shift,0.033,unitless -aircraft:design:supersonic_drag_coeff_factor,1.0,unitless -aircraft:design:ulf_calculated_from_maneuver,False,unitless -aircraft:design:use_alt_mass,False,unitless -aircraft:design:zero_lift_drag_coeff_factor,0.930890028006548,unitless -aircraft:electrical:has_hybrid_system,False,unitless -aircraft:electrical:mass_scaler,1.25,unitless -aircraft:engine:constant_fuel_consumption,0.,lbm/h -aircraft:engine:data_file,models/engines/turbofan_28k.deck,unitless -aircraft:engine:engine_mass_specific,0.21366,lbm/lbf -aircraft:engine:flight_idle_thrust_fraction,0.0,unitless -aircraft:engine:flight_idle_max_fraction,1.0,unitless -aircraft:engine:flight_idle_min_fraction,0.08,unitless -aircraft:engine:fuel_flow_scaler_constant_term,0.,unitless -aircraft:engine:fuel_flow_scaler_linear_term,0.,unitless -aircraft:engine:generate_flight_idle,True,unitless -aircraft:engine:geopotential_alt,False,unitless -aircraft:engine:has_propellers,False,unitless -aircraft:engine:ignore_negative_thrust,False,unitless -aircraft:engine:interpolation_method,slinear,unitless -aircraft:engine:mass_scaler,1.0,unitless -aircraft:engine:mass,7400,lbm -aircraft:engine:additional_mass_fraction,0.14,unitless -aircraft:engine:num_engines,2,unitless -aircraft:engine:num_fuselage_engines,0,unitless -aircraft:engine:num_wing_engines,2,unitless -aircraft:engine:pod_mass_scaler,1,unitless -aircraft:engine:pylon_factor,1.25,unitless -aircraft:engine:reference_diameter,5.8,ft -aircraft:engine:reference_mass,7400,lbm -aircraft:engine:reference_sls_thrust,28928.1,lbf -aircraft:engine:scale_mass,True,unitless -aircraft:engine:scale_performance,True,unitless -aircraft:engine:scaled_sls_thrust,28928.1,lbf -aircraft:engine:subsonic_fuel_flow_scaler,1.,unitless -aircraft:engine:supersonic_fuel_flow_scaler,1.,unitless -aircraft:engine:thrust_reversers_mass_scaler,0.0,unitless -aircraft:engine:type,7,unitless -aircraft:engine:wing_locations,[0.26869218],unitless -aircraft:fins:area,0.0,ft**2 -aircraft:fins:mass_scaler,1.0,unitless -aircraft:fins:mass,0.0,lbm -aircraft:fins:num_fins,0,unitless -aircraft:fins:taper_ratio,10.0,unitless -aircraft:fuel:auxiliary_fuel_capacity,0.0,lbm -aircraft:fuel:density_ratio,1.0,unitless -aircraft:fuel:density,6.687,lbm/galUS -aircraft:fuel:fuel_margin,0,unitless -aircraft:fuel:fuel_system_mass_coefficient,0.041,unitless -aircraft:fuel:fuel_system_mass_scaler,1.0,unitless -aircraft:fuel:fuselage_fuel_capacity,0.0,lbm -aircraft:fuel:num_tanks,7,unitless -aircraft:fuel:total_capacity,45694.0,lbm -aircraft:fuel:unusable_fuel_mass_scaler,1.0,unitless -aircraft:fuel:wing_fuel_fraction,0,unitless -aircraft:fuel:wing_volume_geometric_max,1114.0,ft**3 -aircraft:furnishings:mass_scaler,1.1,unitless -aircraft:fuselage:aisle_width,24,inch -aircraft:fuselage:avg_diameter,12.75,ft -aircraft:fuselage:delta_diameter,4.5,ft -aircraft:fuselage:flat_plate_area_increment,0.25,ft**2 -aircraft:fuselage:form_factor,1.25,unitless -aircraft:fuselage:length,128.0,ft -aircraft:fuselage:mass_coefficient,128,unitless -aircraft:fuselage:mass_scaler,1.0,unitless -aircraft:fuselage:mass,18357.13345514,lbm -aircraft:fuselage:max_height,13.17,ft -aircraft:fuselage:max_width,12.33,ft -aircraft:fuselage:military_cargo_floor,False,unitless -aircraft:fuselage:nose_fineness,1,unitless -aircraft:fuselage:num_aisles,1,unitless -aircraft:fuselage:num_fuselages,1,unitless -aircraft:fuselage:num_seats_abreast,6,unitless -aircraft:fuselage:passenger_compartment_length,85.5,ft -aircraft:fuselage:pilot_compartment_length,9.5,ft -aircraft:fuselage:planform_area,1578.24,ft**2 -aircraft:fuselage:pressure_differential,7.5,psi -aircraft:fuselage:provide_surface_area,True,unitless -aircraft:fuselage:seat_pitch,29,inch -aircraft:fuselage:seat_width,20.2,inch -aircraft:fuselage:tail_fineness,3,unitless -aircraft:fuselage:wetted_area_factor,4000,unitless -aircraft:fuselage:wetted_area_scaler,1.0,unitless -aircraft:fuselage:wetted_area,4158.62,ft**2 -aircraft:horizontal_tail:area,355.0,ft**2 -aircraft:horizontal_tail:aspect_ratio,4.75,unitless -aircraft:horizontal_tail:average_chord,9.577,ft -aircraft:horizontal_tail:form_factor,1.25,unitless -aircraft:horizontal_tail:mass_coefficient,0.232,unitless -aircraft:horizontal_tail:mass_scaler,1.0,unitless -aircraft:horizontal_tail:moment_ratio,0.2307,unitless -aircraft:horizontal_tail:span,42.254,ft -aircraft:horizontal_tail:sweep,25,deg -aircraft:horizontal_tail:taper_ratio,0.22,unitless -aircraft:horizontal_tail:thickness_to_chord,0.125,unitless -aircraft:horizontal_tail:vertical_tail_fraction,0.0,unitless -aircraft:horizontal_tail:volume_coefficient,1.189,unitless -aircraft:horizontal_tail:wetted_area_scaler,1.0,unitless -aircraft:horizontal_tail:wetted_area,592.65,ft**2 -aircraft:hydraulics:mass_scaler,1.0,unitless -aircraft:hydraulics:system_pressure,3000.0,lbf/ft**2 -aircraft:instruments:mass_scaler,1.25,unitless -aircraft:landing_gear:carrier_based,False,unitless -aircraft:landing_gear:fixed_gear,True,unitless -aircraft:landing_gear:main_gear_location,0.15,unitless -aircraft:landing_gear:main_gear_mass_coefficient,0.85,unitless -aircraft:landing_gear:main_gear_mass_scaler,1.1,unitless -aircraft:landing_gear:main_gear_mass,6366.615,lbm -aircraft:landing_gear:main_gear_oleo_length,102.0,inch -aircraft:landing_gear:mass_coefficient,0.04,unitless -aircraft:landing_gear:nose_gear_mass_scaler,1.0,unitless -aircraft:landing_gear:nose_gear_oleo_length,67.0,inch -aircraft:landing_gear:tail_hook_mass_scaler,1,unitless -aircraft:landing_gear:total_mass_scaler,1,unitless -aircraft:nacelle:avg_diameter,7.94,ft -aircraft:nacelle:avg_length,12.3,ft -aircraft:nacelle:clearance_ratio,0.2,unitless -aircraft:nacelle:core_diameter_ratio,1.25,unitless -aircraft:nacelle:count_factor,2,unitless -aircraft:nacelle:fineness,2,unitless -aircraft:nacelle:form_factor,1.5,unitless -aircraft:nacelle:mass_scaler,1.0,unitless -aircraft:nacelle:mass_specific,3,lbm/ft**2 -aircraft:nacelle:surface_area,329.615,ft**2 -aircraft:nacelle:wetted_area_scaler,1.0,unitless -aircraft:paint:mass_per_unit_area,0.037,lbm/ft**2 -aircraft:propulsion:engine_oil_mass_scaler,1.0,unitless -aircraft:propulsion:misc_mass_scaler,1.0,unitless -aircraft:propulsion:total_num_engines,2,unitless -aircraft:strut:area_ratio,0,unitless -aircraft:strut:chord,0,ft -aircraft:strut:dimensional_location_specified,True,unitless -aircraft:strut:fuselage_interference_factor,0,unitless -aircraft:vertical_tail:area,284.0,ft**2 -aircraft:vertical_tail:aspect_ratio,1.75,unitless -aircraft:vertical_tail:average_chord,16.832,ft -aircraft:vertical_tail:form_factor,1.25,unitless -aircraft:vertical_tail:mass_coefficient,0.289,unitless -aircraft:vertical_tail:mass_scaler,1.0,unitless -aircraft:vertical_tail:moment_ratio,2.362,unitless -aircraft:vertical_tail:num_tails,1,unitless -aircraft:vertical_tail:span,27.996,ft -aircraft:vertical_tail:sweep,35,deg -aircraft:vertical_tail:taper_ratio,0.33,unitless -aircraft:vertical_tail:thickness_to_chord,0.1195,unitless -aircraft:vertical_tail:volume_coefficient,0.145,unitless -aircraft:vertical_tail:wetted_area_scaler,1.0,unitless -aircraft:vertical_tail:wetted_area,581.13,ft**2 -aircraft:wing:aeroelastic_tailoring_factor,0.0,unitless -aircraft:wing:airfoil_technology,1.92669766647637,unitless -aircraft:wing:area,1370.0,ft**2 -aircraft:wing:aspect_ratio,10.13,unitless -aircraft:wing:average_chord,12.615,ft -aircraft:wing:bending_mass_scaler,1.0,unitless -aircraft:wing:center_distance,0.463,unitless -aircraft:wing:choose_fold_location,True,unitless -aircraft:wing:chord_per_semispan,0.31,0.23,0.084,unitless -aircraft:wing:composite_fraction,0.2,unitless -aircraft:wing:control_surface_area,137,ft**2 -aircraft:wing:control_surface_area_ratio,0.1,unitless -aircraft:wing:flap_chord_ratio,0.3,unitless -aircraft:wing:flap_deflection_landing,40,deg -aircraft:wing:flap_deflection_takeoff,10,deg -aircraft:wing:flap_type,double_slotted,unitless -aircraft:wing:fold_dimensional_location_specified,False,unitless -aircraft:wing:form_factor,1.25,unitless -aircraft:wing:fuselage_interference_factor,1.1,unitless -aircraft:wing:glove_and_bat,134.0,ft**2 -aircraft:wing:has_fold,False,unitless -aircraft:wing:has_strut,False,unitless -aircraft:wing:height,8,ft -aircraft:wing:high_lift_mass_coefficient,1.9,unitless -aircraft:wing:incidence,0,deg -aircraft:wing:input_station_dist,0.,0.2759,0.9367,unitless -aircraft:wing:load_distribution_control,2.0,unitless -aircraft:wing:load_fraction,1.0,unitless -aircraft:wing:load_path_sweep_dist,0.,22.,deg -aircraft:wing:loading_above_20,True,unitless -aircraft:wing:loading,128.0,lbf/ft**2 -aircraft:wing:mass_coefficient,102.5,unitless -aircraft:wing:mass_scaler,1.0,unitless -aircraft:wing:max_camber_at_70_semispan,0.0,unitless -aircraft:wing:max_thickness_location,0.4,unitless -aircraft:wing:min_pressure_location,0.3,unitless -aircraft:wing:misc_mass_scaler,1.0,unitless -aircraft:wing:mounting_type,0,unitless -aircraft:wing:num_integration_stations,50,unitless -aircraft:wing:shear_control_mass_scaler,1.0,unitless -aircraft:wing:span_efficiency_reduction,False,unitless -aircraft:wing:span,117.83,ft -aircraft:wing:strut_bracing_factor,0.0,unitless -aircraft:wing:surface_ctrl_mass_coefficient,0.95,unitless -aircraft:wing:surface_ctrl_mass_scaler,1.0,unitless -aircraft:wing:sweep,25.0,deg -aircraft:wing:taper_ratio,0.33,unitless -aircraft:wing:thickness_to_chord_dist,0.145,0.115,0.104,unitless -aircraft:wing:thickness_to_chord_root,0.15,unitless -aircraft:wing:thickness_to_chord_tip,0.12,unitless -aircraft:wing:thickness_to_chord_unweighted,0.1397,unitless -aircraft:wing:thickness_to_chord,0.13,unitless -aircraft:wing:ultimate_load_factor,3.91650835,unitless -aircraft:wing:var_sweep_mass_penalty,0.0,unitless -aircraft:wing:wetted_area_scaler,1.0,unitless -aircraft:wing:wetted_area,2396.56,ft**2 -aircraft:wing:zero_lift_angle,-1.2,deg -mission:constraints:max_mach,0.785,unitless -mission:design:cruise_altitude,25000,ft -mission:design:gross_mass,175400.0,lbm -mission:design:lift_coefficient_max_flaps_up,1.2596,unitless -mission:design:range,3500,NM -mission:design:thrust_takeoff_per_eng,28928.1,lbf -mission:landing:airport_altitude,0,ft -mission:landing:drag_coefficient_flap_increment,0.0406,unitless -mission:landing:lift_coefficient_flap_increment,1.0293,unitless -mission:landing:lift_coefficient_max,2.8155,unitless -mission:summary:cruise_mach,0.785,unitless -mission:summary:fuel_flow_scaler,1.0,unitless -mission:summary:gross_mass,175400,lbm -mission:takeoff:airport_altitude,0,ft -mission:takeoff:drag_coefficient_flap_increment,0.0085,unitless -mission:takeoff:fuel_simple,577,lbm -mission:takeoff:lift_coefficient_flap_increment,0.4182,unitless -mission:takeoff:lift_coefficient_max,3.0,unitless -mission:takeoff:lift_over_drag,17.354,unitless -mission:takeoff:rolling_friction_coefficient,0.0175,unitless -settings:equations_of_motion,height_energy -settings:mass_method,GASP \ No newline at end of file diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index 68eed3e2b..7fff9058e 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -274,18 +274,18 @@ def bench_test_swap_4_FwFm(self): "num_segments": 6, "order": 3, "solve_for_distance": False, - "initial_mach": (0.2, "unitless"), + "initial_mach": (0.3, "unitless"), "final_mach": (0.79, "unitless"), "mach_bounds": ((0.1, 0.8), "unitless"), "initial_altitude": (35., "ft"), "final_altitude": (35000.0, "ft"), - "altitude_bounds": ((0.0, 36000.0), "ft"), + "altitude_bounds": ((0.0, 35000.0), "ft"), "throttle_enforcement": "path_constraint", "constrain_final": False, "fix_duration": False, - "initial_bounds": ((0.0, 0.0), "min"), + "initial_bounds": ((0.0, 2.0), "min"), "duration_bounds": ((5.0, 50.0), "min"), - "no_descent": True, + "no_descent": False, "add_initial_mass_constraint": False, }, "initial_guesses": {"times": ([0, 40.0], "min")}, @@ -302,7 +302,7 @@ def bench_test_swap_4_FwFm(self): "solve_for_distance": False, "initial_mach": (0.79, "unitless"), "final_mach": (0.79, "unitless"), - "mach_bounds": ((0.78, 0.8), "unitless"), + "mach_bounds": ((0.79, 0.79), "unitless"), "initial_altitude": (35000.0, "ft"), "final_altitude": (35000.0, "ft"), "altitude_bounds": ((35000.0, 35000.0), "ft"), @@ -311,7 +311,7 @@ def bench_test_swap_4_FwFm(self): "constrain_final": False, "fix_duration": False, "initial_bounds": ((64.0, 192.0), "min"), - "duration_bounds": ((60.0, 7200.0), "min"), + "duration_bounds": ((60.0, 720.0), "min"), }, "initial_guesses": {"times": ([128, 113], "min")}, }, @@ -328,27 +328,27 @@ def bench_test_swap_4_FwFm(self): "final_mach": (0.3, "unitless"), "mach_bounds": ((0.2, 0.8), "unitless"), "initial_altitude": (35000.0, "ft"), - "final_altitude": (500.0, "ft"), + "final_altitude": (35.0, "ft"), "altitude_bounds": ((0.0, 35000.0), "ft"), "throttle_enforcement": "path_constraint", "fix_initial": False, "constrain_final": True, "fix_duration": False, - "initial_bounds": ((120.5, 361.5), "min"), - "duration_bounds": ((5.0, 60.0), "min"), - "no_climb": False + "initial_bounds": ((120., 800.), "min"), + "duration_bounds": ((5.0, 35.0), "min"), + "no_climb": True, }, - "initial_guesses": {"times": ([241, 58], "min")}, + "initial_guesses": {"times": ([241, 30], "min")}, }, "post_mission": { "include_landing": True, "constrain_range": True, - "target_range": (3350.0, "nmi"), + "target_range": (3368.0, "nmi"), }, } prob = run_aviary( - 'models/test_aircraft/aircraft_for_bench_FwFm_simple.csv', phase_info, max_iter=100) + 'models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info, max_iter=50) compare_against_expected_values(prob, self.expected_dict) diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py index 41eb97514..4d173b597 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py @@ -341,10 +341,10 @@ def bench_test_swap_1_GwFm(self): "constrain_final": True, "fix_duration": False, "initial_bounds": ((120.5, 361.5), "min"), - "duration_bounds": ((5.0, 60.0), "min"), - "no_climb": False + "duration_bounds": ((5.0, 30.0), "min"), + "no_climb": True, }, - "initial_guesses": {"times": ([241, 58], "min")}, + "initial_guesses": {"times": ([241, 30], "min")}, }, "post_mission": { "include_landing": True, @@ -353,8 +353,8 @@ def bench_test_swap_1_GwFm(self): }, } - prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwFm_simple.csv', phase_info, - max_iter=15) + prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwFm.csv', phase_info, + max_iter=50) compare_against_expected_values(prob, self.expected_dict) @@ -362,4 +362,4 @@ def bench_test_swap_1_GwFm(self): if __name__ == '__main__': test = ProblemPhaseTestCase() test.setUp() - test.bench_test_swap_1_GwFm_simple() + test.bench_test_swap_1_GwFm() From be4f91e58507070c1131479f97337fe70fc8178f Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 18 Jan 2024 18:26:46 -0600 Subject: [PATCH 116/188] Updated tests and docs --- aviary/docs/examples/OAS_subsystem.ipynb | 2 +- .../examples/additional_flight_phases.ipynb | 2 +- ...oupled_aircraft_mission_optimization.ipynb | 2 +- .../docs/examples/more_advanced_example.ipynb | 6 +- .../examples/simple_mission_example.ipynb | 6 +- .../onboarding_ext_subsystem.ipynb | 8 +- .../getting_started/onboarding_level3.ipynb | 375 +++++++++++++++++- ..._same_mission_at_different_UI_levels.ipynb | 318 +++++++++++++-- .../OAS_weight/run_simple_OAS_mission.py | 2 +- .../external_subsystems/battery/run_cruise.py | 2 +- .../simple_weight/run_simple_weight.py | 2 +- aviary/examples/run_aviary_example.py | 2 +- aviary/examples/run_basic_aviary_example.py | 2 +- aviary/interface/test/test_simple_mission.py | 2 +- .../benchmark_tests/test_0_iters.py | 2 +- .../test_FLOPS_based_sizing_N3CC.py | 2 +- 16 files changed, 671 insertions(+), 64 deletions(-) diff --git a/aviary/docs/examples/OAS_subsystem.ipynb b/aviary/docs/examples/OAS_subsystem.ipynb index cff6691c7..af46777e2 100644 --- a/aviary/docs/examples/OAS_subsystem.ipynb +++ b/aviary/docs/examples/OAS_subsystem.ipynb @@ -329,7 +329,7 @@ "if use_OAS:\n", " phase_info['pre_mission']['external_subsystems'] = [wing_weight_builder]\n", "\n", - "aircraft_definition_file = 'models/test_aircraft/aircraft_for_bench_FwFm_simple.csv'\n", + "aircraft_definition_file = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'\n", "mission_method = 'simple'\n", "mass_method = 'FLOPS'\n", "make_plots = False\n", diff --git a/aviary/docs/examples/additional_flight_phases.ipynb b/aviary/docs/examples/additional_flight_phases.ipynb index 7a5cf85a8..ab4ebb2fd 100644 --- a/aviary/docs/examples/additional_flight_phases.ipynb +++ b/aviary/docs/examples/additional_flight_phases.ipynb @@ -223,7 +223,7 @@ "source": [ "import aviary.api as av\n", "\n", - "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv',\n", + "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',\n", " phase_info, optimizer=\"SLSQP\", make_plots=True)" ] }, diff --git a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb index b39e7217d..6f92f388f 100644 --- a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb +++ b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb @@ -148,7 +148,7 @@ "source": [ "import aviary.api as av\n", "\n", - "aircraft_filename = 'models/test_aircraft/aircraft_for_bench_FwFm_simple.csv'\n", + "aircraft_filename = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'\n", "optimizer = \"IPOPT\"\n", "make_plots = True\n", "max_iter = 200\n", diff --git a/aviary/docs/examples/more_advanced_example.ipynb b/aviary/docs/examples/more_advanced_example.ipynb index bd2875bca..865794564 100644 --- a/aviary/docs/examples/more_advanced_example.ipynb +++ b/aviary/docs/examples/more_advanced_example.ipynb @@ -125,7 +125,7 @@ "source": [ "import aviary.api as av\n", "\n", - "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv',\n", + "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',\n", " phase_info, optimizer=\"SLSQP\", make_plots=True)" ] }, @@ -188,7 +188,7 @@ "source": [ "import csv\n", "\n", - "filename = 'models/test_aircraft/aircraft_for_bench_FwFm_simple.csv'\n", + "filename = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'\n", "filename = av.get_path(filename)\n", "\n", "# Read the file\n", @@ -279,7 +279,7 @@ "phase_info['cruise']['user_options']['polynomial_control_order'] = 1\n", "phase_info['descent_1']['user_options']['polynomial_control_order'] = 3\n", "\n", - "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv',\n", + "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',\n", " phase_info, optimizer=\"IPOPT\", make_plots=True)" ] }, diff --git a/aviary/docs/examples/simple_mission_example.ipynb b/aviary/docs/examples/simple_mission_example.ipynb index 6c3f17509..71dd7a3fb 100644 --- a/aviary/docs/examples/simple_mission_example.ipynb +++ b/aviary/docs/examples/simple_mission_example.ipynb @@ -21,7 +21,7 @@ "* value: the user-defined value of the variable\n", "* units: the units of the variable\n", "\n", - "Let's take a look at the first few lines of an example aircraft file, `aircraft_for_bench_FwFm_simple.csv`.\n", + "Let's take a look at the first few lines of an example aircraft file, `aircraft_for_bench_FwFm.csv`.\n", "This aircraft is a commercial single-aisle aircraft with two conventional turbofan engines.\n", "Think of it in the same class as a Boeing 737 or Airbus A320.\n", "\n", @@ -40,7 +40,7 @@ "source": [ "import aviary.api as av\n", "\n", - "filename = 'models/test_aircraft/aircraft_for_bench_FwFm_simple.csv'\n", + "filename = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'\n", "filename = av.get_path(filename)\n", "\n", "with open(filename, 'r') as file:\n", @@ -279,7 +279,7 @@ "source": [ "import aviary.api as av\n", "\n", - "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv',\n", + "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',\n", " phase_info, optimizer=\"SLSQP\", make_plots=True)" ] }, diff --git a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb index 2b951e8af..c5a9a12b4 100644 --- a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb +++ b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb @@ -60,7 +60,7 @@ "\n", "# Load aircraft and options data from user\n", "# Allow for user overrides here\n", - "prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv', phase_info)\n", + "prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info)\n", "\n", "# Have checks for clashing user inputs\n", "# Raise warnings or errors depending on how clashing the issues are\n", @@ -119,7 +119,7 @@ "\n", "# Load aircraft and options data from user\n", "# Allow for user overrides here\n", - "prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv', av.default_height_energy_phase_info)\n", + "prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm.csv', av.default_height_energy_phase_info)\n", "\n", "# Have checks for clashing user inputs\n", "# Raise warnings or errors depending on how clashing the issues are\n", @@ -231,7 +231,7 @@ "source": [ "prob = av.AviaryProblem()\n", "\n", - "prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv', phase_info)" + "prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info)" ] }, { @@ -622,7 +622,7 @@ "metadata": {}, "outputs": [], "source": [ - "aircraft_definition_file = 'models/test_aircraft/aircraft_for_bench_FwFm_simple.csv'\n", + "aircraft_definition_file = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'\n", "make_plots = False\n", "max_iter = 0\n", "optimizer = 'SNOPT'\n", diff --git a/aviary/docs/getting_started/onboarding_level3.ipynb b/aviary/docs/getting_started/onboarding_level3.ipynb index eddbbcf53..db2c436ec 100644 --- a/aviary/docs/getting_started/onboarding_level3.ipynb +++ b/aviary/docs/getting_started/onboarding_level3.ipynb @@ -57,10 +57,370 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "42c6704a", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "The following variables have been overridden:\n", + " 'aircraft:design:landing_to_takeoff_mass_ratio\n", + " 'aircraft:engine:mass\n", + " 'aircraft:fuel:auxiliary_fuel_capacity\n", + " 'aircraft:fuel:fuselage_fuel_capacity\n", + " 'aircraft:fuselage:planform_area\n", + " 'aircraft:fuselage:wetted_area\n", + " 'aircraft:horizontal_tail:wetted_area\n", + " 'aircraft:nacelle:total_wetted_area\n", + " 'aircraft:nacelle:wetted_area\n", + " 'aircraft:propulsion:total_engine_controls_mass\n", + " 'aircraft:propulsion:total_starter_mass\n", + " 'aircraft:vertical_tail:wetted_area\n", + " 'aircraft:wing:aspect_ratio\n", + " 'aircraft:wing:wetted_area\n", + "\n", + "--- Constraint Report [traj] ---\n", + " --- climb ---\n", + " None\n", + " --- cruise ---\n", + " [path] 3.0000e+02 <= altitude_rate_max [ft/min]\n", + " --- descent ---\n", + " None\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:area', promoted using 'aircraft:canard:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:thickness_to_chord', promoted using 'aircraft:canard:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:wetted_area_scaler', promoted using 'aircraft:canard:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:area', promoted using 'aircraft:canard:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:aspect_ratio', promoted using 'aircraft:canard:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:thickness_to_chord', promoted using 'aircraft:canard:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:fuselage:avg_diameter', promoted using 'aircraft:fuselage:avg_diameter', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:fuselage:length', promoted using 'aircraft:fuselage:length', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:area', promoted using 'aircraft:horizontal_tail:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:aspect_ratio', promoted using 'aircraft:horizontal_tail:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:thickness_to_chord', promoted using 'aircraft:horizontal_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:nacelle:avg_diameter', promoted using 'aircraft:nacelle:avg_diameter', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:nacelle:avg_length', promoted using 'aircraft:nacelle:avg_length', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:area', promoted using 'aircraft:vertical_tail:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:aspect_ratio', promoted using 'aircraft:vertical_tail:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:thickness_to_chord', promoted using 'aircraft:vertical_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:aspect_ratio', promoted using 'aircraft:wing:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:glove_and_bat', promoted using 'aircraft:wing:glove_and_bat', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:taper_ratio', promoted using 'aircraft:wing:taper_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:thickness_to_chord', promoted using 'aircraft:wing:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:avg_diameter', promoted using 'aircraft:fuselage:avg_diameter', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:length', promoted using 'aircraft:fuselage:length', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:wetted_area_scaler', promoted using 'aircraft:fuselage:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:horizontal_tail:thickness_to_chord', promoted using 'aircraft:horizontal_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:horizontal_tail:vertical_tail_fraction', promoted using 'aircraft:horizontal_tail:vertical_tail_fraction', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:vertical_tail:thickness_to_chord', promoted using 'aircraft:vertical_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:aspect_ratio', promoted using 'aircraft:wing:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:glove_and_bat', promoted using 'aircraft:wing:glove_and_bat', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:thickness_to_chord', promoted using 'aircraft:wing:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:avg_diameter', promoted using 'aircraft:nacelle:avg_diameter', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:avg_length', promoted using 'aircraft:nacelle:avg_length', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:wetted_area_scaler', promoted using 'aircraft:nacelle:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:area', promoted using 'aircraft:horizontal_tail:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:vertical_tail_fraction', promoted using 'aircraft:horizontal_tail:vertical_tail_fraction', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:wetted_area_scaler', promoted using 'aircraft:horizontal_tail:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:vertical_tail:area', promoted using 'aircraft:vertical_tail:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:vertical_tail:wetted_area_scaler', promoted using 'aircraft:vertical_tail:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.wing' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.wing' : input variable 'aircraft:wing:wetted_area_scaler', promoted using 'aircraft:wing:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.climb' \n", + " Non-default solvers are required\n", + " implicit duration: False\n", + " solved segments: False\n", + " input initial: True\n", + " Setting `traj.phases.climb.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", + " Explicitly set traj.phases.climb.nonlinear_solver to override.\n", + " Setting `traj.phases.climb.linear_solver = om.DirectSolver(iprint=2)`\n", + " Explicitly set traj.phases.climb.linear_solver to override.\n", + " Set `traj.phases.climb.options[\"auto_solvers\"] = False` to disable this behavior.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model viewer data has already been recorded for Driver.\n", + "\n", + "List of user-set options:\n", + "\n", + " Name Value used\n", + " file_print_level = 5 yes\n", + " hessian_approximation = limited-memory yes\n", + " linear_solver = mumps yes\n", + " max_iter = 100 yes\n", + " nlp_scaling_method = user-scaling yes\n", + " output_file = reports/problem7/IPOPT.out yes\n", + " print_level = 4 yes\n", + " print_user_options = yes yes\n", + " sb = yes yes\n", + " tol = 0.001 yes\n", + "Total number of variables............................: 82\n", + " variables with only lower bounds: 0\n", + " variables with lower and upper bounds: 82\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 79\n", + "Total number of inequality constraints...............: 4\n", + " inequality constraints with only lower bounds: 4\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "\n", + "Number of Iterations....: 25\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 9.4146770609913695e+00 9.4146770609913695e+00\n", + "Dual infeasibility......: 1.0999629934911812e-08 1.0999629934911812e-08\n", + "Constraint violation....: 3.2276147976517677e-08 3.2276147976517677e-08\n", + "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Complementarity.........: 1.2325706634551805e-06 1.2325706634551805e-06\n", + "Overall NLP error.......: 1.2325706634551805e-06 1.2325706634551805e-06\n", + "\n", + "\n", + "Number of objective function evaluations = 28\n", + "Number of objective gradient evaluations = 26\n", + "Number of equality constraint evaluations = 28\n", + "Number of inequality constraint evaluations = 28\n", + "Number of equality constraint Jacobian evaluations = 26\n", + "Number of inequality constraint Jacobian evaluations = 26\n", + "Number of Lagrangian Hessian evaluations = 0\n", + "Total seconds in IPOPT = 13.774\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "\n", + "\n", + "Optimization Problem -- Optimization using pyOpt_sparse\n", + "================================================================================\n", + " Objective Function: _objfunc\n", + "\n", + " Solution: \n", + "--------------------------------------------------------------------------------\n", + " Total Time: 13.7775\n", + " User Objective Time : 9.9599\n", + " User Sensitivity Time : 3.6817\n", + " Interface Time : 0.0666\n", + " Opt Solver Time: 0.0694\n", + " Calls to Objective Function : 28\n", + " Calls to Sens Function : 26\n", + "\n", + "\n", + " Objectives\n", + " Index Name Value\n", + " 0 reg_objective 9.414677E+00\n", + "\n", + " Variables (c - continuous, i - integer, d - discrete)\n", + " Index Name Type Lower Bound Value Upper Bound Status\n", + " 0 mission:design:gross_mass_0 c 7.407407E-01 8.607091E-01 1.481481E+00 \n", + " 1 traj.climb.t_duration_0 c 5.000000E-01 5.000003E-01 2.000000E+00 l\n", + " 2 traj.climb.states:mass_0 c 0.000000E+00 5.241266E+00 1.000000E+17 \n", + " 3 traj.climb.states:mass_1 c 0.000000E+00 5.237291E+00 1.000000E+17 \n", + " 4 traj.climb.states:mass_2 c 0.000000E+00 5.236091E+00 1.000000E+17 \n", + " 5 traj.climb.states:mass_3 c 0.000000E+00 5.230548E+00 1.000000E+17 \n", + " 6 traj.climb.states:mass_4 c 0.000000E+00 5.223489E+00 1.000000E+17 \n", + " 7 traj.climb.states:mass_5 c 0.000000E+00 5.221338E+00 1.000000E+17 \n", + " 8 traj.climb.states:mass_6 c 0.000000E+00 5.215137E+00 1.000000E+17 \n", + " 9 traj.climb.states:mass_7 c 0.000000E+00 5.206956E+00 1.000000E+17 \n", + " 10 traj.climb.states:mass_8 c 0.000000E+00 5.204440E+00 1.000000E+17 \n", + " 11 traj.climb.states:mass_9 c 0.000000E+00 5.198692E+00 1.000000E+17 \n", + " 12 traj.climb.states:mass_10 c 0.000000E+00 5.190826E+00 1.000000E+17 \n", + " 13 traj.climb.states:mass_11 c 0.000000E+00 5.188345E+00 1.000000E+17 \n", + " 14 traj.climb.states:mass_12 c 0.000000E+00 5.183981E+00 1.000000E+17 \n", + " 15 traj.climb.states:mass_13 c 0.000000E+00 5.177987E+00 1.000000E+17 \n", + " 16 traj.climb.states:mass_14 c 0.000000E+00 5.176097E+00 1.000000E+17 \n", + " 17 traj.climb.states:mass_15 c 0.000000E+00 5.174062E+00 1.000000E+17 \n", + " 18 traj.climb.states:mass_16 c 0.000000E+00 5.171248E+00 1.000000E+17 \n", + " 19 traj.climb.states:mass_17 c 0.000000E+00 5.170354E+00 1.000000E+17 \n", + " 20 traj.climb.states:distance_0 c 0.000000E+00 2.764851E-03 1.000000E+15 \n", + " 21 traj.climb.states:distance_1 c 0.000000E+00 5.071419E-03 1.000000E+15 \n", + " 22 traj.climb.states:distance_2 c 0.000000E+00 5.851859E-03 1.000000E+15 \n", + " 23 traj.climb.states:distance_3 c 0.000000E+00 9.998326E-03 1.000000E+15 \n", + " 24 traj.climb.states:distance_4 c 0.000000E+00 1.663641E-02 1.000000E+15 \n", + " 25 traj.climb.states:distance_5 c 0.000000E+00 1.895456E-02 1.000000E+15 \n", + " 26 traj.climb.states:distance_6 c 0.000000E+00 2.644512E-02 1.000000E+15 \n", + " 27 traj.climb.states:distance_7 c 0.000000E+00 3.822814E-02 1.000000E+15 \n", + " 28 traj.climb.states:distance_8 c 0.000000E+00 4.229839E-02 1.000000E+15 \n", + " 29 traj.climb.states:distance_9 c 0.000000E+00 5.222057E-02 1.000000E+15 \n", + " 30 traj.climb.states:distance_10 c 0.000000E+00 6.724973E-02 1.000000E+15 \n", + " 31 traj.climb.states:distance_11 c 0.000000E+00 7.232091E-02 1.000000E+15 \n", + " 32 traj.climb.states:distance_12 c 0.000000E+00 8.163066E-02 1.000000E+15 \n", + " 33 traj.climb.states:distance_13 c 0.000000E+00 9.521093E-02 1.000000E+15 \n", + " 34 traj.climb.states:distance_14 c 0.000000E+00 9.968231E-02 1.000000E+15 \n", + " 35 traj.climb.states:distance_15 c 0.000000E+00 1.045838E-01 1.000000E+15 \n", + " 36 traj.climb.states:distance_16 c 0.000000E+00 1.114998E-01 1.000000E+15 \n", + " 37 traj.climb.states:distance_17 c 0.000000E+00 1.137251E-01 1.000000E+15 \n", + " 38 traj.cruise.t_initial_0 c 7.260000E+02 8.460004E+02 2.904000E+03 \n", + " 39 traj.cruise.t_duration_0 c 5.000000E-01 5.000000E-01 2.000000E+00 l\n", + " 40 traj.cruise.states:mass_0 c 0.000000E+00 5.170354E+00 1.000000E+17 \n", + " 41 traj.cruise.states:mass_1 c 0.000000E+00 5.005025E+00 1.000000E+17 \n", + " 42 traj.cruise.states:mass_2 c 0.000000E+00 4.780360E+00 1.000000E+17 \n", + " 43 traj.cruise.states:mass_3 c 0.000000E+00 4.710045E+00 1.000000E+17 \n", + " 44 traj.cruise.states:distance_0 c 0.000000E+00 1.137251E-01 1.000000E+15 \n", + " 45 traj.cruise.states:distance_1 c 0.000000E+00 1.127228E+00 1.000000E+15 \n", + " 46 traj.cruise.states:distance_2 c 0.000000E+00 2.525655E+00 1.000000E+15 \n", + " 47 traj.cruise.states:distance_3 c 0.000000E+00 2.968252E+00 1.000000E+15 \n", + " 48 traj.descent.t_initial_0 c 1.291140E+04 1.303140E+04 5.164560E+04 \n", + " 49 traj.descent.t_duration_0 c 5.000000E-01 5.000011E-01 2.000000E+00 \n", + " 50 traj.descent.states:mass_0 c 0.000000E+00 4.710045E+00 1.000000E+17 \n", + " 51 traj.descent.states:mass_1 c 0.000000E+00 4.710502E+00 1.000000E+17 \n", + " 52 traj.descent.states:mass_2 c 0.000000E+00 4.711242E+00 1.000000E+17 \n", + " 53 traj.descent.states:mass_3 c 0.000000E+00 4.711494E+00 1.000000E+17 \n", + " 54 traj.descent.states:mass_4 c 0.000000E+00 4.712779E+00 1.000000E+17 \n", + " 55 traj.descent.states:mass_5 c 0.000000E+00 4.714841E+00 1.000000E+17 \n", + " 56 traj.descent.states:mass_6 c 0.000000E+00 4.715567E+00 1.000000E+17 \n", + " 57 traj.descent.states:mass_7 c 0.000000E+00 4.717767E+00 1.000000E+17 \n", + " 58 traj.descent.states:mass_8 c 0.000000E+00 4.721139E+00 1.000000E+17 \n", + " 59 traj.descent.states:mass_9 c 0.000000E+00 4.722228E+00 1.000000E+17 \n", + " 60 traj.descent.states:mass_10 c 0.000000E+00 4.723686E+00 1.000000E+17 \n", + " 61 traj.descent.states:mass_11 c 0.000000E+00 4.725431E+00 1.000000E+17 \n", + " 62 traj.descent.states:mass_12 c 0.000000E+00 4.726157E+00 1.000000E+17 \n", + " 63 traj.descent.states:mass_13 c 0.000000E+00 4.726963E+00 1.000000E+17 \n", + " 64 traj.descent.states:mass_14 c 0.000000E+00 4.728154E+00 1.000000E+17 \n", + " 65 traj.descent.states:mass_15 c 0.000000E+00 4.728551E+00 1.000000E+17 \n", + " 66 traj.descent.states:distance_0 c 0.000000E+00 2.968252E+00 1.000000E+15 \n", + " 67 traj.descent.states:distance_1 c 0.000000E+00 2.976728E+00 1.000000E+15 \n", + " 68 traj.descent.states:distance_2 c 0.000000E+00 2.988146E+00 1.000000E+15 \n", + " 69 traj.descent.states:distance_3 c 0.000000E+00 2.991691E+00 1.000000E+15 \n", + " 70 traj.descent.states:distance_4 c 0.000000E+00 3.007825E+00 1.000000E+15 \n", + " 71 traj.descent.states:distance_5 c 0.000000E+00 3.028841E+00 1.000000E+15 \n", + " 72 traj.descent.states:distance_6 c 0.000000E+00 3.035182E+00 1.000000E+15 \n", + " 73 traj.descent.states:distance_7 c 0.000000E+00 3.051662E+00 1.000000E+15 \n", + " 74 traj.descent.states:distance_8 c 0.000000E+00 3.072458E+00 1.000000E+15 \n", + " 75 traj.descent.states:distance_9 c 0.000000E+00 3.078555E+00 1.000000E+15 \n", + " 76 traj.descent.states:distance_10 c 0.000000E+00 3.089619E+00 1.000000E+15 \n", + " 77 traj.descent.states:distance_11 c 0.000000E+00 3.103383E+00 1.000000E+15 \n", + " 78 traj.descent.states:distance_12 c 0.000000E+00 3.107367E+00 1.000000E+15 \n", + " 79 traj.descent.states:distance_13 c 0.000000E+00 3.111617E+00 1.000000E+15 \n", + " 80 traj.descent.states:distance_14 c 0.000000E+00 3.117100E+00 1.000000E+15 \n", + " 81 traj.descent.states:distance_15 c 0.000000E+00 3.118742E+00 1.000000E+15 \n", + "\n", + " Constraints (i - inequality, e - equality)\n", + " Index Name Type Lower Value Upper Status Lagrange Multiplier (N/A)\n", + " 0 mass_resid e 0.000000E+00 -3.227615E-08 0.000000E+00 9.00000E+100\n", + " 1 traj.linkages.climb:time_final|cruise:time_initial e 0.000000E+00 1.136868E-13 0.000000E+00 9.00000E+100\n", + " 2 traj.linkages.climb:mass_final|cruise:mass_initial e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", + " 3 traj.linkages.climb:distance_final|cruise:distance_initial e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", + " 4 traj.linkages.cruise:time_final|descent:time_initial e 0.000000E+00 -1.818989E-12 0.000000E+00 9.00000E+100\n", + " 5 traj.linkages.cruise:mass_final|descent:mass_initial e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", + " 6 traj.linkages.cruise:distance_final|descent:distance_initial e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", + " 7 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.025097E-14 0.000000E+00 9.00000E+100\n", + " 8 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.860766E-14 0.000000E+00 9.00000E+100\n", + " 9 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.699134E-14 0.000000E+00 9.00000E+100\n", + " 10 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 3.485284E-14 0.000000E+00 9.00000E+100\n", + " 11 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 3.003003E-14 0.000000E+00 9.00000E+100\n", + " 12 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.531926E-14 0.000000E+00 9.00000E+100\n", + " 13 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 3.113611E-14 0.000000E+00 9.00000E+100\n", + " 14 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.886567E-14 0.000000E+00 9.00000E+100\n", + " 15 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.598810E-14 0.000000E+00 9.00000E+100\n", + " 16 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.408043E-14 0.000000E+00 9.00000E+100\n", + " 17 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.173824E-14 0.000000E+00 9.00000E+100\n", + " 18 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.099713E-14 0.000000E+00 9.00000E+100\n", + " 19 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.608025E-14 0.000000E+00 9.00000E+100\n", + " 20 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.587637E-14 0.000000E+00 9.00000E+100\n", + " 21 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.558807E-14 0.000000E+00 9.00000E+100\n", + " 22 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 7.279583E-15 0.000000E+00 9.00000E+100\n", + " 23 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 7.206002E-15 0.000000E+00 9.00000E+100\n", + " 24 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 7.240740E-15 0.000000E+00 9.00000E+100\n", + " 25 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.162790E-14 0.000000E+00 9.00000E+100\n", + " 26 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.105201E-14 0.000000E+00 9.00000E+100\n", + " 27 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.002517E-14 0.000000E+00 9.00000E+100\n", + " 28 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 2.058287E-14 0.000000E+00 9.00000E+100\n", + " 29 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.782458E-14 0.000000E+00 9.00000E+100\n", + " 30 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.511325E-14 0.000000E+00 9.00000E+100\n", + " 31 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.872588E-14 0.000000E+00 9.00000E+100\n", + " 32 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.655588E-14 0.000000E+00 9.00000E+100\n", + " 33 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.434107E-14 0.000000E+00 9.00000E+100\n", + " 34 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.377297E-14 0.000000E+00 9.00000E+100\n", + " 35 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.265000E-14 0.000000E+00 9.00000E+100\n", + " 36 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.141126E-14 0.000000E+00 9.00000E+100\n", + " 37 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 8.538640E-15 0.000000E+00 9.00000E+100\n", + " 38 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 8.126975E-15 0.000000E+00 9.00000E+100\n", + " 39 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 7.635711E-15 0.000000E+00 9.00000E+100\n", + " 40 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 3.521029E-15 0.000000E+00 9.00000E+100\n", + " 41 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 3.453567E-15 0.000000E+00 9.00000E+100\n", + " 42 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 3.366714E-15 0.000000E+00 9.00000E+100\n", + " 43 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 5.312109E-13 0.000000E+00 9.00000E+100\n", + " 44 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 4.063769E-13 0.000000E+00 9.00000E+100\n", + " 45 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 2.575362E-13 0.000000E+00 9.00000E+100\n", + " 46 traj.cruise.collocation_constraint.defects:distance e 0.000000E+00 -6.926598E-18 0.000000E+00 9.00000E+100\n", + " 47 traj.cruise.collocation_constraint.defects:distance e 0.000000E+00 3.463299E-18 0.000000E+00 9.00000E+100\n", + " 48 traj.cruise.collocation_constraint.defects:distance e 0.000000E+00 -6.926598E-18 0.000000E+00 9.00000E+100\n", + " 49 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.910022E-14 0.000000E+00 9.00000E+100\n", + " 50 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.529124E-14 0.000000E+00 9.00000E+100\n", + " 51 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.342543E-14 0.000000E+00 9.00000E+100\n", + " 52 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 6.585307E-14 0.000000E+00 9.00000E+100\n", + " 53 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 5.552915E-14 0.000000E+00 9.00000E+100\n", + " 54 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 4.341976E-14 0.000000E+00 9.00000E+100\n", + " 55 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 4.791654E-14 0.000000E+00 9.00000E+100\n", + " 56 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.929329E-14 0.000000E+00 9.00000E+100\n", + " 57 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.075605E-14 0.000000E+00 9.00000E+100\n", + " 58 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 2.145444E-14 0.000000E+00 9.00000E+100\n", + " 59 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 1.435837E-14 0.000000E+00 9.00000E+100\n", + " 60 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 9.991150E-15 0.000000E+00 9.00000E+100\n", + " 61 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 5.078937E-15 0.000000E+00 9.00000E+100\n", + " 62 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 5.142482E-15 0.000000E+00 9.00000E+100\n", + " 63 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 4.257099E-15 0.000000E+00 9.00000E+100\n", + " 64 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 6.438287E-14 0.000000E+00 9.00000E+100\n", + " 65 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 6.567239E-14 0.000000E+00 9.00000E+100\n", + " 66 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 6.757017E-14 0.000000E+00 9.00000E+100\n", + " 67 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 1.393325E-13 0.000000E+00 9.00000E+100\n", + " 68 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 1.459218E-13 0.000000E+00 9.00000E+100\n", + " 69 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 1.566014E-13 0.000000E+00 9.00000E+100\n", + " 70 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 1.907169E-13 0.000000E+00 9.00000E+100\n", + " 71 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 2.047396E-13 0.000000E+00 9.00000E+100\n", + " 72 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 2.289513E-13 0.000000E+00 9.00000E+100\n", + " 73 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 2.003578E-13 0.000000E+00 9.00000E+100\n", + " 74 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 2.175539E-13 0.000000E+00 9.00000E+100\n", + " 75 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 2.479632E-13 0.000000E+00 9.00000E+100\n", + " 76 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 1.271784E-13 0.000000E+00 9.00000E+100\n", + " 77 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 1.344334E-13 0.000000E+00 9.00000E+100\n", + " 78 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 1.461002E-13 0.000000E+00 9.00000E+100\n", + " 79 traj.phases.cruise->path_constraint->altitude_rate_max i 3.000000E+02 7.127272E+02 1.000000E+30 9.00000E+100\n", + " 80 traj.phases.cruise->path_constraint->altitude_rate_max i 3.000000E+02 7.752630E+02 1.000000E+30 9.00000E+100\n", + " 81 traj.phases.cruise->path_constraint->altitude_rate_max i 3.000000E+02 8.643321E+02 1.000000E+30 9.00000E+100\n", + " 82 traj.phases.cruise->path_constraint->altitude_rate_max i 3.000000E+02 8.932716E+02 1.000000E+30 9.00000E+100\n", + "\n", + "\n", + " Exit Status\n", + " Inform Description\n", + " 0 Solve Succeeded\n", + "--------------------------------------------------------------------------------\n", + "\n", + "-------------------------------\n", + "times_climb: [846.00038137] (s)\n", + "altitudes_climb: [10668.] (m)\n", + "masses_climb: [51703.54384226] (kg)\n", + "ranges_climb: [113725.11889636] (m)\n", + "velocities_climb: [234.25795132] (m/s)\n", + "thrusts_climb: [71713.80312354] (N)\n", + "times_cruise: [13031.40073487] (s)\n", + "altitudes_cruise: [10668.] (m)\n", + "masses_cruise: [47100.44512976] (kg)\n", + "ranges_cruise: [2968252.0417268] (m)\n", + "velocities_cruise: [234.25795132] (m/s)\n", + "thrusts_cruise: [26338.70498784] (N)\n", + "times_descent: [13908.60273889] (s)\n", + "altitudes_descent: [10.668] (m)\n", + "masses_descent: [47285.51458051] (kg)\n", + "ranges_descent: [3118741.8185247] (m)\n", + "velocities_descent: [102.07377559] (m/s)\n", + "thrusts_descent: [-43173.10618655] (N)\n", + "-------------------------------\n" + ] + } + ], "source": [ "'''\n", "NOTES:\n", @@ -301,8 +661,7 @@ "# link phases #\n", "##########################################\n", "\n", - "traj.link_phases([\"climb\", \"cruise\", \"descent\"], [\"time\", Dynamic.Mission.ALTITUDE,\n", - " Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple)\n", + "traj.link_phases([\"climb\", \"cruise\", \"descent\"], [\"time\", av.Dynamic.Mission.MASS, av.Dynamic.Mission.DISTANCE], connected=strong_couple)\n", "\n", "traj = av.setup_trajectory_params(prob.model, traj, aviary_inputs)\n", "\n", @@ -420,7 +779,7 @@ "prob.set_val('traj.climb.states:mass', climb.interp(\n", " av.Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", "prob.set_val('traj.climb.states:distance', climb.interp(\n", - " av.Dynamic.Mission.DISTANCE, ys=[distance_i_climb, distance_f_climb]), units='m')\n", + " av.Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_f_climb]), units='m')\n", "\n", "prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s')\n", "prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s')\n", @@ -433,7 +792,7 @@ "prob.set_val('traj.cruise.states:mass', cruise.interp(\n", " av.Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", "prob.set_val('traj.cruise.states:distance', cruise.interp(\n", - " av.Dynamic.Mission.DISTANCe, ys=[distance_i_cruise, distance_f_cruise]), units='m')\n", + " av.Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_f_cruise]), units='m')\n", "\n", "prob.set_val('traj.descent.t_initial', t_i_descent, units='s')\n", "prob.set_val('traj.descent.t_duration', t_duration_descent, units='s')\n", @@ -446,7 +805,7 @@ "prob.set_val('traj.descent.states:mass', descent.interp(\n", " av.Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", "prob.set_val('traj.descent.states:distance', descent.interp(\n", - " av.Dynamic.Mission.DISTANCe, ys=[distance_i_descent, distance_f_descent]), units='m')\n", + " av.Dynamic.Mission.DISTANCE, ys=[distance_i_descent, distance_f_descent]), units='m')\n", "\n", "# Turn off solver printing so that the SNOPT output is readable.\n", "prob.set_solver_print(level=0)\n", @@ -521,7 +880,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "52550a27", "metadata": {}, "outputs": [], 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 4ee71a14f..5baca4d89 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 @@ -25,9 +25,88 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/subsystems/propulsion/engine_deck.py:198: UserWarning: is a required option for EngineDecks, but has not been specified for EngineDeck . The default value will be used.\n", + " warnings.warn(\n", + "/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "The following variables have been overridden:\n", + " 'aircraft:design:touchdown_mass\n", + " 'aircraft:engine:mass\n", + " 'aircraft:fins:mass\n", + " 'aircraft:fuel:auxiliary_fuel_capacity\n", + " 'aircraft:fuel:fuselage_fuel_capacity\n", + " 'aircraft:fuel:total_capacity\n", + " 'aircraft:fuselage:planform_area\n", + " 'aircraft:fuselage:wetted_area\n", + " 'aircraft:horizontal_tail:wetted_area\n", + " 'aircraft:landing_gear:main_gear_oleo_length\n", + " 'aircraft:landing_gear:nose_gear_oleo_length\n", + " 'aircraft:vertical_tail:wetted_area\n", + " 'aircraft:wing:aspect_ratio\n", + " 'aircraft:wing:control_surface_area\n", + " 'aircraft:wing:wetted_area\n", + "\n", + "--- Constraint Report [traj] ---\n", + " --- climb ---\n", + " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- cruise ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- descent ---\n", + " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, dymos_solution.db, is being overwritten.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model viewer data has already been recorded for Driver.\n", + "Full total jacobian was computed 3 times, taking 0.589048 seconds.\n", + "Total jacobian shape: (135, 94) \n", + "\n", + "\n", + "Jacobian shape: (135, 94) (13.71% nonzero)\n", + "FWD solves: 22 REV solves: 0\n", + "Total colors vs. total size: 22 vs 94 (76.60% improvement)\n", + "\n", + "Sparsity computed using tolerance: 1e-25\n", + "Time to compute sparsity: 0.5890 sec\n", + "Time to compute coloring: 0.0720 sec\n", + "Memory to compute coloring: 0.1992 MB\n", + "Coloring created on: 2024-01-18 18:19:34\n", + "Iteration limit reached (Exit mode 9)\n", + " Current function value: 0.0\n", + " Iterations: 1\n", + " Function evaluations: 1\n", + " Gradient evaluations: 1\n", + "Optimization FAILED.\n", + "Iteration limit reached\n", + "-----------------------------------\n" + ] + } + ], "source": [ "import aviary.api as av\n", "\n", @@ -50,9 +129,96 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "The following variables have been overridden:\n", + " 'aircraft:design:touchdown_mass\n", + " 'aircraft:engine:mass\n", + " 'aircraft:fins:mass\n", + " 'aircraft:fuel:auxiliary_fuel_capacity\n", + " 'aircraft:fuel:fuselage_fuel_capacity\n", + " 'aircraft:fuel:total_capacity\n", + " 'aircraft:fuselage:planform_area\n", + " 'aircraft:fuselage:wetted_area\n", + " 'aircraft:horizontal_tail:wetted_area\n", + " 'aircraft:landing_gear:main_gear_oleo_length\n", + " 'aircraft:landing_gear:nose_gear_oleo_length\n", + " 'aircraft:vertical_tail:wetted_area\n", + " 'aircraft:wing:aspect_ratio\n", + " 'aircraft:wing:control_surface_area\n", + " 'aircraft:wing:wetted_area\n", + "\n", + "--- Constraint Report [traj] ---\n", + " --- climb ---\n", + " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- cruise ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- descent ---\n", + " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, level2_example.db, is being overwritten.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model viewer data has already been recorded for Driver.\n", + "Full total jacobian was computed 3 times, taking 0.528602 seconds.\n", + "Total jacobian shape: (135, 94) \n", + "\n", + "\n", + "Jacobian shape: (135, 94) (13.52% nonzero)\n", + "FWD solves: 21 REV solves: 0\n", + "Total colors vs. total size: 21 vs 94 (77.66% improvement)\n", + "\n", + "Sparsity computed using tolerance: 1e-25\n", + "Time to compute sparsity: 0.5286 sec\n", + "Time to compute coloring: 0.0755 sec\n", + "Memory to compute coloring: 0.0000 MB\n", + "Coloring created on: 2024-01-18 18:19:51\n", + "Iteration limit reached (Exit mode 9)\n", + " Current function value: -0.7956010169800001\n", + " Iterations: 1\n", + " Function evaluations: 1\n", + " Gradient evaluations: 1\n", + "Optimization FAILED.\n", + "Iteration limit reached\n", + "-----------------------------------\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "import aviary.api as av\n", "\n", @@ -183,9 +349,110 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", + " warnings.warn(\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'mach' in phase 'climb': lower, upper, ref\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'climb': lower, upper, ref\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'mach' in phase 'descent': lower, upper, ref\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'descent': lower, upper, ref\n", + " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:area', promoted using 'aircraft:canard:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:thickness_to_chord', promoted using 'aircraft:canard:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:wetted_area_scaler', promoted using 'aircraft:canard:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:area', promoted using 'aircraft:canard:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:aspect_ratio', promoted using 'aircraft:canard:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:thickness_to_chord', promoted using 'aircraft:canard:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:fuselage:avg_diameter', promoted using 'aircraft:fuselage:avg_diameter', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:fuselage:length', promoted using 'aircraft:fuselage:length', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:area', promoted using 'aircraft:horizontal_tail:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:aspect_ratio', promoted using 'aircraft:horizontal_tail:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:thickness_to_chord', promoted using 'aircraft:horizontal_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:nacelle:avg_diameter', promoted using 'aircraft:nacelle:avg_diameter', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:nacelle:avg_length', promoted using 'aircraft:nacelle:avg_length', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:area', promoted using 'aircraft:vertical_tail:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:aspect_ratio', promoted using 'aircraft:vertical_tail:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:thickness_to_chord', promoted using 'aircraft:vertical_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:aspect_ratio', promoted using 'aircraft:wing:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:glove_and_bat', promoted using 'aircraft:wing:glove_and_bat', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:taper_ratio', promoted using 'aircraft:wing:taper_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:thickness_to_chord', promoted using 'aircraft:wing:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:avg_diameter', promoted using 'aircraft:fuselage:avg_diameter', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:length', promoted using 'aircraft:fuselage:length', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:wetted_area_scaler', promoted using 'aircraft:fuselage:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:horizontal_tail:thickness_to_chord', promoted using 'aircraft:horizontal_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:horizontal_tail:vertical_tail_fraction', promoted using 'aircraft:horizontal_tail:vertical_tail_fraction', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:vertical_tail:thickness_to_chord', promoted using 'aircraft:vertical_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:aspect_ratio', promoted using 'aircraft:wing:aspect_ratio', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:glove_and_bat', promoted using 'aircraft:wing:glove_and_bat', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:thickness_to_chord', promoted using 'aircraft:wing:thickness_to_chord', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:avg_diameter', promoted using 'aircraft:nacelle:avg_diameter', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:avg_length', promoted using 'aircraft:nacelle:avg_length', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:wetted_area_scaler', promoted using 'aircraft:nacelle:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:area', promoted using 'aircraft:horizontal_tail:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:vertical_tail_fraction', promoted using 'aircraft:horizontal_tail:vertical_tail_fraction', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:wetted_area_scaler', promoted using 'aircraft:horizontal_tail:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:vertical_tail:area', promoted using 'aircraft:vertical_tail:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:vertical_tail:wetted_area_scaler', promoted using 'aircraft:vertical_tail:wetted_area_scaler', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.wing' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", + "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.wing' : input variable 'aircraft:wing:wetted_area_scaler', promoted using 'aircraft:wing:wetted_area_scaler', was already promoted using 'aircraft*'.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "The following variables have been overridden:\n", + " 'aircraft:design:touchdown_mass\n", + " 'aircraft:engine:mass\n", + " 'aircraft:fins:mass\n", + " 'aircraft:fuel:auxiliary_fuel_capacity\n", + " 'aircraft:fuel:fuselage_fuel_capacity\n", + " 'aircraft:fuel:total_capacity\n", + " 'aircraft:fuselage:planform_area\n", + " 'aircraft:fuselage:wetted_area\n", + " 'aircraft:horizontal_tail:wetted_area\n", + " 'aircraft:landing_gear:main_gear_oleo_length\n", + " 'aircraft:landing_gear:nose_gear_oleo_length\n", + " 'aircraft:vertical_tail:wetted_area\n", + " 'aircraft:wing:aspect_ratio\n", + " 'aircraft:wing:control_surface_area\n", + " 'aircraft:wing:wetted_area\n", + "\n", + "--- Constraint Report [traj] ---\n", + " --- climb ---\n", + " None\n", + " --- cruise ---\n", + " [path] 3.0000e+02 <= altitude_rate_max [ft/min]\n", + " --- descent ---\n", + " None\n", + "\n" + ] + }, + { + "ename": "AttributeError", + "evalue": "type object 'Mission' has no attribute 'RANGE'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[6], line 237\u001b[0m\n\u001b[1;32m 231\u001b[0m prob\u001b[38;5;241m.\u001b[39mset_val(\n\u001b[1;32m 232\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtraj.climb.controls:mach\u001b[39m\u001b[38;5;124m'\u001b[39m, climb\u001b[38;5;241m.\u001b[39minterp(\n\u001b[1;32m 233\u001b[0m av\u001b[38;5;241m.\u001b[39mDynamic\u001b[38;5;241m.\u001b[39mMission\u001b[38;5;241m.\u001b[39mMACH, ys\u001b[38;5;241m=\u001b[39m[mach_i_climb, mach_f_climb]), units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124munitless\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 234\u001b[0m prob\u001b[38;5;241m.\u001b[39mset_val(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtraj.climb.states:mass\u001b[39m\u001b[38;5;124m'\u001b[39m, climb\u001b[38;5;241m.\u001b[39minterp(\n\u001b[1;32m 235\u001b[0m av\u001b[38;5;241m.\u001b[39mDynamic\u001b[38;5;241m.\u001b[39mMission\u001b[38;5;241m.\u001b[39mMASS, ys\u001b[38;5;241m=\u001b[39m[mass_i_climb, mass_f_climb]), units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mkg\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 236\u001b[0m prob\u001b[38;5;241m.\u001b[39mset_val(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtraj.climb.states:distance\u001b[39m\u001b[38;5;124m'\u001b[39m, climb\u001b[38;5;241m.\u001b[39minterp(\n\u001b[0;32m--> 237\u001b[0m \u001b[43mav\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mDynamic\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mMission\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mRANGE\u001b[49m, ys\u001b[38;5;241m=\u001b[39m[distance_i_climb, distance_f_climb]), units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mm\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 239\u001b[0m prob\u001b[38;5;241m.\u001b[39mset_val(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtraj.cruise.t_initial\u001b[39m\u001b[38;5;124m'\u001b[39m, t_i_cruise, units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124ms\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 240\u001b[0m prob\u001b[38;5;241m.\u001b[39mset_val(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtraj.cruise.t_duration\u001b[39m\u001b[38;5;124m'\u001b[39m, t_duration_cruise, units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124ms\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "\u001b[0;31mAttributeError\u001b[0m: type object 'Mission' has no attribute 'RANGE'" + ] + } + ], "source": [ "import dymos as dm\n", "import openmdao.api as om\n", @@ -390,32 +657,6 @@ "prob.model.connect(\"traj.descent.states:mass\",\n", " \"fuel_burn.descent_mass_final\", src_indices=[-1])\n", "\n", - "# TODO: need to add some sort of check that this value is less than the fuel capacity\n", - "# TODO: need to update this with actual FLOPS value, this gives unrealistic\n", - "# TODO: the overall_fuel variable is the burned fuel plus the reserve, but should\n", - "# also include the unused fuel, and the hierarchy variable name should be more clear\n", - "ecomp = om.ExecComp('overall_fuel = fuel_burned + fuel_reserve',\n", - "\n", - "ecomp = om.ExecComp(\n", - " 'mass_resid = operating_empty_mass + overall_fuel + payload_mass '\n", - " '- initial_mass',\n", - " operating_empty_mass={'units': 'lbm'},\n", - " overall_fuel={'units': 'lbm'},\n", - " payload_mass={'units': 'lbm'},\n", - " initial_mass={'units': 'lbm'},\n", - " mass_resid={'units': 'lbm'})\n", - "\n", - "prob.model.add_subsystem(\n", - " 'mass_constraint', ecomp,\n", - " promotes_inputs=[\n", - " ('operating_empty_mass', av.Aircraft.Design.OPERATING_MASS),\n", - " 'overall_fuel',\n", - " ('payload_mass', av.Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS),\n", - " ('initial_mass', av.Mission.Design.GROSS_MASS)],\n", - " promotes_outputs=['mass_resid'])\n", - "\n", - "prob.model.add_constraint('mass_resid', equals=0.0, ref=1.0)\n", - "\n", "##########################\n", "# Add Objective Function #\n", "##########################\n", @@ -449,7 +690,7 @@ "prob.set_val('traj.climb.states:mass', climb.interp(\n", " av.Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')\n", "prob.set_val('traj.climb.states:distance', climb.interp(\n", - " av.Dynamic.Mission.RANGE, ys=[distance_i_climb, distance_f_climb]), units='m')\n", + " av.Dynamic.Mission.DISTANCE, ys=[distance_i_climb, distance_f_climb]), units='m')\n", "\n", "prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s')\n", "prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s')\n", @@ -462,7 +703,7 @@ "prob.set_val('traj.cruise.states:mass', cruise.interp(\n", " av.Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')\n", "prob.set_val('traj.cruise.states:distance', cruise.interp(\n", - " av.Dynamic.Mission.RANGE, ys=[distance_i_cruise, distance_f_cruise]), units='m')\n", + " av.Dynamic.Mission.DISTANCE, ys=[distance_i_cruise, distance_f_cruise]), units='m')\n", "\n", "prob.set_val('traj.descent.t_initial', t_i_descent, units='s')\n", "prob.set_val('traj.descent.t_duration', t_duration_descent, units='s')\n", @@ -475,7 +716,7 @@ "prob.set_val('traj.descent.states:mass', descent.interp(\n", " av.Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')\n", "prob.set_val('traj.descent.states:distance', descent.interp(\n", - " av.Dynamic.Mission.RANGE, ys=[distance_i_descent, distance_f_descent]), units='m')\n", + " av.Dynamic.Mission.DISTANCE, ys=[distance_i_descent, distance_f_descent]), units='m')\n", "\n", "# Turn off solver printing so that the SNOPT output is readable.\n", "prob.set_solver_print(level=0)\n", @@ -483,6 +724,13 @@ "dm.run_problem(prob, simulate=False, make_plots=False, simulate_kwargs={\n", " 'times_per_seg': 100, 'atol': 1e-9, 'rtol': 1e-9})" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py b/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py index 156676327..34bd5d8a6 100644 --- a/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py +++ b/aviary/examples/external_subsystems/OAS_weight/run_simple_OAS_mission.py @@ -108,7 +108,7 @@ if use_OAS: phase_info['pre_mission']['external_subsystems'] = [wing_weight_builder] -aircraft_definition_file = 'models/test_aircraft/aircraft_for_bench_FwFm_simple.csv' +aircraft_definition_file = 'models/test_aircraft/aircraft_for_bench_FwFm.csv' make_plots = False max_iter = 1 # set this to a higher number to fully run the optimization optimizer = 'SLSQP' diff --git a/aviary/examples/external_subsystems/battery/run_cruise.py b/aviary/examples/external_subsystems/battery/run_cruise.py index 44882c487..a0463c89d 100644 --- a/aviary/examples/external_subsystems/battery/run_cruise.py +++ b/aviary/examples/external_subsystems/battery/run_cruise.py @@ -16,7 +16,7 @@ # Load aircraft and options data from user # Allow for user overrides here -prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv', phase_info) +prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info) prob.add_pre_mission_systems() diff --git a/aviary/examples/external_subsystems/simple_weight/run_simple_weight.py b/aviary/examples/external_subsystems/simple_weight/run_simple_weight.py index f3f2f7d0d..f5b7769e2 100644 --- a/aviary/examples/external_subsystems/simple_weight/run_simple_weight.py +++ b/aviary/examples/external_subsystems/simple_weight/run_simple_weight.py @@ -16,7 +16,7 @@ # Load aircraft and options data from user # Allow for user overrides here -prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv', phase_info) +prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info) prob.add_pre_mission_systems() diff --git a/aviary/examples/run_aviary_example.py b/aviary/examples/run_aviary_example.py index 875a5f456..c0ded9597 100644 --- a/aviary/examples/run_aviary_example.py +++ b/aviary/examples/run_aviary_example.py @@ -97,7 +97,7 @@ # Load aircraft and options data from user # Allow for user overrides here -prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv', phase_info) +prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info) # Preprocess inputs diff --git a/aviary/examples/run_basic_aviary_example.py b/aviary/examples/run_basic_aviary_example.py index b53dac620..a1fe4abd7 100644 --- a/aviary/examples/run_basic_aviary_example.py +++ b/aviary/examples/run_basic_aviary_example.py @@ -11,5 +11,5 @@ import aviary.api as av -prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv', av.default_height_energy_phase_info, +prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv', av.default_height_energy_phase_info, optimizer="SLSQP", make_plots=True) diff --git a/aviary/interface/test/test_simple_mission.py b/aviary/interface/test/test_simple_mission.py index d5643c06a..219206590 100644 --- a/aviary/interface/test/test_simple_mission.py +++ b/aviary/interface/test/test_simple_mission.py @@ -94,7 +94,7 @@ def setUp(self): }, } - self.aircraft_definition_file = 'models/test_aircraft/aircraft_for_bench_FwFm_simple.csv' + self.aircraft_definition_file = 'models/test_aircraft/aircraft_for_bench_FwFm.csv' self.make_plots = False self.max_iter = 100 diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index d8fe2c56e..2d58fb26e 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -47,7 +47,7 @@ class HEZeroItersTestCase(BaseProblemPhaseTestCase): @require_pyoptsparse(optimizer="IPOPT") def test_simple_zero_iters(self): local_phase_info = deepcopy(simple_phase_info) - self.build_and_run_problem('models/test_aircraft/aircraft_for_bench_FwFm_simple.csv', + self.build_and_run_problem('models/test_aircraft/aircraft_for_bench_FwFm.csv', local_phase_info) 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 95afa681a..e1b144b94 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 @@ -274,7 +274,7 @@ def run_trajectory(sim=True): promotes_outputs=['mission:*']) traj.link_phases(["climb", "cruise", "descent"], [ - "time", Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) + "time", Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) traj = setup_trajectory_params(prob.model, traj, aviary_inputs) From 2674c0c0d514930243bc15230a81495f42921d51 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 18 Jan 2024 18:27:13 -0600 Subject: [PATCH 117/188] Updated tests and docs --- aviary/docs/build_pdf_book.sh | 1 - .../getting_started/onboarding_level3.ipynb | 366 +----------------- ..._same_mission_at_different_UI_levels.ipynb | 286 +------------- 3 files changed, 9 insertions(+), 644 deletions(-) delete mode 100644 aviary/docs/build_pdf_book.sh diff --git a/aviary/docs/build_pdf_book.sh b/aviary/docs/build_pdf_book.sh deleted file mode 100644 index 846f20db7..000000000 --- a/aviary/docs/build_pdf_book.sh +++ /dev/null @@ -1 +0,0 @@ -jupyter-book build . --builder pdflatex \ No newline at end of file diff --git a/aviary/docs/getting_started/onboarding_level3.ipynb b/aviary/docs/getting_started/onboarding_level3.ipynb index db2c436ec..db5d76a26 100644 --- a/aviary/docs/getting_started/onboarding_level3.ipynb +++ b/aviary/docs/getting_started/onboarding_level3.ipynb @@ -57,370 +57,10 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "42c6704a", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "The following variables have been overridden:\n", - " 'aircraft:design:landing_to_takeoff_mass_ratio\n", - " 'aircraft:engine:mass\n", - " 'aircraft:fuel:auxiliary_fuel_capacity\n", - " 'aircraft:fuel:fuselage_fuel_capacity\n", - " 'aircraft:fuselage:planform_area\n", - " 'aircraft:fuselage:wetted_area\n", - " 'aircraft:horizontal_tail:wetted_area\n", - " 'aircraft:nacelle:total_wetted_area\n", - " 'aircraft:nacelle:wetted_area\n", - " 'aircraft:propulsion:total_engine_controls_mass\n", - " 'aircraft:propulsion:total_starter_mass\n", - " 'aircraft:vertical_tail:wetted_area\n", - " 'aircraft:wing:aspect_ratio\n", - " 'aircraft:wing:wetted_area\n", - "\n", - "--- Constraint Report [traj] ---\n", - " --- climb ---\n", - " None\n", - " --- cruise ---\n", - " [path] 3.0000e+02 <= altitude_rate_max [ft/min]\n", - " --- descent ---\n", - " None\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:area', promoted using 'aircraft:canard:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:thickness_to_chord', promoted using 'aircraft:canard:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:wetted_area_scaler', promoted using 'aircraft:canard:wetted_area_scaler', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:area', promoted using 'aircraft:canard:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:aspect_ratio', promoted using 'aircraft:canard:aspect_ratio', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:thickness_to_chord', promoted using 'aircraft:canard:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:fuselage:avg_diameter', promoted using 'aircraft:fuselage:avg_diameter', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:fuselage:length', promoted using 'aircraft:fuselage:length', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:area', promoted using 'aircraft:horizontal_tail:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:aspect_ratio', promoted using 'aircraft:horizontal_tail:aspect_ratio', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:thickness_to_chord', promoted using 'aircraft:horizontal_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:nacelle:avg_diameter', promoted using 'aircraft:nacelle:avg_diameter', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:nacelle:avg_length', promoted using 'aircraft:nacelle:avg_length', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:area', promoted using 'aircraft:vertical_tail:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:aspect_ratio', promoted using 'aircraft:vertical_tail:aspect_ratio', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:thickness_to_chord', promoted using 'aircraft:vertical_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:aspect_ratio', promoted using 'aircraft:wing:aspect_ratio', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:glove_and_bat', promoted using 'aircraft:wing:glove_and_bat', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:taper_ratio', promoted using 'aircraft:wing:taper_ratio', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:thickness_to_chord', promoted using 'aircraft:wing:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:avg_diameter', promoted using 'aircraft:fuselage:avg_diameter', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:length', promoted using 'aircraft:fuselage:length', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:wetted_area_scaler', promoted using 'aircraft:fuselage:wetted_area_scaler', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:horizontal_tail:thickness_to_chord', promoted using 'aircraft:horizontal_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:horizontal_tail:vertical_tail_fraction', promoted using 'aircraft:horizontal_tail:vertical_tail_fraction', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:vertical_tail:thickness_to_chord', promoted using 'aircraft:vertical_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:aspect_ratio', promoted using 'aircraft:wing:aspect_ratio', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:glove_and_bat', promoted using 'aircraft:wing:glove_and_bat', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:thickness_to_chord', promoted using 'aircraft:wing:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:avg_diameter', promoted using 'aircraft:nacelle:avg_diameter', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:avg_length', promoted using 'aircraft:nacelle:avg_length', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:wetted_area_scaler', promoted using 'aircraft:nacelle:wetted_area_scaler', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:area', promoted using 'aircraft:horizontal_tail:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:vertical_tail_fraction', promoted using 'aircraft:horizontal_tail:vertical_tail_fraction', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:wetted_area_scaler', promoted using 'aircraft:horizontal_tail:wetted_area_scaler', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:vertical_tail:area', promoted using 'aircraft:vertical_tail:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:vertical_tail:wetted_area_scaler', promoted using 'aircraft:vertical_tail:wetted_area_scaler', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.wing' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.wing' : input variable 'aircraft:wing:wetted_area_scaler', promoted using 'aircraft:wing:wetted_area_scaler', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/transcriptions/transcription_base.py:497: OpenMDAOWarning:'traj.phases.climb' \n", - " Non-default solvers are required\n", - " implicit duration: False\n", - " solved segments: False\n", - " input initial: True\n", - " Setting `traj.phases.climb.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`\n", - " Explicitly set traj.phases.climb.nonlinear_solver to override.\n", - " Setting `traj.phases.climb.linear_solver = om.DirectSolver(iprint=2)`\n", - " Explicitly set traj.phases.climb.linear_solver to override.\n", - " Set `traj.phases.climb.options[\"auto_solvers\"] = False` to disable this behavior.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model viewer data has already been recorded for Driver.\n", - "\n", - "List of user-set options:\n", - "\n", - " Name Value used\n", - " file_print_level = 5 yes\n", - " hessian_approximation = limited-memory yes\n", - " linear_solver = mumps yes\n", - " max_iter = 100 yes\n", - " nlp_scaling_method = user-scaling yes\n", - " output_file = reports/problem7/IPOPT.out yes\n", - " print_level = 4 yes\n", - " print_user_options = yes yes\n", - " sb = yes yes\n", - " tol = 0.001 yes\n", - "Total number of variables............................: 82\n", - " variables with only lower bounds: 0\n", - " variables with lower and upper bounds: 82\n", - " variables with only upper bounds: 0\n", - "Total number of equality constraints.................: 79\n", - "Total number of inequality constraints...............: 4\n", - " inequality constraints with only lower bounds: 4\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "\n", - "Number of Iterations....: 25\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: 9.4146770609913695e+00 9.4146770609913695e+00\n", - "Dual infeasibility......: 1.0999629934911812e-08 1.0999629934911812e-08\n", - "Constraint violation....: 3.2276147976517677e-08 3.2276147976517677e-08\n", - "Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Complementarity.........: 1.2325706634551805e-06 1.2325706634551805e-06\n", - "Overall NLP error.......: 1.2325706634551805e-06 1.2325706634551805e-06\n", - "\n", - "\n", - "Number of objective function evaluations = 28\n", - "Number of objective gradient evaluations = 26\n", - "Number of equality constraint evaluations = 28\n", - "Number of inequality constraint evaluations = 28\n", - "Number of equality constraint Jacobian evaluations = 26\n", - "Number of inequality constraint Jacobian evaluations = 26\n", - "Number of Lagrangian Hessian evaluations = 0\n", - "Total seconds in IPOPT = 13.774\n", - "\n", - "EXIT: Optimal Solution Found.\n", - "\n", - "\n", - "Optimization Problem -- Optimization using pyOpt_sparse\n", - "================================================================================\n", - " Objective Function: _objfunc\n", - "\n", - " Solution: \n", - "--------------------------------------------------------------------------------\n", - " Total Time: 13.7775\n", - " User Objective Time : 9.9599\n", - " User Sensitivity Time : 3.6817\n", - " Interface Time : 0.0666\n", - " Opt Solver Time: 0.0694\n", - " Calls to Objective Function : 28\n", - " Calls to Sens Function : 26\n", - "\n", - "\n", - " Objectives\n", - " Index Name Value\n", - " 0 reg_objective 9.414677E+00\n", - "\n", - " Variables (c - continuous, i - integer, d - discrete)\n", - " Index Name Type Lower Bound Value Upper Bound Status\n", - " 0 mission:design:gross_mass_0 c 7.407407E-01 8.607091E-01 1.481481E+00 \n", - " 1 traj.climb.t_duration_0 c 5.000000E-01 5.000003E-01 2.000000E+00 l\n", - " 2 traj.climb.states:mass_0 c 0.000000E+00 5.241266E+00 1.000000E+17 \n", - " 3 traj.climb.states:mass_1 c 0.000000E+00 5.237291E+00 1.000000E+17 \n", - " 4 traj.climb.states:mass_2 c 0.000000E+00 5.236091E+00 1.000000E+17 \n", - " 5 traj.climb.states:mass_3 c 0.000000E+00 5.230548E+00 1.000000E+17 \n", - " 6 traj.climb.states:mass_4 c 0.000000E+00 5.223489E+00 1.000000E+17 \n", - " 7 traj.climb.states:mass_5 c 0.000000E+00 5.221338E+00 1.000000E+17 \n", - " 8 traj.climb.states:mass_6 c 0.000000E+00 5.215137E+00 1.000000E+17 \n", - " 9 traj.climb.states:mass_7 c 0.000000E+00 5.206956E+00 1.000000E+17 \n", - " 10 traj.climb.states:mass_8 c 0.000000E+00 5.204440E+00 1.000000E+17 \n", - " 11 traj.climb.states:mass_9 c 0.000000E+00 5.198692E+00 1.000000E+17 \n", - " 12 traj.climb.states:mass_10 c 0.000000E+00 5.190826E+00 1.000000E+17 \n", - " 13 traj.climb.states:mass_11 c 0.000000E+00 5.188345E+00 1.000000E+17 \n", - " 14 traj.climb.states:mass_12 c 0.000000E+00 5.183981E+00 1.000000E+17 \n", - " 15 traj.climb.states:mass_13 c 0.000000E+00 5.177987E+00 1.000000E+17 \n", - " 16 traj.climb.states:mass_14 c 0.000000E+00 5.176097E+00 1.000000E+17 \n", - " 17 traj.climb.states:mass_15 c 0.000000E+00 5.174062E+00 1.000000E+17 \n", - " 18 traj.climb.states:mass_16 c 0.000000E+00 5.171248E+00 1.000000E+17 \n", - " 19 traj.climb.states:mass_17 c 0.000000E+00 5.170354E+00 1.000000E+17 \n", - " 20 traj.climb.states:distance_0 c 0.000000E+00 2.764851E-03 1.000000E+15 \n", - " 21 traj.climb.states:distance_1 c 0.000000E+00 5.071419E-03 1.000000E+15 \n", - " 22 traj.climb.states:distance_2 c 0.000000E+00 5.851859E-03 1.000000E+15 \n", - " 23 traj.climb.states:distance_3 c 0.000000E+00 9.998326E-03 1.000000E+15 \n", - " 24 traj.climb.states:distance_4 c 0.000000E+00 1.663641E-02 1.000000E+15 \n", - " 25 traj.climb.states:distance_5 c 0.000000E+00 1.895456E-02 1.000000E+15 \n", - " 26 traj.climb.states:distance_6 c 0.000000E+00 2.644512E-02 1.000000E+15 \n", - " 27 traj.climb.states:distance_7 c 0.000000E+00 3.822814E-02 1.000000E+15 \n", - " 28 traj.climb.states:distance_8 c 0.000000E+00 4.229839E-02 1.000000E+15 \n", - " 29 traj.climb.states:distance_9 c 0.000000E+00 5.222057E-02 1.000000E+15 \n", - " 30 traj.climb.states:distance_10 c 0.000000E+00 6.724973E-02 1.000000E+15 \n", - " 31 traj.climb.states:distance_11 c 0.000000E+00 7.232091E-02 1.000000E+15 \n", - " 32 traj.climb.states:distance_12 c 0.000000E+00 8.163066E-02 1.000000E+15 \n", - " 33 traj.climb.states:distance_13 c 0.000000E+00 9.521093E-02 1.000000E+15 \n", - " 34 traj.climb.states:distance_14 c 0.000000E+00 9.968231E-02 1.000000E+15 \n", - " 35 traj.climb.states:distance_15 c 0.000000E+00 1.045838E-01 1.000000E+15 \n", - " 36 traj.climb.states:distance_16 c 0.000000E+00 1.114998E-01 1.000000E+15 \n", - " 37 traj.climb.states:distance_17 c 0.000000E+00 1.137251E-01 1.000000E+15 \n", - " 38 traj.cruise.t_initial_0 c 7.260000E+02 8.460004E+02 2.904000E+03 \n", - " 39 traj.cruise.t_duration_0 c 5.000000E-01 5.000000E-01 2.000000E+00 l\n", - " 40 traj.cruise.states:mass_0 c 0.000000E+00 5.170354E+00 1.000000E+17 \n", - " 41 traj.cruise.states:mass_1 c 0.000000E+00 5.005025E+00 1.000000E+17 \n", - " 42 traj.cruise.states:mass_2 c 0.000000E+00 4.780360E+00 1.000000E+17 \n", - " 43 traj.cruise.states:mass_3 c 0.000000E+00 4.710045E+00 1.000000E+17 \n", - " 44 traj.cruise.states:distance_0 c 0.000000E+00 1.137251E-01 1.000000E+15 \n", - " 45 traj.cruise.states:distance_1 c 0.000000E+00 1.127228E+00 1.000000E+15 \n", - " 46 traj.cruise.states:distance_2 c 0.000000E+00 2.525655E+00 1.000000E+15 \n", - " 47 traj.cruise.states:distance_3 c 0.000000E+00 2.968252E+00 1.000000E+15 \n", - " 48 traj.descent.t_initial_0 c 1.291140E+04 1.303140E+04 5.164560E+04 \n", - " 49 traj.descent.t_duration_0 c 5.000000E-01 5.000011E-01 2.000000E+00 \n", - " 50 traj.descent.states:mass_0 c 0.000000E+00 4.710045E+00 1.000000E+17 \n", - " 51 traj.descent.states:mass_1 c 0.000000E+00 4.710502E+00 1.000000E+17 \n", - " 52 traj.descent.states:mass_2 c 0.000000E+00 4.711242E+00 1.000000E+17 \n", - " 53 traj.descent.states:mass_3 c 0.000000E+00 4.711494E+00 1.000000E+17 \n", - " 54 traj.descent.states:mass_4 c 0.000000E+00 4.712779E+00 1.000000E+17 \n", - " 55 traj.descent.states:mass_5 c 0.000000E+00 4.714841E+00 1.000000E+17 \n", - " 56 traj.descent.states:mass_6 c 0.000000E+00 4.715567E+00 1.000000E+17 \n", - " 57 traj.descent.states:mass_7 c 0.000000E+00 4.717767E+00 1.000000E+17 \n", - " 58 traj.descent.states:mass_8 c 0.000000E+00 4.721139E+00 1.000000E+17 \n", - " 59 traj.descent.states:mass_9 c 0.000000E+00 4.722228E+00 1.000000E+17 \n", - " 60 traj.descent.states:mass_10 c 0.000000E+00 4.723686E+00 1.000000E+17 \n", - " 61 traj.descent.states:mass_11 c 0.000000E+00 4.725431E+00 1.000000E+17 \n", - " 62 traj.descent.states:mass_12 c 0.000000E+00 4.726157E+00 1.000000E+17 \n", - " 63 traj.descent.states:mass_13 c 0.000000E+00 4.726963E+00 1.000000E+17 \n", - " 64 traj.descent.states:mass_14 c 0.000000E+00 4.728154E+00 1.000000E+17 \n", - " 65 traj.descent.states:mass_15 c 0.000000E+00 4.728551E+00 1.000000E+17 \n", - " 66 traj.descent.states:distance_0 c 0.000000E+00 2.968252E+00 1.000000E+15 \n", - " 67 traj.descent.states:distance_1 c 0.000000E+00 2.976728E+00 1.000000E+15 \n", - " 68 traj.descent.states:distance_2 c 0.000000E+00 2.988146E+00 1.000000E+15 \n", - " 69 traj.descent.states:distance_3 c 0.000000E+00 2.991691E+00 1.000000E+15 \n", - " 70 traj.descent.states:distance_4 c 0.000000E+00 3.007825E+00 1.000000E+15 \n", - " 71 traj.descent.states:distance_5 c 0.000000E+00 3.028841E+00 1.000000E+15 \n", - " 72 traj.descent.states:distance_6 c 0.000000E+00 3.035182E+00 1.000000E+15 \n", - " 73 traj.descent.states:distance_7 c 0.000000E+00 3.051662E+00 1.000000E+15 \n", - " 74 traj.descent.states:distance_8 c 0.000000E+00 3.072458E+00 1.000000E+15 \n", - " 75 traj.descent.states:distance_9 c 0.000000E+00 3.078555E+00 1.000000E+15 \n", - " 76 traj.descent.states:distance_10 c 0.000000E+00 3.089619E+00 1.000000E+15 \n", - " 77 traj.descent.states:distance_11 c 0.000000E+00 3.103383E+00 1.000000E+15 \n", - " 78 traj.descent.states:distance_12 c 0.000000E+00 3.107367E+00 1.000000E+15 \n", - " 79 traj.descent.states:distance_13 c 0.000000E+00 3.111617E+00 1.000000E+15 \n", - " 80 traj.descent.states:distance_14 c 0.000000E+00 3.117100E+00 1.000000E+15 \n", - " 81 traj.descent.states:distance_15 c 0.000000E+00 3.118742E+00 1.000000E+15 \n", - "\n", - " Constraints (i - inequality, e - equality)\n", - " Index Name Type Lower Value Upper Status Lagrange Multiplier (N/A)\n", - " 0 mass_resid e 0.000000E+00 -3.227615E-08 0.000000E+00 9.00000E+100\n", - " 1 traj.linkages.climb:time_final|cruise:time_initial e 0.000000E+00 1.136868E-13 0.000000E+00 9.00000E+100\n", - " 2 traj.linkages.climb:mass_final|cruise:mass_initial e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", - " 3 traj.linkages.climb:distance_final|cruise:distance_initial e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", - " 4 traj.linkages.cruise:time_final|descent:time_initial e 0.000000E+00 -1.818989E-12 0.000000E+00 9.00000E+100\n", - " 5 traj.linkages.cruise:mass_final|descent:mass_initial e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", - " 6 traj.linkages.cruise:distance_final|descent:distance_initial e 0.000000E+00 0.000000E+00 0.000000E+00 9.00000E+100\n", - " 7 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.025097E-14 0.000000E+00 9.00000E+100\n", - " 8 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.860766E-14 0.000000E+00 9.00000E+100\n", - " 9 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.699134E-14 0.000000E+00 9.00000E+100\n", - " 10 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 3.485284E-14 0.000000E+00 9.00000E+100\n", - " 11 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 3.003003E-14 0.000000E+00 9.00000E+100\n", - " 12 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.531926E-14 0.000000E+00 9.00000E+100\n", - " 13 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 3.113611E-14 0.000000E+00 9.00000E+100\n", - " 14 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.886567E-14 0.000000E+00 9.00000E+100\n", - " 15 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.598810E-14 0.000000E+00 9.00000E+100\n", - " 16 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.408043E-14 0.000000E+00 9.00000E+100\n", - " 17 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.173824E-14 0.000000E+00 9.00000E+100\n", - " 18 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 2.099713E-14 0.000000E+00 9.00000E+100\n", - " 19 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.608025E-14 0.000000E+00 9.00000E+100\n", - " 20 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.587637E-14 0.000000E+00 9.00000E+100\n", - " 21 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 1.558807E-14 0.000000E+00 9.00000E+100\n", - " 22 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 7.279583E-15 0.000000E+00 9.00000E+100\n", - " 23 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 7.206002E-15 0.000000E+00 9.00000E+100\n", - " 24 traj.climb.collocation_constraint.defects:mass e 0.000000E+00 7.240740E-15 0.000000E+00 9.00000E+100\n", - " 25 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.162790E-14 0.000000E+00 9.00000E+100\n", - " 26 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.105201E-14 0.000000E+00 9.00000E+100\n", - " 27 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.002517E-14 0.000000E+00 9.00000E+100\n", - " 28 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 2.058287E-14 0.000000E+00 9.00000E+100\n", - " 29 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.782458E-14 0.000000E+00 9.00000E+100\n", - " 30 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.511325E-14 0.000000E+00 9.00000E+100\n", - " 31 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.872588E-14 0.000000E+00 9.00000E+100\n", - " 32 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.655588E-14 0.000000E+00 9.00000E+100\n", - " 33 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.434107E-14 0.000000E+00 9.00000E+100\n", - " 34 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.377297E-14 0.000000E+00 9.00000E+100\n", - " 35 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.265000E-14 0.000000E+00 9.00000E+100\n", - " 36 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 1.141126E-14 0.000000E+00 9.00000E+100\n", - " 37 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 8.538640E-15 0.000000E+00 9.00000E+100\n", - " 38 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 8.126975E-15 0.000000E+00 9.00000E+100\n", - " 39 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 7.635711E-15 0.000000E+00 9.00000E+100\n", - " 40 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 3.521029E-15 0.000000E+00 9.00000E+100\n", - " 41 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 3.453567E-15 0.000000E+00 9.00000E+100\n", - " 42 traj.climb.collocation_constraint.defects:distance e 0.000000E+00 3.366714E-15 0.000000E+00 9.00000E+100\n", - " 43 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 5.312109E-13 0.000000E+00 9.00000E+100\n", - " 44 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 4.063769E-13 0.000000E+00 9.00000E+100\n", - " 45 traj.cruise.collocation_constraint.defects:mass e 0.000000E+00 2.575362E-13 0.000000E+00 9.00000E+100\n", - " 46 traj.cruise.collocation_constraint.defects:distance e 0.000000E+00 -6.926598E-18 0.000000E+00 9.00000E+100\n", - " 47 traj.cruise.collocation_constraint.defects:distance e 0.000000E+00 3.463299E-18 0.000000E+00 9.00000E+100\n", - " 48 traj.cruise.collocation_constraint.defects:distance e 0.000000E+00 -6.926598E-18 0.000000E+00 9.00000E+100\n", - " 49 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.910022E-14 0.000000E+00 9.00000E+100\n", - " 50 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.529124E-14 0.000000E+00 9.00000E+100\n", - " 51 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.342543E-14 0.000000E+00 9.00000E+100\n", - " 52 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 6.585307E-14 0.000000E+00 9.00000E+100\n", - " 53 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 5.552915E-14 0.000000E+00 9.00000E+100\n", - " 54 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 4.341976E-14 0.000000E+00 9.00000E+100\n", - " 55 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 4.791654E-14 0.000000E+00 9.00000E+100\n", - " 56 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.929329E-14 0.000000E+00 9.00000E+100\n", - " 57 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 3.075605E-14 0.000000E+00 9.00000E+100\n", - " 58 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 2.145444E-14 0.000000E+00 9.00000E+100\n", - " 59 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 1.435837E-14 0.000000E+00 9.00000E+100\n", - " 60 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 9.991150E-15 0.000000E+00 9.00000E+100\n", - " 61 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 5.078937E-15 0.000000E+00 9.00000E+100\n", - " 62 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 5.142482E-15 0.000000E+00 9.00000E+100\n", - " 63 traj.descent.collocation_constraint.defects:mass e 0.000000E+00 4.257099E-15 0.000000E+00 9.00000E+100\n", - " 64 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 6.438287E-14 0.000000E+00 9.00000E+100\n", - " 65 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 6.567239E-14 0.000000E+00 9.00000E+100\n", - " 66 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 6.757017E-14 0.000000E+00 9.00000E+100\n", - " 67 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 1.393325E-13 0.000000E+00 9.00000E+100\n", - " 68 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 1.459218E-13 0.000000E+00 9.00000E+100\n", - " 69 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 1.566014E-13 0.000000E+00 9.00000E+100\n", - " 70 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 1.907169E-13 0.000000E+00 9.00000E+100\n", - " 71 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 2.047396E-13 0.000000E+00 9.00000E+100\n", - " 72 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 2.289513E-13 0.000000E+00 9.00000E+100\n", - " 73 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 2.003578E-13 0.000000E+00 9.00000E+100\n", - " 74 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 2.175539E-13 0.000000E+00 9.00000E+100\n", - " 75 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 2.479632E-13 0.000000E+00 9.00000E+100\n", - " 76 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 1.271784E-13 0.000000E+00 9.00000E+100\n", - " 77 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 1.344334E-13 0.000000E+00 9.00000E+100\n", - " 78 traj.descent.collocation_constraint.defects:distance e 0.000000E+00 1.461002E-13 0.000000E+00 9.00000E+100\n", - " 79 traj.phases.cruise->path_constraint->altitude_rate_max i 3.000000E+02 7.127272E+02 1.000000E+30 9.00000E+100\n", - " 80 traj.phases.cruise->path_constraint->altitude_rate_max i 3.000000E+02 7.752630E+02 1.000000E+30 9.00000E+100\n", - " 81 traj.phases.cruise->path_constraint->altitude_rate_max i 3.000000E+02 8.643321E+02 1.000000E+30 9.00000E+100\n", - " 82 traj.phases.cruise->path_constraint->altitude_rate_max i 3.000000E+02 8.932716E+02 1.000000E+30 9.00000E+100\n", - "\n", - "\n", - " Exit Status\n", - " Inform Description\n", - " 0 Solve Succeeded\n", - "--------------------------------------------------------------------------------\n", - "\n", - "-------------------------------\n", - "times_climb: [846.00038137] (s)\n", - "altitudes_climb: [10668.] (m)\n", - "masses_climb: [51703.54384226] (kg)\n", - "ranges_climb: [113725.11889636] (m)\n", - "velocities_climb: [234.25795132] (m/s)\n", - "thrusts_climb: [71713.80312354] (N)\n", - "times_cruise: [13031.40073487] (s)\n", - "altitudes_cruise: [10668.] (m)\n", - "masses_cruise: [47100.44512976] (kg)\n", - "ranges_cruise: [2968252.0417268] (m)\n", - "velocities_cruise: [234.25795132] (m/s)\n", - "thrusts_cruise: [26338.70498784] (N)\n", - "times_descent: [13908.60273889] (s)\n", - "altitudes_descent: [10.668] (m)\n", - "masses_descent: [47285.51458051] (kg)\n", - "ranges_descent: [3118741.8185247] (m)\n", - "velocities_descent: [102.07377559] (m/s)\n", - "thrusts_descent: [-43173.10618655] (N)\n", - "-------------------------------\n" - ] - } - ], + "outputs": [], "source": [ "'''\n", "NOTES:\n", @@ -880,7 +520,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "52550a27", "metadata": {}, "outputs": [], 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 5baca4d89..9ed57fff1 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 @@ -25,88 +25,9 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/subsystems/propulsion/engine_deck.py:198: UserWarning: is a required option for EngineDecks, but has not been specified for EngineDeck . The default value will be used.\n", - " warnings.warn(\n", - "/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", - " warnings.warn(\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "The following variables have been overridden:\n", - " 'aircraft:design:touchdown_mass\n", - " 'aircraft:engine:mass\n", - " 'aircraft:fins:mass\n", - " 'aircraft:fuel:auxiliary_fuel_capacity\n", - " 'aircraft:fuel:fuselage_fuel_capacity\n", - " 'aircraft:fuel:total_capacity\n", - " 'aircraft:fuselage:planform_area\n", - " 'aircraft:fuselage:wetted_area\n", - " 'aircraft:horizontal_tail:wetted_area\n", - " 'aircraft:landing_gear:main_gear_oleo_length\n", - " 'aircraft:landing_gear:nose_gear_oleo_length\n", - " 'aircraft:vertical_tail:wetted_area\n", - " 'aircraft:wing:aspect_ratio\n", - " 'aircraft:wing:control_surface_area\n", - " 'aircraft:wing:wetted_area\n", - "\n", - "--- Constraint Report [traj] ---\n", - " --- climb ---\n", - " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- cruise ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- descent ---\n", - " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, dymos_solution.db, is being overwritten.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model viewer data has already been recorded for Driver.\n", - "Full total jacobian was computed 3 times, taking 0.589048 seconds.\n", - "Total jacobian shape: (135, 94) \n", - "\n", - "\n", - "Jacobian shape: (135, 94) (13.71% nonzero)\n", - "FWD solves: 22 REV solves: 0\n", - "Total colors vs. total size: 22 vs 94 (76.60% improvement)\n", - "\n", - "Sparsity computed using tolerance: 1e-25\n", - "Time to compute sparsity: 0.5890 sec\n", - "Time to compute coloring: 0.0720 sec\n", - "Memory to compute coloring: 0.1992 MB\n", - "Coloring created on: 2024-01-18 18:19:34\n", - "Iteration limit reached (Exit mode 9)\n", - " Current function value: 0.0\n", - " Iterations: 1\n", - " Function evaluations: 1\n", - " Gradient evaluations: 1\n", - "Optimization FAILED.\n", - "Iteration limit reached\n", - "-----------------------------------\n" - ] - } - ], + "outputs": [], "source": [ "import aviary.api as av\n", "\n", @@ -129,96 +50,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", - " warnings.warn(\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "The following variables have been overridden:\n", - " 'aircraft:design:touchdown_mass\n", - " 'aircraft:engine:mass\n", - " 'aircraft:fins:mass\n", - " 'aircraft:fuel:auxiliary_fuel_capacity\n", - " 'aircraft:fuel:fuselage_fuel_capacity\n", - " 'aircraft:fuel:total_capacity\n", - " 'aircraft:fuselage:planform_area\n", - " 'aircraft:fuselage:wetted_area\n", - " 'aircraft:horizontal_tail:wetted_area\n", - " 'aircraft:landing_gear:main_gear_oleo_length\n", - " 'aircraft:landing_gear:nose_gear_oleo_length\n", - " 'aircraft:vertical_tail:wetted_area\n", - " 'aircraft:wing:aspect_ratio\n", - " 'aircraft:wing:control_surface_area\n", - " 'aircraft:wing:wetted_area\n", - "\n", - "--- Constraint Report [traj] ---\n", - " --- climb ---\n", - " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- cruise ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- descent ---\n", - " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, level2_example.db, is being overwritten.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model viewer data has already been recorded for Driver.\n", - "Full total jacobian was computed 3 times, taking 0.528602 seconds.\n", - "Total jacobian shape: (135, 94) \n", - "\n", - "\n", - "Jacobian shape: (135, 94) (13.52% nonzero)\n", - "FWD solves: 21 REV solves: 0\n", - "Total colors vs. total size: 21 vs 94 (77.66% improvement)\n", - "\n", - "Sparsity computed using tolerance: 1e-25\n", - "Time to compute sparsity: 0.5286 sec\n", - "Time to compute coloring: 0.0755 sec\n", - "Memory to compute coloring: 0.0000 MB\n", - "Coloring created on: 2024-01-18 18:19:51\n", - "Iteration limit reached (Exit mode 9)\n", - " Current function value: -0.7956010169800001\n", - " Iterations: 1\n", - " Function evaluations: 1\n", - " Gradient evaluations: 1\n", - "Optimization FAILED.\n", - "Iteration limit reached\n", - "-----------------------------------\n" - ] - }, - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "import aviary.api as av\n", "\n", @@ -349,110 +183,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/mnt/c/Users/John/Dropbox/git/om-aviary/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", - " warnings.warn(\n", - "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'mach' in phase 'climb': lower, upper, ref\n", - " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", - "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'climb': lower, upper, ref\n", - " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", - "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'mach' in phase 'descent': lower, upper, ref\n", - " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", - "/mnt/c/Users/John/Dropbox/git/Dymos/dymos/phase/phase.py:2225: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'descent': lower, upper, ref\n", - " warnings.warn(f\"Invalid options for non-optimal control '{name}' in phase \"\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:area', promoted using 'aircraft:canard:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:thickness_to_chord', promoted using 'aircraft:canard:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.canard' : input variable 'aircraft:canard:wetted_area_scaler', promoted using 'aircraft:canard:wetted_area_scaler', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:area', promoted using 'aircraft:canard:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:aspect_ratio', promoted using 'aircraft:canard:aspect_ratio', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:canard:thickness_to_chord', promoted using 'aircraft:canard:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:fuselage:avg_diameter', promoted using 'aircraft:fuselage:avg_diameter', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:fuselage:length', promoted using 'aircraft:fuselage:length', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:area', promoted using 'aircraft:horizontal_tail:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:aspect_ratio', promoted using 'aircraft:horizontal_tail:aspect_ratio', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:horizontal_tail:thickness_to_chord', promoted using 'aircraft:horizontal_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:nacelle:avg_diameter', promoted using 'aircraft:nacelle:avg_diameter', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:nacelle:avg_length', promoted using 'aircraft:nacelle:avg_length', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:area', promoted using 'aircraft:vertical_tail:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:aspect_ratio', promoted using 'aircraft:vertical_tail:aspect_ratio', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:vertical_tail:thickness_to_chord', promoted using 'aircraft:vertical_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:aspect_ratio', promoted using 'aircraft:wing:aspect_ratio', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:glove_and_bat', promoted using 'aircraft:wing:glove_and_bat', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:taper_ratio', promoted using 'aircraft:wing:taper_ratio', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' : input variable 'aircraft:wing:thickness_to_chord', promoted using 'aircraft:wing:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:avg_diameter', promoted using 'aircraft:fuselage:avg_diameter', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:length', promoted using 'aircraft:fuselage:length', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:fuselage:wetted_area_scaler', promoted using 'aircraft:fuselage:wetted_area_scaler', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:horizontal_tail:thickness_to_chord', promoted using 'aircraft:horizontal_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:horizontal_tail:vertical_tail_fraction', promoted using 'aircraft:horizontal_tail:vertical_tail_fraction', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:vertical_tail:thickness_to_chord', promoted using 'aircraft:vertical_tail:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:aspect_ratio', promoted using 'aircraft:wing:aspect_ratio', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:glove_and_bat', promoted using 'aircraft:wing:glove_and_bat', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.fuselage' : input variable 'aircraft:wing:thickness_to_chord', promoted using 'aircraft:wing:thickness_to_chord', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:avg_diameter', promoted using 'aircraft:nacelle:avg_diameter', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:avg_length', promoted using 'aircraft:nacelle:avg_length', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.nacelles' : input variable 'aircraft:nacelle:wetted_area_scaler', promoted using 'aircraft:nacelle:wetted_area_scaler', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:area', promoted using 'aircraft:horizontal_tail:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:vertical_tail_fraction', promoted using 'aircraft:horizontal_tail:vertical_tail_fraction', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:horizontal_tail:wetted_area_scaler', promoted using 'aircraft:horizontal_tail:wetted_area_scaler', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:vertical_tail:area', promoted using 'aircraft:vertical_tail:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.tail' : input variable 'aircraft:vertical_tail:wetted_area_scaler', promoted using 'aircraft:vertical_tail:wetted_area_scaler', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.wing' : input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.\n", - "/mnt/c/Users/John/Dropbox/git/OpenMDAO/openmdao/core/system.py:2431: PromotionWarning:'pre_mission.core_geometry.wing' : input variable 'aircraft:wing:wetted_area_scaler', promoted using 'aircraft:wing:wetted_area_scaler', was already promoted using 'aircraft*'.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "The following variables have been overridden:\n", - " 'aircraft:design:touchdown_mass\n", - " 'aircraft:engine:mass\n", - " 'aircraft:fins:mass\n", - " 'aircraft:fuel:auxiliary_fuel_capacity\n", - " 'aircraft:fuel:fuselage_fuel_capacity\n", - " 'aircraft:fuel:total_capacity\n", - " 'aircraft:fuselage:planform_area\n", - " 'aircraft:fuselage:wetted_area\n", - " 'aircraft:horizontal_tail:wetted_area\n", - " 'aircraft:landing_gear:main_gear_oleo_length\n", - " 'aircraft:landing_gear:nose_gear_oleo_length\n", - " 'aircraft:vertical_tail:wetted_area\n", - " 'aircraft:wing:aspect_ratio\n", - " 'aircraft:wing:control_surface_area\n", - " 'aircraft:wing:wetted_area\n", - "\n", - "--- Constraint Report [traj] ---\n", - " --- climb ---\n", - " None\n", - " --- cruise ---\n", - " [path] 3.0000e+02 <= altitude_rate_max [ft/min]\n", - " --- descent ---\n", - " None\n", - "\n" - ] - }, - { - "ename": "AttributeError", - "evalue": "type object 'Mission' has no attribute 'RANGE'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[6], line 237\u001b[0m\n\u001b[1;32m 231\u001b[0m prob\u001b[38;5;241m.\u001b[39mset_val(\n\u001b[1;32m 232\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtraj.climb.controls:mach\u001b[39m\u001b[38;5;124m'\u001b[39m, climb\u001b[38;5;241m.\u001b[39minterp(\n\u001b[1;32m 233\u001b[0m av\u001b[38;5;241m.\u001b[39mDynamic\u001b[38;5;241m.\u001b[39mMission\u001b[38;5;241m.\u001b[39mMACH, ys\u001b[38;5;241m=\u001b[39m[mach_i_climb, mach_f_climb]), units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124munitless\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 234\u001b[0m prob\u001b[38;5;241m.\u001b[39mset_val(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtraj.climb.states:mass\u001b[39m\u001b[38;5;124m'\u001b[39m, climb\u001b[38;5;241m.\u001b[39minterp(\n\u001b[1;32m 235\u001b[0m av\u001b[38;5;241m.\u001b[39mDynamic\u001b[38;5;241m.\u001b[39mMission\u001b[38;5;241m.\u001b[39mMASS, ys\u001b[38;5;241m=\u001b[39m[mass_i_climb, mass_f_climb]), units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mkg\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 236\u001b[0m prob\u001b[38;5;241m.\u001b[39mset_val(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtraj.climb.states:distance\u001b[39m\u001b[38;5;124m'\u001b[39m, climb\u001b[38;5;241m.\u001b[39minterp(\n\u001b[0;32m--> 237\u001b[0m \u001b[43mav\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mDynamic\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mMission\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mRANGE\u001b[49m, ys\u001b[38;5;241m=\u001b[39m[distance_i_climb, distance_f_climb]), units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mm\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 239\u001b[0m prob\u001b[38;5;241m.\u001b[39mset_val(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtraj.cruise.t_initial\u001b[39m\u001b[38;5;124m'\u001b[39m, t_i_cruise, units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124ms\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 240\u001b[0m prob\u001b[38;5;241m.\u001b[39mset_val(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtraj.cruise.t_duration\u001b[39m\u001b[38;5;124m'\u001b[39m, t_duration_cruise, units\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124ms\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", - "\u001b[0;31mAttributeError\u001b[0m: type object 'Mission' has no attribute 'RANGE'" - ] - } - ], + "outputs": [], "source": [ "import dymos as dm\n", "import openmdao.api as om\n", @@ -724,13 +457,6 @@ "dm.run_problem(prob, simulate=False, make_plots=False, simulate_kwargs={\n", " 'times_per_seg': 100, 'atol': 1e-9, 'rtol': 1e-9})" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { From 6c0c33740232eecbce49ed0e3533ddb0b9b5a6b0 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 18 Jan 2024 18:42:01 -0600 Subject: [PATCH 118/188] Feedback based on PR --- aviary/interface/methods_for_level2.py | 4 +-- .../interface/test/test_check_phase_info.py | 18 +++++++----- aviary/mission/flops_based/ode/mission_EOM.py | 2 +- aviary/mission/flops_based/ode/mission_ODE.py | 7 +++-- .../flops_based/ode/required_thrust.py | 29 ++++++++++--------- .../flops_based/ode/simple_mission_EOM.py | 2 +- .../flops_based/ode/simple_mission_ODE.py | 4 +-- .../benchmark_tests/test_0_iters.py | 6 ++-- aviary/variable_info/enums.py | 3 +- 9 files changed, 39 insertions(+), 36 deletions(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 1e40b3ba9..eec2e2f97 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -691,7 +691,7 @@ def _add_groundroll_eq_constraint(self, phase): promotes_inputs=["t_init_gear", "t_init_flaps"], ) - def _get_simple_phase(self, phase_name, phase_idx): + def _get_height_energy_phase(self, phase_name, phase_idx): base_phase_options = self.phase_info[phase_name] fix_duration = base_phase_options['user_options']['fix_duration'] @@ -1053,7 +1053,7 @@ def add_subsystem_timeseries_outputs(phase, phase_name): elif self.mission_method is HEIGHT_ENERGY: for phase_idx, phase_name in enumerate(phases): phase = traj.add_phase( - phase_name, self._get_simple_phase(phase_name, phase_idx)) + phase_name, self._get_height_energy_phase(phase_name, phase_idx)) add_subsystem_timeseries_outputs(phase, phase_name) # loop through phase_info and external subsystems diff --git a/aviary/interface/test/test_check_phase_info.py b/aviary/interface/test/test_check_phase_info.py index 56774258a..9e18ca521 100644 --- a/aviary/interface/test/test_check_phase_info.py +++ b/aviary/interface/test/test_check_phase_info.py @@ -2,8 +2,8 @@ import copy from aviary.interface.utils.check_phase_info import check_phase_info -from aviary.interface.default_phase_info.height_energy import phase_info as phase_info_flops -from aviary.interface.default_phase_info.two_dof import phase_info as phase_info_gasp +from aviary.interface.default_phase_info.height_energy import phase_info as phase_info_height_energy +from aviary.interface.default_phase_info.two_dof import phase_info as phase_info_two_dof from aviary.variable_info.enums import EquationsOfMotion HEIGHT_ENERGY = EquationsOfMotion.HEIGHT_ENERGY @@ -13,34 +13,36 @@ class TestCheckInputs(unittest.TestCase): def test_correct_input_height_energy(self): # This should pass without any issue as it's the same valid dict as before - self.assertTrue(check_phase_info(phase_info_flops, mission_method=HEIGHT_ENERGY)) + self.assertTrue(check_phase_info( + phase_info_height_energy, mission_method=HEIGHT_ENERGY)) def test_incorrect_tuple(self): # Let's replace a tuple with a float in the 'climb' phase - incorrect_tuple_phase_info = copy.deepcopy(phase_info_flops) + incorrect_tuple_phase_info = copy.deepcopy(phase_info_height_energy) incorrect_tuple_phase_info['climb']['user_options']['initial_altitude'] = 10.668e3 with self.assertRaises(ValueError): check_phase_info(incorrect_tuple_phase_info, mission_method=HEIGHT_ENERGY) def test_incorrect_unit(self): # Let's replace a valid unit with an invalid one in the 'climb' phase - incorrect_unit_phase_info = copy.deepcopy(phase_info_flops) + incorrect_unit_phase_info = copy.deepcopy(phase_info_height_energy) incorrect_unit_phase_info['climb']['user_options']['initial_altitude'] = ( 10.668e3, 'invalid_unit') with self.assertRaisesRegex(ValueError, "Key initial_altitude in phase climb has an invalid unit invalid_unit."): check_phase_info(incorrect_unit_phase_info, mission_method=HEIGHT_ENERGY) - def test_correct_input_gasp(self): + def test_correct_input_two_dof(self): # This should pass without any issue as it's the same valid dict as before - self.assertTrue(check_phase_info(phase_info_gasp, + self.assertTrue(check_phase_info(phase_info_two_dof, mission_method=TWO_DEGREES_OF_FREEDOM)) def test_incorrect_mission_method(self): # Let's pass an incorrect mission_method name incorrect_mission_method = 'INVALID_METHOD' with self.assertRaises(ValueError): - check_phase_info(phase_info_flops, mission_method=incorrect_mission_method) + check_phase_info(phase_info_height_energy, + mission_method=incorrect_mission_method) if __name__ == '__main__': diff --git a/aviary/mission/flops_based/ode/mission_EOM.py b/aviary/mission/flops_based/ode/mission_EOM.py index b726d17b6..55bc58889 100644 --- a/aviary/mission/flops_based/ode/mission_EOM.py +++ b/aviary/mission/flops_based/ode/mission_EOM.py @@ -19,7 +19,7 @@ def setup(self): subsys=RequiredThrust(num_nodes=nn), promotes_inputs=[Dynamic.Mission.DRAG, Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY, Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.MASS], - promotes_outputs=['T_required']) + promotes_outputs=['thrust_required']) self.add_subsystem(name='groundspeed', subsys=RangeRate(num_nodes=nn), diff --git a/aviary/mission/flops_based/ode/mission_ODE.py b/aviary/mission/flops_based/ode/mission_ODE.py index 689df00fc..2a6dcccd4 100644 --- a/aviary/mission/flops_based/ode/mission_ODE.py +++ b/aviary/mission/flops_based/ode/mission_ODE.py @@ -40,7 +40,8 @@ def initialize(self): 'use_actual_takeoff_mass', default=False, desc='flag to use actual takeoff mass in the climb phase, otherwise assume 100 kg fuel burn') self.options.declare( - 'throttle_enforcement', default='path', + 'throttle_enforcement', default='path_constraint', + values=['path_constraint', 'boundary_constraint', 'bounded'], desc='flag to enforce throttle constraints on the path or at the segment boundaries or using solver bounds' ) @@ -149,7 +150,7 @@ def setup(self): Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, Dynamic.Mission.ALTITUDE_RATE_MAX, Dynamic.Mission.DISTANCE_RATE, - 'T_required', + 'thrust_required', ]) # add a balance comp to compute throttle based on the altitude rate @@ -157,7 +158,7 @@ def setup(self): subsys=om.BalanceComp(name=Dynamic.Mission.THROTTLE, units="unitless", val=np.ones(nn), - lhs_name='T_required', + lhs_name='thrust_required', rhs_name=Dynamic.Mission.THRUST_TOTAL, eq_units="lbf", normalize=False, diff --git a/aviary/mission/flops_based/ode/required_thrust.py b/aviary/mission/flops_based/ode/required_thrust.py index 25903ac6d..af3c5ed62 100644 --- a/aviary/mission/flops_based/ode/required_thrust.py +++ b/aviary/mission/flops_based/ode/required_thrust.py @@ -7,7 +7,7 @@ class RequiredThrust(om.ExplicitComponent): """ Computes the required thrust using the equation: - T_required = drag + (altitude_rate*gravity/velocity + velocity_rate) * mass + thrust_required = drag + (altitude_rate*gravity/velocity + velocity_rate) * mass """ def initialize(self): @@ -26,17 +26,18 @@ def setup(self): nn), units='m/s**2', desc='rate of change of velocity') self.add_input(Dynamic.Mission.MASS, val=np.zeros( nn), units='kg', desc='mass of the aircraft') - self.add_output('T_required', val=np.zeros( + self.add_output('thrust_required', val=np.zeros( nn), units='N', desc='required thrust') ar = np.arange(nn) - self.declare_partials('T_required', Dynamic.Mission.DRAG, rows=ar, cols=ar) + self.declare_partials('thrust_required', Dynamic.Mission.DRAG, rows=ar, cols=ar) self.declare_partials( - 'T_required', Dynamic.Mission.ALTITUDE_RATE, rows=ar, cols=ar) - self.declare_partials('T_required', Dynamic.Mission.VELOCITY, rows=ar, cols=ar) + 'thrust_required', Dynamic.Mission.ALTITUDE_RATE, rows=ar, cols=ar) self.declare_partials( - 'T_required', Dynamic.Mission.VELOCITY_RATE, rows=ar, cols=ar) - self.declare_partials('T_required', Dynamic.Mission.MASS, rows=ar, cols=ar) + 'thrust_required', Dynamic.Mission.VELOCITY, rows=ar, cols=ar) + self.declare_partials( + 'thrust_required', Dynamic.Mission.VELOCITY_RATE, rows=ar, cols=ar) + self.declare_partials('thrust_required', Dynamic.Mission.MASS, rows=ar, cols=ar) def compute(self, inputs, outputs): drag = inputs[Dynamic.Mission.DRAG] @@ -45,9 +46,9 @@ def compute(self, inputs, outputs): velocity_rate = inputs[Dynamic.Mission.VELOCITY_RATE] mass = inputs[Dynamic.Mission.MASS] - T_required = drag + (altitude_rate*gravity/velocity + velocity_rate) * mass + thrust_required = drag + (altitude_rate*gravity/velocity + velocity_rate) * mass - outputs['T_required'] = T_required + outputs['thrust_required'] = thrust_required def compute_partials(self, inputs, partials): altitude_rate = inputs[Dynamic.Mission.ALTITUDE_RATE] @@ -55,10 +56,10 @@ def compute_partials(self, inputs, partials): velocity_rate = inputs[Dynamic.Mission.VELOCITY_RATE] mass = inputs[Dynamic.Mission.MASS] - partials['T_required', Dynamic.Mission.DRAG] = 1.0 - partials['T_required', Dynamic.Mission.ALTITUDE_RATE] = gravity/velocity * mass - partials['T_required', Dynamic.Mission.VELOCITY] = - \ + partials['thrust_required', Dynamic.Mission.DRAG] = 1.0 + partials['thrust_required', Dynamic.Mission.ALTITUDE_RATE] = gravity/velocity * mass + partials['thrust_required', Dynamic.Mission.VELOCITY] = - \ altitude_rate*gravity/velocity**2 * mass - partials['T_required', Dynamic.Mission.VELOCITY_RATE] = mass - partials['T_required', Dynamic.Mission.MASS] = altitude_rate * \ + partials['thrust_required', Dynamic.Mission.VELOCITY_RATE] = mass + partials['thrust_required', Dynamic.Mission.MASS] = altitude_rate * \ gravity/velocity + velocity_rate diff --git a/aviary/mission/flops_based/ode/simple_mission_EOM.py b/aviary/mission/flops_based/ode/simple_mission_EOM.py index b726d17b6..55bc58889 100644 --- a/aviary/mission/flops_based/ode/simple_mission_EOM.py +++ b/aviary/mission/flops_based/ode/simple_mission_EOM.py @@ -19,7 +19,7 @@ def setup(self): subsys=RequiredThrust(num_nodes=nn), promotes_inputs=[Dynamic.Mission.DRAG, Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY, Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.MASS], - promotes_outputs=['T_required']) + promotes_outputs=['thrust_required']) self.add_subsystem(name='groundspeed', subsys=RangeRate(num_nodes=nn), diff --git a/aviary/mission/flops_based/ode/simple_mission_ODE.py b/aviary/mission/flops_based/ode/simple_mission_ODE.py index 0a34ad7ee..beb8016c9 100644 --- a/aviary/mission/flops_based/ode/simple_mission_ODE.py +++ b/aviary/mission/flops_based/ode/simple_mission_ODE.py @@ -149,7 +149,7 @@ def setup(self): Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, Dynamic.Mission.ALTITUDE_RATE_MAX, Dynamic.Mission.DISTANCE_RATE, - 'T_required', + 'thrust_required', ]) # add a balance comp to compute throttle based on the altitude rate @@ -157,7 +157,7 @@ def setup(self): subsys=om.BalanceComp(name=Dynamic.Mission.THROTTLE, units="unitless", val=np.ones(nn), - lhs_name='T_required', + lhs_name='thrust_required', rhs_name=Dynamic.Mission.THRUST_TOTAL, eq_units="lbf", normalize=False, diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index 2d58fb26e..c60146b11 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -5,7 +5,7 @@ from aviary.interface.methods_for_level2 import AviaryProblem from aviary.interface.default_phase_info.two_dof import phase_info as two_dof_phase_info -from aviary.interface.default_phase_info.height_energy import phase_info as simple_phase_info +from aviary.interface.default_phase_info.height_energy import phase_info as height_energy_phase_info from aviary.interface.default_phase_info.solved import phase_info as solved_phase_info from aviary.variable_info.enums import EquationsOfMotion @@ -45,8 +45,8 @@ def test_gasp_zero_iters(self): class HEZeroItersTestCase(BaseProblemPhaseTestCase): @require_pyoptsparse(optimizer="IPOPT") - def test_simple_zero_iters(self): - local_phase_info = deepcopy(simple_phase_info) + def test_height_energy_zero_iters(self): + local_phase_info = deepcopy(height_energy_phase_info) self.build_and_run_problem('models/test_aircraft/aircraft_for_bench_FwFm.csv', local_phase_info) diff --git a/aviary/variable_info/enums.py b/aviary/variable_info/enums.py index 17e8f102c..7978e4da3 100644 --- a/aviary/variable_info/enums.py +++ b/aviary/variable_info/enums.py @@ -57,9 +57,8 @@ class EquationsOfMotion(Enum): """ Available equations of motion for use during mission analysis """ - TWO_DEGREES_OF_FREEDOM = '2DOF' - # TODO these are a little out of place atm HEIGHT_ENERGY = 'height_energy' + TWO_DEGREES_OF_FREEDOM = '2DOF' SOLVED = 'solved' From d83a3fbe31de71e572e43eca76c512bf0eb56f6e Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Fri, 19 Jan 2024 08:35:41 -0500 Subject: [PATCH 119/188] statics XDSM upd to pass spec, climb and descent XDSM upd for clarity --- aviary/xdsm/climb_xdsm.py | 14 +++++++++++++- aviary/xdsm/descent1_xdsm.py | 11 +++++++++++ aviary/xdsm/descent2_xdsm.py | 11 +++++++++++ aviary/xdsm/statics_xdsm.py | 16 ++++++++++++---- 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/aviary/xdsm/climb_xdsm.py b/aviary/xdsm/climb_xdsm.py index 764ad79ca..cd775b221 100644 --- a/aviary/xdsm/climb_xdsm.py +++ b/aviary/xdsm/climb_xdsm.py @@ -19,6 +19,8 @@ x.add_system("eom", GROUP, [r"\textbf{ClimbEOM}"]) x.add_system("balance_lift", IFUNC, ["BalanceLift"]) x.add_system("constraints", FUNC, [r"\textbf{Constraints}"]) +x.add_system('specific_energy', FUNC, ["specific_energy"]) +x.add_system('alt_rate', FUNC, ["alt_rate"]) # create inputs x.add_input("speeds", [Dynamic.Mission.MACH]) @@ -49,8 +51,10 @@ Aircraft.Engine.SCALE_FACTOR, ]) x.add_input("eom", [Dynamic.Mission.MASS]) +x.add_input("specific_energy", [Dynamic.Mission.MASS]) +x.add_input("alt_rate", ["TAS_rate"]) -# make connections +# make connections6 x.connect("atmos", "fc", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) # x.connect("atmos", "prop", [Dynamic.Mission.TEMPERATURE, Dynamic.Mission.STATIC_PRESSURE]) x.connect("atmos", "constraints", ["rho"]) @@ -71,6 +75,12 @@ x.connect("eom", "balance_lift", ["required_lift"]) x.connect("balance_lift", "constraints", ["alpha"]) x.connect("balance_lift", "aero", ["alpha"]) +x.connect("fc", "specific_energy", ["TAS"]) +x.connect("aero", "specific_energy", [Dynamic.Mission.DRAG]) +x.connect("prop", "specific_energy", [Dynamic.Mission.THRUST_MAX_TOTAL]) +x.connect("specific_energy", "alt_rate", [Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS]) +x.connect("fc", "alt_rate", ["TAS"]) + # create outputs x.add_output("eom", [ @@ -86,5 +96,7 @@ "CL_max", ], side="right") +x.add_output("alt_rate", [Dynamic.Mission.ALTITUDE_RATE_MAX], side="right") + x.write("climb_xdsm") x.write_sys_specs("climb_specs") diff --git a/aviary/xdsm/descent1_xdsm.py b/aviary/xdsm/descent1_xdsm.py index 74e3b0f02..a405f9b93 100644 --- a/aviary/xdsm/descent1_xdsm.py +++ b/aviary/xdsm/descent1_xdsm.py @@ -19,6 +19,8 @@ x.add_system("balance_lift", FUNC, ["BalanceLift"]) x.add_system("aero", IGROUP, ["CruiseAero", "(alpha~in)"]) x.add_system("pitch", FUNC, ["Constraints"]) +x.add_system('specific_energy', FUNC, ["specific_energy"]) +x.add_system('alt_rate', FUNC, ["alt_rate"]) # create inputs # x.add_input("fc", [Dynamic.Mission.MACH]) @@ -37,6 +39,8 @@ Aircraft.Wing.AREA, Aircraft.Wing.INCIDENCE, ]) +x.add_input("specific_energy", [Dynamic.Mission.MASS]) +x.add_input("alt_rate", ["TAS_rate"]) # make connections x.connect("atmos", "fc", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) @@ -62,6 +66,11 @@ x.connect("aero", "eom", [Dynamic.Mission.DRAG]) x.connect("aero", "pitch", ["CL_max"]) x.connect("aero", "balance_lift", [Dynamic.Mission.LIFT]) +x.connect("fc", "specific_energy", ["TAS"]) +x.connect("aero", "specific_energy", [Dynamic.Mission.DRAG]) +x.connect("prop", "specific_energy", [Dynamic.Mission.THRUST_MAX_TOTAL]) +x.connect("specific_energy", "alt_rate", [Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS]) +x.connect("fc", "alt_rate", ["TAS"]) # create outputs x.add_output("eom", [ @@ -70,5 +79,7 @@ "required_lift" ], side="right") +x.add_output("alt_rate", [Dynamic.Mission.ALTITUDE_RATE_MAX], side="right") + x.write("descent1_xdsm") x.write_sys_specs("descent1_specs") diff --git a/aviary/xdsm/descent2_xdsm.py b/aviary/xdsm/descent2_xdsm.py index 20ba3f889..f23e9cd45 100644 --- a/aviary/xdsm/descent2_xdsm.py +++ b/aviary/xdsm/descent2_xdsm.py @@ -13,6 +13,8 @@ x.add_system("balance_lift", FUNC, ["BalanceLift"]) x.add_system("aero", IGROUP, ["CruiseAero", "(alpha~in)"]) x.add_system("pitch", FUNC, ["Constraints"]) +x.add_system('specific_energy', FUNC, ["specific_energy"]) +x.add_system('alt_rate', FUNC, ["alt_rate"]) # create inputs # x.add_input("fc", ["EAS"]) @@ -29,6 +31,8 @@ Aircraft.Wing.AREA, Aircraft.Wing.INCIDENCE, ]) +x.add_input("specific_energy", [Dynamic.Mission.MASS]) +x.add_input("alt_rate", ["TAS_rate"]) # make connections x.add_input("fc", ["EAS"]) @@ -50,6 +54,11 @@ x.connect("aero", "eom", [Dynamic.Mission.DRAG]) x.connect("aero", "pitch", ["CL_max"]) x.connect("aero", "balance_lift", [Dynamic.Mission.LIFT]) +x.connect("fc", "specific_energy", ["TAS"]) +x.connect("aero", "specific_energy", [Dynamic.Mission.DRAG]) +x.connect("prop", "specific_energy", [Dynamic.Mission.THRUST_MAX_TOTAL]) +x.connect("specific_energy", "alt_rate", [Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS]) +x.connect("fc", "alt_rate", ["TAS"]) # create outputs x.add_output("eom", [ @@ -58,5 +67,7 @@ "required_lift" ], side="right") +x.add_output("alt_rate", [Dynamic.Mission.ALTITUDE_RATE_MAX], side="right") + x.write("descent2_xdsm") x.write_sys_specs("descent2_specs") diff --git a/aviary/xdsm/statics_xdsm.py b/aviary/xdsm/statics_xdsm.py index 2d5c5eed5..69920ccfe 100644 --- a/aviary/xdsm/statics_xdsm.py +++ b/aviary/xdsm/statics_xdsm.py @@ -343,6 +343,10 @@ # Create outputs x.add_output("landing", [Mission.Landing.GROUND_DISTANCE], side="right") +x.add_output("climb1", [Dynamic.Mission.ALTITUDE_RATE_MAX], side="right") +x.add_output("climb2", [Dynamic.Mission.ALTITUDE_RATE_MAX], side="right") +x.add_output("descent2", [Dynamic.Mission.ALTITUDE_RATE_MAX], side="right") +x.add_output("descent1", [Dynamic.Mission.ALTITUDE_RATE_MAX], side="right") # Create phase continuities x.connect("dymos", "groundroll", [Dynamic.Mission.MASS, "TAS", "t_curr"]) @@ -351,10 +355,13 @@ x.connect("dymos", "ascent", [Dynamic.Mission.MASS, Dynamic.Mission.ALTITUDE, "TAS", Dynamic.Mission.FLIGHT_PATH_ANGLE, "t_curr", "alpha"]) x.connect("dymos", "accelerate", [Dynamic.Mission.ALTITUDE, "TAS", Dynamic.Mission.MASS]) -x.connect("dymos", "climb1", [Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS]) -x.connect("dymos", "climb2", [Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS]) +x.connect("dymos", "climb1", [Dynamic.Mission.ALTITUDE, + Dynamic.Mission.MASS, "TAS_rate"]) +x.connect("dymos", "climb2", [Dynamic.Mission.ALTITUDE, + Dynamic.Mission.MASS, "TAS_rate"]) x.connect("dymos", "poly", ["time_cp", "h_cp"]) -x.connect("dymos", "descent2", [Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS]) +x.connect("dymos", "descent2", [Dynamic.Mission.ALTITUDE, + Dynamic.Mission.MASS, "TAS_rate"]) x.connect("dymos", "landing", [Dynamic.Mission.MASS]) x.connect("taxi", "groundroll", [Dynamic.Mission.MASS]) x.connect("dymos", @@ -365,7 +372,8 @@ "cruise_time_initial", "cruise_distance_initial"], ) -x.connect("dymos", "descent1", [Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS]) +x.connect("dymos", "descent1", [Dynamic.Mission.ALTITUDE, + Dynamic.Mission.MASS, "TAS_rate"]) x.connect("dymos", "fuelburn", [Mission.Landing.TOUCHDOWN_MASS]) x.connect("dymos", Dynamic.Mission.DISTANCE, [Mission.Summary.RANGE]) x.connect("cruise", "dymos", ["cruise_time_final", "cruise_distance_final"]) From 19048cf69a27aef9dae088d64edf42f33ee7758d Mon Sep 17 00:00:00 2001 From: jkirk5 Date: Fri, 19 Jan 2024 10:56:50 -0500 Subject: [PATCH 120/188] merge fix --- aviary/utils/process_input_decks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/aviary/utils/process_input_decks.py b/aviary/utils/process_input_decks.py index 41f52680e..4f7ea1161 100644 --- a/aviary/utils/process_input_decks.py +++ b/aviary/utils/process_input_decks.py @@ -153,7 +153,6 @@ def update_GASP_options(aircraft_values: AviaryValues(), initial_guesses): GASP_defaults.set_val('mass_defect', val=10000, units='lbm') GASP_defaults.set_val('problem_type', val=ProblemType.SIZING) GASP_defaults.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False) - GASP_defaults.set_val(Aircraft.Design.RESERVES, val=4998) # overwrite GASP_defaults with values from aircraft_values, then replace # aircraft_values with this merged set From e6f5efcc316476d60ff0a9b187fe23cec7671960 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Fri, 19 Jan 2024 11:43:00 -0500 Subject: [PATCH 121/188] removed dupe import and fixed up the dashboard test to use the correct reports subdirectory --- aviary/interface/test/test_simple_mission.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aviary/interface/test/test_simple_mission.py b/aviary/interface/test/test_simple_mission.py index f9559b691..bbf17e394 100644 --- a/aviary/interface/test/test_simple_mission.py +++ b/aviary/interface/test/test_simple_mission.py @@ -6,7 +6,6 @@ from aviary.interface.methods_for_level1 import run_aviary from aviary.subsystems.test.test_dummy_subsystem import ArrayGuessSubsystemBuilder -from openmdao.utils.testing_utils import require_pyoptsparse, use_tempdirs @use_tempdirs @@ -131,7 +130,7 @@ def test_mission_basic_and_dashboard(self): self.assertIsNotNone(prob) self.assertFalse(prob.failed) - cmd = f'aviary dashboard --problem_recorder dymos_solution.db --driver_recorder driver_test.db test_simple_mission' + cmd = f'aviary dashboard --problem_recorder dymos_solution.db --driver_recorder driver_test.db {prob.driver._problem()._name}' # this only tests that a given command line tool returns a 0 return code. It doesn't # check the expected output at all. The underlying functions that implement the # commands should be tested seperately. From d0dd94be65cdfc49a5cc9fb1beedb65c6c1d00ea Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Fri, 19 Jan 2024 12:14:46 -0500 Subject: [PATCH 122/188] removed tmate from workflow --- .github/workflows/test_workflow.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 436b1947c..3edbe2f3e 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -213,10 +213,6 @@ jobs: python run_all.py cd ../.. - - name: Setup tmate session - uses: mxschmitt/action-tmate@v3 - - - name: Run tests if: matrix.MAKE_DOCS == 0 shell: bash -l {0} From db5f28e1b61605ba4be6a74b9d39fd0117d0deb1 Mon Sep 17 00:00:00 2001 From: swryan Date: Fri, 19 Jan 2024 12:29:40 -0500 Subject: [PATCH 123/188] use only conda-forge for depndencies --- .github/workflows/test_workflow.yml | 3 ++- .github/workflows/test_workflow_no_dev_install.yml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 3edbe2f3e..b95cfb4a0 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -106,6 +106,7 @@ jobs: with: auto-update-conda: true python-version: ${{ matrix.PY }} + channels: conda-forge - name: Install dependencies shell: bash -l {0} @@ -232,7 +233,7 @@ jobs: echo "Build the docs" echo "=============================================================" bash build_book.sh - + - name: Display doc build reports continue-on-error: True if: matrix.MAKE_DOCS diff --git a/.github/workflows/test_workflow_no_dev_install.yml b/.github/workflows/test_workflow_no_dev_install.yml index 74c498830..7fc2bf431 100644 --- a/.github/workflows/test_workflow_no_dev_install.yml +++ b/.github/workflows/test_workflow_no_dev_install.yml @@ -54,6 +54,7 @@ jobs: with: auto-update-conda: true python-version: ${{ matrix.PY }} + channels: conda-forge - name: Checkout Aviary uses: actions/checkout@v2 From 18320937f5b2d6248aad0a7f80efac801c1431f5 Mon Sep 17 00:00:00 2001 From: swryan Date: Fri, 19 Jan 2024 12:32:09 -0500 Subject: [PATCH 124/188] enable workflow_dispatch to run tests workflows --- .github/workflows/test_workflow.yml | 3 +++ .github/workflows/test_workflow_no_dev_install.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index b95cfb4a0..95980162e 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -11,6 +11,9 @@ on: merge_group: branches: [ main ] + # Allow running the workflow manually from the Actions tab + workflow_dispatch: + jobs: pre_commit: diff --git a/.github/workflows/test_workflow_no_dev_install.yml b/.github/workflows/test_workflow_no_dev_install.yml index 7fc2bf431..7e0ca5d54 100644 --- a/.github/workflows/test_workflow_no_dev_install.yml +++ b/.github/workflows/test_workflow_no_dev_install.yml @@ -11,6 +11,9 @@ on: merge_group: branches: [ main ] + # Allow running the workflow manually from the Actions tab + workflow_dispatch: + jobs: test_ubuntu_no_dev_install: From 810dc0740a2e58789794aa449e90e0d0a67f5a78 Mon Sep 17 00:00:00 2001 From: swryan Date: Fri, 19 Jan 2024 12:41:40 -0500 Subject: [PATCH 125/188] remove owner condition from workflows --- .github/workflows/test_workflow.yml | 2 -- .github/workflows/test_workflow_no_dev_install.yml | 1 - 2 files changed, 3 deletions(-) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 95980162e..ff240cea6 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -17,7 +17,6 @@ on: jobs: pre_commit: - if: github.repository_owner == 'OpenMDAO' # run pre-commit checks runs-on: ubuntu-latest @@ -29,7 +28,6 @@ jobs: - uses: pre-commit/action@v3.0.0 test_ubuntu: - if: github.repository_owner == 'OpenMDAO' runs-on: ubuntu-latest timeout-minutes: 90 diff --git a/.github/workflows/test_workflow_no_dev_install.yml b/.github/workflows/test_workflow_no_dev_install.yml index 7e0ca5d54..b963e3666 100644 --- a/.github/workflows/test_workflow_no_dev_install.yml +++ b/.github/workflows/test_workflow_no_dev_install.yml @@ -17,7 +17,6 @@ on: jobs: test_ubuntu_no_dev_install: - if: github.repository_owner == 'OpenMDAO' runs-on: ubuntu-latest timeout-minutes: 90 From fc1e4c25327f28ceadbe0f3e2b1bac664994c2d7 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 19 Jan 2024 11:48:34 -0600 Subject: [PATCH 126/188] PR feedback changes --- .../default_phase_info/height_energy.py | 56 ++++++++++++- .../interface/default_phase_info/two_dof.py | 4 +- aviary/interface/methods_for_level2.py | 16 ++-- aviary/interface/test/test_phase_info.py | 50 ++++++++++-- .../test/test_solved_aero_group.py | 78 +------------------ .../test/test_custom_engine_model.py | 3 +- .../benchmark_tests/test_0_iters.py | 4 +- .../benchmark_tests/test_bench_FwFm.py | 2 +- 8 files changed, 116 insertions(+), 97 deletions(-) diff --git a/aviary/interface/default_phase_info/height_energy.py b/aviary/interface/default_phase_info/height_energy.py index 4aceafb61..e42c67172 100644 --- a/aviary/interface/default_phase_info/height_energy.py +++ b/aviary/interface/default_phase_info/height_energy.py @@ -3,6 +3,7 @@ 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 @@ -23,7 +24,6 @@ "user_options": { "optimize_mach": False, "optimize_altitude": False, - "polynomial_control_order": 1, "num_segments": 5, "order": 3, "solve_for_distance": False, @@ -48,7 +48,6 @@ "user_options": { "optimize_mach": False, "optimize_altitude": False, - "polynomial_control_order": 1, "num_segments": 5, "order": 3, "solve_for_distance": False, @@ -72,7 +71,6 @@ "user_options": { "optimize_mach": False, "optimize_altitude": False, - "polynomial_control_order": 1, "num_segments": 5, "order": 3, "solve_for_distance": False, @@ -94,6 +92,56 @@ "post_mission": { "include_landing": False, "constrain_range": True, - "target_range": (1906, "nmi"), + "target_range": (1906., "nmi"), }, } + + +def phase_info_parameterization(phase_info, post_mission_info, aviary_inputs): + """ + Modify the values in the phase_info dictionary to accommodate different values + for the following mission design inputs: cruise altitude, cruise Mach number, + cruise range, design gross mass. + + Parameters + ---------- + phase_info : dict + Dictionary of phase settings for a mission profile + aviary_inputs : + Object containing values and units for all aviary inputs and options + + Returns + ------- + dict + Modified phase_info that has been changed to match the new mission + parameters + """ + + alt_cruise = aviary_inputs.get_val(Mission.Design.CRUISE_ALTITUDE, units='ft') + mach_cruise = aviary_inputs.get_val(Mission.Summary.CRUISE_MACH) + + # Range + old_range_cruise, range_units = post_mission_info['target_range'] + range_cruise = aviary_inputs.get_val(Mission.Design.RANGE, units=range_units) + print(old_range_cruise, range_cruise) + if range_cruise != old_range_cruise: + new_val = post_mission_info['target_range'][0] * range_cruise / old_range_cruise + post_mission_info['target_range'] = (new_val, range_units) + + # Altitude + old_alt_cruise = 32000. + if alt_cruise != old_alt_cruise: + phase_info['climb']['user_options']['final_altitude'] = (alt_cruise, 'ft') + phase_info['cruise']['user_options']['initial_altitude'] = (alt_cruise, 'ft') + phase_info['cruise']['user_options']['final_altitude'] = (alt_cruise, 'ft') + phase_info['descent']['user_options']['initial_altitude'] = (alt_cruise, 'ft') + + # Mach + old_mach_cruise = 0.72 + if mach_cruise != old_mach_cruise: + phase_info['climb']['user_options']['final_mach'] = (mach_cruise, "unitless") + phase_info['cruise']['user_options']['initial_mach'] = (mach_cruise, "unitless") + phase_info['cruise']['user_options']['final_mach'] = (mach_cruise, "unitless") + phase_info['descent']['user_options']['initial_mach'] = (mach_cruise, "unitless") + + return phase_info, post_mission_info diff --git a/aviary/interface/default_phase_info/two_dof.py b/aviary/interface/default_phase_info/two_dof.py index a34a5098d..c1733d16b 100644 --- a/aviary/interface/default_phase_info/two_dof.py +++ b/aviary/interface/default_phase_info/two_dof.py @@ -306,7 +306,7 @@ } -def phase_info_parameterization(phase_info, aviary_inputs): +def phase_info_parameterization(phase_info, post_mission_info, aviary_inputs): """ Modify the values in the phase_info dictionary to accomodate different values for the following mission design inputs: cruise altitude, cruise mach number, @@ -383,4 +383,4 @@ def phase_info_parameterization(phase_info, aviary_inputs): phase_info['cruise']['initial_guesses']['mach'] = (mach_cruise, 'unitless') - return phase_info + return phase_info, post_mission_info diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index eec2e2f97..701927249 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -951,8 +951,9 @@ def add_phases(self, phase_info_parameterization=None): traj: The Dymos Trajectory object containing the added mission phases. """ if phase_info_parameterization is not None: - self.phase_info = phase_info_parameterization(self.phase_info, - self.aviary_inputs) + self.phase_info, self.post_mission_info = phase_info_parameterization(self.phase_info, + self.post_mission_info, + self.aviary_inputs) phase_info = self.phase_info @@ -2385,7 +2386,8 @@ def _add_flops_landing_systems(self): 'traj.climb.initial_states:distance') # Create an ExecComp to compute the difference in mach - mach_diff_comp = om.ExecComp('mach_difference = final_mach - initial_mach') + mach_diff_comp = om.ExecComp( + 'mach_resid_for_connecting_takeoff = final_mach - initial_mach') self.model.add_subsystem('mach_diff_comp', mach_diff_comp) # Connect the inputs to the mach difference component @@ -2394,11 +2396,12 @@ def _add_flops_landing_systems(self): 'mach_diff_comp.initial_mach', src_indices=[0]) # Add constraint for mach difference - self.model.add_constraint('mach_diff_comp.mach_difference', equals=0.0) + self.model.add_constraint( + 'mach_diff_comp.mach_resid_for_connecting_takeoff', equals=0.0) # Similar steps for altitude difference alt_diff_comp = om.ExecComp( - 'altitude_difference = final_altitude - initial_altitude', units='ft') + 'altitude_resid_for_connecting_takeoff = final_altitude - initial_altitude', units='ft') self.model.add_subsystem('alt_diff_comp', alt_diff_comp) self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, @@ -2406,7 +2409,8 @@ def _add_flops_landing_systems(self): self.model.connect('traj.climb.control_values:altitude', 'alt_diff_comp.initial_altitude', src_indices=[0]) - self.model.add_constraint('alt_diff_comp.altitude_difference', equals=0.0) + self.model.add_constraint( + 'alt_diff_comp.altitude_resid_for_connecting_takeoff', equals=0.0) self.model.connect('traj.descent.states:mass', Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1]) diff --git a/aviary/interface/test/test_phase_info.py b/aviary/interface/test/test_phase_info.py index 6fab50d7a..c8d8cc62c 100644 --- a/aviary/interface/test/test_phase_info.py +++ b/aviary/interface/test/test_phase_info.py @@ -7,13 +7,14 @@ from openmdao.utils.assert_utils import assert_near_equal -from aviary.interface.default_phase_info.two_dof import phase_info as ph_in_gasp -from aviary.interface.default_phase_info.two_dof import phase_info_parameterization as phase_info_parameterization_gasp +from aviary.interface.default_phase_info.two_dof import phase_info as ph_in_two_dof +from aviary.interface.default_phase_info.two_dof import phase_info_parameterization as phase_info_parameterization_two_dof +from aviary.interface.default_phase_info.height_energy import phase_info as ph_in_height_energy +from aviary.interface.default_phase_info.height_energy import phase_info_parameterization as phase_info_parameterization_height_energy from aviary.interface.methods_for_level2 import AviaryProblem from aviary.mission.flops_based.phases.phase_builder_base import \ PhaseBuilderBase as PhaseBuilder, phase_info_to_builder -# must keep this import to register the phase from aviary.variable_info.variables import Aircraft, Mission @@ -85,8 +86,8 @@ def test_default_phase_height_energy(self): class TestParameterizePhaseInfo(unittest.TestCase): - def test_phase_info_parameterization_gasp(self): - phase_info = deepcopy(ph_in_gasp) + def test_phase_info_parameterization_two_dof(self): + phase_info = deepcopy(ph_in_two_dof) prob = AviaryProblem() @@ -102,7 +103,7 @@ def test_phase_info_parameterization_gasp(self): prob.aviary_inputs.set_val(Mission.Design.MACH, 0.6, 'unitless') prob.add_pre_mission_systems() - prob.add_phases(phase_info_parameterization=phase_info_parameterization_gasp) + prob.add_phases(phase_info_parameterization=phase_info_parameterization_two_dof) prob.add_post_mission_systems() prob.link_phases() @@ -121,7 +122,44 @@ def test_phase_info_parameterization_gasp(self): assert_near_equal(prob.get_val("traj.cruise.rhs.mach")[0], 0.6) + def test_phase_info_parameterization_height_energy(self): + phase_info = deepcopy(ph_in_height_energy) + + prob = AviaryProblem() + + csv_path = "models/test_aircraft/aircraft_for_bench_FwFm.csv" + + prob.load_inputs(csv_path, phase_info) + prob.check_and_preprocess_inputs() + + # We can set some crazy vals, since we aren't going to optimize. + prob.aviary_inputs.set_val(Mission.Design.RANGE, 5000., 'km') + prob.aviary_inputs.set_val(Mission.Design.CRUISE_ALTITUDE, 31000., units='ft') + prob.aviary_inputs.set_val(Mission.Design.GROSS_MASS, 195000., 'lbm') + prob.aviary_inputs.set_val(Mission.Summary.CRUISE_MACH, 0.6, 'unitless') + + prob.add_pre_mission_systems() + prob.add_phases( + phase_info_parameterization=phase_info_parameterization_height_energy) + prob.add_post_mission_systems() + + prob.link_phases() + + prob.setup() + prob.set_initial_guesses() + + prob.run_model() + + range_resid = prob.get_val(Mission.Constraints.RANGE_RESIDUAL, units='km')[-1] + assert_near_equal(range_resid, 5000.0 - 1.e-3) + assert_near_equal(prob.get_val("traj.cruise.timeseries.polynomial_controls:altitude", units='ft')[0], + 31000.0) + assert_near_equal(prob.get_val("traj.cruise.timeseries.polynomial_controls:mach")[0], + 0.6) + # To run the tests if __name__ == '__main__': unittest.main() + # test = TestPhaseInfo() + # test.test_default_phase_height_energy() diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py index d84d9860b..dd07de05f 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_solved_aero_group.py @@ -187,80 +187,6 @@ def test_solved_aero_pass_polar_unique_abscissa(self): assert_near_equal(CL_pass, CL_base, 1e-6) assert_near_equal(CD_pass, CD_base, 1e-6) - def test_solved_aero_pass_polar_unique_abscissa(self): - # Solved Aero with shortened lists of table abscissa. - local_phase_info = deepcopy(phase_info) - - prob = AviaryProblem() - - csv_path = "subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv" - - prob.load_inputs(csv_path, local_phase_info) - prob.add_pre_mission_systems() - prob.add_phases() - prob.add_post_mission_systems() - - prob.link_phases() - - prob.setup() - - prob.set_initial_guesses() - - prob.run_model() - - CL_base = prob.get_val("traj.cruise.rhs_all.core_aerodynamics.tabular_aero.CL") - CD_base = prob.get_val("traj.cruise.rhs_all.core_aerodynamics.tabular_aero.CD") - - # Lift and Drag polars passed from external component in static. - - ph_in = deepcopy(phase_info) - - alt = np.array([0., 3000., 6000., 9000., 12000., 15000., 18000., 21000., - 24000., 27000., 30000., 33000., 36000., 38000., 42000.]) - mach = np.array([0., 0.2, 0.4, 0.5, 0.6, 0.7, 0.75, 0.8, 0.85, 0.9]) - alpha = np.array([-2., 0., 2., 4., 6., 8., 10.]) - - polar_builder = FakeDragPolarBuilder(name="aero", altitude=alt, mach=mach, - alpha=alpha) - aero_data = NamedValues() - aero_data.set_val('altitude', alt, 'ft') - aero_data.set_val('mach', mach, 'unitless') - aero_data.set_val('angle_of_attack', alpha, 'deg') - - subsystem_options = {'method': 'solved_alpha', - 'aero_data': aero_data, - 'training_data': True} - ph_in['pre_mission']['external_subsystems'] = [polar_builder] - - ph_in['cruise']['subsystem_options'] = {'core_aerodynamics': subsystem_options} - - prob = AviaryProblem() - - prob.load_inputs(csv_path, ph_in) - - prob.aviary_inputs.set_val(Aircraft.Design.LIFT_POLAR, - np.zeros_like(CL), units='unitless') - prob.aviary_inputs.set_val(Aircraft.Design.DRAG_POLAR, - np.zeros_like(CD), units='unitless') - - prob.add_pre_mission_systems() - prob.add_phases() - prob.add_post_mission_systems() - - prob.link_phases() - - prob.setup() - - prob.set_initial_guesses() - - prob.run_model() - - CL_pass = prob.get_val("traj.cruise.rhs_all.core_aerodynamics.tabular_aero.CL") - CD_pass = prob.get_val("traj.cruise.rhs_all.core_aerodynamics.tabular_aero.CD") - - assert_near_equal(CL_pass, CL_base, 1e-6) - assert_near_equal(CD_pass, CD_base, 1e-6) - class FakeCalcDragPolar(om.ExplicitComponent): """ @@ -349,4 +275,6 @@ def build_pre_mission(self, aviary_inputs): if __name__ == "__main__": - unittest.main() + # unittest.main() + test = TestSolvedAero() + test.test_solved_aero_pass_polar_unique_abscissa() diff --git a/aviary/subsystems/propulsion/test/test_custom_engine_model.py b/aviary/subsystems/propulsion/test/test_custom_engine_model.py index b079f01fb..2222168a5 100644 --- a/aviary/subsystems/propulsion/test/test_custom_engine_model.py +++ b/aviary/subsystems/propulsion/test/test_custom_engine_model.py @@ -167,8 +167,7 @@ def test_custom_engine(self): prob.load_inputs("models/test_aircraft/aircraft_for_bench_GwFm.csv", phase_info, engine_builder=SimpleTestEngine()) - -# Preprocess inputs + # Preprocess inputs prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index c60146b11..31761bd19 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -63,4 +63,6 @@ def test_zero_iters_solved(self): if __name__ == "__main__": - unittest.main() + # unittest.main() + test = SolvedProblemTestCase() + test.test_zero_iters_solved() diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index 7fff9058e..bd73cb077 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -343,7 +343,7 @@ def bench_test_swap_4_FwFm(self): "post_mission": { "include_landing": True, "constrain_range": True, - "target_range": (3368.0, "nmi"), + "target_range": (3375.0, "nmi"), }, } From 7f9dc5b63dc6af6a6056c77dfa1e2f0c3d6bc3f1 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 19 Jan 2024 11:58:51 -0600 Subject: [PATCH 127/188] Fixed doc build --- aviary/mission/flops_based/ode/mission_ODE.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/mission/flops_based/ode/mission_ODE.py b/aviary/mission/flops_based/ode/mission_ODE.py index 2a6dcccd4..60cfba24e 100644 --- a/aviary/mission/flops_based/ode/mission_ODE.py +++ b/aviary/mission/flops_based/ode/mission_ODE.py @@ -41,7 +41,7 @@ def initialize(self): desc='flag to use actual takeoff mass in the climb phase, otherwise assume 100 kg fuel burn') self.options.declare( 'throttle_enforcement', default='path_constraint', - values=['path_constraint', 'boundary_constraint', 'bounded'], + values=['path_constraint', 'boundary_constraint', 'bounded', None], desc='flag to enforce throttle constraints on the path or at the segment boundaries or using solver bounds' ) From 32067f85f94fb7f05180fd4d7f5ba601e8e24796 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 19 Jan 2024 13:45:32 -0600 Subject: [PATCH 128/188] Removed unnecessary files --- .../phases/benchmark/test_bench_ascent.py | 3 +- .../gasp_based/phases/run_phases/run_accel.py | 98 ------- .../gasp_based/phases/run_phases/run_climb.py | 277 ------------------ .../phases/run_phases/run_groundroll.py | 136 --------- .../phases/run_phases/run_rotation.py | 53 ---- .../phases/run_phases/run_takeoff.py | 197 ------------- 6 files changed, 2 insertions(+), 762 deletions(-) delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_accel.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_climb.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_groundroll.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_rotation.py delete mode 100644 aviary/mission/gasp_based/phases/run_phases/run_takeoff.py diff --git a/aviary/mission/gasp_based/phases/benchmark/test_bench_ascent.py b/aviary/mission/gasp_based/phases/benchmark/test_bench_ascent.py index 7d6b31633..bc281dfef 100644 --- a/aviary/mission/gasp_based/phases/benchmark/test_bench_ascent.py +++ b/aviary/mission/gasp_based/phases/benchmark/test_bench_ascent.py @@ -54,4 +54,5 @@ def bench_test_ascent(self): if __name__ == "__main__": - unittest.main() + test = AccelPhaseTestCase() + test.bench_test_ascent() diff --git a/aviary/mission/gasp_based/phases/run_phases/run_accel.py b/aviary/mission/gasp_based/phases/run_phases/run_accel.py deleted file mode 100644 index 1031e215e..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_accel.py +++ /dev/null @@ -1,98 +0,0 @@ -import dymos as dm -import matplotlib.pyplot as plt -import openmdao.api as om -import numpy as np - -from aviary.mission.gasp_based.phases.accel_phase import AccelPhase -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 - - -def run_accel(): - # Column-wise data from CSV - time_GASP = np.array([0.182, 0.188]) - distance_GASP = np.array([0.00, 1.57]) - weight_GASP = np.array([174974., 174878.]) - TAS_GASP = np.array([185., 252.]) - EAS_GASP = np.array([184., 250.]) - - time_GASP = time_GASP * 3600 - time_GASP = time_GASP - time_GASP[0] - - prob = om.Problem(model=om.Group()) - - prob.driver = om.pyOptSparseDriver() - prob.driver.options["optimizer"] = "SNOPT" - prob.driver.opt_settings["Major iterations limit"] = 100 - prob.driver.opt_settings["Major optimality tolerance"] = 5.0e-3 - prob.driver.opt_settings["Major feasibility tolerance"] = 1e-6 - prob.driver.opt_settings["iSumm"] = 6 - prob.driver.declare_coloring() - - transcription = dm.Radau(num_segments=15, order=4, compressed=False) - - aviary_options = get_option_defaults() - - phase_name = "accel" - phase_options = { - 'user_options': { - 'alt': (500, 'ft'), - 'EAS_constraint_eq': (250, 'kn'), - 'fix_initial': True, - 'time_initial_bounds': ((0, 0), 's'), - 'duration_bounds': ((0, 36_000), 's'), - 'duration_ref': (1000, 's'), - 'TAS_lower': (0, 'kn'), - 'TAS_upper': (1000, 'kn'), - 'TAS_ref': (250, 'kn'), - 'TAS_ref0': (150, 'kn'), - 'mass_lower': (0, 'lbm'), - 'mass_upper': (None, 'lbm'), - 'mass_ref': (175_500, 'lbm'), - 'distance_lower': (0, 'NM'), - 'distance_upper': (150, 'NM'), - 'distance_ref': (1, 'NM'), - 'distance_defect_ref': (1, 'NM'), - } - } - - phase_object = AccelPhase.from_phase_info( - phase_name, phase_options, default_mission_subsystems, transcription=transcription) - accel = phase_object.build_phase(aviary_options=aviary_options) - - accel.add_parameter( - Aircraft.Wing.AREA, opt=False, units="ft**2", val=1370.0, static_target=True - ) - - prob.model.add_subsystem(name='accel', subsys=accel) - accel.add_timeseries_output("EAS", output_name="EAS", units="kn") - accel.add_timeseries_output("TAS", output_name="TAS", units="kn") - accel.add_timeseries_output("mass", output_name="mass", units="lbm") - accel.add_timeseries_output(Dynamic.Mission.DISTANCE, - output_name=Dynamic.Mission.DISTANCE, units="NM") - accel.timeseries_options['use_prefix'] = True - - accel.add_objective("time", loc="final") - prob.model.linear_solver.options["iprint"] = 0 - prob.model.nonlinear_solver.options["iprint"] = 0 - - prob.model.options["assembled_jac_type"] = "csc" - prob.model.linear_solver = om.DirectSolver(assemble_jac=True) - - prob.set_solver_print(level=0) - - prob.setup() - prob.set_val("accel.states:mass", accel.interp("mass", ys=[174974, 174878])) - prob.set_val("accel.states:TAS", accel.interp("TAS", ys=[185, 252])) - prob.set_val("accel.states:distance", accel.interp( - Dynamic.Mission.DISTANCE, ys=[0, 1.57])) - prob.set_val("accel.t_duration", 1000) - prob.set_val("accel.t_initial", 0) - - dm.run_problem(problem=prob, simulate=True) - print() - print("Done Running Model, Now Simulating") - print() - - return prob diff --git a/aviary/mission/gasp_based/phases/run_phases/run_climb.py b/aviary/mission/gasp_based/phases/run_phases/run_climb.py deleted file mode 100644 index 003222ec4..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_climb.py +++ /dev/null @@ -1,277 +0,0 @@ -import argparse -import os - -import dymos as dm -import matplotlib.pyplot as plt -import openmdao.api as om -import pandas as pd - -from aviary.mission.gasp_based.ode.params import ParamPort -from aviary.mission.gasp_based.phases.climb_phase import get_climb -from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Dynamic - -thisdir = os.path.dirname(__file__) -def_outdir = os.path.join(thisdir, "output") - -gaspdata_dir = os.path.join(thisdir, "..", "..", "problem", - "large_single_aisle_validation_data") - -theta_max = 15 -TAS_violation_max = 0 -use_surrogate = True - -ode_args = {} - -# name: (gaspname, path, units) -varinfo = { - "time": ("TIME", "time", "s"), - Dynamic.Mission.ALTITUDE: ("ALT", "states:altitude", "ft"), - "mass": ("MASS", "states:mass", "lbm"), - Dynamic.Mission.DISTANCE: (Dynamic.Mission.DISTANCE, "states:distance", "NM"), - Dynamic.Mission.MACH: ("MACH", Dynamic.Mission.MACH, None), - "EAS": ("EAS", "EAS", "kn"), - "alpha": ("ALPHA", "alpha", "deg"), - Dynamic.Mission.FLIGHT_PATH_ANGLE: ("GAMMA", Dynamic.Mission.FLIGHT_PATH_ANGLE, "deg"), - "theta": ("FUSANGLE", "theta", "deg"), - "TAS_violation": (None, "TAS_violation", "kn"), - "CL": ("CL", "CL", None), - "CD": ("CD", "CD", None), - Dynamic.Mission.THRUST_TOTAL: ("THRUST", Dynamic.Mission.THRUST_TOTAL, "lbf"), -} - - -def setup_climb1(): - prob = om.Problem(model=om.Group(), name="main") - setup_driver(prob) - - ode_args["aviary_options"] = get_option_defaults() - - transcription = dm.Radau(num_segments=1, order=5, compressed=False) - climb1 = get_climb( - ode_args=ode_args, - transcription=transcription, - fix_initial=True, - alt_lower=0, - alt_upper=11000, - mass_lower=0, - mass_upper=200_000, - distance_lower=0, - distance_upper=300, - time_initial_bounds=(0, 0), - duration_bounds=(1.1, 36_000), - EAS_target=250, - mach_cruise=0.8, - target_mach=False, - final_alt=10000, - alt_ref=10000, - mass_ref=200000, - distance_ref=300, - ) - prob.model.add_subsystem(name="climb1", subsys=climb1) - - # add all params and promote them to prob.model level - ParamPort.promote_params(prob.model, phases=["climb1"]) - ParamPort.set_default_vals(prob.model) - - climb1.add_objective("time", loc="final") - - prob.model.options["assembled_jac_type"] = "csc" - prob.model.linear_solver = om.LinearRunOnce() - - prob.setup() - - prob.set_val("climb1.controls:throttle", - climb1.interp("throttle", ys=[1.0, 1.0])) - prob.set_val("climb1.states:mass", climb1.interp("mass", ys=[174878, 174219])) - prob.set_val( - "climb1.timeseries:altitude", climb1.interp( - Dynamic.Mission.ALTITUDE, ys=[ - 500, 10000])) - prob.set_val("climb1.states:distance", climb1.interp( - Dynamic.Mission.DISTANCE, ys=[2, 15])) - prob.set_val("climb1.t_duration", 1000) - prob.set_val("climb1.t_initial", 0) - - return prob - - -def setup_climb2(): - prob = om.Problem(model=om.Group(), name="main") - - setup_driver(prob) - - ode_args["aviary_options"] = get_option_defaults() - - transcription = dm.Radau(num_segments=3, order=3, compressed=False) - climb2 = get_climb( - ode_args=ode_args, - transcription=transcription, - fix_initial=True, - alt_lower=9000, - alt_upper=60000, - mass_lower=0, - mass_upper=200_000, - distance_lower=0, - distance_upper=300, - time_initial_bounds=(0, 0), - duration_bounds=(2, 36_000), - EAS_target=270, - mach_cruise=0.8, - target_mach=True, - final_alt=37500, - alt_ref=40000, - mass_ref=200000, - distance_ref=300, - required_available_climb_rate=300, - ) - prob.model.add_subsystem(name="climb2", subsys=climb2) - - # fixed initial mass, so max final mass is equivalent to min fuel burn - climb2.add_objective("mass", loc="final", ref=-1) - - # add all params and promote them to prob.model level - ParamPort.promote_params(prob.model, phases=["climb2"]) - ParamPort.set_default_vals(prob.model) - - prob.model.options["assembled_jac_type"] = "csc" - prob.model.linear_solver = om.LinearRunOnce() - - prob.setup() - prob.set_val("climb2.states:mass", climb2.interp("mass", ys=[174219, 171481])) - prob.set_val("climb2.controls:throttle", - climb2.interp("throttle", ys=[1.0, 1.0])) - prob.set_val( - "climb2.states:altitude", climb2.interp( - Dynamic.Mission.ALTITUDE, ys=[ - 10000, 37500])) - prob.set_val("climb2.states:distance", climb2.interp( - Dynamic.Mission.DISTANCE, ys=[15, 154])) - prob.set_val("climb2.t_duration", 1500) - prob.set_val("climb2.t_initial", 0) - - return prob - - -def setup_driver(prob): - prob.driver = om.pyOptSparseDriver() - prob.driver.options["optimizer"] = "SNOPT" - prob.driver.opt_settings["Major iterations limit"] = 100 - prob.driver.opt_settings["Major optimality tolerance"] = 5.0e-3 - prob.driver.opt_settings["Major feasibility tolerance"] = 1e-6 - prob.driver.opt_settings["iSumm"] = 6 - prob.driver.declare_coloring() - prob.set_solver_print(level=0) - - -def make_recorder_filepaths(phasename, outdir): - return ( - os.path.join(outdir, f"{phasename}_prob.sql"), - os.path.join(outdir, f"{phasename}_sim.sql"), - ) - - -def run_phase(phasename, prob, outdir=def_outdir): - os.makedirs(outdir, exist_ok=True) - prob_rec_fp = make_recorder_filepaths(phasename, outdir)[0] - - recorder = om.SqliteRecorder(prob_rec_fp) - prob.driver.add_recorder(recorder) - prob.driver.recording_options["includes"] = ["*timeseries*"] - prob.add_recorder(recorder) - - print("\nRunning driver...\n") - prob.run_driver() - - prob.record("final") - prob.cleanup() - - return prob - - -def sim_phase(phasename, prob, outdir=def_outdir): - os.makedirs(outdir, exist_ok=True) - sim_rec_fp = make_recorder_filepaths(phasename, outdir)[1] - - print("\nSimulating...\n") - sys = getattr(prob.model, phasename) - prob.set_solver_print(level=-1) - sys.rhs_all.prop.set_solver_print(level=-1, depth=1e99) - simprob = sys.simulate(atol=1e-6, rtol=1e-6, record_file=sim_rec_fp) - - return simprob - - -def load_phase(phasename, outdir=def_outdir): - for fp in make_recorder_filepaths(phasename, outdir): - cr = om.CaseReader(fp) - yield cr.get_case("final") - - -def load_phase_nosim(phasename, outdir=def_outdir): - fp = make_recorder_filepaths(phasename, outdir)[0] - cr = om.CaseReader(fp) - return cr.get_case("final") - - -def gen_plots(phasename, probdata, simdata, plot_dir, show=False): - gaspdata = pd.read_csv(os.path.join(gaspdata_dir, f"{phasename}_data.csv")) - # gasp data in hours, convert to seconds, reference to 0 - gaspdata["TIME"] = 3600 * (gaspdata["TIME"] - gaspdata["TIME"][0]) - - def gen_plot(title, varnames): - fig, axs = plt.subplots(len(varnames), 1, sharex=True) - fig.suptitle(title) - - if len(varnames) == 1: - axs = [axs] - - gaspname, path, units = varinfo["time"] - path = f"{phasename}.timeseries.{path}" - t_solved = probdata.get_val(path, units=units) - if simdata: - t_sim = simdata.get_val(path, units=units) - t_gasp = gaspdata[gaspname] - - for ax, varname in zip(axs, varnames): - gaspname, path, units = varinfo[varname] - path = f"{phasename}.timeseries.{path}" - ax.plot(t_solved, probdata.get_val(path, units=units), "bo", label="opt") - if simdata: - ax.plot(t_sim, simdata.get_val(path, units=units), "b--", label="sim") - if gaspname is not None: - ax.plot(t_gasp, gaspdata[gaspname], "k-", label="GASP") - ylabel = f"{varname}" - if units: - ylabel += f" ({units})" - ax.set_ylabel(ylabel) - - axs[0].legend() - axs[-1].set_xlabel("time (s)") - - plt.tight_layout() - - return fig - - gen_plot("States", [Dynamic.Mission.ALTITUDE, "mass", Dynamic.Mission.DISTANCE]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_states.pdf")) - - gen_plot("Speeds", [Dynamic.Mission.MACH, "EAS"]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_speeds.pdf")) - - gen_plot("Angles", ["alpha", Dynamic.Mission.FLIGHT_PATH_ANGLE]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_angles.pdf")) - - fig = gen_plot("Constraints", ["TAS_violation", "theta"]) - fig.axes[0].axhline(theta_max, color="r", linestyle=":") - fig.axes[1].axhline(TAS_violation_max, color="r", linestyle=":") - plt.savefig(os.path.join(plot_dir, f"{phasename}_constraints.pdf")) - - gen_plot("Aero", ["CL", "CD"]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_aero.pdf")) - - gen_plot("Thrust", [Dynamic.Mission.THRUST_TOTAL]) - plt.savefig(os.path.join(plot_dir, f"{phasename}_thrust.pdf")) - - if show: - plt.show() diff --git a/aviary/mission/gasp_based/phases/run_phases/run_groundroll.py b/aviary/mission/gasp_based/phases/run_phases/run_groundroll.py deleted file mode 100644 index f71e699ea..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_groundroll.py +++ /dev/null @@ -1,136 +0,0 @@ -import dymos as dm -import openmdao.api as om - -from aviary.constants import GRAV_ENGLISH_LBM, RHO_SEA_LEVEL_ENGLISH -from aviary.mission.gasp_based.phases.groundroll_phase import get_groundroll -from aviary.variable_info.variables import Aircraft, Mission -from aviary.variable_info.options import get_option_defaults - - -def run_groundroll(): - num_segments = 5 - transcription = dm.Radau( - num_segments=num_segments, order=3, compressed=True, solve_segments=False - ) - - ode_args = dict( - aviary_options=get_option_defaults() - ) - - groundroll = get_groundroll( - fix_initial=True, - fix_initial_mass=True, - connect_initial_mass=False, - ode_args=ode_args, - transcription=transcription, - ) - - p = om.Problem() - - # calculate speed at which to initiate rotation - p.model.add_subsystem( - "vrot", - om.ExecComp( - "Vrot = ((2 * mass * g) / (rho * wing_area * CLmax))**0.5 + dV1 + dVR", - Vrot={"units": "ft/s"}, - mass={"units": "lbm"}, - g={"units": "lbf/lbm", "val": GRAV_ENGLISH_LBM}, - rho={"units": "slug/ft**3", "val": RHO_SEA_LEVEL_ENGLISH}, - wing_area={"units": "ft**2"}, - dV1={ - "units": "ft/s", - "desc": "Increment of engine failure decision speed above stall", - }, - dVR={ - "units": "ft/s", - "desc": "Increment of takeoff rotation speed above engine failure " - "decision speed", - }, - ), - promotes_inputs=[ - ("wing_area", Aircraft.Wing.AREA), - "mass", - "dV1", - "dVR", - ("CLmax", Mission.Takeoff.LIFT_COEFFICIENT_MAX), - ], - promotes_outputs=[("Vrot", Mission.Takeoff.ROTATION_VELOCITY)] - ) - - traj = p.model.add_subsystem("traj", dm.Trajectory()) - traj.add_phase("groundroll", groundroll) - - p.model.add_subsystem( - "groundroll_boundary", - om.EQConstraintComp( - "TAS", - eq_units="ft/s", - normalize=True, - add_constraint=True, - ), - ) - p.model.connect(Mission.Takeoff.ROTATION_VELOCITY, "groundroll_boundary.rhs:TAS") - p.model.connect("traj.groundroll.states:TAS", "groundroll_boundary.lhs:TAS", - src_indices=[-1], - flat_src_indices=True, - ) - - groundroll.add_objective('time', ref=1.0) - - p.driver = om.pyOptSparseDriver() - p.driver.declare_coloring() - p.driver.options["print_results"] = p.comm.rank == 0 - - optimizer = 'IPOPT' - print_opt_iters = True - - p.driver.options["optimizer"] = optimizer - - if optimizer == "SNOPT": - p.driver.opt_settings["Major optimality tolerance"] = 3e-4 - p.driver.opt_settings["Major feasibility tolerance"] = 1e-6 - p.driver.opt_settings["Function precision"] = 1e-6 - p.driver.opt_settings["Linesearch tolerance"] = 0.99 - if print_opt_iters: - p.driver.opt_settings["iSumm"] = 6 - p.driver.opt_settings["Major iterations limit"] = 75 - elif optimizer == "IPOPT": - p.driver.opt_settings["max_iter"] = 500 - p.driver.opt_settings["tol"] = 1e-5 - if print_opt_iters: - p.driver.opt_settings["print_level"] = 5 - p.driver.opt_settings[ - "nlp_scaling_method" - ] = "gradient-based" # for faster convergence - p.driver.opt_settings["alpha_for_y"] = "safer-min-dual-infeas" - p.driver.opt_settings["mu_strategy"] = "monotone" - p.driver.opt_settings["bound_mult_init_method"] = "mu-based" - - p.set_solver_print(level=-1) - - p.setup() - - p.set_val("traj.groundroll.states:TAS", 0, units="kn") - p.set_val( - "traj.groundroll.states:mass", - groundroll.interp("mass", [175100, 174000]), - units="lbm", - ) - p.set_val('mass', 175100, units='lbm') - p.set_val("dV1", 10, units="kn") - p.set_val("dVR", 5, units="kn") - p.set_val(Aircraft.Wing.AREA, units="ft**2", val=1370) - p.set_val(Mission.Takeoff.LIFT_COEFFICIENT_MAX, 2.1886) - - p.set_val( - "traj.groundroll.states:distance", - groundroll.interp(Dynamic.Mission.DISTANCE, [0, 1000]), - units="ft", - ) - - p.set_val("traj.groundroll.t_duration", 27.7) - - p.run_driver() - # simout = traj.simulate(atol=1e-6, rtol=1e-6) - - return p diff --git a/aviary/mission/gasp_based/phases/run_phases/run_rotation.py b/aviary/mission/gasp_based/phases/run_phases/run_rotation.py deleted file mode 100644 index ef6bd5b49..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_rotation.py +++ /dev/null @@ -1,53 +0,0 @@ -import dymos as dm -import openmdao.api as om - -from aviary.mission.gasp_based.phases.rotation_phase import get_rotation -from aviary.variable_info.options import get_option_defaults - - -def run_rotation(make_plots=False): - rotation_trans = dm.Radau( - num_segments=1, order=3, compressed=True, solve_segments=False - ) - rotation = get_rotation( - ode_args=get_option_defaults(), - fix_initial=True, - connect_initial_mass=False, - transcription=rotation_trans, - ) - - p = om.Problem() - traj = p.model.add_subsystem("traj", dm.Trajectory()) - traj.add_phase("rotation", rotation) - - p.driver = om.pyOptSparseDriver() - p.driver.options["optimizer"] = "SNOPT" - p.driver.opt_settings["iSumm"] = 6 - p.driver.declare_coloring() - - p.model.add_objective( - "traj.rotation.timeseries.states:mass", index=-1, ref=1.4e5, ref0=1.3e5 - ) - p.set_solver_print(level=-1) - - p.setup() - - p.set_val( - "traj.rotation.states:alpha", rotation.interp("alpha", [0, 2.5]), units="deg" - ) - p.set_val("traj.rotation.states:TAS", 143, units="kn") - p.set_val( - "traj.rotation.states:mass", - rotation.interp("mass", [174975.12776915, 174000]), - units="lbm", - ) - p.set_val( - "traj.rotation.states:distance", - rotation.interp(Dynamic.Mission.DISTANCE, [3680.37217765, 4000]), - units="ft", - ) - p.set_val("traj.rotation.t_duration", 50.0) - - dm.run_problem(p, simulate=True, make_plots=make_plots) - - return p diff --git a/aviary/mission/gasp_based/phases/run_phases/run_takeoff.py b/aviary/mission/gasp_based/phases/run_phases/run_takeoff.py deleted file mode 100644 index 41c33ddfe..000000000 --- a/aviary/mission/gasp_based/phases/run_phases/run_takeoff.py +++ /dev/null @@ -1,197 +0,0 @@ -import dymos as dm -import openmdao.api as om - -from aviary.mission.gasp_based.phases.ascent_phase import get_ascent -from aviary.mission.gasp_based.phases.groundroll_phase import get_groundroll -from aviary.mission.gasp_based.phases.rotation_phase import get_rotation -from aviary.mission.gasp_based.polynomial_fit import PolynomialFit -from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Dynamic, Mission - - -def run_takeoff(make_plots=False): - option_defaults = get_option_defaults() - groundroll_trans = dm.Radau( - num_segments=1, order=3, compressed=True, solve_segments=False - ) - groundroll = get_groundroll( - ode_args=option_defaults, - fix_initial=True, - connect_initial_mass=False, - transcription=groundroll_trans, - ) - - p = om.Problem() - - p.model.add_subsystem( - "event_xform", - om.ExecComp( - ["t_init_gear=m*tau_gear+b", "t_init_flaps=m*tau_flaps+b"], units="s" - ), - promotes_inputs=[ - "tau_gear", - "tau_flaps", - ("m", Mission.Takeoff.ASCENT_DURATION), - ("b", "ascent:t_initial"), - ], - promotes_outputs=["t_init_gear", "t_init_flaps"], - ) - - p.model.add_design_var("ascent:t_initial", lower=0, upper=100) - p.model.add_design_var(Mission.Takeoff.ASCENT_DURATION, lower=1, upper=1000) - - traj = p.model.add_subsystem("traj", dm.Trajectory()) - traj.add_phase("groundroll", groundroll) - - rotation_trans = dm.Radau( - num_segments=1, order=3, compressed=True, solve_segments=False - ) - rotation = get_rotation( - ode_args=option_defaults, - fix_initial=False, - connect_initial_mass=False, - transcription=rotation_trans, - ) - traj.add_phase("rotation", rotation) - traj.link_phases(["groundroll", "rotation"], [ - "time", "TAS", "mass", Dynamic.Mission.DISTANCE]) - - ascent_trans = dm.Radau( - num_segments=2, order=5, compressed=True, solve_segments=False - ) - ascent = get_ascent( - ode_args=option_defaults, - fix_initial=False, - connect_initial_mass=False, - transcription=ascent_trans, - ) - traj.add_phase("ascent", ascent) - traj.link_phases( - ["rotation", "ascent"], ["time", "TAS", "mass", Dynamic.Mission.DISTANCE, "alpha"] - ) - p.model.promotes( - "traj", - inputs=[ - ("ascent.parameters:t_init_gear", "t_init_gear"), - ("ascent.parameters:t_init_flaps", "t_init_flaps"), - ("ascent.t_initial", "ascent:t_initial"), - ("ascent.t_duration", Mission.Takeoff.ASCENT_DURATION), - ], - ) - - p.model.promotes( - "traj", - inputs=[ - ( - "groundroll.parameters:" + Mission.Design.GROSS_MASS, - Mission.Design.GROSS_MASS, - ), - ( - "rotation.parameters:" + Mission.Design.GROSS_MASS, - Mission.Design.GROSS_MASS, - ), - ( - "ascent.parameters:" + Mission.Design.GROSS_MASS, - Mission.Design.GROSS_MASS, - ), - ], - ) - p.model.set_input_defaults(Mission.Design.GROSS_MASS, 175400, units="lbm") - - p.model.set_input_defaults("ascent:t_initial", val=10.0) - p.model.set_input_defaults(Mission.Takeoff.ASCENT_DURATION, val=30.0) - - ascent_tx = ascent.options["transcription"] - ascent_num_nodes = ascent_tx.grid_data.num_nodes - p.model.add_subsystem( - "h_fit", - PolynomialFit(N_cp=ascent_num_nodes), - promotes_inputs=["t_init_gear", "t_init_flaps"], - ) - p.model.connect("traj.ascent.timeseries.time", "h_fit.time_cp") - p.model.connect("traj.ascent.timeseries.states:altitude", "h_fit.h_cp") - - # TODO: re-parameterize time to be 0-1 (i.e. add a component that offsets by t_initial/t_duration) - p.model.add_design_var("tau_gear", lower=0.01, upper=0.75, units="s", ref=1) - p.model.add_constraint("h_fit.h_init_gear", equals=50.0, units="ft", ref=50.0) - - p.model.add_design_var("tau_flaps", lower=0.3, upper=1.0, units="s", ref=1) - p.model.add_constraint("h_fit.h_init_flaps", equals=400.0, units="ft", ref=400.0) - - p.model.add_objective( - "traj.ascent.timeseries.states:mass", index=-1, ref0=-1.747e5, ref=-1.749e5 - ) - - p.driver = om.pyOptSparseDriver() - p.driver.options["optimizer"] = "SNOPT" - p.driver.opt_settings["Major feasibility tolerance"] = 1.0e-7 - p.driver.opt_settings["Major optimality tolerance"] = 1.0e-2 - p.driver.opt_settings["Function precision"] = 1e-6 - p.driver.opt_settings["Linesearch tolerance"] = 0.95 - p.driver.opt_settings["iSumm"] = 6 - p.driver.declare_coloring() - - p.model.linear_solver = om.DirectSolver() - - p.setup() - - p.set_val("traj.groundroll.states:TAS", 0, units="kn") - p.set_val( - "traj.groundroll.states:mass", - groundroll.interp("mass", [175100, 174000]), - units="lbm", - ) - p.set_val( - "traj.groundroll.states:distance", - groundroll.interp(Dynamic.Mission.DISTANCE, [0, 1000]), - units="ft", - ) - p.set_val("traj.groundroll.t_duration", 50.0) - - p.set_val( - "traj.rotation.states:alpha", rotation.interp("alpha", [0, 2.5]), units="deg" - ) - p.set_val("traj.rotation.states:TAS", 143, units="kn") - p.set_val( - "traj.rotation.states:mass", - rotation.interp("mass", [174975.12776915, 174000]), - units="lbm", - ) - p.set_val( - "traj.rotation.states:distance", - rotation.interp(Dynamic.Mission.DISTANCE, [3680.37217765, 4000]), - units="ft", - ) - p.set_val("traj.rotation.t_duration", 50.0) - - p.set_val( - "traj.ascent.states:altitude", - ascent.interp(Dynamic.Mission.ALTITUDE, ys=[0, 100, 500], xs=[0, 1, 10]), - units="ft", - ) - p.set_val("traj.ascent.states:flight_path_angle", 0.0, units="rad") - p.set_val( - "traj.ascent.states:TAS", ascent.interp("TAS", [153.3196491, 500]), units="kn" - ) - p.set_val( - "traj.ascent.states:mass", - ascent.interp("mass", [174963.74211336, 174000]), - units="lbm", - ) - p.set_val( - "traj.ascent.states:distance", - ascent.interp(Dynamic.Mission.DISTANCE, [4330.83393029, 5000]), - units="ft", - ) - p.set_val("traj.ascent.t_initial", 31.2) - p.set_val("traj.ascent.t_duration", 10.0) - - # event trigger times - p.set_val("tau_gear", 0.2) # initial guess - p.set_val("tau_flaps", 0.5) # initial guess - - p.set_solver_print(level=-1) - - dm.run_problem(p, simulate=True, make_plots=make_plots) - - return p From da8f828d038a7d5ec2a831a0c1dfa9e1803e1fba Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 19 Jan 2024 14:01:25 -0600 Subject: [PATCH 129/188] Removed more unnecessary files --- aviary/interface/methods_for_level2.py | 3 +- .../flops_based/ode/simple_mission_EOM.py | 46 -- .../flops_based/ode/simple_mission_ODE.py | 206 -------- .../mission/flops_based/phases/climb_phase.py | 99 ---- .../flops_based/phases/cruise_phase.py | 437 ----------------- .../flops_based/phases/descent_phase.py | 100 ---- .../flops_based/phases/simple_energy_phase.py | 439 ------------------ .../gasp_based/phases/benchmark/__init__.py | 0 .../gasp_based/phases/benchmark/test_accel.py | 179 ------- .../phases/benchmark/test_bench_accel.py | 33 -- .../phases/benchmark/test_bench_ascent.py | 58 --- .../phases/benchmark/test_bench_desc1.py | 33 -- .../phases/benchmark/test_bench_desc2.py | 33 -- .../phases/benchmark/test_bench_groundroll.py | 36 -- .../phases/benchmark/test_bench_new_ascent.py | 427 ----------------- .../benchmark/test_bench_new_groundroll.py | 183 -------- .../benchmark/test_bench_new_rotation.py | 176 ------- .../phases/benchmark/test_bench_rotation.py | 43 -- .../phases/benchmark/test_bench_takeoff.py | 59 --- .../gasp_based/phases/benchmark/test_climb.py | 248 ---------- .../benchmark/test_conventional_problem.py | 27 -- .../phases/benchmark/test_cruise.py | 106 ----- .../test_FLOPS_based_sizing_N3CC.py | 2 +- 23 files changed, 2 insertions(+), 2971 deletions(-) delete mode 100644 aviary/mission/flops_based/ode/simple_mission_EOM.py delete mode 100644 aviary/mission/flops_based/ode/simple_mission_ODE.py delete mode 100644 aviary/mission/flops_based/phases/climb_phase.py delete mode 100644 aviary/mission/flops_based/phases/cruise_phase.py delete mode 100644 aviary/mission/flops_based/phases/descent_phase.py delete mode 100644 aviary/mission/flops_based/phases/simple_energy_phase.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/__init__.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_accel.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_bench_ascent.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_bench_desc1.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_bench_desc2.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_bench_groundroll.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_bench_new_ascent.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_bench_new_groundroll.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_bench_new_rotation.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_bench_rotation.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_bench_takeoff.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_climb.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_conventional_problem.py delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_cruise.py diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index c3c8f05fa..ba986aaf1 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -36,8 +36,7 @@ from aviary.mission.gasp_based.phases.v_rotate_comp import VRotateComp from aviary.mission.gasp_based.polynomial_fit import PolynomialFit from aviary.subsystems.premission import CorePreMission -from aviary.mission.gasp_based.ode.breguet_cruise_ode import BreguetCruiseODESolution -from aviary.utils.functions import set_aviary_initial_values, Null, create_opts2vals, add_opts2vals, promote_aircraft_and_mission_vars +from aviary.utils.functions import set_aviary_initial_values, create_opts2vals, add_opts2vals, promote_aircraft_and_mission_vars from aviary.utils.process_input_decks import create_vehicle from aviary.utils.preprocessors import preprocess_crewpayload from aviary.interface.utils.check_phase_info import check_phase_info diff --git a/aviary/mission/flops_based/ode/simple_mission_EOM.py b/aviary/mission/flops_based/ode/simple_mission_EOM.py deleted file mode 100644 index 55bc58889..000000000 --- a/aviary/mission/flops_based/ode/simple_mission_EOM.py +++ /dev/null @@ -1,46 +0,0 @@ -import openmdao.api as om - -from aviary.variable_info.variables import Dynamic -from aviary.mission.flops_based.ode.altitude_rate import AltitudeRate -from aviary.mission.flops_based.ode.range_rate import RangeRate -from aviary.mission.flops_based.ode.specific_energy_rate import SpecificEnergyRate -from aviary.mission.flops_based.ode.required_thrust import RequiredThrust - - -class MissionEOM(om.Group): - def initialize(self): - self.options.declare('num_nodes', types=int, - desc='Number of nodes to be evaluated in the RHS') - - def setup(self): - nn = self.options['num_nodes'] - - self.add_subsystem(name='required_thrust', - subsys=RequiredThrust(num_nodes=nn), - promotes_inputs=[Dynamic.Mission.DRAG, Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.VELOCITY, Dynamic.Mission.VELOCITY_RATE, Dynamic.Mission.MASS], - promotes_outputs=['thrust_required']) - - self.add_subsystem(name='groundspeed', - subsys=RangeRate(num_nodes=nn), - promotes_inputs=[ - Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY], - promotes_outputs=[Dynamic.Mission.DISTANCE_RATE]) - - self.add_subsystem(name='excess_specific_power', - subsys=SpecificEnergyRate(num_nodes=nn), - promotes_inputs=[(Dynamic.Mission.THRUST_TOTAL, Dynamic.Mission.THRUST_MAX_TOTAL), - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, Dynamic.Mission.DRAG], - promotes_outputs=[(Dynamic.Mission.SPECIFIC_ENERGY_RATE, Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS)]) - self.add_subsystem( - name=Dynamic.Mission.ALTITUDE_RATE_MAX, - subsys=AltitudeRate( - num_nodes=nn), - promotes_inputs=[ - (Dynamic.Mission.SPECIFIC_ENERGY_RATE, - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS), - Dynamic.Mission.VELOCITY_RATE, - Dynamic.Mission.VELOCITY], - promotes_outputs=[ - (Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.ALTITUDE_RATE_MAX)]) diff --git a/aviary/mission/flops_based/ode/simple_mission_ODE.py b/aviary/mission/flops_based/ode/simple_mission_ODE.py deleted file mode 100644 index beb8016c9..000000000 --- a/aviary/mission/flops_based/ode/simple_mission_ODE.py +++ /dev/null @@ -1,206 +0,0 @@ -import numpy as np -import openmdao.api as om -from dymos.models.atmosphere import USatm1976Comp - -from aviary.mission.flops_based.ode.simple_mission_EOM import MissionEOM -from aviary.utils.aviary_values import AviaryValues -from aviary.utils.functions import promote_aircraft_and_mission_vars -from aviary.variable_info.variable_meta_data import _MetaData -from aviary.variable_info.variables import Dynamic, Mission -from aviary.variable_info.variables_in import VariablesIn - - -class ExternalSubsystemGroup(om.Group): - def configure(self): - promote_aircraft_and_mission_vars(self) - - -class MissionODE(om.Group): - def initialize(self): - self.options.declare( - 'num_nodes', types=int, - desc='Number of nodes to be evaluated in the RHS') - self.options.declare( - 'subsystem_options', types=dict, default={}, - desc='dictionary of parameters to be passed to the subsystem builders') - self.options.declare( - 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') - self.options.declare( - 'core_subsystems', - desc='list of core subsystem builder instances to be added to the ODE' - ) - self.options.declare( - 'external_subsystems', default=[], - desc='list of external subsystem builder instances to be added to the ODE') - self.options.declare( - 'meta_data', default=_MetaData, - desc='metadata associated with the variables to be passed into the ODE') - self.options.declare( - 'use_actual_takeoff_mass', default=False, - desc='flag to use actual takeoff mass in the climb phase, otherwise assume 100 kg fuel burn') - self.options.declare( - 'throttle_enforcement', default='path', - desc='flag to enforce throttle constraints on the path or at the segment boundaries or using solver bounds' - ) - - def setup(self): - options = self.options - nn = options['num_nodes'] - aviary_options = options['aviary_options'] - core_subsystems = options['core_subsystems'] - subsystem_options = options['subsystem_options'] - engine_count = len(aviary_options.get_val('engine_models')) - - self.add_subsystem( - 'input_port', - VariablesIn(aviary_options=aviary_options, - meta_data=self.options['meta_data'], - context='mission'), - promotes_inputs=['*'], - promotes_outputs=['*']) - self.add_subsystem( - name='atmosphere', - subsys=USatm1976Comp(num_nodes=nn), - promotes_inputs=[('h', Dynamic.Mission.ALTITUDE)], - promotes_outputs=[ - ('sos', Dynamic.Mission.SPEED_OF_SOUND), ('rho', Dynamic.Mission.DENSITY), - ('temp', Dynamic.Mission.TEMPERATURE), ('pres', Dynamic.Mission.STATIC_PRESSURE)]) - - # add an execcomp to compute velocity based off mach and sos - self.add_subsystem( - name='velocity_comp', - subsys=om.ExecComp( - 'velocity = mach * sos', - mach={'units': 'unitless', 'shape': (nn,)}, - sos={'units': 'm/s', 'shape': (nn,)}, - velocity={'units': 'm/s', 'shape': (nn,)}, - has_diag_partials=True, - ), - promotes_inputs=[('mach', Dynamic.Mission.MACH), - ('sos', Dynamic.Mission.SPEED_OF_SOUND)], - promotes_outputs=[('velocity', Dynamic.Mission.VELOCITY)], - ) - - # add execcomp to compute velocity_rate based off mach_rate and sos - self.add_subsystem( - name='velocity_rate_comp', - subsys=om.ExecComp( - 'velocity_rate = mach_rate * sos', - mach_rate={'units': 'unitless/s', 'shape': (nn,)}, - sos={'units': 'm/s', 'shape': (nn,)}, - velocity_rate={'units': 'm/s**2', 'shape': (nn,)}, - has_diag_partials=True, - ), - promotes_inputs=[('mach_rate', Dynamic.Mission.MACH_RATE), - ('sos', Dynamic.Mission.SPEED_OF_SOUND)], - promotes_outputs=[('velocity_rate', Dynamic.Mission.VELOCITY_RATE)], - ) - - base_options = {'num_nodes': nn, 'aviary_inputs': aviary_options} - - for subsystem in core_subsystems: - # check if subsystem_options has entry for a subsystem of this name - if subsystem.name in subsystem_options: - kwargs = subsystem_options[subsystem.name] - else: - kwargs = {} - - kwargs.update(base_options) - system = subsystem.build_mission(**kwargs) - - if system is not None: - self.add_subsystem(subsystem.name, - system, - promotes_inputs=subsystem.mission_inputs(**kwargs), - promotes_outputs=subsystem.mission_outputs(**kwargs)) - - # Create a lightly modified version of an OM group to add external subsystems - # to the ODE with a special configure() method that promotes - # all aircraft:* and mission:* variables to the ODE. - external_subsystem_group = ExternalSubsystemGroup() - add_subsystem_group = False - - for subsystem in self.options['external_subsystems']: - subsystem_mission = subsystem.build_mission( - num_nodes=nn, aviary_inputs=aviary_options) - if subsystem_mission is not None: - add_subsystem_group = True - external_subsystem_group.add_subsystem(subsystem.name, subsystem_mission) - - # Only add the external subsystem group if it has at least one subsystem. - # Without this logic there'd be an empty OM group added to the ODE. - if add_subsystem_group: - self.add_subsystem( - name='external_subsystems', - subsys=external_subsystem_group, - promotes_inputs=['*'], - promotes_outputs=['*']) - - self.add_subsystem( - name='mission_EOM', - subsys=MissionEOM(num_nodes=nn), - promotes_inputs=[ - Dynamic.Mission.VELOCITY, Dynamic.Mission.MASS, - Dynamic.Mission.THRUST_MAX_TOTAL, - Dynamic.Mission.DRAG, Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.VELOCITY_RATE], - promotes_outputs=[ - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, - Dynamic.Mission.ALTITUDE_RATE_MAX, - Dynamic.Mission.DISTANCE_RATE, - 'thrust_required', - ]) - - # add a balance comp to compute throttle based on the altitude rate - self.add_subsystem(name='throttle_balance', - subsys=om.BalanceComp(name=Dynamic.Mission.THROTTLE, - units="unitless", - val=np.ones(nn), - lhs_name='thrust_required', - rhs_name=Dynamic.Mission.THRUST_TOTAL, - eq_units="lbf", - normalize=False, - lower=0.0 if options['throttle_enforcement'] == 'bounded' else None, - upper=1.0 if options['throttle_enforcement'] == 'bounded' else None, - ), - promotes_inputs=['*'], - promotes_outputs=['*']) - - self.set_input_defaults(Dynamic.Mission.MASS, val=np.ones(nn), units='kg') - self.set_input_defaults(Dynamic.Mission.VELOCITY, val=np.ones(nn), units='m/s') - self.set_input_defaults(Dynamic.Mission.ALTITUDE, val=np.ones(nn), units='m') - self.set_input_defaults( - Dynamic.Mission.THROTTLE, val=np.ones((nn, engine_count)), - units='unitless') - - if options['use_actual_takeoff_mass']: - exec_comp_string = 'initial_mass_residual = initial_mass - mass[0]' - initial_mass_string = Mission.Takeoff.FINAL_MASS - else: - exec_comp_string = 'initial_mass_residual = initial_mass - mass[0] - 100.' - initial_mass_string = Mission.Design.GROSS_MASS - - # Experimental: Add a component to constrain the initial mass to be equal to design gross weight. - initial_mass_residual_constraint = om.ExecComp( - exec_comp_string, - initial_mass={'units': 'kg'}, - mass={'units': 'kg', 'shape': (nn,)}, - initial_mass_residual={'units': 'kg'}, - ) - - self.add_subsystem('initial_mass_residual_constraint', initial_mass_residual_constraint, - promotes_inputs=[ - ('initial_mass', initial_mass_string), - ('mass', Dynamic.Mission.MASS) - ], - promotes_outputs=['initial_mass_residual']) - - self.nonlinear_solver = om.NewtonSolver(solve_subsystems=True, - atol=1.0e-10, - rtol=1.0e-10, - ) - self.nonlinear_solver.linesearch = om.BoundsEnforceLS() - self.linear_solver = om.DirectSolver(assemble_jac=True) - self.nonlinear_solver.options['err_on_non_converge'] = True - self.nonlinear_solver.options['iprint'] = 2 diff --git a/aviary/mission/flops_based/phases/climb_phase.py b/aviary/mission/flops_based/phases/climb_phase.py deleted file mode 100644 index ca5042410..000000000 --- a/aviary/mission/flops_based/phases/climb_phase.py +++ /dev/null @@ -1,99 +0,0 @@ -from aviary.mission.flops_based.phases.energy_phase import EnergyPhase, register - - -Climb = None # forward declaration for type hints - - -@register -class Climb(EnergyPhase): - ''' - Define a phase builder class for a typical FLOPS based climb phase. - - Attributes - ---------- - name : str ('climb') - object label - - user_options : AviaryValues () - state/path constraint values and flags - - supported options: - - num_segments : int (5) - transcription: number of segments - - order : int (3) - transcription: order of the state transcription; the order of the control - transcription is `order - 1` - - fix_initial : bool (True) - - fix_initial_time : bool (None) - - initial_ref : float (1.0, 's') - note: applied if, and only if, "fix_initial_time" is unspecified - - initial_bounds : pair ((0.0, 100.0) 's') - note: applied if, and only if, "fix_initial_time" is unspecified - - duration_ref : float (1.0, 's') - - duration_bounds : pair ((0.0, 100.0) 's') - - initial_altitude : float (0.0, 'ft) - starting true altitude from mean sea level - - final_altitude : float - ending true altitude from mean sea level - - initial_mach : float (0.0, 'ft) - starting Mach number - - final_mach : float - ending Mach number - - required_altitude_rate : float (None) - minimum avaliable climb rate - - no_climb : bool (False) - aircraft is not allowed to climb during phase - - no_descent : bool (False) - aircraft is not allowed to descend during phase - - fix_range : bool (False) - - input_initial : bool (False) - - initial_guesses : AviaryValues () - state/path beginning values to be set on the problem - - supported options: - - times - - range - - altitude - - velocity - - velocity_rate - - mass - - throttle - - ode_class : type (None) - advanced: the type of system defining the ODE - - transcription : "Dymos transcription object" (None) - advanced: an object providing the transcription technique of the - optimal control problem - - external_subsystems : Sequence["subsystem builder"] () - advanced - - meta_data : dict (<"builtin" meta data>) - advanced: meta data associated with variables in the Aviary data hierarchy - - default_name : str - class attribute: derived type customization point; the default value - for name - - default_ode_class : type - class attribute: derived type customization point; the default value - for ode_class used by build_phase - - default_meta_data : dict - class attribute: derived type customization point; the default value for - meta_data - - Methods - ------- - build_phase - make_default_transcription - validate_options - assign_default_options - ''' - # region : derived type customization points - __slots__ = () - - default_name = 'climb' - # endregion : derived type customization points diff --git a/aviary/mission/flops_based/phases/cruise_phase.py b/aviary/mission/flops_based/phases/cruise_phase.py deleted file mode 100644 index 184297c14..000000000 --- a/aviary/mission/flops_based/phases/cruise_phase.py +++ /dev/null @@ -1,437 +0,0 @@ -from math import isclose - -import dymos as dm - -from aviary.mission.flops_based.phases.phase_builder_base import ( - register, PhaseBuilderBase, InitialGuessControl, InitialGuessParameter, - InitialGuessPolynomialControl, InitialGuessState, InitialGuessTime) - -from aviary.utils.aviary_values import AviaryValues - -from aviary.variable_info.variable_meta_data import _MetaData -from aviary.variable_info.variables import Dynamic -from aviary.mission.flops_based.phases.phase_utils import add_subsystem_variables_to_phase, get_initial - - -Cruise = None # forward declaration for type hints - - -# TODO: support/handle the following in the base class -# - phase.set_time_options() -# - currently handled in level 3 interface implementation -# - self.external_subsystems -# - self.meta_data, with cls.default_meta_data customization point -class Cruise(PhaseBuilderBase): - ''' - Define a phase builder base class for typical energy phases such as climb and - descent. - - Attributes - ---------- - name : str ('energy_phase') - object label - - subsystem_options (None) - dictionary of parameters to be passed to the subsystem builders - - user_options : AviaryValues () - state/path constraint values and flags - - supported options: - - num_segments : int (5) - transcription: number of segments - - order : int (3) - transcription: order of the state transcription; the order of the control - transcription is `order - 1` - - fix_initial : bool (True) - - fix_initial_time : bool (None) - - initial_ref : float (1.0, 's') - note: applied if, and only if, "fix_initial_time" is unspecified - - initial_bounds : pair ((0.0, 100.0) 's') - note: applied if, and only if, "fix_initial_time" is unspecified - - duration_ref : float (1.0, 's') - - duration_bounds : pair ((0.0, 100.0) 's') - - min_altitude : float (0.0, 'ft) - starting true altitude from mean sea level - - max_altitude : float - ending true altitude from mean sea level - - min_mach : float (0.0, 'ft) - starting Mach number - - max_mach : float - ending Mach number - - required_available_climb_rate : float (None) - minimum avaliable climb rate - - fix_final : bool (False) - - input_initial : bool (False) - - polynomial_control_order : None or int - When set to an integer value, replace controls with - polynomial controls of that specified order. - - initial_guesses : AviaryValues () - state/path beginning values to be set on the problem - - supported options: - - times - - range - - altitude - - velocity - - velocity_rate - - mass - - throttle - - ode_class : type (None) - advanced: the type of system defining the ODE - - transcription : "Dymos transcription object" (None) - advanced: an object providing the transcription technique of the - optimal control problem - - external_subsystems : Sequence["subsystem builder"] () - advanced - - meta_data : dict (<"builtin" meta data>) - advanced: meta data associated with variables in the Aviary data hierarchy - - default_name : str - class attribute: derived type customization point; the default value - for name - - default_ode_class : type - class attribute: derived type customization point; the default value - for ode_class used by build_phase - - default_meta_data : dict - class attribute: derived type customization point; the default value for - meta_data - - Methods - ------- - build_phase - make_default_transcription - validate_options - assign_default_options - ''' - __slots__ = ('external_subsystems', 'meta_data') - - # region : derived type customization points - _meta_data_ = {} - - _initial_guesses_meta_data_ = {} - - default_name = 'cruise_phase' - - # default_ode_class = MissionODE - - default_meta_data = _MetaData - - # endregion : derived type customization points - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, core_subsystems=core_subsystems, subsystem_options=subsystem_options, user_options=user_options, initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription) - - # TODO: support external_subsystems and meta_data in the base class - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - - def build_phase(self, aviary_options: AviaryValues = None): - ''' - Return a new cruise phase for analysis using these constraints. - - If ode_class is None, default_ode_class is used. - - If transcription is None, the return value from calling - make_default_transcription is used. - - Parameters - ---------- - aviary_options : AviaryValues () - collection of Aircraft/Mission specific options - - Returns - ------- - dymos.Phase - ''' - phase: dm.Phase = super().build_phase(aviary_options) - - user_options: AviaryValues = self.user_options - - fix_initial = user_options.get_val('fix_initial') - min_mach = user_options.get_val('min_mach') - max_mach = user_options.get_val('max_mach') - min_altitude = user_options.get_val('min_altitude', units='m') - max_altitude = user_options.get_val('max_altitude', units='m') - fix_final = user_options.get_val('fix_final') - input_initial = user_options.get_val('input_initial') - num_engines = len(aviary_options.get_val('engine_models')) - input_initial = user_options.get_val('input_initial') - mass_f_cruise = user_options.get_val('mass_f_cruise', units='kg') - distance_f_cruise = user_options.get_val('distance_f_cruise', units='m') - polynomial_control_order = user_options.get_item('polynomial_control_order')[0] - - ############## - # Add States # - ############## - - input_initial_alt = get_initial(input_initial, Dynamic.Mission.ALTITUDE) - fix_initial_alt = get_initial(fix_initial, Dynamic.Mission.ALTITUDE) - phase.add_state( - Dynamic.Mission.ALTITUDE, fix_initial=fix_initial_alt, fix_final=False, - lower=0.0, ref=max_altitude, defect_ref=max_altitude, units='m', - rate_source=Dynamic.Mission.ALTITUDE_RATE, targets=Dynamic.Mission.ALTITUDE, - input_initial=input_initial_alt - ) - - input_initial_vel = get_initial(input_initial, Dynamic.Mission.VELOCITY) - fix_initial_vel = get_initial(fix_initial, Dynamic.Mission.VELOCITY) - phase.add_state( - Dynamic.Mission.VELOCITY, fix_initial=fix_initial_vel, fix_final=False, - lower=0.0, ref=1e2, defect_ref=1e2, units='m/s', - rate_source=Dynamic.Mission.VELOCITY_RATE, targets=Dynamic.Mission.VELOCITY, - input_initial=input_initial_vel - ) - - input_initial_mass = get_initial(input_initial, Dynamic.Mission.MASS) - fix_initial_mass = get_initial(fix_initial, Dynamic.Mission.MASS, True) - phase.add_state( - Dynamic.Mission.MASS, fix_initial=fix_initial_mass, fix_final=False, - lower=0.0, ref=mass_f_cruise, defect_ref=mass_f_cruise, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - input_initial=input_initial_mass - ) - - input_initial_distance = get_initial(input_initial, Dynamic.Mission.DISTANCE) - fix_initial_distance = get_initial(fix_initial, Dynamic.Mission.DISTANCE, True) - phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=fix_initial_distance, fix_final=fix_final, - lower=0.0, ref=distance_f_cruise, defect_ref=distance_f_cruise, units='m', - rate_source=Dynamic.Mission.DISTANCE_RATE, - input_initial=input_initial_distance - ) - - phase = add_subsystem_variables_to_phase( - phase, self.name, self.external_subsystems) - - ################ - # Add Controls # - ################ - if polynomial_control_order is not None: - phase.add_polynomial_control( - Dynamic.Mission.VELOCITY_RATE, - targets=Dynamic.Mission.VELOCITY_RATE, units='m/s**2', - opt=True, lower=-2.12, upper=2.12, - order=polynomial_control_order, - ) - else: - phase.add_control( - Dynamic.Mission.VELOCITY_RATE, - targets=Dynamic.Mission.VELOCITY_RATE, units='m/s**2', - opt=True, lower=-2.12, upper=2.12, - ) - - if num_engines > 0: - if polynomial_control_order is not None: - phase.add_polynomial_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', - opt=True, lower=0.0, upper=1.0, scaler=1, - order=polynomial_control_order, - ) - else: - phase.add_control( - Dynamic.Mission.THROTTLE, - targets=Dynamic.Mission.THROTTLE, units='unitless', - opt=True, lower=0.0, upper=1.0, scaler=1, - ) - - ################## - # Add Timeseries # - ################## - phase.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units='unitless' - ) - - phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' - ) - - phase.add_timeseries_output( - Dynamic.Mission.THRUST_MAX_TOTAL, - output_name=Dynamic.Mission.THRUST_MAX_TOTAL, units='lbf' - ) - - phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' - ) - - phase.add_timeseries_output( - Dynamic.Mission.SPECIFIC_ENERGY_RATE, - output_name=Dynamic.Mission.SPECIFIC_ENERGY_RATE, units='m/s' - ) - - phase.add_timeseries_output( - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, - output_name=Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, units='m/s' - ) - - phase.add_timeseries_output( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - output_name=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units='lbm/h' - ) - - phase.add_timeseries_output( - Dynamic.Mission.ALTITUDE_RATE, - output_name=Dynamic.Mission.ALTITUDE_RATE, units='ft/s' - ) - - phase.add_timeseries_output( - Dynamic.Mission.ALTITUDE_RATE_MAX, - output_name=Dynamic.Mission.ALTITUDE_RATE_MAX, units='ft/min' - ) - - ################### - # Add Constraints # - ################### - required_available_climb_rate = user_options.get_val( - 'required_available_climb_rate', 'm/s') - - if required_available_climb_rate is not None: - phase.add_path_constraint( - Dynamic.Mission.ALTITUDE_RATE_MAX, - ref=required_available_climb_rate, - constraint_name='altitude_rate_minimum', - lower=required_available_climb_rate, units='m/s' - ) - - if isclose(min_mach, max_mach): - phase.add_path_constraint( - Dynamic.Mission.MACH, - equals=min_mach, units='unitless', - # ref=1.e4, - ) - - else: - phase.add_path_constraint( - Dynamic.Mission.MACH, - lower=min_mach, upper=max_mach, units='unitless', - # ref=1.e4, - ) - - # avoid scaling constraints by zero - ref = max_altitude - if ref == 0: - ref = None - - if isclose(min_altitude, max_altitude): - phase.add_path_constraint( - Dynamic.Mission.ALTITUDE, - equals=min_altitude, units='m', ref=ref, - ) - - else: - phase.add_path_constraint( - Dynamic.Mission.ALTITUDE, - lower=min_altitude, upper=max_altitude, - units='m', ref=ref, - ) - - return phase - - def _extra_ode_init_kwargs(self): - """ - Return extra kwargs required for initializing the ODE. - """ - # TODO: support external_subsystems and meta_data in the base class - return { - 'external_subsystems': self.external_subsystems, - 'meta_data': self.meta_data} - - -Cruise._add_meta_data( - 'num_segments', val=1, desc='transcription: number of segments') - -Cruise._add_meta_data( - 'order', val=3, - desc='transcription: order of the state transcription; the order of the control' - ' transcription is `order - 1`') - -Cruise._add_meta_data('fix_initial', val=True) - -Cruise._add_meta_data('fix_initial_time', val=None) - -Cruise._add_meta_data('initial_ref', val=1., units='s') - -Cruise._add_meta_data('initial_bounds', val=(0., 100.), units='s') - -Cruise._add_meta_data('duration_ref', val=1., units='s') - -Cruise._add_meta_data('duration_bounds', val=(0., 100.), units='s') - -Cruise._add_meta_data( - 'min_altitude', val=0., units='m', - desc='starting true altitude from mean sea level') - -Cruise._add_meta_data( - 'max_altitude', val=None, units='m', - desc='ending true altitude from mean sea level') - -Cruise._add_meta_data('min_mach', val=0., desc='starting Mach number') - -Cruise._add_meta_data('max_mach', val=None, desc='ending Mach number') - -Cruise._add_meta_data('mass_i_cruise', val=1.e4, units='kg') - -Cruise._add_meta_data('mass_f_cruise', val=1.e4, units='kg') - -Cruise._add_meta_data('distance_f_cruise', val=1.e6, units='m') - -Cruise._add_meta_data( - 'required_available_climb_rate', val=None, units='m/s', - desc='minimum avaliable climb rate') - -Cruise._add_meta_data('fix_final', val=True) - -Cruise._add_meta_data('input_initial', val=False) - -Cruise._add_meta_data('polynomial_control_order', val=None) - -Cruise._add_initial_guess_meta_data( - InitialGuessTime(), - desc='initial guess for initial time and duration specified as a tuple') - -Cruise._add_initial_guess_meta_data( - InitialGuessState('distance'), - desc='initial guess for horizontal distance traveled') - -Cruise._add_initial_guess_meta_data( - InitialGuessState('altitude'), - desc='initial guess for vertical distances') - -Cruise._add_initial_guess_meta_data( - InitialGuessState('velocity'), - desc='initial guess for speed') - -Cruise._add_initial_guess_meta_data( - InitialGuessControl('velocity_rate'), - desc='initial guess for acceleration') - -Cruise._add_initial_guess_meta_data( - InitialGuessState('mass'), - desc='initial guess for mass') - -Cruise._add_initial_guess_meta_data( - InitialGuessControl('throttle'), - desc='initial guess for throttle') diff --git a/aviary/mission/flops_based/phases/descent_phase.py b/aviary/mission/flops_based/phases/descent_phase.py deleted file mode 100644 index b76164fc7..000000000 --- a/aviary/mission/flops_based/phases/descent_phase.py +++ /dev/null @@ -1,100 +0,0 @@ -from aviary.mission.flops_based.phases.energy_phase import EnergyPhase, register - - -Descent = None # forward declaration for type hints - - -@register -class Descent(EnergyPhase): - ''' - Define a phase builder class for a typical FLOPS based descent phase. - - Attributes - ---------- - name : str ('descent') - object label - - user_options : AviaryValues () - state/path constraint values and flags - - supported options: - - num_segments : int (5) - transcription: number of segments - - order : int (3) - transcription: order of the state transcription; the order of the control - transcription is `order - 1` - - fix_initial : bool (True) - - fix_initial_time : bool (None) - - initial_ref : float (1.0, 's') - note: applied if, and only if, "fix_initial_time" is unspecified - - initial_bounds : pair ((0.0, 100.0) 's') - note: applied if, and only if, "fix_initial_time" is unspecified - - duration_ref : float (1.0, 's') - - duration_bounds : pair ((0.0, 100.0) 's') - - initial_altitude : float (0.0, 'ft) - starting true altitude from mean sea level - - final_altitude : float - ending true altitude from mean sea level - - initial_mach : float (0.0, 'ft) - starting Mach number - - final_mach : float - ending Mach number - - required_altitude_rate : float (None) - minimum avaliable descent rate - - no_descent : bool (False) - aircraft is not allowed to descent during phase - - no_descent : bool (False) - aircraft is not allowed to descend during phase - - fix_range : bool (False) - - input_initial : bool (False) - - initial_guesses : AviaryValues () - state/path beginning values to be set on the problem - - supported options: - - times - - range - - altitude - - velocity - - velocity_rate - - mass - - throttle - - ode_class : type (None) - advanced: the type of system defining the ODE - - transcription : "Dymos transcription object" (None) - advanced: an object providing the transcription technique of the - optimal control problem - - external_subsystems : Sequence["subsystem builder"] () - advanced - - meta_data : dict (<"builtin" meta data>) - advanced: meta data associated with variables in the Aviary data hierarchy - - default_name : str - class attribute: derived type customization point; the default value - for name - - default_ode_class : type - class attribute: derived type customization point; the default value - for ode_class used by build_phase - - default_meta_data : dict - class attribute: derived type customization point; the default value for - meta_data - - Methods - ------- - build_phase - make_default_transcription - validate_options - assign_default_options - ''' - # region : derived type customization points - __slots__ = () - - default_name = 'descent' - - # endregion : derived type customization points diff --git a/aviary/mission/flops_based/phases/simple_energy_phase.py b/aviary/mission/flops_based/phases/simple_energy_phase.py deleted file mode 100644 index 65782f9f0..000000000 --- a/aviary/mission/flops_based/phases/simple_energy_phase.py +++ /dev/null @@ -1,439 +0,0 @@ -import dymos as dm - -from aviary.mission.flops_based.phases.phase_builder_base import ( - register, PhaseBuilderBase, InitialGuessControl, InitialGuessParameter, - InitialGuessPolynomialControl, InitialGuessState, InitialGuessTime) - -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.variable_meta_data import _MetaData -from aviary.mission.flops_based.phases.phase_utils import add_subsystem_variables_to_phase, get_initial -from aviary.variable_info.variables import Dynamic -from aviary.mission.flops_based.ode.simple_mission_ODE import MissionODE - - -# TODO: support/handle the following in the base class -# - phase.set_time_options() -# - currently handled in level 3 interface implementation -# - self.external_subsystems -# - self.meta_data, with cls.default_meta_data customization point -class EnergyPhase(PhaseBuilderBase): - ''' - A phase builder for a simple energy phase. - - Attributes - ---------- - name : str ('energy_phase') - object label - - subsystem_options (None) - dictionary of parameters to be passed to the subsystem builders - - user_options : AviaryValues () - state/path constraint values and flags - - supported options: - - num_segments : int (5) - transcription: number of segments - - order : int (3) - transcription: order of the state transcription; the order of the control - transcription is `order - 1` - - fix_initial : bool (True) - - initial_ref : float (1.0, 's') - - initial_bounds : pair ((0.0, 100.0) 's') - - duration_ref : float (1.0, 's') - - duration_bounds : pair ((0.0, 100.0) 's') - - required_available_climb_rate : float (None) - minimum avaliable climb rate - - constrain_final : bool (False) - - input_initial : bool (False) - - initial_guesses : AviaryValues () - state/path beginning values to be set on the problem - - supported options: - - times - - range - - altitude - - velocity - - velocity_rate - - mass - - throttle - - ode_class : type (None) - advanced: the type of system defining the ODE - - transcription : "Dymos transcription object" (None) - advanced: an object providing the transcription technique of the - optimal control problem - - external_subsystems : Sequence["subsystem builder"] () - advanced - - meta_data : dict (<"builtin" meta data>) - advanced: meta data associated with variables in the Aviary data hierarchy - - default_name : str - class attribute: derived type customization point; the default value - for name - - default_ode_class : type - class attribute: derived type customization point; the default value - for ode_class used by build_phase - - default_meta_data : dict - class attribute: derived type customization point; the default value for - meta_data - - Methods - ------- - build_phase - make_default_transcription - validate_options - assign_default_options - ''' - __slots__ = ('external_subsystems', 'meta_data') - - # region : derived type customization points - _meta_data_ = {} - - _initial_guesses_meta_data_ = {} - - default_name = 'energy_phase' - - default_ode_class = MissionODE - - default_meta_data = _MetaData - # endregion : derived type customization points - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, core_subsystems=core_subsystems, subsystem_options=subsystem_options, user_options=user_options, initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription) - - # TODO: support external_subsystems and meta_data in the base class - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - - def build_phase(self, aviary_options: AviaryValues = None): - ''' - Return a new energy phase for analysis using these constraints. - - If ode_class is None, default_ode_class is used. - - If transcription is None, the return value from calling - make_default_transcription is used. - - Parameters - ---------- - aviary_options : AviaryValues () - collection of Aircraft/Mission specific options - - Returns - ------- - dymos.Phase - ''' - phase: dm.Phase = super().build_phase(aviary_options) - - user_options: AviaryValues = self.user_options - - fix_initial = user_options.get_val('fix_initial') - constrain_final = user_options.get_val('constrain_final') - optimize_mach = user_options.get_val('optimize_mach') - optimize_altitude = user_options.get_val('optimize_altitude') - input_initial = user_options.get_val('input_initial') - polynomial_control_order = user_options.get_item('polynomial_control_order')[0] - use_polynomial_control = user_options.get_val('use_polynomial_control') - throttle_enforcement = user_options.get_val('throttle_enforcement') - mach_bounds = user_options.get_item('mach_bounds') - altitude_bounds = user_options.get_item('altitude_bounds') - initial_mach = user_options.get_item('initial_mach')[0] - final_mach = user_options.get_item('final_mach')[0] - initial_altitude = user_options.get_item('initial_altitude')[0] - final_altitude = user_options.get_item('final_altitude')[0] - solve_for_distance = user_options.get_val('solve_for_distance') - no_descent = user_options.get_val('no_descent') - no_climb = user_options.get_val('no_climb') - - ############## - # Add States # - ############## - # TODO: critically think about how we should handle fix_initial and input_initial defaults. - # In keeping with Dymos standards, the default should be False instead of True. - input_initial_mass = get_initial(input_initial, Dynamic.Mission.MASS) - fix_initial_mass = get_initial(fix_initial, Dynamic.Mission.MASS, True) - - # Experiment: use a constraint for mass instead of connected initial. - # This is due to some problems in mpi. - # This is needed for the cutting edge full subsystem integration. - # TODO: when a Dymos fix is in and we've verified that full case works with the fix, - # remove this argument. - if user_options.get_val('add_initial_mass_constraint'): - phase.add_constraint('rhs_all.initial_mass_residual', equals=0.0, ref=1e4) - input_initial_mass = False - - phase.add_state( - Dynamic.Mission.MASS, fix_initial=fix_initial_mass, fix_final=False, - lower=0.0, ref=1e4, defect_ref=1e6, units='kg', - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - input_initial=input_initial_mass, - # solve_segments='forward', - ) - - input_initial_distance = get_initial(input_initial, Dynamic.Mission.DISTANCE) - fix_initial_distance = get_initial(fix_initial, Dynamic.Mission.DISTANCE, True) - phase.add_state( - Dynamic.Mission.DISTANCE, fix_initial=fix_initial_distance, fix_final=False, - lower=0.0, ref=1e6, defect_ref=1e8, units='m', - rate_source=Dynamic.Mission.DISTANCE_RATE, - input_initial=input_initial_distance, - solve_segments='forward' if solve_for_distance else None, - ) - - phase = add_subsystem_variables_to_phase( - phase, self.name, self.external_subsystems) - - ################ - # Add Controls # - ################ - if use_polynomial_control: - phase.add_polynomial_control( - Dynamic.Mission.MACH, - targets=Dynamic.Mission.MACH, units=mach_bounds[1], - opt=optimize_mach, lower=mach_bounds[0][0], upper=mach_bounds[0][1], - rate_targets=[Dynamic.Mission.MACH_RATE], - order=polynomial_control_order, ref=0.5, - ) - else: - phase.add_control( - Dynamic.Mission.MACH, - targets=Dynamic.Mission.MACH, units=mach_bounds[1], - opt=optimize_mach, lower=mach_bounds[0][0], upper=mach_bounds[0][1], - rate_targets=[Dynamic.Mission.MACH_RATE], - ref=0.5, - ) - - if optimize_mach and fix_initial: - phase.add_boundary_constraint( - Dynamic.Mission.MACH, loc='initial', equals=initial_mach, - ) - - if optimize_mach and constrain_final: - phase.add_boundary_constraint( - Dynamic.Mission.MACH, loc='final', equals=final_mach, - ) - - # Add altitude rate as a control - if use_polynomial_control: - phase.add_polynomial_control( - Dynamic.Mission.ALTITUDE, - targets=Dynamic.Mission.ALTITUDE, units=altitude_bounds[1], - opt=optimize_altitude, lower=altitude_bounds[0][0], upper=altitude_bounds[0][1], - rate_targets=[Dynamic.Mission.ALTITUDE_RATE], - order=polynomial_control_order, ref=altitude_bounds[0][1], - ) - else: - phase.add_control( - Dynamic.Mission.ALTITUDE, - targets=Dynamic.Mission.ALTITUDE, units=altitude_bounds[1], - opt=optimize_altitude, lower=altitude_bounds[0][0], upper=altitude_bounds[0][1], - rate_targets=[Dynamic.Mission.ALTITUDE_RATE], - ref=altitude_bounds[0][1], - ) - - if optimize_altitude and fix_initial: - phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc='initial', equals=initial_altitude, units=altitude_bounds[1], ref=1.e4, - ) - - if optimize_altitude and constrain_final: - phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc='final', equals=final_altitude, units=altitude_bounds[1], ref=1.e4, - ) - - ################## - # Add Timeseries # - ################## - phase.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units='unitless' - ) - - phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' - ) - - phase.add_timeseries_output( - Dynamic.Mission.DRAG, output_name=Dynamic.Mission.DRAG, units='lbf' - ) - - phase.add_timeseries_output( - Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, - output_name=Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS, units='m/s' - ) - - phase.add_timeseries_output( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - output_name=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units='lbm/h' - ) - - phase.add_timeseries_output( - Dynamic.Mission.ALTITUDE_RATE, - output_name=Dynamic.Mission.ALTITUDE_RATE, units='ft/s' - ) - - phase.add_timeseries_output( - Dynamic.Mission.THROTTLE, - output_name=Dynamic.Mission.THROTTLE, units='unitless' - ) - - phase.add_timeseries_output( - Dynamic.Mission.VELOCITY, - output_name=Dynamic.Mission.VELOCITY, units='m/s' - ) - - ################### - # Add Constraints # - ################### - if no_descent: - phase.add_path_constraint(Dynamic.Mission.ALTITUDE_RATE, lower=0.0) - - if no_climb: - phase.add_path_constraint(Dynamic.Mission.ALTITUDE_RATE, upper=0.0) - - required_available_climb_rate, units = user_options.get_item( - 'required_available_climb_rate') - - if required_available_climb_rate is not None: - phase.add_path_constraint( - Dynamic.Mission.ALTITUDE_RATE_MAX, - lower=required_available_climb_rate, units=units - ) - - if throttle_enforcement == 'boundary_constraint': - phase.add_boundary_constraint( - Dynamic.Mission.THROTTLE, loc='initial', lower=0.0, upper=1.0, units='unitless', - ) - phase.add_boundary_constraint( - Dynamic.Mission.THROTTLE, loc='final', lower=0.0, upper=1.0, units='unitless', - ) - elif throttle_enforcement == 'path_constraint': - phase.add_path_constraint( - Dynamic.Mission.THROTTLE, lower=0.0, upper=1.0, units='unitless', - ) - - return phase - - def make_default_transcription(self): - ''' - Return a transcription object to be used by default in build_phase. - ''' - user_options = self.user_options - - num_segments, _ = user_options.get_item('num_segments') - order, _ = user_options.get_item('order') - - seg_ends, _ = dm.utils.lgl.lgl(num_segments + 1) - - transcription = dm.Radau( - num_segments=num_segments, order=order, compressed=True, - segment_ends=seg_ends) - - return transcription - - def _extra_ode_init_kwargs(self): - """ - Return extra kwargs required for initializing the ODE. - """ - # TODO: support external_subsystems and meta_data in the base class - return { - 'external_subsystems': self.external_subsystems, - 'meta_data': self.meta_data, - 'subsystem_options': self.subsystem_options, - 'throttle_enforcement': self.user_options.get_val('throttle_enforcement'), - } - - -EnergyPhase._add_meta_data( - 'num_segments', val=5, desc='transcription: number of segments') - -EnergyPhase._add_meta_data( - 'order', val=3, - desc='transcription: order of the state transcription; the order of the control' - ' transcription is `order - 1`') - -EnergyPhase._add_meta_data('polynomial_control_order', val=None) - -EnergyPhase._add_meta_data('use_polynomial_control', val=True) - -EnergyPhase._add_meta_data('add_initial_mass_constraint', val=False) - -EnergyPhase._add_meta_data('fix_initial', val=True) - -EnergyPhase._add_meta_data('optimize_mach', val=False) - -EnergyPhase._add_meta_data('optimize_altitude', val=False) - -EnergyPhase._add_meta_data('initial_bounds', val=(0., 100.), units='s') - -EnergyPhase._add_meta_data('duration_bounds', val=(0., 100.), units='s') - -EnergyPhase._add_meta_data( - 'required_available_climb_rate', val=None, units='m/s', - desc='minimum avaliable climb rate') - -EnergyPhase._add_meta_data( - 'no_climb', val=False, desc='aircraft is not allowed to climb during phase') - -EnergyPhase._add_meta_data( - 'no_descent', val=False, desc='aircraft is not allowed to descend during phase') - -EnergyPhase._add_meta_data('constrain_final', val=False) - -EnergyPhase._add_meta_data('input_initial', val=False) - -EnergyPhase._add_meta_data('initial_mach', val=None, units='unitless') - -EnergyPhase._add_meta_data('final_mach', val=None, units='unitless') - -EnergyPhase._add_meta_data('initial_altitude', val=None, units='ft') - -EnergyPhase._add_meta_data('final_altitude', val=None, units='ft') - -EnergyPhase._add_meta_data('throttle_enforcement', val=None) - -EnergyPhase._add_meta_data('mach_bounds', val=(0., 2.), units='unitless') - -EnergyPhase._add_meta_data('altitude_bounds', val=(0., 60.e3), units='ft') - -EnergyPhase._add_meta_data('solve_for_distance', val=False) - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessTime(), - desc='initial guess for initial time and duration specified as a tuple') - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('distance'), - desc='initial guess for horizontal distance traveled') - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('altitude'), - desc='initial guess for vertical distances') - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('mach'), - desc='initial guess for speed') - -EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('mass'), - desc='initial guess for mass') diff --git a/aviary/mission/gasp_based/phases/benchmark/__init__.py b/aviary/mission/gasp_based/phases/benchmark/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/aviary/mission/gasp_based/phases/benchmark/test_accel.py b/aviary/mission/gasp_based/phases/benchmark/test_accel.py deleted file mode 100644 index 3ac9323b0..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_accel.py +++ /dev/null @@ -1,179 +0,0 @@ -import unittest - -import dymos as dm -import numpy as np -import openmdao.api as om -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import require_pyoptsparse, use_tempdirs - -from aviary.constants import GRAV_ENGLISH_LBM -from aviary.mission.gasp_based.ode.flight_path_ode import FlightPathODE -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 - - -def make_accel_problem( - optimizer='IPOPT', - print_opt_iters=False, - constant_quantity=Dynamic.Mission.MACH): - prob = om.Problem(model=om.Group()) - - prob.driver = om.pyOptSparseDriver() - - if optimizer == "SNOPT": - prob.driver.options["optimizer"] = "SNOPT" - prob.driver.opt_settings['Major iterations limit'] = 100 - # prob.driver.opt_settings['Major step limit'] = 0.05 - prob.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 - prob.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 - if print_opt_iters: - prob.driver.opt_settings["iSumm"] = 6 - elif optimizer == "IPOPT": - prob.driver.options["optimizer"] = "IPOPT" - prob.driver.opt_settings["max_iter"] = 500 - prob.driver.opt_settings["tol"] = 1e-5 - prob.driver.opt_settings["print_level"] = 5 - # prob.driver.opt_settings["nlp_scaling_method"] = "gradient-based" - prob.driver.opt_settings["alpha_for_y"] = "safer-min-dual-infeas" - prob.driver.opt_settings["mu_strategy"] = "monotone" - prob.driver.opt_settings["bound_mult_init_method"] = "mu-based" - - transcription = dm.Radau(num_segments=5, order=3, compressed=True) - - ode_args = dict( - clean=True, - aviary_options=get_option_defaults(), - core_subsystems=default_mission_subsystems - ) - - accel = dm.Phase(ode_class=FlightPathODE, transcription=transcription, - ode_init_kwargs=ode_args) - - accel.set_time_options(fix_initial=True, duration_bounds=( - 10, 5000), units="s", duration_ref=100) - - accel.set_state_options("TAS", - fix_initial=True, fix_final=False, lower=1, upper=1000, units="kn", ref=250, defect_ref=250) - - accel.set_state_options("mass", - fix_initial=True, fix_final=False, lower=1, upper=None, units="lbm", ref=200000, defect_ref=200000, rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL) - - accel.set_state_options(Dynamic.Mission.DISTANCE, - fix_initial=True, fix_final=False, lower=0, upper=None, units="ft", ref=10000, defect_ref=10000) - - accel.set_state_options(Dynamic.Mission.ALTITUDE, - fix_initial=True, fix_final=False, lower=490, upper=510, units="ft", ref=100, defect_ref=100) - - accel.set_state_options(Dynamic.Mission.FLIGHT_PATH_ANGLE, - fix_initial=True, fix_final=False, units="rad", lower=0.0, ref=1.0, defect_ref=1.0) - - accel.add_control("alpha", opt=True, units="rad", val=0.0, - lower=np.radians(-14), upper=np.radians(14), rate_continuity=True, rate2_continuity=False) - - accel.add_boundary_constraint( - "EAS", loc="final", equals=250, ref=250, units="kn") - - throttle_climb = 0.956 - accel.add_parameter( - Dynamic.Mission.THROTTLE, - opt=False, - units="unitless", - val=throttle_climb, - static_target=False) - - accel.add_parameter( - Aircraft.Wing.AREA, opt=False, units="ft**2", val=1370.0, static_target=True - ) - - accel.add_timeseries_output("EAS", output_name="EAS", units="kn") - accel.add_timeseries_output( - Dynamic.Mission.MACH, - output_name=Dynamic.Mission.MACH, - units="unitless") - accel.add_timeseries_output("alpha", output_name="alpha", units="deg") - accel.add_timeseries_output("CL", output_name="CL", units="unitless") - accel.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") - accel.add_timeseries_output("CD", output_name="CD", units="unitless") - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - traj.add_phase('accel', accel) - - accel.add_objective("mass", loc="final", ref=-1.e4) - # accel.add_objective("time", loc="final", ref=1.e2) - - prob.model.linear_solver.options["iprint"] = 0 - prob.model.nonlinear_solver.options["iprint"] = 0 - - traj.nonlinear_solver = om.NonlinearBlockGS(iprint=0) - traj.options['assembled_jac_type'] = 'csc' - traj.linear_solver = om.DirectSolver() - - prob.set_solver_print(level=0) - - for phase_name, phase in traj._phases.items(): - phase.add_timeseries_output('normal_force') - phase.add_timeseries_output('fuselage_pitch') - phase.add_timeseries_output(Dynamic.Mission.ALTITUDE, units='ft') - phase.add_timeseries_output('mass', units='lbm') - phase.add_timeseries_output(Dynamic.Mission.LIFT, units='lbf') - phase.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, units='deg') - phase.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units='lbf') - phase.add_timeseries_output('alpha', units='deg') - - prob.setup() - - prob.set_val("traj.accel.states:TAS", accel.interp( - "TAS", ys=[200., 250.]), units='kn') - prob.set_val("traj.accel.states:altitude", accel.interp( - Dynamic.Mission.ALTITUDE, ys=[500., 500.]), units='ft') - prob.set_val("traj.accel.states:flight_path_angle", accel.interp( - Dynamic.Mission.FLIGHT_PATH_ANGLE, ys=[0, 0]), units='deg') - prob.set_val("traj.accel.states:mass", accel.interp( - "mass", ys=[174219, 170000]), units='lbm') - - prob.set_val("traj.accel.states:distance", accel.interp( - Dynamic.Mission.DISTANCE, ys=[0, 154]), units='NM') - prob.set_val("traj.accel.t_duration", 10, units='s') - prob.set_val("traj.accel.t_initial", 0, units='s') - - return prob - - -@use_tempdirs -class Testaccel(unittest.TestCase): - - def assert_constant_EAS_result(self, p): - final_mass = p.get_val( - "traj.accel.timeseries.mass", units="lbm")[-1, ...] - assert_near_equal(final_mass, 174.15124423509e3, tolerance=0.0001) - - @require_pyoptsparse(optimizer='IPOPT') - def test_accel_ipopt(self): - p = make_accel_problem(optimizer='IPOPT', constant_quantity='EAS') - dm.run_problem(p, run_driver=True, simulate=False, make_plots=False) - - lift = p.get_val("traj.accel.timeseries.lift") - weight = p.get_val("traj.accel.timeseries.mass") * GRAV_ENGLISH_LBM - gamma = p.get_val("traj.accel.timeseries.flight_path_angle", units="rad") - thrust = p.get_val("traj.accel.timeseries.thrust_net_total") - alpha = p.get_val("traj.accel.timeseries.alpha", units="rad") - - alpha_constant_gamma = np.arcsin((lift - weight * np.cos(gamma)) / thrust) - - with np.printoptions(linewidth=1024): - print(lift.T) - print(weight.T) - print(gamma.T) - print(thrust.T) - print(alpha.T) - print(alpha_constant_gamma.T) - self.assert_constant_EAS_result(p) - - @require_pyoptsparse(optimizer='SNOPT') - def test_accel_snopt(self): - p = make_accel_problem( - optimizer='SNOPT', constant_quantity='EAS', print_opt_iters=True) - dm.run_problem(p, run_driver=True, simulate=True, make_plots=False) - self.assert_constant_EAS_result(p) diff --git a/aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py b/aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py deleted file mode 100644 index e31ec51c4..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py +++ /dev/null @@ -1,33 +0,0 @@ -import unittest - -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.gasp_based.phases.run_phases.run_accel import run_accel - - -class AccelPhaseTestCase(unittest.TestCase): - def bench_test_accel(self): - - prob = run_accel() - - TAS = prob.get_val("accel.timeseries.TAS", units="kn") - weight = prob.get_val("accel.timeseries.mass", units="lbm") - distance = prob.get_val("accel.timeseries.distance", units="ft") - time = prob.get_val("accel.timeseries.time", units="s") - - assert_near_equal(TAS[0], 185, 1e-4) - assert_near_equal(TAS[-1], 251.82436866, 1e-4) - - assert_near_equal(weight[0], 174974, 1e-4) - assert_near_equal(weight[-1], 174886.73023817, 1e-4) - - assert_near_equal(distance[0], 0, 1e-5) - assert_near_equal(distance[-1], 7519.70802292, 1e-5) - - assert_near_equal(time[0], 0, 1e-3) - assert_near_equal(time[-1], 20.36335559, 1e-4) - - -if __name__ == "__main__": - test = AccelPhaseTestCase() - test.bench_test_accel() diff --git a/aviary/mission/gasp_based/phases/benchmark/test_bench_ascent.py b/aviary/mission/gasp_based/phases/benchmark/test_bench_ascent.py deleted file mode 100644 index bc281dfef..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_bench_ascent.py +++ /dev/null @@ -1,58 +0,0 @@ -import unittest - -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.gasp_based.phases.run_phases.run_ascent import run_ascent - - -@unittest.skip("this wasn't being run and needs to be updated") -class AccelPhaseTestCase(unittest.TestCase): - def bench_test_ascent(self): - - prob = run_ascent(make_plots=False) - - gamma = prob.get_val( - "traj.ascent.timeseries.states:flight_path_angle", units="deg") - alt = prob.get_val("traj.ascent.timeseries.states:altitude", units="ft") - TAS = prob.get_val("traj.ascent.timeseries.states:TAS", units="kn") - distance = prob.get_val("traj.ascent.timeseries.states:distance", units="ft") - load_factor = prob.get_val( - "traj.ascent.timeseries.load_factor", units="unitless") - fuselage_pitch = prob.get_val( - "traj.ascent.timeseries.fuselage_pitch", units="deg" - ) - alpha = prob.get_val("traj.ascent.timeseries.controls:alpha", units="deg") - weight = prob.get_val("traj.ascent.timeseries.states:weight", units="lbm") - time = prob.get_val("traj.ascent.timeseries.time", units="s") - - assert_near_equal(gamma[0], 11.4591559, 1e-3) - assert_near_equal(gamma[-1], 6.12703133, 1e-3) - - assert_near_equal(alt[0], 0, 1e-4) - assert_near_equal(alt[-1], 500, 1e-4) - - assert_near_equal(TAS[0], 153.3196491, 1e-4) - assert_near_equal(TAS[-1], 176.63794989, 1e-4) - - assert_near_equal(distance[0], 4330.83393029, 1e-5) - assert_near_equal(distance[-1], 8847.37626223, 1e-5) - - assert_near_equal(load_factor[0], 0.67732548, 1e-2) - assert_near_equal(load_factor[-1], 0.84455828, 1e-2) - - assert_near_equal(fuselage_pitch[0], 15, 1e-3) - assert_near_equal(fuselage_pitch[-1], 14.92380341, 1e-3) - - assert_near_equal(alpha[0], 3.5408441, 1e-3) - assert_near_equal(alpha[-1], 8.79677208, 1e-3) - - assert_near_equal(weight[0], 174963.74211336, 1e-5) - assert_near_equal(weight[-1], 174892.40464724, 1e-5) - - assert_near_equal(time[0], 31.2, 1e-3) - assert_near_equal(time[-1], 47.5236357, 1e-3) - - -if __name__ == "__main__": - test = AccelPhaseTestCase() - test.bench_test_ascent() diff --git a/aviary/mission/gasp_based/phases/benchmark/test_bench_desc1.py b/aviary/mission/gasp_based/phases/benchmark/test_bench_desc1.py deleted file mode 100644 index c61bc24c6..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_bench_desc1.py +++ /dev/null @@ -1,33 +0,0 @@ -import unittest - -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.gasp_based.phases.run_phases.run_desc1 import run_desc1 - - -@unittest.skip('this benchmark is defunct and needs to be updated') -class Desc1PhaseTestCase(unittest.TestCase): - def bench_test_desc1(self): - - prob = run_desc1(make_plots=False) - - alt = prob.get_val("desc1.timeseries.states:altitude", units="ft") - weight = prob.get_val("desc1.timeseries.states:weight", units="lbm") - distance = prob.get_val("desc1.timeseries.states:distance", units="ft") - time = prob.get_val("desc1.timeseries.time", units="s") - - assert_near_equal(alt[0], 37500, 1e-5) - assert_near_equal(alt[-1], 10.e3, 1e-5) - - assert_near_equal(weight[0], 147664, 1e-5) - assert_near_equal(weight[-1], 147539.71665978, 1e-5) - - assert_near_equal(distance[0], 15129527.55905512, 1e-5) - assert_near_equal(distance[-1], 15595089.68838349, 1e-5) - - assert_near_equal(time[0], 0, 1e-4) - assert_near_equal(time[-1], 598.6264441, 1e-5) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/gasp_based/phases/benchmark/test_bench_desc2.py b/aviary/mission/gasp_based/phases/benchmark/test_bench_desc2.py deleted file mode 100644 index f47f6a4d6..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_bench_desc2.py +++ /dev/null @@ -1,33 +0,0 @@ -import unittest - -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.gasp_based.phases.run_phases.run_desc2 import run_desc2 - - -@unittest.skip('this benchmark is defunct and needs to be updated') -class Desc2PhaseTestCase(unittest.TestCase): - def bench_test_desc2(self): - - prob = run_desc2(make_plots=False) - - alt = prob.get_val("desc2.timeseries.states:altitude", units="ft") - weight = prob.get_val("desc2.timeseries.states:weight", units="lbm") - distance = prob.get_val("desc2.timeseries.states:distance", units="ft") - time = prob.get_val("desc2.timeseries.time", units="s") - - assert_near_equal(alt[0], 10.e3, 1e-5) - assert_near_equal(alt[-1], 1000, 1e-4) - - assert_near_equal(weight[0], 147541.5, 1e-5) - assert_near_equal(weight[-1], 147401.60702539, 1e-5) - - assert_near_equal(distance[0], 15576122.0472441, 1e-5) - assert_near_equal(distance[-1], 15776177.53801624, 1e-5) - - assert_near_equal(time[0], 0, 1e-4) - assert_near_equal(time[-1], 437.62278284, 1e-5) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/gasp_based/phases/benchmark/test_bench_groundroll.py b/aviary/mission/gasp_based/phases/benchmark/test_bench_groundroll.py deleted file mode 100644 index 8203b429c..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_bench_groundroll.py +++ /dev/null @@ -1,36 +0,0 @@ -import unittest - -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.gasp_based.phases.run_phases.run_groundroll import \ - run_groundroll - - -@unittest.skip('this benchmark is defunct and needs to be updated') -class GroundrollPhaseTestCase(unittest.TestCase): - def bench_test_groundroll(self): - - prob = run_groundroll(make_plots=False) - - TAS = prob.get_val("traj.groundroll.timeseries.states:TAS", units="kn") - mass = prob.get_val("traj.groundroll.timeseries.states:mass", units="lbm") - distance = prob.get_val( - "traj.groundroll.timeseries.states:distance", units="ft" - ) - time = prob.get_val("traj.groundroll.timeseries.time", units="s") - - assert_near_equal(TAS[0], 0, 1e-4) - assert_near_equal(TAS[-1], 145.37726917, 1e-4) - - assert_near_equal(mass[0], 175100, 1e-6) - assert_near_equal(mass[-1], 174978.19460438, 1e-6) - - assert_near_equal(distance[0], 0, 1e-4) - assert_near_equal(distance[-1], 3547.50615602, 1e-4) - - assert_near_equal(time[0], 0, 1e-3) - assert_near_equal(time[-1], 28.03023543, 1e-3) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/gasp_based/phases/benchmark/test_bench_new_ascent.py b/aviary/mission/gasp_based/phases/benchmark/test_bench_new_ascent.py deleted file mode 100644 index 684c88728..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_bench_new_ascent.py +++ /dev/null @@ -1,427 +0,0 @@ -import unittest - -import dymos as dm -import numpy as np -import openmdao.api as om -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import require_pyoptsparse, use_tempdirs - -from aviary.mission.gasp_based.ode.flight_path_ode import FlightPathODE -from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Dynamic -from aviary.interface.default_phase_info.two_dof import default_mission_subsystems - - -def make_ascent_problem(optimizer='IPOPT', print_opt_iters=False): - - ode_args = dict( - aviary_options=get_option_defaults(), - core_subsystems=default_mission_subsystems - ) - - # - # ASCENT TO GEAR RETRACTION - # - # Initial States Fixed - # Final States Free - # - # Controls: - # alpha - # - # Boundary Constraints: - # alt(final) = 50 ft - # - # Path Constraints: - # 0.0 < load_factor < 1.10 - # 0.0 < fuselage_pitch < 15 deg - # - ascent0_tx = dm.Radau(num_segments=5, order=3, compressed=True, solve_segments=False) - ascent_to_gear_retract = dm.Phase( - ode_class=FlightPathODE, ode_init_kwargs=ode_args, transcription=ascent0_tx) - - ascent_to_gear_retract.set_time_options( - units="s", targets="t_curr", fix_initial=True, - duration_bounds=(0, 10)) - - # Rate sources and units of states are set with tags in AscentEOM - ascent_to_gear_retract.set_state_options(Dynamic.Mission.FLIGHT_PATH_ANGLE, units="rad", - fix_initial=True, fix_final=False, lower=0, upper=0.30, ref=0.1, defect_ref=0.1) - - ascent_to_gear_retract.set_state_options(Dynamic.Mission.ALTITUDE, - fix_initial=True, fix_final=False, lower=0, upper=500, ref=100, defect_ref=100) - - ascent_to_gear_retract.set_state_options("TAS", - fix_initial=True, fix_final=False, lower=0, upper=500, ref=100, defect_ref=100) - - ascent_to_gear_retract.set_state_options("mass", - fix_initial=True, fix_final=False, lower=100.e3, upper=None, ref=175_000, defect_ref=175_000, rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL) - - ascent_to_gear_retract.set_state_options(Dynamic.Mission.DISTANCE, - fix_initial=True, fix_final=False, lower=0, upper=15_000, ref=5280, defect_ref=5280) - - # Note that t_init_gear and t_init_flaps are taking values of 100 s here while not being connected to the - # those trajectory-level parameters. This means that we'll have some small discontinuity in the aerodynamics - # across these phases, but making the assumption of time here removes the feedback loop, removes the need for - # a nonlinear solver on the trajectory, and makes things happen faster. - ascent_to_gear_retract.add_parameter( - "t_init_gear", units="s", static_target=True, opt=False, val=100.0) - ascent_to_gear_retract.add_parameter( - "t_init_flaps", units="s", static_target=True, opt=False, val=100.0) - ascent_to_gear_retract.add_parameter( - "wing_area", units="ft**2", val=1370, static_target=True, opt=False) - - # Using Radau, we need to apply rate continuity if desired for controls even when the transcription is compressed. - # The final value of a control in a segment is interpolated, not a design variable. - # Note we specify units as radians here, since alpha inputs in the ODE are in degrees. - # ascent_to_gear_retract.add_control("alpha", - # units="rad", val=0.0, continuity=True, rate_continuity=False, - # opt=True, lower=np.radians(-30), upper=np.radians(30), ref=0.01) - ascent_to_gear_retract.add_polynomial_control("alpha", order=1, - units="rad", val=0.0, opt=True, lower=np.radians(-14), upper=np.radians(14), ref=0.1) - - # boundary/path constraints + controls - # Final altitude can be a linear constraint, since the final value of altitude is a design variable. - ascent_to_gear_retract.add_boundary_constraint(Dynamic.Mission.ALTITUDE, - loc="final", equals=50, units="ft", ref=1.0, ref0=0.0, linear=True - ) - - # Load factor can be treated as a linear constraint as long as i_wing is not a design variable. - ascent_to_gear_retract.add_path_constraint("load_factor", - lower=0.0, upper=1.10, linear=False) - - ascent_to_gear_retract.add_path_constraint("fuselage_pitch", constraint_name="theta", - lower=0, upper=15, units="deg", ref=15, linear=False) - - # - # ASCENT TO FLAP RETRACTION - # - # Initial States Free - # Final States Free - # - # Controls: - # alpha - # - # Boundary Constraints: - # alt(final) = 400 ft - # - # Path Constraints: - # 0.0 < load_factor < 1.10 - # 0.0 < fuselage_pitch < 15 deg - # - ascent1_tx = dm.Radau(num_segments=5, order=3, compressed=True, solve_segments=False) - ascent_to_flap_retract = dm.Phase( - ode_class=FlightPathODE, ode_init_kwargs=ode_args, transcription=ascent1_tx) - - ascent_to_flap_retract.set_time_options( - units="s", targets="t_curr", fix_initial=False, - initial_bounds=(5, 50), duration_bounds=(5, 50)) - - # Rate sources and units of states are set with tags in AscentEOM - ascent_to_flap_retract.set_state_options(Dynamic.Mission.FLIGHT_PATH_ANGLE, units="rad", - fix_initial=False, fix_final=False, lower=0, upper=0.5, ref=0.1, defect_ref=0.1) - - ascent_to_flap_retract.set_state_options(Dynamic.Mission.ALTITUDE, - fix_initial=False, fix_final=False, lower=0, upper=500, ref=100, defect_ref=100) - - ascent_to_flap_retract.set_state_options("TAS", - fix_initial=False, fix_final=False, lower=0, upper=1000, ref=100, defect_ref=100) - - ascent_to_flap_retract.set_state_options("mass", - fix_initial=False, fix_final=False, lower=1, upper=None, ref=175_000, defect_ref=175_000, rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL) - - ascent_to_flap_retract.set_state_options(Dynamic.Mission.DISTANCE, - fix_initial=False, fix_final=False, lower=0, upper=15_000, ref=5280, defect_ref=5280) - - # Targets are not needed when there is a top-level ODE input with the same name as the parameter, state, or control - ascent_to_flap_retract.add_parameter( - "t_init_gear", units="s", static_target=True, opt=False, val=100) - ascent_to_flap_retract.add_parameter( - "t_init_flaps", units="s", static_target=True, opt=False, val=100) - ascent_to_flap_retract.add_parameter( - "wing_area", units="ft**2", val=1370, static_target=True, opt=False) - - # Using Radau, we need to apply rate continuity if desired for controls even when the transcription is compressed. - # The final value of a control in a segment is interpolated, not a design variable. - # Note we specify units as radians here, since alpha inputs in the ODE are in degrees. - ascent_to_flap_retract.add_polynomial_control("alpha", order=1, - units="rad", val=0.0, - opt=True, lower=np.radians(-14), upper=np.radians(14), ref=0.01) - - # boundary/path constraints + controls - # Final altitude can be a linear constraint, since the final value of altitude is a design variable. - ascent_to_flap_retract.add_boundary_constraint(Dynamic.Mission.ALTITUDE, - loc="final", equals=400, units="ft", ref=1.0, ref0=0.0, linear=True - ) - - # Load factor can be treated as a linear constraint as long as i_wing is not a design variable. - ascent_to_flap_retract.add_path_constraint("load_factor", - lower=0.0, upper=1.10, linear=False) - - ascent_to_flap_retract.add_path_constraint("fuselage_pitch", constraint_name="theta", - lower=0, upper=15, units="deg", ref=15, linear=False) - - # - # ASCENT TO CLEAN AERO CONFIG - # - # Initial States Free - # Final States Free - # - # Controls: - # alpha - # - # Boundary Constraints: - # alt(final) = 500 ft - # flap_factor(final) = 0 (fully retracted) - # - # Path Constraints: - # 0.0 < load_factor < 1.10 - # 0.0 < fuselage_pitch < 15 deg - # - ascent2_tx = dm.Radau(num_segments=5, order=3, compressed=True, solve_segments=False) - ascent_to_clean_aero = dm.Phase( - ode_class=FlightPathODE, ode_init_kwargs=ode_args, transcription=ascent2_tx) - - ascent_to_clean_aero.set_time_options( - units="s", targets="t_curr", fix_initial=False, - initial_bounds=(10, 100), duration_bounds=(1, 50)) - - # Rate sources and units of states are set with tags in AscentEOM - ascent_to_clean_aero.set_state_options(Dynamic.Mission.FLIGHT_PATH_ANGLE, units="rad", - fix_initial=False, fix_final=False, lower=0, upper=0.5, ref=0.1, defect_ref=0.1) - - ascent_to_clean_aero.set_state_options(Dynamic.Mission.ALTITUDE, - fix_initial=False, fix_final=False, lower=0, upper=500, ref=100, defect_ref=100) - - ascent_to_clean_aero.set_state_options("TAS", - fix_initial=False, fix_final=False, lower=0, upper=1000, ref=100, defect_ref=100) - - ascent_to_clean_aero.set_state_options("mass", - fix_initial=False, fix_final=False, lower=1, upper=None, ref=175_000, defect_ref=175_000, rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL) - - ascent_to_clean_aero.set_state_options(Dynamic.Mission.DISTANCE, - fix_initial=False, fix_final=False, lower=0, upper=15_000, ref=5_280, defect_ref=5_280) - - # Targets are not needed when there is a top-level ODE input with the same name as the parameter, state, or control - ascent_to_clean_aero.add_parameter( - "t_init_gear", units="s", static_target=True, opt=False) - ascent_to_clean_aero.add_parameter( - "t_init_flaps", units="s", static_target=True, opt=False) - ascent_to_clean_aero.add_parameter( - "wing_area", units="ft**2", val=1370, static_target=True, opt=False) - - # Using Radau, we need to apply rate continuity if desired for controls even when the transcription is compressed. - # The final value of a control in a segment is interpolated, not a design variable. - # Note we specify units as radians here, since alpha inputs in the ODE are in degrees. - ascent_to_clean_aero.add_polynomial_control("alpha", order=1, - units="rad", val=0.0, # continuity=True, rate_continuity=True, - opt=True, lower=np.radians(-14), upper=np.radians(14), ref=0.01) - - # boundary/path constraints + controls - # Final altitude can be a linear constraint, since the final value of altitude is a design variable. - ascent_to_clean_aero.add_boundary_constraint(Dynamic.Mission.ALTITUDE, - loc="final", equals=500, units="ft", ref=1.0, ref0=0.0, linear=True - ) - - # Ensure gear and flaps are fully retracted - # Note setting equals=0.0 here will result in a failure of the optimization, since flap_factor approaches - # zero asymptotically. - ascent_to_clean_aero.add_boundary_constraint("gear_factor", - loc="final", upper=1.0E-3, ref=1.0, ref0=0.0, linear=False - ) - - ascent_to_clean_aero.add_boundary_constraint("flap_factor", - loc="final", upper=1.0E-3, ref=1.0, ref0=0.0, linear=False - ) - - # Load factor can be treated as a linear constraint as long as i_wing is not a design variable. - ascent_to_clean_aero.add_path_constraint("load_factor", - lower=0.0, upper=1.10, linear=False) - - ascent_to_clean_aero.add_path_constraint("fuselage_pitch", constraint_name="theta", - lower=0, upper=15, units="deg", ref=15, linear=False) - - # - # PROBLEM DEFINITION - # - p = om.Problem() - traj = p.model.add_subsystem("traj", dm.Trajectory()) - traj.add_phase("ascent_to_gear_retract", ascent_to_gear_retract) - traj.add_phase("ascent_to_flap_retract", ascent_to_flap_retract) - traj.add_phase("ascent_to_clean_aero", ascent_to_clean_aero) - - traj.add_parameter('wing_area', units='ft**2', static_target=True, opt=False) - - # Inter-phase connections - # 1. Connect final time of ascent_to_gear_retract to the trajectory as t_init_gear - # traj.connect(src_name='ascent_to_gear_retract.timeseries.time', - # tgt_name=('ascent_to_flap_retract.parameters:t_init_gear', - # 'ascent_to_clean_aero.parameters:t_init_gear'), - # src_indices=om.slicer[-1, ...]) - - # 2. Connect final time of ascent_to_flap_retract to the trajectory as t_init_flaps - traj.connect(src_name='ascent_to_flap_retract.timeseries.time', - tgt_name='ascent_to_clean_aero.parameters:t_init_flaps', - src_indices=om.slicer[-1, ...]) - - # 3. Enforce value continuity between all phases in ascent for time, states, and alpha control - traj.link_phases(['ascent_to_gear_retract', 'ascent_to_flap_retract', 'ascent_to_clean_aero'], - vars=['time', Dynamic.Mission.FLIGHT_PATH_ANGLE, Dynamic.Mission.ALTITUDE, 'TAS', Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE, 'alpha']) - - traj.add_linkage_constraint(phase_a='ascent_to_gear_retract', - phase_b='ascent_to_flap_retract', - var_a='time', - var_b='t_init_gear', - loc_a='final', - loc_b='initial', - connected=True) - - traj.add_linkage_constraint(phase_a='ascent_to_gear_retract', - phase_b='ascent_to_clean_aero', - var_a='time', - var_b='t_init_gear', - loc_a='final', - loc_b='initial', - connected=True) - - # traj.nonlinear_solver = om.NonlinearBlockGS(iprint=0) - # traj.options['assembled_jac_type'] = 'csc' - # traj.linear_solver = om.DirectSolver() - - for phase_name, phase in traj._phases.items(): - phase.add_timeseries_output('flap_factor') - phase.add_timeseries_output('normal_force') - # Add alpha to the timeseries as 'alpha' regardless of whether it is a control or polynomial control. - phase.add_timeseries_output('alpha', units='deg') - - p.driver = om.pyOptSparseDriver() - - p.driver.options["optimizer"] = optimizer - - if optimizer == 'SNOPT': - p.driver.opt_settings["iSumm"] = 6 - p.driver.opt_settings['Major step limit'] = 1 - p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 - p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 - elif optimizer == 'IPOPT': - p.driver.options['optimizer'] = 'IPOPT' - p.driver.opt_settings['tol'] = 1.0E-6 - p.driver.opt_settings['mu_init'] = 1e-5 - p.driver.opt_settings['max_iter'] = 100 - p.driver.opt_settings['print_level'] = 5 - # for faster convergence - p.driver.opt_settings['nlp_scaling_method'] = 'gradient-based' - p.driver.opt_settings['alpha_for_y'] = 'safer-min-dual-infeas' - p.driver.opt_settings['mu_strategy'] = 'monotone' - - # p.driver.options['debug_print'] = ['desvars'] - - # Uncomment declare_coloring when the coloring needs to be reset (number of nodes have changed, constraints changed, - # or underlying models have changed) - # p.driver.use_fixed_coloring() - # p.model.use_fixed_coloring(recurse=True) - p.driver.declare_coloring(tol=1.0E-12) - - # p.model.add_objective("traj.ascent_to_gear_retract.timeseries.states:mass", index=-1, ref=1.4e5, ref0=1.3e5) - ascent_to_clean_aero.add_objective("mass", loc="final", ref=-1.e3) - - # p.model.connect('wing_area','traj.ascent_to_gear_retract.parameters:wing_area') - # p.model.set_input_defaults("gross_wt_initial", val=174000, units="lbf") - p.setup() - - # SET INITIAL TIMES GUESSES - # p.set_val('traj.parameters:t_init_gear', 40.0, units='s') - # p.set_val('traj.parameters:t_init_flaps', 47.5, units='s') - p.set_val('traj.parameters:wing_area', 1370, units='ft**2') - - # SET ALTITUDE GUESSES - p.set_val("traj.ascent_to_gear_retract.states:altitude", - ascent_to_gear_retract.interp(Dynamic.Mission.ALTITUDE, ys=[0, 50]), units="ft") - p.set_val("traj.ascent_to_flap_retract.states:altitude", - ascent_to_flap_retract.interp(Dynamic.Mission.ALTITUDE, ys=[50, 400]), units="ft") - p.set_val("traj.ascent_to_clean_aero.states:altitude", - ascent_to_clean_aero.interp(Dynamic.Mission.ALTITUDE, ys=[400, 500]), units="ft") - - # SET FLIGHT PATH ANGLE GUESSES - p.set_val("traj.ascent_to_gear_retract.states:flight_path_angle", 0.2, units="rad") - p.set_val("traj.ascent_to_flap_retract.states:flight_path_angle", 10, units="deg") - p.set_val("traj.ascent_to_clean_aero.states:flight_path_angle", 10, units="deg") - - # SET TRUE AIRSPEED GUESSES - p.set_val("traj.ascent_to_gear_retract.states:TAS", - ascent_to_gear_retract.interp("TAS", [153.3196491, 170]), units="kn") - p.set_val("traj.ascent_to_flap_retract.states:TAS", - ascent_to_flap_retract.interp("TAS", [170, 190]), units="kn") - p.set_val("traj.ascent_to_clean_aero.states:TAS", - ascent_to_clean_aero.interp("TAS", [190, 195]), units="kn") - - # SET MASS GUESSES - p.set_val("traj.ascent_to_gear_retract.states:mass", ascent_to_gear_retract.interp( - "mass", [174963.74211336, 174000]), units="lbm") - p.set_val("traj.ascent_to_flap_retract.states:mass", - ascent_to_flap_retract.interp("mass", [174000., 173900]), units="lbm") - p.set_val("traj.ascent_to_clean_aero.states:mass", - ascent_to_clean_aero.interp("mass", [173900., 173800]), units="lbm") - - # SET RANGE GUESSES - p.set_val("traj.ascent_to_gear_retract.states:distance", ascent_to_gear_retract.interp( - Dynamic.Mission.DISTANCE, [4330.83393029, 5000]), units="ft") - p.set_val("traj.ascent_to_flap_retract.states:distance", - ascent_to_flap_retract.interp(Dynamic.Mission.DISTANCE, [5000., 6000]), units="ft") - p.set_val("traj.ascent_to_clean_aero.states:distance", - ascent_to_clean_aero.interp(Dynamic.Mission.DISTANCE, [6000., 7000]), units="ft") - - # SET TIME GUESSES - p.set_val("traj.ascent_to_gear_retract.t_initial", 31.2) - p.set_val("traj.ascent_to_gear_retract.t_duration", 3.0) - - p.set_val("traj.ascent_to_flap_retract.t_initial", 35.0) - p.set_val("traj.ascent_to_flap_retract.t_duration", 5.0) - - p.set_val("traj.ascent_to_clean_aero.t_initial", 44.0) - p.set_val("traj.ascent_to_clean_aero.t_duration", 10.0) - - # SET ALPHA GUESSES - p.set_val("traj.ascent_to_gear_retract.polynomial_controls:alpha", - ascent_to_gear_retract.interp('alpha', ys=[0, 0]), units="deg") - p.set_val("traj.ascent_to_flap_retract.polynomial_controls:alpha", - ascent_to_flap_retract.interp('alpha', ys=[0, 0]), units="deg") - p.set_val("traj.ascent_to_clean_aero.polynomial_controls:alpha", - ascent_to_clean_aero.interp('alpha', ys=[0, 0]), units="deg") - - p.set_solver_print(level=2, depth=1e99) - - return p - - -@use_tempdirs -class TestAscent(unittest.TestCase): - - def assert_result(self, p): - t_init_gear = p.get_val( - "traj.ascent_to_gear_retract.timeseries.time", units="s")[-1, ...] - t_init_flaps = p.get_val( - "traj.ascent_to_flap_retract.timeseries.time", units="s")[-1, ...] - - print("t_init_gear (s)", t_init_gear) - print("t_init_flaps (s)", t_init_flaps) - - assert_near_equal(t_init_gear, 32.3, tolerance=0.01) - assert_near_equal(t_init_flaps, 50.93320588, tolerance=0.01) - - @require_pyoptsparse(optimizer='IPOPT') - def bench_test_ascent_result_ipopt(self): - p = make_ascent_problem(optimizer='IPOPT') - dm.run_problem(p, run_driver=True, simulate=False, make_plots=False, - solution_record_file='ascent_solution_IPOPT.db') - self.assert_result(p) - - @require_pyoptsparse(optimizer='SNOPT') - def bench_test_ascent_result_snopt(self): - p = make_ascent_problem(optimizer='SNOPT') - dm.run_problem(p, run_driver=True, simulate=False, make_plots=False, - solution_record_file='ascent_solution_SNOPT.db') - self.assert_result(p) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/gasp_based/phases/benchmark/test_bench_new_groundroll.py b/aviary/mission/gasp_based/phases/benchmark/test_bench_new_groundroll.py deleted file mode 100644 index 7b9feb768..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_bench_new_groundroll.py +++ /dev/null @@ -1,183 +0,0 @@ -import unittest - -import dymos as dm -import openmdao.api as om -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import require_pyoptsparse, use_tempdirs - -from aviary.constants import RHO_SEA_LEVEL_ENGLISH -from aviary.mission.gasp_based.ode.flight_path_ode import FlightPathODE -from aviary.mission.gasp_based.ode.params import ParamPort -from aviary.mission.gasp_based.phases.v_rotate_comp import VRotateComp -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 - - -def make_groundroll_problem(optimizer='IPOPT', print_opt_iters=False, solve_segments=False): - groundroll_trans = dm.Radau( - num_segments=5, order=3, compressed=True, solve_segments=solve_segments - ) - - ode_args = dict( - aviary_options=get_option_defaults(), - core_subsystems=default_mission_subsystems - ) - - groundroll = dm.Phase( - ode_class=FlightPathODE, - ode_init_kwargs=dict(ode_args, ground_roll=True), - transcription=groundroll_trans, - ) - - groundroll.set_time_options(fix_initial=True, fix_duration=False, - units="s", targets="t_curr", - duration_bounds=(20, 100), duration_ref=1) - - groundroll.set_state_options("TAS", - fix_initial=True, fix_final=False, lower=1.0E-6, upper=1000, ref=1, defect_ref=1) - - groundroll.set_state_options("mass", - fix_initial=True, fix_final=False, lower=1, upper=195_000, ref=1000, defect_ref=1000, rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL) - - groundroll.set_state_options(Dynamic.Mission.DISTANCE, - fix_initial=True, fix_final=False, lower=0, upper=100_000, ref=1, defect_ref=1) - - groundroll.add_parameter("t_init_gear", units="s", - static_target=True, opt=False, val=32.3) - groundroll.add_parameter("t_init_flaps", units="s", - static_target=True, opt=False, val=44.0) - - groundroll.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") - groundroll.add_timeseries_output("normal_force") - groundroll.add_timeseries_output(Dynamic.Mission.MACH) - groundroll.add_timeseries_output("EAS", units="kn") - groundroll.add_timeseries_output(Dynamic.Mission.LIFT) - groundroll.add_timeseries_output("CL") - groundroll.add_timeseries_output("CD") - groundroll.add_timeseries_output("fuselage_pitch", output_name="theta", units="deg") - - p = om.Problem() - - traj = p.model.add_subsystem("traj", dm.Trajectory()) - groundroll = traj.add_phase("groundroll", groundroll) - - groundroll.add_objective('time', loc='final', ref=1.0) - - p.model.add_subsystem("vrot_comp", VRotateComp()) - p.model.connect('traj.groundroll.states:mass', - 'vrot_comp.mass', src_indices=om.slicer[0, ...]) - - vrot_eq_comp = p.model.add_subsystem("vrot_eq_comp", om.EQConstraintComp()) - vrot_eq_comp.add_eq_output("v_rotate_error", eq_units="kn", - lhs_name="v_rot_computed", rhs_name="groundroll_v_final", add_constraint=True) - - p.model.connect('vrot_comp.Vrot', 'vrot_eq_comp.v_rot_computed') - p.model.connect('traj.groundroll.states:TAS', - 'vrot_eq_comp.groundroll_v_final', src_indices=om.slicer[-1, ...]) - - p.driver = om.pyOptSparseDriver() - p.driver.declare_coloring() - p.driver.options["print_results"] = p.comm.rank == 0 - - p.driver.options["optimizer"] = optimizer - - if optimizer == "SNOPT": - p.driver.opt_settings["Major optimality tolerance"] = 3e-4 - p.driver.opt_settings["Major feasibility tolerance"] = 1e-6 - p.driver.opt_settings["Function precision"] = 1e-6 - p.driver.opt_settings["Linesearch tolerance"] = 0.99 - if print_opt_iters: - p.driver.opt_settings["iSumm"] = 6 - p.driver.opt_settings["Major iterations limit"] = 75 - elif optimizer == "IPOPT": - p.driver.opt_settings["max_iter"] = 500 - p.driver.opt_settings["tol"] = 1e-5 - if print_opt_iters: - p.driver.opt_settings["print_level"] = 5 - p.driver.opt_settings[ - "nlp_scaling_method" - ] = "gradient-based" # for faster convergence - p.driver.opt_settings["alpha_for_y"] = "safer-min-dual-infeas" - p.driver.opt_settings["mu_strategy"] = "monotone" - p.driver.opt_settings["bound_mult_init_method"] = "mu-based" - - p.set_solver_print(level=-1) - - p.setup() - - # TODO: paramport - params = ParamPort.param_data - p.set_val('vrot_comp.' + Aircraft.Wing.AREA, - params[Aircraft.Wing.AREA]["val"], units=params[Aircraft.Wing.AREA]["units"]) - - p.set_val("vrot_comp.dV1", val=10, units="kn") - p.set_val("vrot_comp.dVR", val=5, units="kn") - p.set_val("vrot_comp.rho", val=RHO_SEA_LEVEL_ENGLISH, units="slug/ft**3") - p.set_val("vrot_comp.CL_max", val=2.1886, units="unitless") - - p.set_val("traj.groundroll.states:TAS", - groundroll.interp("TAS", [0, 146]), - units="kn") - - p.set_val( - "traj.groundroll.states:mass", - groundroll.interp("mass", [175100, 174000]), - units="lbm", - ) - - p.set_val( - "traj.groundroll.states:distance", - groundroll.interp(Dynamic.Mission.DISTANCE, [0, 3000]), - units="ft", - ) - - p.set_val("traj.groundroll.t_duration", 20.0) - - return p - - -@use_tempdirs -class TestGroundRoll(unittest.TestCase): - - # @require_pyoptsparse(optimizer='IPOPT') - # def benchmark_groundroll_result_ipopt(self): - # p = make_groundroll_problem(optimizer='IPOPT') - # dm.run_problem(p, run_driver=True, simulate=False, make_plots=False) - - # tf = p.get_val('traj.groundroll.timeseries.time', units='s')[-1, 0] - # vrot = p.get_val('vrot_comp.Vrot', units='kn')[0] - - # print(f't_final: {tf:8.3f} s') - # print(f'v_rotate: {vrot:8.3f} knots') - - # assert_near_equal(tf, 29.6, tolerance=0.01) - # assert_near_equal(vrot, 146.4, tolerance=0.02) - - @require_pyoptsparse(optimizer='IPOPT') - def bench_test_groundroll_result_ipopt_solve(self): - p = make_groundroll_problem(optimizer='IPOPT', solve_segments='forward') - dm.run_problem(p, run_driver=True, simulate=False, make_plots=False) - - tf = p.get_val('traj.groundroll.timeseries.time', units='s')[-1, 0] - vrot = p.get_val('vrot_comp.Vrot', units='kn')[0] - - print(f't_final: {tf:8.3f} s') - print(f'v_rotate: {vrot:8.3f} knots') - - assert_near_equal(tf, 30.99546852, tolerance=0.01) - assert_near_equal(vrot, 146.4, tolerance=0.02) - - # @require_pyoptsparse(optimizer='SNOPT') - # def benchmark_groundroll_result_snopt(self): - # p = make_groundroll_problem(optimizer='SNOPT') - # dm.run_problem(p, run_driver=True, simulate=False, make_plots=False) - - # tf = p.get_val('traj.groundroll.timeseries.time', units='s')[-1, 0] - # vrot = p.get_val('vrot_comp.Vrot', units='kn')[0] - - # print(f't_final: {tf:8.3f} s') - # print(f'v_rotate: {vrot:8.3f} knots') - - # assert_near_equal(tf, 29.6, tolerance=0.01) - # assert_near_equal(vrot, 146.4, tolerance=0.02) diff --git a/aviary/mission/gasp_based/phases/benchmark/test_bench_new_rotation.py b/aviary/mission/gasp_based/phases/benchmark/test_bench_new_rotation.py deleted file mode 100644 index c26080b6d..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_bench_new_rotation.py +++ /dev/null @@ -1,176 +0,0 @@ -import unittest - -import dymos as dm -import numpy as np -import openmdao.api as om -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import require_pyoptsparse, use_tempdirs -from packaging import version - -from aviary.mission.gasp_based.ode.flight_path_ode import FlightPathODE -from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Dynamic -from aviary.interface.default_phase_info.two_dof import default_mission_subsystems - - -def make_rotation_problem(optimizer='IPOPT', print_opt_iters=False): - # - # ROTATION TO TAKEOFF - # - # Initial States Fixed - # Final States Free - # - # Controls: - # None - # - # Boundary Constraints: - # normal_force(final) = 0 lbf - # - # Path Constraints: - # None - # - - rotation_trans = dm.Radau( - num_segments=5, order=3, compressed=True, solve_segments=False - ) - - ode_args = dict( - aviary_options=get_option_defaults(), - core_subsystems=default_mission_subsystems - ) - - rotation = dm.Phase( - ode_class=FlightPathODE, - # Use the standard ode_args and update it for ground_roll dynamics - ode_init_kwargs=dict(ode_args, ground_roll=True), - transcription=rotation_trans, - ) - - rotation.set_time_options( - fix_initial=True, - fix_duration=False, - units="s", - targets="t_curr", - duration_bounds=(1, 100), - duration_ref=1.0, - ) - - rotation.add_parameter('alpha_rate', opt=False, - static_target=True, val=3.33, units='deg/s') - rotation.add_parameter("t_init_gear", units="s", - static_target=True, opt=False, val=32.3) - rotation.add_parameter("t_init_flaps", units="s", - static_target=True, opt=False, val=44.0) - rotation.add_parameter("wing_area", units="ft**2", - static_target=True, opt=False, val=1370) - - # State alpha is not defined in the ODE, taken from the parameter "alpha_rate" - rotation.add_state("alpha", units="rad", rate_source="alpha_rate", - fix_initial=True, fix_final=False, lower=0.0, upper=np.radians(25), ref=1.0) - - rotation.set_state_options("TAS", - fix_initial=True, fix_final=False, lower=0.0, upper=1000.0, ref=100.0, defect_ref=100.0) - - rotation.set_state_options("mass", - fix_initial=True, fix_final=False, lower=1.0, upper=190_000.0, ref=1000.0, - defect_ref=1000.0, rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - ) - - rotation.set_state_options(Dynamic.Mission.DISTANCE, - fix_initial=True, fix_final=False, lower=0, upper=10.e3, ref=100, defect_ref=100) - - # boundary/path constraints + controls - rotation.add_boundary_constraint( - "normal_force", loc="final", equals=0, units="lbf", ref=1000.0) - - rotation.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, units="lbf") - rotation.add_timeseries_output("normal_force") - rotation.add_timeseries_output(Dynamic.Mission.MACH) - rotation.add_timeseries_output("EAS", units="kn") - rotation.add_timeseries_output(Dynamic.Mission.LIFT) - rotation.add_timeseries_output("CL") - rotation.add_timeseries_output("CD") - rotation.add_timeseries_output("fuselage_pitch", output_name="theta", units="deg") - - p = om.Problem() - traj = p.model.add_subsystem("traj", dm.Trajectory()) - traj.add_phase("rotation", rotation) - - rotation.timeseries_options['use_prefix'] = True - - p.driver = om.pyOptSparseDriver() - p.driver.options["optimizer"] = optimizer - - if optimizer == 'SNOPT': - if print_opt_iters: - p.driver.opt_settings["iSumm"] = 6 - p.driver.opt_settings['Major step limit'] = 1 - p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 - p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 - elif optimizer == 'IPOPT': - p.driver.options['optimizer'] = 'IPOPT' - p.driver.opt_settings['tol'] = 1.0E-6 - p.driver.opt_settings['mu_init'] = 1e-3 - p.driver.opt_settings['max_iter'] = 100 - if print_opt_iters: - p.driver.opt_settings['print_level'] = 5 - # for faster convergence - p.driver.opt_settings['nlp_scaling_method'] = 'gradient-based' - p.driver.opt_settings['alpha_for_y'] = 'safer-min-dual-infeas' - p.driver.opt_settings['mu_strategy'] = 'monotone' - - p.model.add_objective( - "traj.rotation.timeseries.states:mass", index=-1, ref=1.4e5, ref0=1.3e5 - ) - p.set_solver_print(level=-1) - - p.setup() - - # SET INITIAL ALPHA INITIAL GUESS - p.set_val("traj.rotation.states:alpha", - rotation.interp("alpha", [0, 2.5]), units="deg") - - # SET TRUE AIRSPEED INITIAL GUESS - p.set_val("traj.rotation.states:TAS", 143, units="kn") - - # SET MASS INITIAL GUESS - p.set_val("traj.rotation.states:mass", rotation.interp( - "mass", [174975.12776915, 174900]), units="lbm") - - # SET RANGE INITIAL GUESS - p.set_val("traj.rotation.states:distance", rotation.interp( - Dynamic.Mission.DISTANCE, [3680.37217765, 4000]), units="ft") - - # SET TIME INITIAL GUESS - p.set_val("traj.rotation.t_initial", 30.0) - p.set_val("traj.rotation.t_duration", 4.0) - - return p - - -@use_tempdirs -class TestRotation(unittest.TestCase): - - def assert_result(self, p): - tf = p.get_val('traj.rotation.timeseries.time', units='s')[-1, 0] - vf = p.get_val('traj.rotation.timeseries.states:TAS', units='kn')[-1, 0] - - print(f't_final: {tf:8.3f} s') - print(f'v_final: {vf:8.3f} knots') - - assert_near_equal(tf, 32.993, tolerance=0.01) - assert_near_equal(vf, 155.246, tolerance=0.01) - - @require_pyoptsparse(optimizer='IPOPT') - def bench_test_rotation_result_ipopt(self): - p = make_rotation_problem(optimizer='IPOPT') - dm.run_problem(p, run_driver=True, simulate=False, make_plots=False, - solution_record_file='rotation_IPOPT.db') - self.assert_result(p) - - @require_pyoptsparse(optimizer='SNOPT') - def bench_test_rotation_result_snopt(self): - p = make_rotation_problem(optimizer='SNOPT') - dm.run_problem(p, run_driver=True, simulate=False, make_plots=False, - solution_record_file='rotation_SNOPT.db') - self.assert_result(p) diff --git a/aviary/mission/gasp_based/phases/benchmark/test_bench_rotation.py b/aviary/mission/gasp_based/phases/benchmark/test_bench_rotation.py deleted file mode 100644 index dfb96ab8c..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_bench_rotation.py +++ /dev/null @@ -1,43 +0,0 @@ -import unittest - -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.gasp_based.phases.run_phases.run_rotation import run_rotation - - -@unittest.skip('this benchmark is defunct and needs to be updated') -class RotationPhaseTestCase(unittest.TestCase): - def bench_test_rotation(self): - - prob = run_rotation(make_plots=False) - - alpha = prob.get_val("traj.rotation.timeseries.states:alpha", units="deg") - TAS = prob.get_val("traj.rotation.timeseries.states:TAS", units="kn") - weight = prob.get_val("traj.rotation.timeseries.states:weight", units="lbm") - distance = prob.get_val("traj.rotation.timeseries.states:distance", units="ft") - normal_force = prob.get_val( - "traj.rotation.timeseries.normal_force", units="lbf" - ) - time = prob.get_val("traj.rotation.timeseries.time", units="s") - - assert_near_equal(alpha[0], 0, 1e-4) - assert_near_equal(alpha[-1], 25, 1e-4) - - assert_near_equal(TAS[0], 143, 1e-4) - assert_near_equal(TAS[-1], 173.4636624, 1e-4) - - assert_near_equal(weight[0], 174975.12776915, 1e-6) - assert_near_equal(weight[-1], 174942.19649927, 1e-6) - - assert_near_equal(distance[0], 3680.37217765, 1e-4) - assert_near_equal(distance[-1], 5693.05954272, 1e-4) - - assert_near_equal(normal_force[0], 118093.50754183, 1e-5) - assert_near_equal(normal_force[-1], 0, 1e-5) - - assert_near_equal(time[0], 0, 1e-3) - assert_near_equal(time[-1], 7.50750751, 1e-3) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/gasp_based/phases/benchmark/test_bench_takeoff.py b/aviary/mission/gasp_based/phases/benchmark/test_bench_takeoff.py deleted file mode 100644 index 44fe17859..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_bench_takeoff.py +++ /dev/null @@ -1,59 +0,0 @@ -import unittest - -from openmdao.utils.assert_utils import assert_near_equal - -from aviary.mission.gasp_based.phases.run_phases.run_takeoff import run_takeoff - - -@unittest.skip('this benchmark is defunct and needs to be updated') -class TakeoffPhaseTestCase(unittest.TestCase): - def bench_test_takeoff(self): - - prob = run_takeoff(make_plots=False) - - TAS0 = prob.get_val("traj.groundroll.timeseries.states:TAS", units="kn") - distance0 = prob.get_val( - "traj.groundroll.timeseries.states:distance", units="ft" - ) - weight0 = prob.get_val("traj.groundroll.timeseries.states:weight", units="lbm") - time0 = prob.get_val("traj.groundroll.timeseries.time", units="s") - - gamma1 = prob.get_val( - "traj.ascent.timeseries.states:flight_path_angle", units="deg") - alt1 = prob.get_val("traj.ascent.timeseries.states:altitude", units="ft") - TAS1 = prob.get_val("traj.ascent.timeseries.states:TAS", units="kn") - distance1 = prob.get_val("traj.ascent.timeseries.states:distance", units="ft") - load_factor1 = prob.get_val( - "traj.ascent.timeseries.load_factor", units="unitless") - fuselage_pitch1 = prob.get_val( - "traj.ascent.timeseries.fuselage_pitch", units="deg" - ) - alpha1 = prob.get_val("traj.ascent.timeseries.controls:alpha", units="deg") - weight1 = prob.get_val("traj.ascent.timeseries.states:weight", units="lbm") - time1 = prob.get_val("traj.ascent.timeseries.time", units="s") - - assert_near_equal(gamma1[-1], -0.62446459, 1e-3) - - assert_near_equal(alt1[-1], 500, 1e-4) - - assert_near_equal(TAS0[0], 0, 1e-4) - assert_near_equal(TAS1[-1], 191.15818794, 1e-4) - - assert_near_equal(distance0[0], 0, 1e-5) - assert_near_equal(distance1[-1], 10000.0, 1e-5) - - assert_near_equal(load_factor1[-1], 0.16259711, 1e-2) - - assert_near_equal(fuselage_pitch1[-1], 0, 1e-3) - - assert_near_equal(alpha1[-1], 0.62446459, 1e-3) - - assert_near_equal(weight0[0], 175100, 1e-5) - assert_near_equal(weight1[-1], 174879.40581381, 1e-5) - - assert_near_equal(time0[0], 0, 1e-3) - assert_near_equal(time1[-1], 50.5763888, 1e-3) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/gasp_based/phases/benchmark/test_climb.py b/aviary/mission/gasp_based/phases/benchmark/test_climb.py deleted file mode 100644 index 736d7ff39..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_climb.py +++ /dev/null @@ -1,248 +0,0 @@ -import unittest - -import dymos as dm -import numpy as np -import openmdao.api as om -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import require_pyoptsparse, use_tempdirs - -from aviary.mission.gasp_based.ode.flight_path_ode import FlightPathODE -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 - - -def make_climb_problem( - optimizer='IPOPT', - print_opt_iters=False, - constant_quantity=Dynamic.Mission.MACH): - prob = om.Problem(model=om.Group()) - - prob.driver = om.pyOptSparseDriver() - - if optimizer == "SNOPT": - prob.driver.options["optimizer"] = "SNOPT" - prob.driver.opt_settings['Major iterations limit'] = 100 - # prob.driver.opt_settings['Major step limit'] = 0.05 - prob.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 - prob.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 - if print_opt_iters: - prob.driver.opt_settings["iSumm"] = 6 - elif optimizer == "IPOPT": - prob.driver.options["optimizer"] = "IPOPT" - prob.driver.opt_settings["max_iter"] = 500 - prob.driver.opt_settings["tol"] = 1e-5 - prob.driver.opt_settings["print_level"] = 5 - prob.driver.opt_settings[ - "nlp_scaling_method" - ] = "gradient-based" # for faster convergence - prob.driver.opt_settings["alpha_for_y"] = "safer-min-dual-infeas" - prob.driver.opt_settings["mu_strategy"] = "monotone" - prob.driver.opt_settings["bound_mult_init_method"] = "mu-based" - - transcription = dm.Radau(num_segments=11, order=3, compressed=True) - - ode_args = dict( - clean=True, - aviary_options=get_option_defaults(), - core_subsystems=default_mission_subsystems - ) - - climb = dm.Phase(ode_class=FlightPathODE, transcription=transcription, - ode_init_kwargs=ode_args) - - climb.set_time_options(fix_initial=True, duration_bounds=( - 10, 5000), units="s", duration_ref=200) - - climb.set_state_options( - "TAS", - fix_initial=False, - fix_final=False, - lower=1, - upper=1000, - units="kn", - ref=250, - defect_ref=250) - - climb.set_state_options( - "mass", - fix_initial=True, - fix_final=False, - lower=1, - upper=None, - units="lbm", - ref=200000, - defect_ref=200000, - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL) - - climb.set_state_options( - Dynamic.Mission.DISTANCE, - fix_initial=True, - fix_final=False, - lower=0, - upper=None, - units="ft", - ref=10000, - defect_ref=10000) - - if constant_quantity == 'EAS': - climb.set_state_options( - Dynamic.Mission.ALTITUDE, - fix_initial=True, - fix_final=False, - lower=400, - upper=20000, - units="ft", - ref=20.e3, - defect_ref=20.e3) - else: - climb.set_state_options( - Dynamic.Mission.ALTITUDE, - fix_initial=True, - fix_final=False, - lower=9000, - upper=50000, - units="ft", - ref=40000, - defect_ref=40000) - - climb.set_state_options( - Dynamic.Mission.FLIGHT_PATH_ANGLE, - fix_initial=False, - fix_final=False, - units="rad", - ref=1.0, - defect_ref=1.0) - - # climb.add_polynomial_control( - # "alpha", order=3, opt=True, units="rad", val=0.0, lower=np.radians(-4), upper=np.radians(14)) - climb.add_control("alpha", - opt=True, - units="rad", - val=0.0, - lower=np.radians(-14), - upper=np.radians(14), - rate_continuity=True, - rate2_continuity=False) - - if constant_quantity == 'EAS': - climb.add_path_constraint("EAS", lower=249.9, upper=250.1, ref=250., units="kn") - # climb.add_path_constraint("EAS", equals=350., ref=350., units="kn") - climb.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc="final", equals=10.e3, ref=10.e3, units="ft") - else: - climb.add_path_constraint(Dynamic.Mission.MACH, - lower=0.799, upper=0.801) - climb.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, loc="final", equals=37.5e3, ref=40.e3, units="ft") - - throttle_climb = 0.956 - climb.add_parameter( - Dynamic.Mission.THROTTLE, opt=False, units="unitless", val=throttle_climb, static_target=False - ) - - climb.add_parameter( - Aircraft.Wing.AREA, opt=False, units="ft**2", val=1370.0, static_target=True - ) - - climb.add_timeseries_output("EAS", output_name="EAS", units="kn") - climb.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") - climb.add_timeseries_output("alpha", output_name="alpha", units="deg") - climb.add_timeseries_output("CL", output_name="CL", units="unitless") - climb.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") - climb.add_timeseries_output("CD", output_name="CD", units="unitless") - - traj = prob.model.add_subsystem('traj', dm.Trajectory()) - traj.add_phase('climb', climb) - - climb.add_objective("mass", loc="final", ref=-1.e4) - # climb.add_objective("time", loc="final", ref=1.e2) - - prob.model.linear_solver.options["iprint"] = 0 - prob.model.nonlinear_solver.options["iprint"] = 0 - - traj.nonlinear_solver = om.NonlinearBlockGS(iprint=0) - traj.options['assembled_jac_type'] = 'csc' - traj.linear_solver = om.DirectSolver() - - prob.set_solver_print(level=0) - - for phase_name, phase in traj._phases.items(): - phase.add_timeseries_output('normal_force') - phase.add_timeseries_output('fuselage_pitch') - - phase.add_timeseries_output(Dynamic.Mission.ALTITUDE, units='ft') - phase.add_timeseries_output('mass', units='lbm') - - prob.setup() - - if constant_quantity == 'EAS': - prob.set_val("traj.climb.states:TAS", climb.interp( - "TAS", ys=[250., 250.]), units='kn') - prob.set_val("traj.climb.states:altitude", climb.interp( - Dynamic.Mission.ALTITUDE, ys=[500., 10.e3]), units='ft') - prob.set_val("traj.climb.states:flight_path_angle", climb.interp( - Dynamic.Mission.FLIGHT_PATH_ANGLE, ys=[0, 1]), units='deg') - prob.set_val("traj.climb.states:mass", climb.interp( - "mass", ys=[174219, 170000]), units='lbm') - else: - prob.set_val("traj.climb.states:TAS", climb.interp( - "TAS", ys=[490.5, 500]), units='kn') - prob.set_val("traj.climb.states:altitude", climb.interp( - Dynamic.Mission.ALTITUDE, ys=[20.e3, 37.5e3]), units='ft') - prob.set_val("traj.climb.states:flight_path_angle", climb.interp( - Dynamic.Mission.FLIGHT_PATH_ANGLE, ys=[1, 0.5]), units='deg') - prob.set_val("traj.climb.states:mass", climb.interp( - "mass", ys=[172.83e3, 171.e3]), units='lbm') - - prob.set_val("traj.climb.states:distance", climb.interp( - Dynamic.Mission.DISTANCE, ys=[15, 154]), units='NM') - prob.set_val("traj.climb.controls:alpha", - climb.interp("alpha", ys=[3, 2]), units='deg') - prob.set_val("traj.climb.t_duration", 200, units='s') - prob.set_val("traj.climb.t_initial", 0, units='s') - - return prob - - -@use_tempdirs -class Testclimb(unittest.TestCase): - - def assert_constant_EAS_result(self, p): - final_mass = p.get_val("traj.climb.timeseries.mass", units="lbm")[-1, ...] - assert_near_equal(final_mass, 173_558, tolerance=0.0001) - - @require_pyoptsparse(optimizer='IPOPT') - def test_constant_EAS_climb_ipopt(self): - p = make_climb_problem(optimizer='IPOPT', constant_quantity='EAS') - dm.run_problem(p, run_driver=True, simulate=False, make_plots=False) - self.assert_constant_EAS_result(p) - - @require_pyoptsparse(optimizer='SNOPT') - def test_constant_EAS_climb_snopt(self): - p = make_climb_problem( - optimizer='SNOPT', constant_quantity='EAS', print_opt_iters=True) - dm.run_problem(p, run_driver=True, simulate=True, make_plots=False) - self.assert_constant_EAS_result(p) - - def assert_constant_mach_result(self, p): - final_mass = p.get_val("traj.climb.timeseries.mass", units="lbm")[-1, ...] - assert_near_equal(final_mass, 171_073, tolerance=0.0001) - - @require_pyoptsparse(optimizer='IPOPT') - def test_constant_mach_climb_ipopt(self): - p = make_climb_problem(optimizer='IPOPT', constant_quantity=Dynamic.Mission.MACH) - dm.run_problem(p, run_driver=True, simulate=False, make_plots=False) - self.assert_constant_mach_result(p) - - @require_pyoptsparse(optimizer='SNOPT') - def test_constant_mach_climb_snopt(self): - p = make_climb_problem(optimizer='SNOPT', constant_quantity=Dynamic.Mission.MACH) - dm.run_problem(p, run_driver=True, simulate=False, make_plots=False) - self.assert_constant_mach_result(p) - - -if __name__ == "__main__": - unittest.main() diff --git a/aviary/mission/gasp_based/phases/benchmark/test_conventional_problem.py b/aviary/mission/gasp_based/phases/benchmark/test_conventional_problem.py deleted file mode 100644 index 261702430..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_conventional_problem.py +++ /dev/null @@ -1,27 +0,0 @@ -import unittest - -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import require_pyoptsparse - -from aviary.mission.gasp_based.phases.run_phases.run_conventional_problem import \ - run_conventional_problem - - -@unittest.skip('Currently skipping the new conventional problem setup due to formulation instabilities') -class TestConventionalProblem(unittest.TestCase): - - def assert_result(self, p): - mass_after_climbs = p.get_val( - "traj.climb_to_cruise.states:mass", units="lbm")[-1, ...] - - assert_near_equal(mass_after_climbs, 171.329e3, tolerance=1.e-4) - - @require_pyoptsparse(optimizer="IPOPT") - def test_conventional_problem_ipopt(self): - p = run_conventional_problem(optimizer="IPOPT") - self.assert_result(p) - - @require_pyoptsparse(optimizer="SNOPT") - def test_conventional_problem_snopt(self): - p = run_conventional_problem(optimizer="SNOPT") - self.assert_result(p) diff --git a/aviary/mission/gasp_based/phases/benchmark/test_cruise.py b/aviary/mission/gasp_based/phases/benchmark/test_cruise.py deleted file mode 100644 index d3c33ad84..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_cruise.py +++ /dev/null @@ -1,106 +0,0 @@ -import unittest - -import dymos as dm -import openmdao.api as om -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import use_tempdirs - -from aviary.mission.gasp_based.ode.breguet_cruise_ode import BreguetCruiseODESolution -from aviary.variable_info.options import get_option_defaults -from aviary.variable_info.variables import Dynamic - - -def make_cruise_problem(): - # - # CRUISE UNDER BREGUET RANGE ASSUMPTION - # - # Initial States Fixed - # Final States Free - # - # Controls: - # None - # - # Boundary Constraints: - # None - # - # Path Constraints: - # None - # - ode_args = dict( - aviary_options=get_option_defaults(), - ) - - cruise = dm.AnalyticPhase( - ode_class=BreguetCruiseODESolution, - # Use the standard ode_args and update it for ground_roll dynamics - ode_init_kwargs=ode_args, - num_nodes=2 - ) - - # Time here is really the independent variable through which we are integrating. - # In the case of the Breguet Range ODE, it's mass. - # We rely on mass being monotonically non-increasing across the phase. - cruise.set_time_options( - fix_initial=True, - fix_duration=False, - units="lbm", - name="mass", - duration_bounds=(-20000, 0), - duration_ref=10000, - ) - - throttle_cruise = 0.930 - cruise.add_parameter( - Dynamic.Mission.THROTTLE, opt=False, units="unitless", val=throttle_cruise, static_target=False - ) - cruise.add_parameter(Dynamic.Mission.ALTITUDE, opt=False, val=37500.0, units='ft') - cruise.add_parameter(Dynamic.Mission.MACH, opt=False, val=0.8, units="unitless") - cruise.add_parameter("wing_area", opt=False, val=1370, units="ft**2") - cruise.add_parameter("initial_cruise_range", opt=False, val=0.0, units="NM") - cruise.add_parameter("initial_cruise_time", opt=False, val=0.0, units="s") - - cruise.add_timeseries_output("time", output_name="time", units="s") - - p = om.Problem() - traj = p.model.add_subsystem("traj", dm.Trajectory()) - traj.add_phase("cruise", cruise) - - p.set_solver_print(level=-1) - - p.setup(force_alloc_complex=True) - - # SET TIME INITIAL GUESS - p.set_val("traj.cruise.t_initial", 171481, units="lbm") # Initial mass in cruise - p.set_val("traj.cruise.t_duration", -10000, units="lbm") # Mass of fuel consumed - - p.set_val("traj.cruise.parameters:altitude", val=37500.0, units="ft") - p.set_val("traj.cruise.parameters:mach", val=0.8, units="unitless") - p.set_val("traj.cruise.parameters:wing_area", val=1370, units="ft**2") - p.set_val("traj.cruise.parameters:initial_cruise_range", val=0.0, units="NM") - p.set_val("traj.cruise.parameters:initial_cruise_time", val=0.0, units="s") - - return p - - -@use_tempdirs -class TestCruise(unittest.TestCase): - - def assert_result(self, p): - tf = p.get_val('traj.cruise.timeseries.states:cruise_time', units='s')[-1, 0] - rf = p.get_val('traj.cruise.timeseries.states:distance', units='NM')[-1, 0] - wf = p.get_val('traj.cruise.timeseries.mass', units='lbm')[-1, 0] - - print(f't_final: {tf:8.3f} s') - print(f'w_final: {wf:8.3f} lbm') - print(f'r_final: {rf:8.3f} NM') - - assert_near_equal(wf, 161481.0, tolerance=0.01) - assert_near_equal(tf, 7368.56, tolerance=0.01) - assert_near_equal(rf, 939.178, tolerance=0.01) - - @unittest.skip('Skipping this benchmark for now as the analytic cruise is not used in GASP currently.') - def test_cruise_result(self): - p = make_cruise_problem() - dm.run_problem(p, run_driver=False, simulate=False) - - self.assert_result(p) 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 e1b144b94..95afa681a 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 @@ -274,7 +274,7 @@ def run_trajectory(sim=True): promotes_outputs=['mission:*']) traj.link_phases(["climb", "cruise", "descent"], [ - "time", Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) + "time", Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) traj = setup_trajectory_params(prob.model, traj, aviary_inputs) From 03c5e029945aeb19159c5bb05aaad1cd11863800 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 19 Jan 2024 14:32:16 -0600 Subject: [PATCH 130/188] Tests, benches, docs all pass --- aviary/docs/getting_started/onboarding_level2.ipynb | 9 ++++++--- aviary/docs/user_guide/aerodynamics.ipynb | 2 +- aviary/examples/test/test_all_examples.py | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/aviary/docs/getting_started/onboarding_level2.ipynb b/aviary/docs/getting_started/onboarding_level2.ipynb index 658f10790..44eccd804 100644 --- a/aviary/docs/getting_started/onboarding_level2.ipynb +++ b/aviary/docs/getting_started/onboarding_level2.ipynb @@ -76,6 +76,7 @@ "source": [ "from aviary.api import Aircraft, Mission\n", "import aviary.api as av\n", + "from copy import deepcopy\n", "\n", "\n", "# inputs that run_aviary() requires\n", @@ -86,13 +87,14 @@ "record_filename = 'aviary_history.db'\n", "restart_filename = None\n", "max_iter = 0\n", + "phase_info = deepcopy(av.default_2DOF_phase_info)\n", "\n", "# Build problem\n", "prob = av.AviaryProblem(analysis_scheme)\n", "\n", "# Load aircraft and options data from user\n", "# Allow for user overrides here\n", - "prob.load_inputs(aircraft_filename, av.default_2DOF_phase_info)\n", + "prob.load_inputs(aircraft_filename, phase_info)\n", "\n", "# Preprocess inputs\n", "prob.check_and_preprocess_inputs()\n", @@ -196,7 +198,8 @@ "metadata": {}, "outputs": [], "source": [ - "prob.load_inputs(aircraft_filename, av.default_2DOF_phase_info)" + "phase_info = deepcopy(av.default_2DOF_phase_info)\n", + "prob.load_inputs(aircraft_filename, phase_info)" ] }, { @@ -897,7 +900,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.8" + "version": "3.8.17" } }, "nbformat": 4, diff --git a/aviary/docs/user_guide/aerodynamics.ipynb b/aviary/docs/user_guide/aerodynamics.ipynb index 8cc0b5929..18a25ca75 100644 --- a/aviary/docs/user_guide/aerodynamics.ipynb +++ b/aviary/docs/user_guide/aerodynamics.ipynb @@ -124,7 +124,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.8" + "version": "3.8.17" } }, "nbformat": 4, diff --git a/aviary/examples/test/test_all_examples.py b/aviary/examples/test/test_all_examples.py index efab5eed4..a405e0827 100644 --- a/aviary/examples/test/test_all_examples.py +++ b/aviary/examples/test/test_all_examples.py @@ -94,7 +94,8 @@ def run_script(self, script_path): if 'ImportError' in str(stderr): self.skipTest(f"Skipped {script_path.name} due to ImportError") else: - raise + raise Exception( + f"Error running {script_path.name}:\n{stderr.decode('utf-8')}") def test_run_scripts(self): """ From 0f903788bd3b3db907e842757dca58ac98f3816c Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 19 Jan 2024 15:19:37 -0600 Subject: [PATCH 131/188] Improved bench convergence --- aviary/validation_cases/benchmark_tests/test_bench_FwFm.py | 2 +- aviary/validation_cases/benchmark_tests/test_bench_GwFm.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index bd73cb077..c21310e0f 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -286,7 +286,7 @@ def bench_test_swap_4_FwFm(self): "initial_bounds": ((0.0, 2.0), "min"), "duration_bounds": ((5.0, 50.0), "min"), "no_descent": False, - "add_initial_mass_constraint": False, + "add_initial_mass_constraint": True, }, "initial_guesses": {"times": ([0, 40.0], "min")}, }, diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py index 4d173b597..bfbb991f3 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py @@ -292,7 +292,7 @@ def bench_test_swap_1_GwFm(self): "initial_bounds": ((0.0, 0.0), "min"), "duration_bounds": ((5.0, 50.0), "min"), "no_descent": True, - "add_initial_mass_constraint": False, + "add_initial_mass_constraint": True, }, "initial_guesses": {"times": ([0, 40.0], "min")}, }, From 470ecc66b6e04d87d7fd3aa245e1e487cba7e888 Mon Sep 17 00:00:00 2001 From: crecine <51181861+crecine@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:03:44 -0800 Subject: [PATCH 132/188] updated simple to HE --- aviary/validation_cases/benchmark_tests/test_0_iters.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index 6121652f6..4654feea7 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -7,7 +7,6 @@ from aviary.interface.default_phase_info.two_dof import phase_info as two_dof_phase_info from aviary.interface.default_phase_info.height_energy import phase_info as height_energy_phase_info from aviary.interface.default_phase_info.solved import phase_info as solved_phase_info -from aviary.interface.default_phase_info.simple import phase_info as simple_phase_info from aviary.models.N3CC.N3CC_data import inputs from aviary.variable_info.variables import Settings from aviary.variable_info.enums import EquationsOfMotion @@ -49,7 +48,7 @@ class HEZeroItersTestCase(BaseProblemPhaseTestCase): @require_pyoptsparse(optimizer="IPOPT") def test_zero_iters_height_energy(self): - local_phase_info = deepcopy(simple_phase_info) + local_phase_info = deepcopy(height_energy_phase_info) inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.SIMPLE) self.build_and_run_problem(inputs, local_phase_info) From be458616eb24e940beed6503f49f0d8dfcec5a0a Mon Sep 17 00:00:00 2001 From: crecine <51181861+crecine@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:54:13 -0800 Subject: [PATCH 133/188] Removed unused setting --- aviary/validation_cases/benchmark_tests/test_0_iters.py | 1 - 1 file changed, 1 deletion(-) diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index 4654feea7..baa403fad 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -49,7 +49,6 @@ class HEZeroItersTestCase(BaseProblemPhaseTestCase): @require_pyoptsparse(optimizer="IPOPT") def test_zero_iters_height_energy(self): local_phase_info = deepcopy(height_energy_phase_info) - inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.SIMPLE) self.build_and_run_problem(inputs, local_phase_info) From 0fa7be3f5f848c2a9dbf43f324cced9460d36fbe Mon Sep 17 00:00:00 2001 From: Gregory Wrenn Date: Mon, 22 Jan 2024 11:41:19 -0500 Subject: [PATCH 134/188] [no ci] Change all occurances of 'final_alt' to 'final_altitude'. --- aviary/interface/default_phase_info/two_dof.py | 12 ++++++------ aviary/interface/methods_for_level2.py | 4 ++-- aviary/interface/utils/check_phase_info.py | 6 +++--- .../flops_based/phases/detailed_takeoff_phases.py | 4 ++-- aviary/mission/gasp_based/phases/climb_phase.py | 6 +++--- aviary/mission/gasp_based/phases/desc_phase.py | 4 ++-- .../gasp_based/phases/run_phases/run_climb.py | 4 ++-- .../phases/run_phases/run_climb_test_FLOPS_prop.py | 4 ++-- .../gasp_based/phases/run_phases/run_desc1.py | 2 +- .../gasp_based/phases/run_phases/run_desc2.py | 2 +- 10 files changed, 24 insertions(+), 24 deletions(-) diff --git a/aviary/interface/default_phase_info/two_dof.py b/aviary/interface/default_phase_info/two_dof.py index c1733d16b..7ef53244d 100644 --- a/aviary/interface/default_phase_info/two_dof.py +++ b/aviary/interface/default_phase_info/two_dof.py @@ -165,7 +165,7 @@ 'EAS_target': (250, 'kn'), 'mach_cruise': 0.8, 'target_mach': False, - 'final_alt': (10.e3, 'ft'), + 'final_altitude': (10.e3, 'ft'), 'time_initial_bounds': ((20, 200), 's'), 'duration_bounds': ((30, 300), 's'), 'duration_ref': (1000, 's'), @@ -195,7 +195,7 @@ 'EAS_target': (270, 'kn'), 'mach_cruise': 0.8, 'target_mach': True, - 'final_alt': (37.5e3, 'ft'), + 'final_altitude': (37.5e3, 'ft'), 'required_available_climb_rate': (0.1, 'ft/min'), 'time_initial_bounds': ((10, 700), 's'), 'duration_bounds': ((200, 17_000), 's'), @@ -239,7 +239,7 @@ 'EAS_limit': (350, 'kn'), 'mach_cruise': 0.8, 'input_speed_type': SpeedType.MACH, - 'final_alt': (10.e3, 'ft'), + 'final_altitude': (10.e3, 'ft'), 'time_initial_bounds': ((1000, 35_000), 's'), 'time_initial_ref': (10_000, 's'), 'duration_bounds': ((300., 900.), 's'), @@ -276,7 +276,7 @@ 'EAS_limit': (250, 'kn'), 'mach_cruise': 0.80, 'input_speed_type': SpeedType.EAS, - 'final_alt': (1000, 'ft'), + 'final_altitude': (1000, 'ft'), 'time_initial_bounds': ((2000, 50_000), 's'), 'time_initial_ref': (15000, 's'), 'duration_bounds': ((100., 5000), 's'), @@ -343,10 +343,10 @@ def phase_info_parameterization(phase_info, post_mission_info, aviary_inputs): range_scale = range_cruise / old_range_cruise # Altitude - old_alt_cruise = phase_info['climb2']['final_alt'][0] + old_alt_cruise = phase_info['climb2']['final_altitude'][0] if alt_cruise != old_alt_cruise: - phase_info['climb2']['final_alt'] = (alt_cruise, 'ft') + phase_info['climb2']['final_altitude'] = (alt_cruise, 'ft') phase_info['climb2']['initial_guesses']['altitude'] = ([10.e3, alt_cruise], 'ft') phase_info['cruise']['initial_guesses']['altitude'] = (alt_cruise, 'ft') phase_info['desc1']['initial_guesses']['altitude'] = ([alt_cruise, 10.e3], 'ft') diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 028f05b27..5b9496e0b 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -587,7 +587,7 @@ def _get_2dof_phase(self, phase_name): ) phase.add_parameter(Dynamic.Mission.ALTITUDE, opt=False, - val=self.phase_info['climb2']['final_alt'][0], units=self.phase_info['climb2']['final_alt'][1]) + val=self.phase_info['climb2']['final_altitude'][0], units=self.phase_info['climb2']['final_altitude'][1]) phase.add_parameter(Dynamic.Mission.MACH, opt=False, val=self.phase_info['climb2']['mach_cruise']) phase.add_parameter("initial_distance", opt=False, val=0.0, @@ -640,7 +640,7 @@ def _get_2dof_phase(self, phase_name): 'angle': 'deg', 'pitch': 'deg', 'normal': 'lbf', - 'final_alt': 'ft', + 'final_altitude': 'ft', 'required_available_climb_rate': 'ft/min', } diff --git a/aviary/interface/utils/check_phase_info.py b/aviary/interface/utils/check_phase_info.py index 3094e338b..e206bc816 100644 --- a/aviary/interface/utils/check_phase_info.py +++ b/aviary/interface/utils/check_phase_info.py @@ -74,7 +74,7 @@ def check_phase_info(phase_info, mission_method): 'EAS_limit': tuple, 'mach_cruise': float, 'input_speed_type': SpeedType, - 'final_alt': tuple, + 'final_altitude': tuple, 'time_initial_bounds': tuple, 'time_initial_ref': tuple, 'alt_constraint_ref': tuple, @@ -137,7 +137,7 @@ def check_phase_info(phase_info, mission_method): 'EAS_target': tuple, 'mach_cruise': float, 'target_mach': bool, - 'final_alt': tuple, + 'final_altitude': tuple, 'time_initial_bounds': tuple, **common_duration, **common_alt, @@ -150,7 +150,7 @@ def check_phase_info(phase_info, mission_method): 'EAS_target': tuple, 'mach_cruise': float, 'target_mach': bool, - 'final_alt': tuple, + 'final_altitude': tuple, 'required_available_climb_rate': tuple, 'time_initial_bounds': tuple, **common_duration, diff --git a/aviary/mission/flops_based/phases/detailed_takeoff_phases.py b/aviary/mission/flops_based/phases/detailed_takeoff_phases.py index 068157ae1..68b16423b 100644 --- a/aviary/mission/flops_based/phases/detailed_takeoff_phases.py +++ b/aviary/mission/flops_based/phases/detailed_takeoff_phases.py @@ -1114,12 +1114,12 @@ def build_phase(self, aviary_options: AviaryValues = None): output_name=Dynamic.Mission.THRUST_TOTAL, units='lbf' ) - final_alt, units = user_options.get_item('mic_altitude') + final_altitude, units = user_options.get_item('mic_altitude') airport_altitude = aviary_options.get_val( Mission.Takeoff.AIRPORT_ALTITUDE, units) - h = final_alt + airport_altitude + h = final_altitude + airport_altitude phase.add_boundary_constraint( Dynamic.Mission.ALTITUDE, loc='final', equals=h, ref=h, units=units, linear=True) diff --git a/aviary/mission/gasp_based/phases/climb_phase.py b/aviary/mission/gasp_based/phases/climb_phase.py index 026ece771..88cdf7777 100644 --- a/aviary/mission/gasp_based/phases/climb_phase.py +++ b/aviary/mission/gasp_based/phases/climb_phase.py @@ -12,7 +12,7 @@ def get_climb( EAS_target=0, mach_cruise=0, target_mach=False, - final_alt=0, + final_altitude=0, required_available_climb_rate=None, time_initial_bounds=(0, 0), duration_bounds=(0, 0), @@ -99,9 +99,9 @@ def get_climb( climb.add_boundary_constraint( Dynamic.Mission.ALTITUDE, loc="final", - equals=final_alt, + equals=final_altitude, units="ft", - ref=final_alt) + ref=final_altitude) if required_available_climb_rate: climb.add_boundary_constraint( Dynamic.Mission.ALTITUDE_RATE, diff --git a/aviary/mission/gasp_based/phases/desc_phase.py b/aviary/mission/gasp_based/phases/desc_phase.py index 0ace98f27..5bb549c95 100644 --- a/aviary/mission/gasp_based/phases/desc_phase.py +++ b/aviary/mission/gasp_based/phases/desc_phase.py @@ -13,7 +13,7 @@ def get_descent( EAS_limit=0, mach_cruise=0, input_speed_type=SpeedType.MACH, - final_alt=0, + final_altitude=0, time_initial_bounds=(0, 0), time_initial_ref=1, duration_bounds=(0, 0), @@ -110,7 +110,7 @@ def get_descent( desc.add_boundary_constraint( Dynamic.Mission.ALTITUDE, loc="final", - equals=final_alt, + equals=final_altitude, units="ft", ref=alt_constraint_ref) diff --git a/aviary/mission/gasp_based/phases/run_phases/run_climb.py b/aviary/mission/gasp_based/phases/run_phases/run_climb.py index 003222ec4..54cc94aa6 100644 --- a/aviary/mission/gasp_based/phases/run_phases/run_climb.py +++ b/aviary/mission/gasp_based/phases/run_phases/run_climb.py @@ -63,7 +63,7 @@ def setup_climb1(): EAS_target=250, mach_cruise=0.8, target_mach=False, - final_alt=10000, + final_altitude=10000, alt_ref=10000, mass_ref=200000, distance_ref=300, @@ -119,7 +119,7 @@ def setup_climb2(): EAS_target=270, mach_cruise=0.8, target_mach=True, - final_alt=37500, + final_altitude=37500, alt_ref=40000, mass_ref=200000, distance_ref=300, diff --git a/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py b/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py index 13d7c45fc..4a3671b05 100644 --- a/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py +++ b/aviary/mission/gasp_based/phases/run_phases/run_climb_test_FLOPS_prop.py @@ -76,7 +76,7 @@ def setup_climb1(): EAS_target=250, mach_cruise=0.8, target_mach=False, - final_alt=10.e3, + final_altitude=10.e3, alt_ref=10.e3, distance_ref=300, ) @@ -135,7 +135,7 @@ def setup_climb2(): EAS_target=270, mach_cruise=0.8, target_mach=True, - final_alt=37500, + final_altitude=37500, alt_ref=40000, mass_ref=200000, distance_ref=300, diff --git a/aviary/mission/gasp_based/phases/run_phases/run_desc1.py b/aviary/mission/gasp_based/phases/run_phases/run_desc1.py index 9b18c15ea..029a8e430 100644 --- a/aviary/mission/gasp_based/phases/run_phases/run_desc1.py +++ b/aviary/mission/gasp_based/phases/run_phases/run_desc1.py @@ -43,7 +43,7 @@ def run_desc1(make_plots=False): EAS_limit=350, mach_cruise=0.8, transcription=transcription, - final_alt=10000, + final_altitude=10000, input_speed_type=SpeedType.MACH, ) diff --git a/aviary/mission/gasp_based/phases/run_phases/run_desc2.py b/aviary/mission/gasp_based/phases/run_phases/run_desc2.py index d7d30deb3..6792603e0 100644 --- a/aviary/mission/gasp_based/phases/run_phases/run_desc2.py +++ b/aviary/mission/gasp_based/phases/run_phases/run_desc2.py @@ -40,7 +40,7 @@ def run_desc2(): EAS_limit=250, mach_cruise=0.8, transcription=transcription, - final_alt=1000, + final_altitude=1000, input_speed_type=SpeedType.EAS, ) From b7bd2700a9ea3754a789d79428cf010d723e49f9 Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Mon, 22 Jan 2024 09:45:56 -0800 Subject: [PATCH 135/188] Declared states so that nox doesn't have to be blocked --- aviary/examples/level2_shooting_traj.py | 1 - .../default_phase_info/two_dof_fiti.py | 10 ---- .../ode/time_integration_base_classes.py | 52 +++++++++++++--- .../phases/time_integration_phases.py | 60 ++++++++++++++----- .../phases/time_integration_traj.py | 4 ++ 5 files changed, 91 insertions(+), 36 deletions(-) diff --git a/aviary/examples/level2_shooting_traj.py b/aviary/examples/level2_shooting_traj.py index 0bbd323b5..5c66e0bbe 100644 --- a/aviary/examples/level2_shooting_traj.py +++ b/aviary/examples/level2_shooting_traj.py @@ -74,7 +74,6 @@ def run_aviary(aircraft_filename, phase_info, optimizer=None, analysis_scheme=An ode_args=prob.ode_args, simupy_args=dict( DEBUG=False, - blocked_state_names=['engine.nox', 'nox'], ), ) descent1_vals = { diff --git a/aviary/interface/default_phase_info/two_dof_fiti.py b/aviary/interface/default_phase_info/two_dof_fiti.py index 577bfc20c..def0c1fdc 100644 --- a/aviary/interface/default_phase_info/two_dof_fiti.py +++ b/aviary/interface/default_phase_info/two_dof_fiti.py @@ -17,7 +17,6 @@ def create_2dof_based_ascent_phases( ode_args=ode_args, simupy_args=dict( DEBUG=False, - blocked_state_names=['engine_deck.nox', 'nox'], ), ) groundroll_vals = { @@ -29,7 +28,6 @@ def create_2dof_based_ascent_phases( ode_args=ode_args, simupy_args=dict( DEBUG=False, - blocked_state_names=['engine_deck.nox', 'nox'], ), ) rotation_vals = {} @@ -38,7 +36,6 @@ def create_2dof_based_ascent_phases( ode_args=ode_args, simupy_args=dict( DEBUG=False, - blocked_state_names=['engine_deck.nox', 'nox'], ), ) ascent_vals = { @@ -53,7 +50,6 @@ def create_2dof_based_ascent_phases( ode_args=ode_args, simupy_args=dict( DEBUG=False, - blocked_state_names=['engine_deck.nox', 'nox'], ), ) accel_vals = {} @@ -64,7 +60,6 @@ def create_2dof_based_ascent_phases( ode_args=ode_args, simupy_args=dict( DEBUG=False, - blocked_state_names=['engine_deck.nox', 'nox'], ), ) climb1_vals = { @@ -79,7 +74,6 @@ def create_2dof_based_ascent_phases( ode_args=ode_args, simupy_args=dict( DEBUG=False, - blocked_state_names=['engine_deck.nox', 'nox'], ), ) climb2_vals = { @@ -94,7 +88,6 @@ def create_2dof_based_ascent_phases( ode_args=ode_args, simupy_args=dict( DEBUG=False, - blocked_state_names=['engine_deck.nox', 'nox'], ), ) climb3_vals = { @@ -150,7 +143,6 @@ def create_2dof_based_descent_phases( ode_args=ode_args, simupy_args=dict( DEBUG=False, - blocked_state_names=['engine_deck.nox', 'nox'], ), ) descent1_vals = { @@ -166,7 +158,6 @@ def create_2dof_based_descent_phases( ode_args=ode_args, simupy_args=dict( DEBUG=False, - blocked_state_names=['engine_deck.nox', 'nox'], ), ) descent2_vals = { @@ -182,7 +173,6 @@ def create_2dof_based_descent_phases( ode_args=ode_args, simupy_args=dict( DEBUG=False, - blocked_state_names=['engine_deck.nox', 'nox'], ), ) descent3_vals = { diff --git a/aviary/mission/gasp_based/ode/time_integration_base_classes.py b/aviary/mission/gasp_based/ode/time_integration_base_classes.py index d612c1618..e9b09033d 100644 --- a/aviary/mission/gasp_based/ode/time_integration_base_classes.py +++ b/aviary/mission/gasp_based/ode/time_integration_base_classes.py @@ -8,7 +8,18 @@ from aviary.mission.gasp_based.ode.params import ParamPort +def add_SGM_required_inputs(group: om.Group, inputs_to_add: dict): + blank_execcomp = om.ExecComp() + for input, details in inputs_to_add.items(): + blank_execcomp.add_input(input, **details) + group.add_subsystem('SGM_required_inputs', + blank_execcomp, + promotes_inputs=list(inputs_to_add.keys()), + ) + # Subproblem used as a basis for forward in time integration phases. + + class SimuPyProblem(SimulationMixin): def __init__( self, @@ -61,6 +72,10 @@ def __init__( self.time_independent = time_independent if control_names is None: control_names = [] + if alternate_state_names is None: + alternate_state_names = {} + if alternate_state_rate_names is None: + alternate_state_rate_names = {} self.control_names = control_names if control_units is not None: self.control_units = control_units @@ -97,7 +112,7 @@ def __init__( for name in blocked_state_names: if name in state_names: state_names.remove(name) - if alternate_state_names is not None: + if alternate_state_names: for key, val in alternate_state_names.items(): state_key = key.replace(rate_suffix, "") if state_key in state_names: # Used to rename an existing state @@ -107,7 +122,7 @@ def __init__( if state_rate_names is None: state_rate_names = [state_name + rate_suffix for state_name in state_names] - if alternate_state_names is not None: + if alternate_state_rate_names: state_rate_names = [name if name not in alternate_state_rate_names.keys( ) else alternate_state_rate_names[name] for name in state_rate_names] @@ -169,7 +184,7 @@ def __init__( for output_name in output_names ] - if include_state_outputs: + if include_state_outputs or output_names == []: # prevent empty outputs output_names = state_names + output_names self.output_units = self.state_units + self.output_units @@ -189,6 +204,8 @@ def __init__( if DEBUG: om.n2(prob, outfile="n2_simupy_problem.html", show_browser=False) + with open('input_list_simupy.txt', 'w') as outfile: + prob.model.list_inputs(out_stream=outfile,) print(state_names) print(self.state_units) print(state_rate_names) @@ -360,8 +377,10 @@ def initialize(self): def setup_params( self, ODEs, + promote_all_auto_ivc=False, traj_final_state_output=None, traj_promote_final_output=None, + traj_promote_initial_input=None, traj_initial_state_input=None, traj_event_trigger_input=None, ): @@ -381,13 +400,29 @@ def setup_params( traj_final_state_output = [] if traj_promote_final_output is None: traj_promote_final_output = [] + if traj_promote_initial_input is None: + traj_promote_initial_input = {} if traj_initial_state_input is None: traj_initial_state_input = [] if traj_event_trigger_input is None: traj_event_trigger_input = [] - for name, kwargs in self.options["param_dict"].items(): + if promote_all_auto_ivc: + for ode in ODEs: + ode: SimuPyProblem + ode.auto_ivc_vars = ode.prob.model.list_inputs( + is_indep_var=True, units=True, out_stream=None) + for abs_name, data in ode.auto_ivc_vars: + prom_name = data.pop('prom_name') + if '.' in prom_name: + continue + traj_promote_initial_input[prom_name] = data + + self.traj_promote_initial_input = { + **self.options["param_dict"], **traj_promote_initial_input} + for name, kwargs in self.traj_promote_initial_input.items(): self.add_input(name, **kwargs) + final_suffix = "_final" self.traj_final_state_output = { final_state_output: { @@ -463,17 +498,16 @@ def setup_params( self.declare_partials(["*"], ["*"],) def compute_params(self, inputs): - # parameter pass-through setup - for param_input in self.options["param_dict"].keys(): + for input in self.traj_promote_initial_input.keys(): for ode in self.ODEs: try: - ode.set_val(param_input, inputs[param_input]) + ode.set_val(input, inputs[input]) except KeyError: if self.DEBUG: print( - "*** ParamPort input not found:", + "*** Input not found:", ode, - param_input + input ) pass diff --git a/aviary/mission/gasp_based/phases/time_integration_phases.py b/aviary/mission/gasp_based/phases/time_integration_phases.py index 1d4a784c7..7b5865192 100644 --- a/aviary/mission/gasp_based/phases/time_integration_phases.py +++ b/aviary/mission/gasp_based/phases/time_integration_phases.py @@ -9,8 +9,7 @@ from aviary.mission.gasp_based.phases.landing_group import LandingSegment from aviary.mission.gasp_based.ode.groundroll_ode import GroundrollODE from aviary.mission.gasp_based.ode.rotation_ode import RotationODE -from aviary.mission.gasp_based.ode.time_integration_base_classes import ( - SGMTrajBase, SimuPyProblem) +from aviary.mission.gasp_based.ode.time_integration_base_classes import SimuPyProblem from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.enums import AlphaModes, AnalysisScheme, SpeedType from aviary.variable_info.variables import Aircraft, Dynamic, Mission @@ -37,8 +36,13 @@ def __init__( super().__init__( GroundrollODE(analysis_scheme=AnalysisScheme.SHOOTING, **ode_args), output_names=["normal_force"], - alternate_state_names={Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL: Dynamic.Mission.MASS, - 'TAS': 'TAS'}, + state_names=[ + Dynamic.Mission.MASS, + Dynamic.Mission.DISTANCE, + Dynamic.Mission.ALTITUDE, + 'TAS' + ], + # state_units=['lbm','nmi','ft','ft/s'], alternate_state_rate_names={ Dynamic.Mission.MASS_RATE: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, **simupy_args, @@ -73,8 +77,12 @@ def __init__( super().__init__( RotationODE(analysis_scheme=AnalysisScheme.SHOOTING, **ode_args), output_names=["normal_force", "alpha"], - alternate_state_names={ - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL: Dynamic.Mission.MASS}, + state_names=[ + Dynamic.Mission.MASS, + Dynamic.Mission.DISTANCE, + Dynamic.Mission.ALTITUDE, + ], + # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ Dynamic.Mission.MASS_RATE: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, **simupy_args, @@ -127,8 +135,12 @@ def __init__( "normal_force", "alpha", ], - alternate_state_names={ - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL: Dynamic.Mission.MASS}, + state_names=[ + Dynamic.Mission.MASS, + Dynamic.Mission.DISTANCE, + Dynamic.Mission.ALTITUDE, + ], + # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ Dynamic.Mission.MASS_RATE: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, control_names=control_names, @@ -366,8 +378,12 @@ def __init__( super().__init__( ode, output_names=["EAS", "mach", "alpha"], - alternate_state_names={ - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL: Dynamic.Mission.MASS}, + state_names=[ + Dynamic.Mission.MASS, + Dynamic.Mission.DISTANCE, + Dynamic.Mission.ALTITUDE, + ], + # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ Dynamic.Mission.MASS_RATE: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, **simupy_args, @@ -432,8 +448,12 @@ def __init__( "drag", Dynamic.Mission.ALTITUDE_RATE, ], - alternate_state_names={ - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL: Dynamic.Mission.MASS}, + state_names=[ + Dynamic.Mission.MASS, + Dynamic.Mission.DISTANCE, + Dynamic.Mission.ALTITUDE, + ], + # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ Dynamic.Mission.MASS_RATE: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, **simupy_args, @@ -496,8 +516,12 @@ def __init__( "drag", Dynamic.Mission.ALTITUDE_RATE, ], - alternate_state_names={ - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL: Dynamic.Mission.MASS}, + state_names=[ + Dynamic.Mission.MASS, + Dynamic.Mission.DISTANCE, + Dynamic.Mission.ALTITUDE, + ], + # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ Dynamic.Mission.MASS_RATE: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, **simupy_args, @@ -571,8 +595,12 @@ def __init__( "drag", Dynamic.Mission.ALTITUDE_RATE, ], - alternate_state_names={ - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL: Dynamic.Mission.MASS}, + state_names=[ + Dynamic.Mission.MASS, + Dynamic.Mission.DISTANCE, + Dynamic.Mission.ALTITUDE, + ], + # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ Dynamic.Mission.MASS_RATE: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, **simupy_args, diff --git a/aviary/mission/gasp_based/phases/time_integration_traj.py b/aviary/mission/gasp_based/phases/time_integration_traj.py index cc136d943..d566635d3 100644 --- a/aviary/mission/gasp_based/phases/time_integration_traj.py +++ b/aviary/mission/gasp_based/phases/time_integration_traj.py @@ -29,8 +29,10 @@ class FlexibleTraj(TimeIntegrationTrajBase): def initialize(self): super().initialize() self.options.declare('Phases', default=None) + self.options.declare('promote_all_auto_ivc', default=False) self.options.declare('traj_final_state_output', default=None) self.options.declare('traj_promote_final_output', default=None) + self.options.declare('traj_promote_initial_input', default=None) self.options.declare('traj_initial_state_input', default=None) self.options.declare('traj_event_trigger_input', default=None) @@ -44,9 +46,11 @@ def setup(self): self.setup_params( ODEs=ODEs, + promote_all_auto_ivc=self.options['promote_all_auto_ivc'], traj_final_state_output=self.options['traj_final_state_output'], traj_promote_final_output=self.options['traj_promote_final_output'], + traj_promote_initial_input=self.options['traj_promote_initial_input'], traj_initial_state_input=self.options['traj_initial_state_input'], traj_event_trigger_input=self.options['traj_event_trigger_input'], ) From 70d4a9874aa9d0d5c3e2e5d8309289140df6e1e3 Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Mon, 22 Jan 2024 09:49:30 -0800 Subject: [PATCH 136/188] fixed extra lines added by precommit --- aviary/mission/gasp_based/ode/time_integration_base_classes.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aviary/mission/gasp_based/ode/time_integration_base_classes.py b/aviary/mission/gasp_based/ode/time_integration_base_classes.py index e9b09033d..a6b675643 100644 --- a/aviary/mission/gasp_based/ode/time_integration_base_classes.py +++ b/aviary/mission/gasp_based/ode/time_integration_base_classes.py @@ -17,9 +17,8 @@ def add_SGM_required_inputs(group: om.Group, inputs_to_add: dict): promotes_inputs=list(inputs_to_add.keys()), ) -# Subproblem used as a basis for forward in time integration phases. - +# Subproblem used as a basis for forward in time integration phases. class SimuPyProblem(SimulationMixin): def __init__( self, From fee4f8a18a4ae29d91c71bf80b93a7aaa8db7e14 Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Mon, 22 Jan 2024 09:56:45 -0800 Subject: [PATCH 137/188] grabbed two more instances --- aviary/examples/level2_shooting_traj.py | 2 -- aviary/interface/methods_for_level2.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/aviary/examples/level2_shooting_traj.py b/aviary/examples/level2_shooting_traj.py index 5c66e0bbe..b02eba8ee 100644 --- a/aviary/examples/level2_shooting_traj.py +++ b/aviary/examples/level2_shooting_traj.py @@ -58,8 +58,6 @@ def run_aviary(aircraft_filename, phase_info, optimizer=None, analysis_scheme=An alpha_mode=AlphaModes.REQUIRED_LIFT, simupy_args=dict( DEBUG=True, - blocked_state_names=['engine.nox', 'nox', - 'TAS', Dynamic.Mission.FLIGHT_PATH_ANGLE], ), ) cruise_vals = { diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 028f05b27..19e65fe53 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -1001,8 +1001,6 @@ def add_phases(self, phase_info_parameterization=None): alpha_mode=AlphaModes.REQUIRED_LIFT, simupy_args=dict( DEBUG=True, - blocked_state_names=['engine.nox', 'nox', - 'TAS', Dynamic.Mission.FLIGHT_PATH_ANGLE], ), ) cruise_vals = { From 47a560c3b2acf7b86d03b389fb786ea047cffcdc Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Mon, 22 Jan 2024 10:02:25 -0800 Subject: [PATCH 138/188] Added test for level 1 with SGM --- aviary/interface/test/test_cmd_entry_points.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aviary/interface/test/test_cmd_entry_points.py b/aviary/interface/test/test_cmd_entry_points.py index 41da59bd7..1ae378f7e 100644 --- a/aviary/interface/test/test_cmd_entry_points.py +++ b/aviary/interface/test/test_cmd_entry_points.py @@ -28,6 +28,12 @@ def bench_test_IPOPT_cmd(self): cmd = 'aviary run_mission models/test_aircraft/aircraft_for_bench_GwGm.csv --optimizer IPOPT --max_iter 1' self.run_and_test_cmd(cmd) + @require_pyoptsparse(optimizer="IPOPT") + def bench_test_IPOPT_cmd(self): + cmd = 'aviary run_mission models/test_aircraft/aircraft_for_bench_GwGm.csv' \ + ' --optimizer IPOPT --max_iter 1 --shooting' + self.run_and_test_cmd(cmd) + def test_diff_configuration_conversion(self): filepath = pkg_resources.resource_filename('aviary', 'models/test_aircraft/converter_configuration_test_data_GwGm.dat') From b29273a420bb29f5de4b9c77d4ba57e437f2ba68 Mon Sep 17 00:00:00 2001 From: Gregory Wrenn Date: Mon, 22 Jan 2024 13:05:30 -0500 Subject: [PATCH 139/188] [no ci] Restore passenger count to 180. --- aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py | 2 +- .../models/large_single_aisle_1/large_single_aisle_1_GwGm.csv | 2 +- .../models/large_single_aisle_1/large_single_aisle_1_GwGm.dat | 2 +- aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv | 2 +- aviary/models/test_aircraft/aircraft_for_bench_GwGm_solved.csv | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py b/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py index 0809183c3..113fc4748 100644 --- a/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py +++ b/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py @@ -13,7 +13,7 @@ V3_bug_fixed_options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') V3_bug_fixed_options.set_val( - Aircraft.CrewPayload.NUM_PASSENGERS, val=169, units='unitless') + Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') V3_bug_fixed_options.set_val(Mission.Design.CRUISE_ALTITUDE, val=37500, units='ft') V3_bug_fixed_options.set_val( Aircraft.Wing.CHOOSE_FOLD_LOCATION, val=False, units='unitless') diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv index 603362b3e..5226249f0 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv @@ -6,7 +6,7 @@ aircraft:controls:control_mass_increment,0,lbm aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless aircraft:crew_and_payload:cargo_mass,10040,lbm -aircraft:crew_and_payload:num_passengers,169,unitless +aircraft:crew_and_payload:num_passengers,180,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,16.5,unitless diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat index 633061c3c..f23fff285 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat @@ -18,7 +18,7 @@ aircraft:engine:data_file=models/engines/turbofan_23k_1.deck HCK=4.5, ! mean fuselage cabin diameter minus mean fuselage nose diameter in feet (2.47) HTG=8., ! wing height about ground during ground run in feet (3.0) HWING=0.0, ! wing location on fuselage =0, low wing; =1 high wing - PAX=169., ! number of passenger seats excluding crew + PAX=180., ! number of passenger seats excluding crew PS=29.0, ! seat pitch in inches RELR=0.4524, ! cg of fuselage and contents, fraction fuselage(.4) if LCWING <> 0 SAB=6., ! seats abreast in fuselage diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv index b94349906..85217169b 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv @@ -5,7 +5,7 @@ aircraft:controls:control_mass_increment,0,lbm aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless aircraft:crew_and_payload:cargo_mass,10040,lbm -aircraft:crew_and_payload:num_passengers,169,unitless +aircraft:crew_and_payload:num_passengers,180,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,16.5,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwGm_solved.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwGm_solved.csv index ba578e05d..720764ca5 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwGm_solved.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwGm_solved.csv @@ -5,7 +5,7 @@ aircraft:controls:control_mass_increment,0,lbm aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless aircraft:crew_and_payload:cargo_mass,10040,lbm -aircraft:crew_and_payload:num_passengers,169,unitless +aircraft:crew_and_payload:num_passengers,180,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,16.5,unitless From 407d7bab38dfe3033040fe023be3f4599c326ba2 Mon Sep 17 00:00:00 2001 From: Gregory Wrenn Date: Mon, 22 Jan 2024 13:10:33 -0500 Subject: [PATCH 140/188] [no ci] Restore passsenger count to 180. --- aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py | 2 +- .../models/large_single_aisle_1/large_single_aisle_1_GwGm.csv | 2 +- .../models/large_single_aisle_1/large_single_aisle_1_GwGm.dat | 2 +- aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv | 2 +- aviary/models/test_aircraft/aircraft_for_bench_GwGm_solved.csv | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py b/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py index 0809183c3..113fc4748 100644 --- a/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py +++ b/aviary/models/large_single_aisle_1/V3_bug_fixed_IO.py @@ -13,7 +13,7 @@ V3_bug_fixed_options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') V3_bug_fixed_options.set_val( - Aircraft.CrewPayload.NUM_PASSENGERS, val=169, units='unitless') + Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') V3_bug_fixed_options.set_val(Mission.Design.CRUISE_ALTITUDE, val=37500, units='ft') V3_bug_fixed_options.set_val( Aircraft.Wing.CHOOSE_FOLD_LOCATION, val=False, units='unitless') diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv index 603362b3e..5226249f0 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.csv @@ -6,7 +6,7 @@ aircraft:controls:control_mass_increment,0,lbm aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless aircraft:crew_and_payload:cargo_mass,10040,lbm -aircraft:crew_and_payload:num_passengers,169,unitless +aircraft:crew_and_payload:num_passengers,180,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,16.5,unitless diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat index 633061c3c..f23fff285 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_GwGm.dat @@ -18,7 +18,7 @@ aircraft:engine:data_file=models/engines/turbofan_23k_1.deck HCK=4.5, ! mean fuselage cabin diameter minus mean fuselage nose diameter in feet (2.47) HTG=8., ! wing height about ground during ground run in feet (3.0) HWING=0.0, ! wing location on fuselage =0, low wing; =1 high wing - PAX=169., ! number of passenger seats excluding crew + PAX=180., ! number of passenger seats excluding crew PS=29.0, ! seat pitch in inches RELR=0.4524, ! cg of fuselage and contents, fraction fuselage(.4) if LCWING <> 0 SAB=6., ! seats abreast in fuselage diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv index b94349906..85217169b 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv @@ -5,7 +5,7 @@ aircraft:controls:control_mass_increment,0,lbm aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless aircraft:crew_and_payload:cargo_mass,10040,lbm -aircraft:crew_and_payload:num_passengers,169,unitless +aircraft:crew_and_payload:num_passengers,180,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,16.5,unitless diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwGm_solved.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwGm_solved.csv index ba578e05d..720764ca5 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwGm_solved.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwGm_solved.csv @@ -5,7 +5,7 @@ aircraft:controls:control_mass_increment,0,lbm aircraft:controls:stability_augmentation_system_mass,0,lbm aircraft:controls:stability_augmentation_system_mass_scaler,1,unitless aircraft:crew_and_payload:cargo_mass,10040,lbm -aircraft:crew_and_payload:num_passengers,169,unitless +aircraft:crew_and_payload:num_passengers,180,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:design:cg_delta,0.25,unitless aircraft:design:cockpit_control_mass_coefficient,16.5,unitless From c2503433b05a93a3e14e91ec3dde37d51b8f3609 Mon Sep 17 00:00:00 2001 From: Gregory Wrenn Date: Mon, 22 Jan 2024 14:32:05 -0500 Subject: [PATCH 141/188] [no ci] Restoring changes made for issue 394 to agree with the current om-Aviary main. --- aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv | 2 +- aviary/utils/preprocessors.py | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv index 120717a9e..ffd4be8af 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv @@ -21,7 +21,7 @@ aircraft:crew_and_payload:num_flight_attendants,3,unitless aircraft:crew_and_payload:num_flight_crew,2,unitless aircraft:crew_and_payload:num_galley_crew,0,unitless aircraft:crew_and_payload:num_non_flight_crew,3,unitless -aircraft:crew_and_payload:num_passengers,169,unitless +aircraft:crew_and_payload:num_passengers,180,unitless aircraft:crew_and_payload:num_tourist_class,158,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:crew_and_payload:passenger_service_mass_scaler,1.0,unitless diff --git a/aviary/utils/preprocessors.py b/aviary/utils/preprocessors.py index c2cce0604..28f222f7b 100644 --- a/aviary/utils/preprocessors.py +++ b/aviary/utils/preprocessors.py @@ -55,10 +55,9 @@ def preprocess_crewpayload(aviary_options: AviaryValues): passenger_check += aviary_options.get_val( Aircraft.CrewPayload.NUM_BUSINESS_CLASS) passenger_check += aviary_options.get_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS) - # only perform check if at least one passenger class is entered - if passenger_check > 0 and passenger_count != passenger_check: - raise om.AnalysisError( - "ERROR: In preprocesssors.py: passenger_count does not equal the sum of firt class + business class + tourist class passengers.") + # if passenger_count != passenger_check: + # raise om.AnalysisError( + # "ERROR: In preprocesssors.py: passenger_count does not equal the sum of firt class + business class + tourist class passengers.") if Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS not in aviary_options: flight_attendants_count = 0 # assume no passengers From 9d90a746466a1a30464d219fd2ae4933c11e6b81 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 22 Jan 2024 15:29:36 -0600 Subject: [PATCH 142/188] Updated GwGm truth values and added workflow for benchmarks --- .github/workflows/test_workflow.yml | 29 +++++++++++++++++-- .../benchmark_tests/test_bench_GwGm.py | 8 ++--- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index ff240cea6..7410a715d 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -46,6 +46,7 @@ jobs: OPENMDAO: '3.27' DYMOS: '1.8.0' MAKE_DOCS: 0 + RUN_BENCHES: 0 # development versions of openmdao/dymos - NAME: dev @@ -57,6 +58,7 @@ jobs: OPENMDAO: 'dev' DYMOS: 'dev' MAKE_DOCS: 0 + RUN_BENCHES: 0 # latest versions of openmdao/dymos - NAME: latest @@ -68,6 +70,7 @@ jobs: OPENMDAO: 'latest' DYMOS: 'latest' MAKE_DOCS: 0 + RUN_BENCHES: 0 # latest versions of openmdao/dymos for docs only - NAME: latest_docs @@ -79,6 +82,19 @@ jobs: OPENMDAO: 'latest' DYMOS: 'latest' MAKE_DOCS: 1 + RUN_BENCHES: 0 + + # latest versions of openmdao/dymos for benches only + - NAME: latest_benches + PY: 3 + NUMPY: 1 + SCIPY: 1 + PYOPTSPARSE: 'v2.9.1' + SNOPT: '7.7' + OPENMDAO: 'latest' + DYMOS: 'latest' + MAKE_DOCS: 0 + RUN_BENCHES: 1 steps: - name: Display run details @@ -205,7 +221,7 @@ jobs: retention-days: 5 - name: Generate specs - if: matrix.MAKE_DOCS == 0 + if: matrix.MAKE_DOCS == 0 && matrix.RUN_BENCHES == 0 shell: bash -l {0} run: | echo "=============================================================" @@ -216,7 +232,7 @@ jobs: cd ../.. - name: Run tests - if: matrix.MAKE_DOCS == 0 + if: matrix.MAKE_DOCS == 0 && matrix.RUN_BENCHES == 0 shell: bash -l {0} run: | echo "=============================================================" @@ -224,6 +240,15 @@ jobs: echo "=============================================================" testflo . -n 1 --show_skipped --coverage --coverpkg aviary + - name: Run benchmarks + if: matrix.RUN_BENCHES + shell: bash -l {0} + run: | + echo "=============================================================" + echo "Run Benchmarks" + echo "=============================================================" + testflo . --testmatch=bench_test* + - name: Build docs if: matrix.MAKE_DOCS shell: bash -l {0} diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py index d87013d8d..7dda04ad4 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py @@ -23,16 +23,16 @@ def bench_test_swap_2_GwGm(self): # There are no truth values for these. assert_near_equal(prob.get_val(Mission.Design.GROSS_MASS), - 174039., tolerance=rtol) + 181654., tolerance=rtol) assert_near_equal(prob.get_val(Aircraft.Design.OPERATING_MASS), - 95509, tolerance=rtol) + 101555., tolerance=rtol) assert_near_equal(prob.get_val(Mission.Summary.TOTAL_FUEL_MASS), - 42529., tolerance=rtol) + 44098., tolerance=rtol) assert_near_equal(prob.get_val('landing.' + Mission.Landing.GROUND_DISTANCE), - 2634.8, tolerance=rtol) + 2637.86, tolerance=rtol) assert_near_equal(prob.get_val("traj.desc2.timeseries.states:distance")[-1], 3675.0, tolerance=rtol) From 5593aaf67600f184e6e1b6c7b8574e157061b367 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 22 Jan 2024 15:52:00 -0600 Subject: [PATCH 143/188] Updated benches to pass CI --- .../mission/gasp_based/phases/benchmark/test_bench_accel.py | 2 ++ .../benchmark_tests/test_FLOPS_based_sizing_N3CC.py | 5 ++++- aviary/validation_cases/benchmark_tests/test_bench_FwFm.py | 4 +++- aviary/validation_cases/benchmark_tests/test_bench_FwGm.py | 5 ++--- aviary/validation_cases/benchmark_tests/test_bench_GwFm.py | 4 +++- aviary/validation_cases/benchmark_tests/test_bench_GwGm.py | 5 ++--- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py b/aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py index ac1f1294e..6d53ac5d4 100644 --- a/aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py +++ b/aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py @@ -1,10 +1,12 @@ import unittest from openmdao.utils.assert_utils import assert_near_equal +from openmdao.utils.testing_utils import require_pyoptsparse from aviary.mission.gasp_based.phases.run_phases.run_accel import run_accel +@require_pyoptsparse(optimizer="SNOPT") class AccelPhaseTestCase(unittest.TestCase): def bench_test_accel(self): 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 e1b144b94..d1f982f5d 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 @@ -13,6 +13,7 @@ import scipy.constants as _units from openmdao.utils.assert_utils import assert_near_equal from openmdao.utils.testing_utils import use_tempdirs +from openmdao.utils.testing_utils import require_pyoptsparse from aviary.mission.flops_based.phases.build_landing import Landing from aviary.mission.flops_based.phases.build_takeoff import Takeoff @@ -274,7 +275,7 @@ def run_trajectory(sim=True): promotes_outputs=['mission:*']) traj.link_phases(["climb", "cruise", "descent"], [ - "time", Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) + "time", Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) traj = setup_trajectory_params(prob.model, traj, aviary_inputs) @@ -437,6 +438,8 @@ def run_trajectory(sim=True): @use_tempdirs class ProblemPhaseTestCase(unittest.TestCase): + + @require_pyoptsparse(optimizer="SNOPT") def bench_test_sizing_N3CC(self): prob = run_trajectory(sim=False) diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index bd73cb077..365291916 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -2,6 +2,7 @@ import numpy as np from openmdao.utils.testing_utils import use_tempdirs +from openmdao.utils.testing_utils import require_pyoptsparse from aviary.interface.methods_for_level1 import run_aviary from aviary.validation_cases.benchmark_utils import \ @@ -260,6 +261,7 @@ def setUp(self): self.expected_dict = expected_dict + @require_pyoptsparse(optimizer="IPOPT") def bench_test_swap_4_FwFm(self): phase_info = { "pre_mission": {"include_takeoff": True, "optimize_mass": True}, @@ -348,7 +350,7 @@ def bench_test_swap_4_FwFm(self): } prob = run_aviary( - 'models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info, max_iter=50) + 'models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info, max_iter=50, optimizer='IPOPT') compare_against_expected_values(prob, self.expected_dict) diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py index 29dacddbf..21c076e17 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py @@ -1,5 +1,4 @@ from copy import deepcopy -import os import unittest from openmdao.utils.assert_utils import assert_near_equal @@ -13,11 +12,11 @@ @use_tempdirs class ProblemPhaseTestCase(unittest.TestCase): - @require_pyoptsparse(optimizer="SNOPT") + @require_pyoptsparse(optimizer="IPOPT") def bench_test_swap_3_FwGm(self): local_phase_info = deepcopy(phase_info) prob = run_aviary('models/test_aircraft/aircraft_for_bench_FwGm.csv', - local_phase_info) + local_phase_info, optimizer='IPOPT') rtol = 1e-2 diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py index 4d173b597..129d71978 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py @@ -9,6 +9,7 @@ import numpy as np from openmdao.utils.testing_utils import use_tempdirs +from openmdao.utils.testing_utils import require_pyoptsparse from aviary.interface.methods_for_level1 import run_aviary from aviary.validation_cases.benchmark_utils import \ @@ -266,6 +267,7 @@ def setUp(self): self.expected_dict = expected_dict + @require_pyoptsparse(optimizer="IPOPT") def bench_test_swap_1_GwFm(self): phase_info = { "pre_mission": {"include_takeoff": True, "optimize_mass": True}, @@ -354,7 +356,7 @@ def bench_test_swap_1_GwFm(self): } prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwFm.csv', phase_info, - max_iter=50) + max_iter=50, optimizer='IPOPT') compare_against_expected_values(prob, self.expected_dict) diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py index 7dda04ad4..b6e6b7eb5 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py @@ -1,5 +1,4 @@ from copy import deepcopy -import os import unittest from openmdao.utils.assert_utils import assert_near_equal @@ -13,11 +12,11 @@ @use_tempdirs class ProblemPhaseTestCase(unittest.TestCase): - @require_pyoptsparse(optimizer="SNOPT") + @require_pyoptsparse(optimizer="IPOPT") def bench_test_swap_2_GwGm(self): local_phase_info = deepcopy(phase_info) prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwGm.csv', - local_phase_info) + local_phase_info, optimizer='IPOPT') rtol = 0.01 From 388445bb7cea88182989e1e9e773940984e2eb81 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 22 Jan 2024 16:35:21 -0600 Subject: [PATCH 144/188] Updated bench values --- aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv | 4 ++-- aviary/utils/preprocessors.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv index 120717a9e..a3bcfe007 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwFm.csv @@ -21,8 +21,8 @@ aircraft:crew_and_payload:num_flight_attendants,3,unitless aircraft:crew_and_payload:num_flight_crew,2,unitless aircraft:crew_and_payload:num_galley_crew,0,unitless aircraft:crew_and_payload:num_non_flight_crew,3,unitless -aircraft:crew_and_payload:num_passengers,169,unitless -aircraft:crew_and_payload:num_tourist_class,158,unitless +aircraft:crew_and_payload:num_passengers,180,unitless +aircraft:crew_and_payload:num_tourist_class,169,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:crew_and_payload:passenger_service_mass_scaler,1.0,unitless aircraft:crew_and_payload:wing_cargo,0.0,lbm diff --git a/aviary/utils/preprocessors.py b/aviary/utils/preprocessors.py index c2cce0604..57cd37f84 100644 --- a/aviary/utils/preprocessors.py +++ b/aviary/utils/preprocessors.py @@ -58,7 +58,7 @@ def preprocess_crewpayload(aviary_options: AviaryValues): # only perform check if at least one passenger class is entered if passenger_check > 0 and passenger_count != passenger_check: raise om.AnalysisError( - "ERROR: In preprocesssors.py: passenger_count does not equal the sum of firt class + business class + tourist class passengers.") + f"ERROR: In preprocesssors.py: passenger_count ({passenger_count}) does not equal the sum of first class + business class + tourist class passengers (total of {passenger_check}).") if Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS not in aviary_options: flight_attendants_count = 0 # assume no passengers From 377dc18fe3951b4fa5527a62c3e9e26e86fca26c Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 22 Jan 2024 17:00:32 -0600 Subject: [PATCH 145/188] Changed takeoff/landing systems addition for height_energy --- aviary/interface/methods_for_level2.py | 35 ++++++++++--------- .../benchmark_tests/test_0_iters.py | 2 -- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 028f05b27..f3e12c0b9 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -416,13 +416,13 @@ def add_pre_mission_systems(self): # Check for 2DOF mission method # NOTE should solved trigger this as well? if self.mission_method is TWO_DEGREES_OF_FREEDOM: - self._add_gasp_takeoff_systems() + self._add_two_dof_takeoff_systems() # Check for HE mission method elif self.mission_method is HEIGHT_ENERGY: - self._add_flops_takeoff_systems() + self._add_height_energy_takeoff_systems() - def _add_flops_takeoff_systems(self): + def _add_height_energy_takeoff_systems(self): # Initialize takeoff options takeoff_options = Takeoff( airport_altitude=0., # ft @@ -435,7 +435,7 @@ def _add_flops_takeoff_systems(self): 'takeoff', takeoff, promotes_inputs=['aircraft:*', 'mission:*'], promotes_outputs=['mission:*']) - def _add_gasp_takeoff_systems(self): + def _add_two_dof_takeoff_systems(self): # Create options to values OptionsToValues = create_opts2vals( [Aircraft.CrewPayload.NUM_PASSENGERS, @@ -1180,11 +1180,14 @@ def add_post_mission_systems(self, include_landing=True): A user can override this with their own postmission systems. """ + if self.pre_mission_info['include_takeoff'] and self.mission_method is HEIGHT_ENERGY: + self._add_post_mission_takeoff_systems() + if include_landing and self.post_mission_info['include_landing']: if self.mission_method is HEIGHT_ENERGY: - self._add_flops_landing_systems() + self._add_height_energy_landing_systems() elif self.mission_method is TWO_DEGREES_OF_FREEDOM: - self._add_gasp_landing_systems() + self._add_two_dof_landing_systems() self.model.add_subsystem('post_mission', self.post_mission, promotes_inputs=['*'], @@ -1750,7 +1753,6 @@ def add_objective(self, objective_type=None, ref=None): elif objective_type == "fuel": self.model.add_objective(Mission.Objectives.FUEL, ref=ref) - # If 'mission_method' is 'FLOPS', add a 'fuel_burned' objective elif self.mission_method is HEIGHT_ENERGY: ref = ref if ref is not None else default_ref_values.get("fuel_burned", 1) self.model.add_objective("fuel_burned", ref=ref) @@ -2369,7 +2371,7 @@ def _get_all_subsystems(self, external_subsystems=None): return all_subsystems - def _add_flops_landing_systems(self): + def _add_height_energy_landing_systems(self): landing_options = Landing( ref_wing_area=self.aviary_inputs.get_val( Aircraft.Wing.AREA, units='ft**2'), @@ -2377,13 +2379,17 @@ def _add_flops_landing_systems(self): Mission.Landing.LIFT_COEFFICIENT_MAX) # no units ) - landing = landing_options.build_phase( - False, - ) + landing = landing_options.build_phase(False) self.model.add_subsystem( 'landing', landing, promotes_inputs=['aircraft:*', 'mission:*'], promotes_outputs=['mission:*']) + self.model.connect('traj.descent.states:mass', + Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1]) + self.model.connect('traj.descent.control_values:altitude', Mission.Landing.INITIAL_ALTITUDE, + src_indices=[0]) + + def _add_post_mission_takeoff_systems(self): connect_takeoff_to_climb = not self.phase_info['climb']['user_options'].get( 'add_initial_mass_constraint', True) @@ -2420,12 +2426,7 @@ def _add_flops_landing_systems(self): self.model.add_constraint( 'alt_diff_comp.altitude_resid_for_connecting_takeoff', equals=0.0) - self.model.connect('traj.descent.states:mass', - Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1]) - self.model.connect('traj.descent.control_values:altitude', Mission.Landing.INITIAL_ALTITUDE, - src_indices=[0]) - - def _add_gasp_landing_systems(self): + def _add_two_dof_landing_systems(self): self.model.add_subsystem( "landing", LandingSegment( diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index baa403fad..4c8622e32 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -8,8 +8,6 @@ from aviary.interface.default_phase_info.height_energy import phase_info as height_energy_phase_info from aviary.interface.default_phase_info.solved import phase_info as solved_phase_info from aviary.models.N3CC.N3CC_data import inputs -from aviary.variable_info.variables import Settings -from aviary.variable_info.enums import EquationsOfMotion class BaseProblemPhaseTestCase(unittest.TestCase): From 51c71ce910e6b9a2e6a16082994019b73c4dd9d2 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 22 Jan 2024 17:48:27 -0600 Subject: [PATCH 146/188] Fixes for height energy mission --- aviary/interface/methods_for_level2.py | 79 +++++++++++-------- aviary/models/N3CC/N3CC_data.py | 2 + .../benchmark_tests/test_0_iters.py | 4 + .../test_FLOPS_based_sizing_N3CC.py | 2 +- 4 files changed, 54 insertions(+), 33 deletions(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index f3e12c0b9..606756977 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -2384,47 +2384,62 @@ def _add_height_energy_landing_systems(self): 'landing', landing, promotes_inputs=['aircraft:*', 'mission:*'], promotes_outputs=['mission:*']) - self.model.connect('traj.descent.states:mass', + last_flight_phase_name = list(self.phase_info.keys())[-1] + if self.phase_info[last_flight_phase_name]['user_options'].get('use_polynomial_control', True): + control_type_string = 'polynomial_control_values' + else: + control_type_string = 'control_values' + + self.model.connect(f'traj.{last_flight_phase_name}.states:mass', Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1]) - self.model.connect('traj.descent.control_values:altitude', Mission.Landing.INITIAL_ALTITUDE, + self.model.connect(f'traj.{last_flight_phase_name}.{control_type_string}:altitude', Mission.Landing.INITIAL_ALTITUDE, src_indices=[0]) def _add_post_mission_takeoff_systems(self): - connect_takeoff_to_climb = not self.phase_info['climb']['user_options'].get( + first_flight_phase_name = list(self.phase_info.keys())[0] + connect_takeoff_to_climb = not self.phase_info[first_flight_phase_name]['user_options'].get( 'add_initial_mass_constraint', True) if connect_takeoff_to_climb: self.model.connect(Mission.Takeoff.FINAL_MASS, - 'traj.climb.initial_states:mass') + f'traj.{first_flight_phase_name}.initial_states:mass') self.model.connect(Mission.Takeoff.GROUND_DISTANCE, - 'traj.climb.initial_states:distance') - - # Create an ExecComp to compute the difference in mach - mach_diff_comp = om.ExecComp( - 'mach_resid_for_connecting_takeoff = final_mach - initial_mach') - self.model.add_subsystem('mach_diff_comp', mach_diff_comp) - - # Connect the inputs to the mach difference component - self.model.connect(Mission.Takeoff.FINAL_MACH, 'mach_diff_comp.final_mach') - self.model.connect('traj.climb.control_values:mach', - 'mach_diff_comp.initial_mach', src_indices=[0]) - - # Add constraint for mach difference - self.model.add_constraint( - 'mach_diff_comp.mach_resid_for_connecting_takeoff', equals=0.0) - - # Similar steps for altitude difference - alt_diff_comp = om.ExecComp( - 'altitude_resid_for_connecting_takeoff = final_altitude - initial_altitude', units='ft') - self.model.add_subsystem('alt_diff_comp', alt_diff_comp) - - self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, - 'alt_diff_comp.final_altitude') - self.model.connect('traj.climb.control_values:altitude', - 'alt_diff_comp.initial_altitude', src_indices=[0]) - - self.model.add_constraint( - 'alt_diff_comp.altitude_resid_for_connecting_takeoff', equals=0.0) + f'traj.{first_flight_phase_name}.initial_states:distance') + + if self.phase_info[first_flight_phase_name].get('optimize_mach', False): + if self.phase_info[first_flight_phase_name].get('use_polynomial_control', True): + control_type_string = 'polynomial_control_values' + else: + control_type_string = 'control_values' + + # Create an ExecComp to compute the difference in mach + mach_diff_comp = om.ExecComp( + 'mach_resid_for_connecting_takeoff = final_mach - initial_mach') + self.model.add_subsystem('mach_diff_comp', mach_diff_comp) + + # Connect the inputs to the mach difference component + self.model.connect(Mission.Takeoff.FINAL_MACH, + 'mach_diff_comp.final_mach') + self.model.connect(f'traj.{first_flight_phase_name}.{control_type_string}:mach', + 'mach_diff_comp.initial_mach', src_indices=[0]) + + # Add constraint for mach difference + self.model.add_constraint( + 'mach_diff_comp.mach_resid_for_connecting_takeoff', equals=0.0) + + if self.phase_info[first_flight_phase_name].get('optimize_altitude', False): + # Similar steps for altitude difference + alt_diff_comp = om.ExecComp( + 'altitude_resid_for_connecting_takeoff = final_altitude - initial_altitude', units='ft') + self.model.add_subsystem('alt_diff_comp', alt_diff_comp) + + self.model.connect(Mission.Takeoff.FINAL_ALTITUDE, + 'alt_diff_comp.final_altitude') + self.model.connect(f'traj.{first_flight_phase_name}.{control_type_string}:altitude', + 'alt_diff_comp.initial_altitude', src_indices=[0]) + + self.model.add_constraint( + 'alt_diff_comp.altitude_resid_for_connecting_takeoff', equals=0.0) def _add_two_dof_landing_systems(self): self.model.add_subsystem( diff --git a/aviary/models/N3CC/N3CC_data.py b/aviary/models/N3CC/N3CC_data.py index 764d4d43f..976cf9c13 100644 --- a/aviary/models/N3CC/N3CC_data.py +++ b/aviary/models/N3CC/N3CC_data.py @@ -291,6 +291,7 @@ inputs.set_val(Mission.Design.RANGE, 3500, 'NM') inputs.set_val(Mission.Constraints.MAX_MACH, 0.785) inputs.set_val(Mission.Landing.DRAG_COEFFICIENT, 0.045, 'unitless') +inputs.set_val(Mission.Landing.LIFT_COEFFICIENT_MAX, 2.0, 'unitless') inputs.set_val(Mission.Takeoff.AIRPORT_ALTITUDE, 0., 'ft') inputs.set_val(Mission.Takeoff.DRAG_COEFFICIENT_MIN, 0.05, 'unitless') inputs.set_val(Mission.Takeoff.LIFT_COEFFICIENT_MAX, 2.0, 'unitless') @@ -308,6 +309,7 @@ inputs.set_val(Mission.Landing.SPOILER_DRAG_COEFFICIENT, 0.085000) inputs.set_val(Mission.Landing.SPOILER_LIFT_COEFFICIENT, -0.810000) inputs.set_val(Mission.Takeoff.THRUST_INCIDENCE, 0., 'deg') +inputs.set_val(Mission.Takeoff.FUEL_SIMPLE, 577., 'lbm') # Settings # --------------------------- diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index 4c8622e32..c51f02e90 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -47,6 +47,10 @@ class HEZeroItersTestCase(BaseProblemPhaseTestCase): @require_pyoptsparse(optimizer="IPOPT") def test_zero_iters_height_energy(self): local_phase_info = deepcopy(height_energy_phase_info) + local_phase_info['pre_mission']['include_takeoff'] = True + local_phase_info['post_mission']['include_landing'] = True + local_phase_info['climb']['user_options']['fix_initial'] = False + local_phase_info['climb']['user_options']['input_initial'] = True self.build_and_run_problem(inputs, local_phase_info) 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 e1b144b94..95afa681a 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 @@ -274,7 +274,7 @@ def run_trajectory(sim=True): promotes_outputs=['mission:*']) traj.link_phases(["climb", "cruise", "descent"], [ - "time", Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) + "time", Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE], connected=strong_couple) traj = setup_trajectory_params(prob.model, traj, aviary_inputs) From 7b79cbd2bee05feca10376d1bb1db6266a237037 Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Mon, 22 Jan 2024 16:39:55 -0800 Subject: [PATCH 147/188] Combined lists of names and lists of units into dicts of name:units --- .../gasp_based/idle_descent_estimation.py | 7 +- .../ode/time_integration_base_classes.py | 357 +++++++++--------- .../phases/time_integration_phases.py | 30 +- .../phases/time_integration_traj.py | 4 +- 4 files changed, 196 insertions(+), 202 deletions(-) diff --git a/aviary/mission/gasp_based/idle_descent_estimation.py b/aviary/mission/gasp_based/idle_descent_estimation.py index 0371183fa..50fb3759d 100644 --- a/aviary/mission/gasp_based/idle_descent_estimation.py +++ b/aviary/mission/gasp_based/idle_descent_estimation.py @@ -34,8 +34,11 @@ def descent_range_and_fuel( traj = FlexibleTraj( Phases=phases, - traj_final_state_output=[Dynamic.Mission.MASS, - Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE], + traj_final_state_output=[ + Dynamic.Mission.MASS, + Dynamic.Mission.DISTANCE, + Dynamic.Mission.ALTITUDE, + ], traj_initial_state_input=[ Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE, diff --git a/aviary/mission/gasp_based/ode/time_integration_base_classes.py b/aviary/mission/gasp_based/ode/time_integration_base_classes.py index a6b675643..5ad167b01 100644 --- a/aviary/mission/gasp_based/ode/time_integration_base_classes.py +++ b/aviary/mission/gasp_based/ode/time_integration_base_classes.py @@ -25,19 +25,14 @@ def __init__( ode, time_independent=False, t_name="t_curr", - state_names=None, + states=None, alternate_state_names=None, blocked_state_names=None, - state_units=None, - state_rate_names=None, + state_rates=None, alternate_state_rate_names=None, - state_rate_units=None, - parameter_names=None, - parameter_units=None, - output_names=None, - output_units=None, - control_names=None, - control_units=None, + parameters=None, + outputs=None, + controls=None, include_state_outputs=False, rate_suffix="_rate", DEBUG=False, @@ -46,9 +41,21 @@ def __init__( ): """ + states: a dictionary of the form {state_name:{'units':unit, 'rate':state_rate_name}} + alternate_state_names: a dictionary of the form {state_to_replace:'new_state_name'} + blocked_state_names: a list of the form [state_name_to_block] + state_rates: a dictionary of the form {state_rate_name:unit} + alternate_state_rate_names: a dictionary of the form {state_rate_to_replace:'new_state_rate_name'} + parameters: a dictionary of the form {parameter_name:unit} + outputs: a dictionary of the form {output_name:unit} + controls: a dictionary of the form {control_name:unit} include_state_outputs : automatically add the state to the input works well for auto-parsed naming, does not check for duplication before adding + states, state_rates, parameters, outputs, and controls can also be input as a list of keys for the dictionary """ + + default_args = dict(prom_name=True, val=False, out_stream=None, units=True) + self.DEBUG = DEBUG self.max_allowable_time = max_allowable_time self.adjoint_int_opts = adjoint_int_opts @@ -69,146 +76,144 @@ def __init__( prob.final_setup() self.time_independent = time_independent - if control_names is None: - control_names = [] + if type(states) is list: + states = {state: {'units': None, 'rate': state+rate_suffix} + for state in states} + if type(parameters) is list: + parameters = {parameter: None for parameter in parameters} + if type(outputs) is list: + outputs = {output: None for output in outputs} + if controls is None: + controls = {} + elif type(controls) is list: + controls = {control: None for control in controls} if alternate_state_names is None: alternate_state_names = {} if alternate_state_rate_names is None: alternate_state_rate_names = {} - self.control_names = control_names - if control_units is not None: - self.control_units = control_units - else: - self.control_units = [ - om_dict["units"] - for om_name, om_dict in prob.model.list_inputs( - includes=control_names, - out_stream=False, - val=False, - units=True, - ) - ] + + data = prob.model.list_inputs(includes=controls.keys(), **default_args) + control_data = {val.pop('prom_name'): val for key, val in data} + for control_name, control_units in controls.items(): + if control_units is None: + controls[control_name] = control_data[control_name]["units"] + self.controls = controls if ( - state_names is None - or parameter_names is None - or output_names is None # or + states is None + or parameters is None + or outputs is None # or # event_names is None ): - data = prob.model.list_outputs(prom_name=True, val=False, out_stream=None) - outputs = [val['prom_name'] for key, val in data] - data = prob.model.list_inputs(prom_name=True, val=False, out_stream=None) - inputs = [val['prom_name'] for key, val in data] - - if state_names is None: - state_names = [ - output.replace(rate_suffix, "") - for output in outputs + data = prob.model.list_outputs(**default_args) + model_outputs = [val['prom_name'] for key, val in data] + data = prob.model.list_inputs(**default_args) + model_inputs = [val['prom_name'] for key, val in data] + + if states is None: + states = { + output.replace(rate_suffix, ""): {'units': None, 'rate': output} + for output in model_outputs if output.endswith(rate_suffix) or output in alternate_state_names.keys() - ] + } + if blocked_state_names is not None: for name in blocked_state_names: - if name in state_names: - state_names.remove(name) + if name in states.keys(): + states.pop(name) if alternate_state_names: - for key, val in alternate_state_names.items(): - state_key = key.replace(rate_suffix, "") - if state_key in state_names: # Used to rename an existing state - state_names[state_names.index(state_key)] = val + for state_key, val in alternate_state_names.items(): + if state_key in states.keys(): # Used to rename an existing state + # modified_states = {} + # for name, state_data in states.items(): + # key = name if name not in alternate_state_names else alternate_state_names[name] + # modified_states[key] = state_data + # states = modified_states + states[val] = states.pop(state_key) else: # Used to add a new state - state_names.append(val) + states[val]: {'units': None, 'rate': val+rate_suffix} - if state_rate_names is None: - state_rate_names = [state_name + rate_suffix for state_name in state_names] + if state_rates is None: + state_rates = { + state_name + rate_suffix: None + for state_name in states.keys()} if alternate_state_rate_names: - state_rate_names = [name if name not in alternate_state_rate_names.keys( - ) else alternate_state_rate_names[name] for name in state_rate_names] - - if state_rate_units is not None: - self.state_rate_units = state_rate_units - else: - self.state_rate_units = [ - om_dict["units"] - for om_name, om_dict in prob.model.list_outputs( - includes=state_rate_names, - out_stream=False, - val=False, - units=True, - ) - ] - - if state_units is not None: - self.state_units = state_units - else: - self.state_units = [ - units.simplify_unit("s*" + rate_unit) - for rate_unit in self.state_rate_units - ] + for rate_name, val in alternate_state_rate_names.items(): + if rate_name in state_rates.keys(): + # state_rates[val] = state_rates.pop(rate_name) + modified_rates = {} + for name, rate_data in state_rates.items(): + key = name if name not in alternate_state_rate_names else alternate_state_rate_names[ + name] + modified_rates[key] = rate_data + state_rates = modified_rates + + state_name = rate_name.replace(rate_suffix, "") + if state_name in states.keys(): + states[state_name]['rate'] = val + + data = prob.model.list_outputs(includes=state_rates.keys(), **default_args) + rate_data = {val.pop('prom_name'): val for key, val in data} + for rate_name, rate_units in state_rates.items(): + if rate_units is None: + state_rates[rate_name] = rate_data[rate_name]["units"] + + for state_name, state_data in states.items(): + if state_data['units'] is None: + rate_unit = rate_data[state_data['rate']]["units"] + states[state_name]['units'] = units.simplify_unit("s*" + rate_unit) + + if parameters is None: + parameters = { + inp: None + for inp in set(model_inputs) + if inp not in list(states.keys()) + list(controls.keys()) + [t_name] + } - if parameter_names is None: - parameter_names = [ - inp - for inp in set(inputs) - if inp not in state_names + control_names + [t_name] - ] - if parameter_units is not None: - self.parameter_units = parameter_units - else: - self.parameter_units = [ - om_dict["units"] - for om_name, om_dict in prob.model.list_inputs( - includes=parameter_names, - out_stream=False, - val=False, - units=True, - ) - ] + data = prob.model.list_inputs(includes=parameters.keys(), **default_args) + parameter_data = {val.pop('prom_name'): val for key, val in data} + for parameter_name, parameter_units in parameters.items(): + if parameter_units is None: + parameters[parameter_name] = parameter_data[parameter_name]["units"] - if output_names is None: - output_names = [ - outp + if outputs is None: + outputs = { + outp: None for outp in outputs - if outp not in state_rate_names # + event_names - ] + if outp not in state_rates # + event_names + } - if output_units is not None: - self.output_units = output_units - else: - self.output_units = [ - next(iter(prob.model.get_io_metadata( + for output_name, output_units in outputs.items(): + if output_units is None: + outputs[output_name] = next(iter(prob.model.get_io_metadata( includes=[output_name], metadata_keys=["units"] ).values()))["units"] - for output_name in output_names - ] - if include_state_outputs or output_names == []: # prevent empty outputs - output_names = state_names + output_names - self.output_units = self.state_units + self.output_units + if include_state_outputs or outputs == {}: # prevent empty outputs + outputs = states + outputs self.t_name = t_name - self.state_names = state_names + self.states = states - self.state_rate_names = state_rate_names - self.parameter_names = parameter_names - self.output_names = output_names + self.state_rates = state_rates + self.parameters = parameters + self.outputs = outputs - self.dim_state = len(state_names) - self.dim_output = len(output_names) - self.dim_input = len(control_names) - self.dim_parameters = len(parameter_names) + self.dim_state = len(states) + self.dim_output = len(outputs) + self.dim_input = len(controls) + self.dim_parameters = len(parameters) # TODO: add defensive checks to make sure dimensions match in both setup and # calls - if DEBUG: + if DEBUG or True: om.n2(prob, outfile="n2_simupy_problem.html", show_browser=False) with open('input_list_simupy.txt', 'w') as outfile: prob.model.list_inputs(out_stream=outfile,) - print(state_names) - print(self.state_units) - print(state_rate_names) - print(self.state_rate_units) + print(states) + print(state_rates) @property def time(self): @@ -224,8 +229,8 @@ def time(self, value): def state(self): return np.array( [ - self.prob.get_val(state_name, units=unit)[0] - for state_name, unit in zip(self.state_names, self.state_units) + self.prob.get_val(state_name, units=state_data['units'])[0] + for state_name, state_data in self.states.items() ] ) @@ -233,15 +238,17 @@ def state(self): def state(self, value): if np.all(self.state == value): return - for state_name, elem_val, unit in zip( - self.state_names, value, self.state_units + for state_name, elem_val in zip( + self.states.keys(), value ): - self.prob.set_val(state_name, elem_val, units=unit) + self.prob.set_val(state_name, elem_val, + units=self.states[state_name]['units']) def compute_along_traj(self, ts, xs): self.prob.set_val(self.t_name, ts) - for state_name, elem_val, unit in zip(self.state_names, xs.T, self.state_units): - self.prob.set_val(state_name, elem_val, units=unit) + for state_name, elem_val in zip(self.states.keys(), xs.T): + self.prob.set_val(state_name, elem_val, + units=self.states[state_name]['units']) self.prob.run_model() @@ -250,7 +257,7 @@ def control(self): return np.array( [ self.prob.get_val(control_name, units=unit)[0] - for control_name, unit in zip(self.control_names, self.control_units) + for control_name, unit in self.controls.items() ] ) @@ -260,19 +267,17 @@ def control(self, value): value = np.array([]) if (self.control.size == value.size) and np.all(self.control == value): return - for control_name, elem_val, unit in zip( - self.control_names, value, self.control_units + for control_name, elem_val in zip( + self.controls, value ): - self.prob.set_val(control_name, elem_val, units=unit) + self.prob.set_val(control_name, elem_val, units=self.controls[control_name]) @property def parameter(self): return np.array( [ self.prob.get_val(parameter_name, units=unit)[0] - for parameter_name, unit in zip( - self.parameter_names, self.parameter_units - ) + for parameter_name, unit in self.parameters.items() ] ) @@ -280,8 +285,8 @@ def parameter(self): def parameter(self, value): if np.all(self.parameter == value): return - for parameter_name, elem_val, unit in zip( - self.parameter_names, value, self.parameter_units + for parameter_name, elem_val in zip( + self.paramaters, value ): self.prob.set_val(parameter_name, elem_val) @@ -290,9 +295,7 @@ def state_rate(self): return np.array( [ self.prob.get_val(state_rate_name, units=unit)[0] - for state_rate_name, unit in zip( - self.state_rate_names, self.state_rate_units - ) + for state_rate_name, unit in self.state_rates.items() ] ) @@ -301,7 +304,7 @@ def output(self): return np.array( [ self.prob.get_val(output_name, units=unit)[0] - for output_name, unit in zip(self.output_names, self.output_units) + for output_name, unit in self.outputs.items() ] ) @@ -431,9 +434,7 @@ def setup_params( ), **self.add_output( final_state_output+final_suffix, - units=ODEs[-1].state_units[ - ODEs[-1].state_names.index(final_state_output) - ], + units=ODEs[-1].states[final_state_output]['units'], ) } for final_state_output in traj_final_state_output @@ -446,9 +447,7 @@ def setup_params( ), **self.add_output( promoted_final_output+final_suffix, - units=ODEs[-1].output_units[ - ODEs[-1].output_names.index(promoted_final_output) - ], + units=ODEs[-1].outputs[promoted_final_output], ), } for promoted_final_output in traj_promote_final_output @@ -463,9 +462,7 @@ def setup_params( **dict(name=initial_state_input+initial_suffix), **self.add_input( initial_state_input+initial_suffix, - units=ODEs[0].state_units[ - ODEs[0].state_names.index(initial_state_input) - ], + units=ODEs[0].states[initial_state_input]['units'], ) } for initial_state_input in traj_initial_state_input @@ -486,9 +483,7 @@ def setup_params( event_trigger_input[1], trigger_suffix ]), - units=event_trigger_input[0].state_units[ - event_trigger_input[0].state_names.index(event_trigger_input[1]) - ], + units=event_trigger_input[0].states[event_trigger_input[1]]['units'], ) } for event_trigger_input in traj_event_trigger_input @@ -523,7 +518,7 @@ def compute_traj_loop(self, first_problem, inputs, outputs, t0=0., state0=None): inputs[state_name+"_initial"].squeeze() if state_name in self.traj_initial_state_input else 0. - for state_name in first_problem.state_names + for state_name in first_problem.states.keys() ]).squeeze() while True: @@ -566,10 +561,8 @@ def compute_traj_loop(self, first_problem, inputs, outputs, t0=0., state0=None): current_problem.output_equation_function(t, x) state = np.array( [ - current_problem.prob.get_val(state_name, units=unit) - for state_name, unit in zip( - next_problem.state_names, next_problem.state_units - ) + current_problem.prob.get_val(state_name, units=state_data['units']) + for state_name, state_data in next_problem.states.items() ] ).squeeze() sim_problems.append(next_problem) @@ -588,7 +581,7 @@ def compute_traj_loop(self, first_problem, inputs, outputs, t0=0., state0=None): outputs[output_name] = sim_results[-1].x[ -1, - sim_problems[-1].state_names.index(state_name) + list(sim_problems[-1].states.keys()).index(state_name) ] for output in self.traj_promote_final_output: @@ -597,7 +590,7 @@ def compute_traj_loop(self, first_problem, inputs, outputs, t0=0., state0=None): outputs[promoted_name] = sim_results[-1].y[ -1, - sim_problems[-1].output_names.index(output_name) + list(sim_problems[-1].outputs.keys()).index(output_name) ] self.last_inputs = np.array(list(inputs.values())) @@ -645,13 +638,13 @@ def compute_partials(self, inputs, J): param_deriv = np.zeros(len(param_dict)) if output in self.traj_final_state_output: - costate[next_prob.state_names.index(output)] = 1. + costate[list(next_prob.states.keys()).index(output)] = 1. else: # in self.traj_promote_final_output next_prob.state_equation_function(next_res.t[-1], next_res.x[-1, :]) costate[:] = next_prob.compute_totals( output, - next_prob.state_names, + next_prob.states.keys(), return_format='array' ).squeeze() @@ -692,12 +685,12 @@ def compute_partials(self, inputs, J): num_active_event_channels += 1 dg_dx = np.zeros((1, prob.dim_state)) - if channel_name in prob.state_names: - dg_dx[0, prob.state_names.index(channel_name)] = 1. + if channel_name in prob.states.keys(): + dg_dx[0, list(prob.states.keys()).index(channel_name)] = 1. else: dg_dx[0, :] = prob.compute_totals( [channel_name], - prob.state_names, + prob.states.keys(), return_format='array' ) @@ -733,17 +726,17 @@ def compute_partials(self, inputs, J): # here and co-state assume number of states is only decreasing # forward in time - for state_name in next_prob.state_names: - state_idx = next_prob.state_names.index(state_name) + for state_name in next_prob.states.keys(): + state_idx = list(next_prob.states.keys()).index(state_name) - if state_name in prob.state_names: + if state_name in prob.states.keys(): f_plus[ state_idx - ] = plus_rate[prob.state_names.index(state_name)] + ] = plus_rate[list(prob.states.keys()).index(state_name)] # state_update[ - # next_prob.state_names.index(state_name) - # ] = x[prob.state_names.index(state_name)] + # list(next_prob.states.keys()).index(state_name) + # ] = x[list(prob.states.keys()).index(state_name)] # TODO: make sure index multiplying next_pronb costate # lines up -- since costate is pre-filled to next_prob's @@ -751,14 +744,14 @@ def compute_partials(self, inputs, J): # column should map to dh_dx[state_idx, state_idx] = 1. - elif state_name in prob.output_names: + elif state_name in prob.outputs.keys(): state_update[ state_idx - ] = res.y[-1, prob.output_names.index(state_name)] + ] = res.y[-1, list(prob.outputs.keys()).index(state_name)] dh_j_dx = prob.compute_totals( [state_name], - prob.state_names, + prob.states.keys(), return_format='array').squeeze() dh_dparam[state_idx, :] = prob.compute_totals( @@ -767,15 +760,15 @@ def compute_partials(self, inputs, J): return_format='array' ).squeeze() - for state_name_2 in prob.state_names: + for state_name_2 in prob.states.keys(): # I'm actually computing dh_dx.T # dh_dx rows are new state, columns are old state # now, dh_dx.T rows are old state, columns are new # so I think this is right dh_dx[ - next_prob.state_names.index(state_name_2), + list(next_prob.states.keys()).index(state_name_2), state_idx, - ] = dh_j_dx[prob.state_names.index(state_name_2)] + ] = dh_j_dx[list(prob.states.keys()).index(state_name_2)] else: state_update[ @@ -787,12 +780,12 @@ def compute_partials(self, inputs, J): dh_dxs.append(dh_dx) dh_dparams.append(dh_dparam) - df_dx_data[idx, :, :] = prob.compute_totals(prob.state_rate_names, - prob.state_names, + df_dx_data[idx, :, :] = prob.compute_totals(prob.state_rates.keys(), + prob.states.keys(), return_format='array').T if param_dict: df_dparam_data[idx, ...] = prob.compute_totals( - prob.state_rate_names, + prob.state_rates.keys(), list(param_dict.keys()), return_format='array' ) @@ -903,7 +896,7 @@ def compute_partials(self, inputs, J): # lamda_dot_plus = lamda_dot if self.DEBUG: if np.any(state_disc): - print("update is non-zero!", prob, prob.state_names, + print("update is non-zero!", prob, prob.states.keys(), state_disc, costate, lamda_dot) print( "inner product becomes...", @@ -912,7 +905,7 @@ def compute_partials(self, inputs, J): state_disc[None, :] @ dh_dx.T @ lamda_dot_plus[:, None] ) - print("dh_dx for", prob, prob.state_names, "\n", dh_dx) + print("dh_dx for", prob, prob.states.keys(), "\n", dh_dx) print("costate", costate) costate_update_terms = [ dh_dx.T @ costate[:, None], @@ -1009,17 +1002,17 @@ def co_state_rate(t, costate, *args): # TODO: do co-states need unit changes? probably not... for state_name in prob.state_names: - costate[next_prob.state_names.index(state_name)] = co_res.x[-1, - prob.state_names.index(state_name)] + costate[list(next_prob.states.keys()).index( + state_name)] = co_res.x[-1, list(prob.states.keys()).index(state_name)] lamda_dot_plus[ - next_prob.state_names.index(state_name) - ] = lamda_dot_plus_rate[prob.state_names.index(state_name)] + list(next_prob.states.keys()).index(state_name) + ] = lamda_dot_plus_rate[list(prob.states.keys()).index(state_name)] for state_to_deriv, metadata in self.traj_initial_state_input.items(): param_name = metadata["name"] J[output_name, param_name] = costate_reses[output][-1].x[ -1, - prob.state_names.index(state_to_deriv) + list(prob.states.keys()).index(state_to_deriv) ] for param_deriv_val, param_deriv_name in zip(param_deriv, param_dict): J[output_name, param_deriv_name] = param_deriv_val diff --git a/aviary/mission/gasp_based/phases/time_integration_phases.py b/aviary/mission/gasp_based/phases/time_integration_phases.py index 7b5865192..fa6d3f62a 100644 --- a/aviary/mission/gasp_based/phases/time_integration_phases.py +++ b/aviary/mission/gasp_based/phases/time_integration_phases.py @@ -35,8 +35,8 @@ def __init__( super().__init__( GroundrollODE(analysis_scheme=AnalysisScheme.SHOOTING, **ode_args), - output_names=["normal_force"], - state_names=[ + outputs=["normal_force"], + states=[ Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, @@ -76,8 +76,8 @@ def __init__( ): super().__init__( RotationODE(analysis_scheme=AnalysisScheme.SHOOTING, **ode_args), - output_names=["normal_force", "alpha"], - state_names=[ + outputs=["normal_force", "alpha"], + states=[ Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, @@ -129,13 +129,13 @@ def __init__( super().__init__( AscentODE(analysis_scheme=AnalysisScheme.SHOOTING, alpha_mode=alpha_mode, **ode_args), - output_names=[ + outputs=[ "load_factor", "fuselage_pitch", "normal_force", "alpha", ], - state_names=[ + states=[ Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, @@ -258,7 +258,7 @@ def set_val(self, *args, **kwargs): ode.set_val(*args, **kwargs) def compute_alpha(self, ode, t, x): - return ode.output_equation_function(t, x)[ode.output_names.index("alpha")] + return ode.output_equation_function(t, x)[list(ode.outputs.keys()).index("alpha")] def get_alpha(self, t, x): a_key = (t,) + tuple(x) @@ -377,8 +377,8 @@ def __init__( ode = AccelODE(analysis_scheme=AnalysisScheme.SHOOTING, **ode_args) super().__init__( ode, - output_names=["EAS", "mach", "alpha"], - state_names=[ + outputs=["EAS", "mach", "alpha"], + states=[ Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, @@ -436,7 +436,7 @@ def __init__( self.alt_trigger_units = alt_trigger_units super().__init__( ode, - output_names=[ + outputs=[ "alpha", Dynamic.Mission.FLIGHT_PATH_ANGLE, "required_lift", @@ -448,7 +448,7 @@ def __init__( "drag", Dynamic.Mission.ALTITUDE_RATE, ], - state_names=[ + states=[ Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, @@ -507,7 +507,7 @@ def __init__( super().__init__( ode, - output_names=[ + outputs=[ "alpha", # ? "lift", "EAS", @@ -516,7 +516,7 @@ def __init__( "drag", Dynamic.Mission.ALTITUDE_RATE, ], - state_names=[ + states=[ Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, @@ -585,7 +585,7 @@ def __init__( self.alt_trigger_units = alt_trigger_units super().__init__( ode, - output_names=[ + outputs=[ "alpha", "required_lift", "lift", @@ -595,7 +595,7 @@ def __init__( "drag", Dynamic.Mission.ALTITUDE_RATE, ], - state_names=[ + states=[ Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE, Dynamic.Mission.ALTITUDE, diff --git a/aviary/mission/gasp_based/phases/time_integration_traj.py b/aviary/mission/gasp_based/phases/time_integration_traj.py index d566635d3..5e1884012 100644 --- a/aviary/mission/gasp_based/phases/time_integration_traj.py +++ b/aviary/mission/gasp_based/phases/time_integration_traj.py @@ -103,9 +103,7 @@ def compute(self, inputs, outputs): print('t_final', t_final) print('x_final', x_final) - print('states', self.ODEs[-1].state_names) - print('units', self.ODEs[-1].state_units) - + print(self.ODEs[-1].states) # class SGMTraj1(TimeIntegrationTrajBase): # ''' From 01844796a71578fea00a6118d64929757243b21d Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Mon, 22 Jan 2024 17:07:51 -0800 Subject: [PATCH 148/188] moved all rate information into the states --- .../ode/time_integration_base_classes.py | 63 ++++++------------- .../phases/time_integration_phases.py | 14 ++--- 2 files changed, 27 insertions(+), 50 deletions(-) diff --git a/aviary/mission/gasp_based/ode/time_integration_base_classes.py b/aviary/mission/gasp_based/ode/time_integration_base_classes.py index 5ad167b01..54208b01d 100644 --- a/aviary/mission/gasp_based/ode/time_integration_base_classes.py +++ b/aviary/mission/gasp_based/ode/time_integration_base_classes.py @@ -28,7 +28,6 @@ def __init__( states=None, alternate_state_names=None, blocked_state_names=None, - state_rates=None, alternate_state_rate_names=None, parameters=None, outputs=None, @@ -41,17 +40,16 @@ def __init__( ): """ - states: a dictionary of the form {state_name:{'units':unit, 'rate':state_rate_name}} - alternate_state_names: a dictionary of the form {state_to_replace:'new_state_name'} + states: a dictionary of the form {state_name:{'units':unit, 'rate':state_rate_name, 'rate_units':state_rate_units}} + alternate_state_names: a dictionary of the form {state_to_replace:new_state_name} blocked_state_names: a list of the form [state_name_to_block] - state_rates: a dictionary of the form {state_rate_name:unit} - alternate_state_rate_names: a dictionary of the form {state_rate_to_replace:'new_state_rate_name'} + alternate_state_rate_names: a dictionary of the form {state_to_modify:new_state_rate_name} parameters: a dictionary of the form {parameter_name:unit} outputs: a dictionary of the form {output_name:unit} controls: a dictionary of the form {control_name:unit} include_state_outputs : automatically add the state to the input works well for auto-parsed naming, does not check for duplication before adding - states, state_rates, parameters, outputs, and controls can also be input as a list of keys for the dictionary + states, parameters, outputs, and controls can also be input as a list of keys for the dictionary """ default_args = dict(prom_name=True, val=False, out_stream=None, units=True) @@ -77,7 +75,7 @@ def __init__( self.time_independent = time_independent if type(states) is list: - states = {state: {'units': None, 'rate': state+rate_suffix} + states = {state: {'units': None, 'rate': state+rate_suffix, 'rate_units': None} for state in states} if type(parameters) is list: parameters = {parameter: None for parameter in parameters} @@ -125,41 +123,21 @@ def __init__( if alternate_state_names: for state_key, val in alternate_state_names.items(): if state_key in states.keys(): # Used to rename an existing state - # modified_states = {} - # for name, state_data in states.items(): - # key = name if name not in alternate_state_names else alternate_state_names[name] - # modified_states[key] = state_data - # states = modified_states states[val] = states.pop(state_key) else: # Used to add a new state states[val]: {'units': None, 'rate': val+rate_suffix} - if state_rates is None: - state_rates = { - state_name + rate_suffix: None - for state_name in states.keys()} - if alternate_state_rate_names: - for rate_name, val in alternate_state_rate_names.items(): - if rate_name in state_rates.keys(): - # state_rates[val] = state_rates.pop(rate_name) - modified_rates = {} - for name, rate_data in state_rates.items(): - key = name if name not in alternate_state_rate_names else alternate_state_rate_names[ - name] - modified_rates[key] = rate_data - state_rates = modified_rates - - state_name = rate_name.replace(rate_suffix, "") - if state_name in states.keys(): - states[state_name]['rate'] = val - - data = prob.model.list_outputs(includes=state_rates.keys(), **default_args) - rate_data = {val.pop('prom_name'): val for key, val in data} - for rate_name, rate_units in state_rates.items(): - if rate_units is None: - state_rates[rate_name] = rate_data[rate_name]["units"] + if alternate_state_rate_names: + for state_name, val in alternate_state_rate_names.items(): + if state_name in states.keys(): + states[state_name]['rate'] = val + state_rate_names = [val['rate'] for _, val in states.items()] + data = prob.model.list_outputs(includes=state_rate_names, **default_args) + rate_data = {val.pop('prom_name'): val for key, val in data} for state_name, state_data in states.items(): + if state_data['rate_units'] is None: + state_data['rate_units'] = rate_data[state_data['rate']]["units"] if state_data['units'] is None: rate_unit = rate_data[state_data['rate']]["units"] states[state_name]['units'] = units.simplify_unit("s*" + rate_unit) @@ -181,7 +159,7 @@ def __init__( outputs = { outp: None for outp in outputs - if outp not in state_rates # + event_names + if outp not in state_rate_names # + event_names } for output_name, output_units in outputs.items(): @@ -197,7 +175,6 @@ def __init__( self.t_name = t_name self.states = states - self.state_rates = state_rates self.parameters = parameters self.outputs = outputs @@ -213,7 +190,6 @@ def __init__( with open('input_list_simupy.txt', 'w') as outfile: prob.model.list_inputs(out_stream=outfile,) print(states) - print(state_rates) @property def time(self): @@ -294,8 +270,8 @@ def parameter(self, value): def state_rate(self): return np.array( [ - self.prob.get_val(state_rate_name, units=unit)[0] - for state_rate_name, unit in self.state_rates.items() + self.prob.get_val(state_data['rate'], units=state_data['rate_units'])[0] + for _, state_data in self.states.items() ] ) @@ -780,12 +756,13 @@ def compute_partials(self, inputs, J): dh_dxs.append(dh_dx) dh_dparams.append(dh_dparam) - df_dx_data[idx, :, :] = prob.compute_totals(prob.state_rates.keys(), + state_rate_names = [val['rate'] for _, val in prob.states.items()] + df_dx_data[idx, :, :] = prob.compute_totals(state_rate_names, prob.states.keys(), return_format='array').T if param_dict: df_dparam_data[idx, ...] = prob.compute_totals( - prob.state_rates.keys(), + state_rate_names, list(param_dict.keys()), return_format='array' ) diff --git a/aviary/mission/gasp_based/phases/time_integration_phases.py b/aviary/mission/gasp_based/phases/time_integration_phases.py index fa6d3f62a..b0b53c5ca 100644 --- a/aviary/mission/gasp_based/phases/time_integration_phases.py +++ b/aviary/mission/gasp_based/phases/time_integration_phases.py @@ -44,7 +44,7 @@ def __init__( ], # state_units=['lbm','nmi','ft','ft/s'], alternate_state_rate_names={ - Dynamic.Mission.MASS_RATE: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, **simupy_args, ) @@ -84,7 +84,7 @@ def __init__( ], # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ - Dynamic.Mission.MASS_RATE: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, **simupy_args, ) @@ -142,7 +142,7 @@ def __init__( ], # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ - Dynamic.Mission.MASS_RATE: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, control_names=control_names, **simupy_args, ) @@ -385,7 +385,7 @@ def __init__( ], # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ - Dynamic.Mission.MASS_RATE: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, **simupy_args, ) self.phase_name = phase_name @@ -455,7 +455,7 @@ def __init__( ], # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ - Dynamic.Mission.MASS_RATE: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, **simupy_args, ) self.phase_name = phase_name @@ -523,7 +523,7 @@ def __init__( ], # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ - Dynamic.Mission.MASS_RATE: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, **simupy_args, ) @@ -602,7 +602,7 @@ def __init__( ], # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ - Dynamic.Mission.MASS_RATE: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, + Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, **simupy_args, ) From 984cdf4c1a6ffcfea8a30c0d22dd751df4ae28c1 Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Tue, 23 Jan 2024 08:57:17 -0800 Subject: [PATCH 149/188] Renamed variable for clarity --- .../gasp_based/ode/time_integration_base_classes.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/aviary/mission/gasp_based/ode/time_integration_base_classes.py b/aviary/mission/gasp_based/ode/time_integration_base_classes.py index 54208b01d..b3a8d0e17 100644 --- a/aviary/mission/gasp_based/ode/time_integration_base_classes.py +++ b/aviary/mission/gasp_based/ode/time_integration_base_classes.py @@ -52,7 +52,8 @@ def __init__( states, parameters, outputs, and controls can also be input as a list of keys for the dictionary """ - default_args = dict(prom_name=True, val=False, out_stream=None, units=True) + default_om_list_args = dict(prom_name=True, val=False, + out_stream=None, units=True) self.DEBUG = DEBUG self.max_allowable_time = max_allowable_time @@ -90,7 +91,7 @@ def __init__( if alternate_state_rate_names is None: alternate_state_rate_names = {} - data = prob.model.list_inputs(includes=controls.keys(), **default_args) + data = prob.model.list_inputs(includes=controls.keys(), **default_om_list_args) control_data = {val.pop('prom_name'): val for key, val in data} for control_name, control_units in controls.items(): if control_units is None: @@ -103,9 +104,9 @@ def __init__( or outputs is None # or # event_names is None ): - data = prob.model.list_outputs(**default_args) + data = prob.model.list_outputs(**default_om_list_args) model_outputs = [val['prom_name'] for key, val in data] - data = prob.model.list_inputs(**default_args) + data = prob.model.list_inputs(**default_om_list_args) model_inputs = [val['prom_name'] for key, val in data] if states is None: @@ -133,7 +134,7 @@ def __init__( states[state_name]['rate'] = val state_rate_names = [val['rate'] for _, val in states.items()] - data = prob.model.list_outputs(includes=state_rate_names, **default_args) + data = prob.model.list_outputs(includes=state_rate_names, **default_om_list_args) rate_data = {val.pop('prom_name'): val for key, val in data} for state_name, state_data in states.items(): if state_data['rate_units'] is None: @@ -149,7 +150,7 @@ def __init__( if inp not in list(states.keys()) + list(controls.keys()) + [t_name] } - data = prob.model.list_inputs(includes=parameters.keys(), **default_args) + data = prob.model.list_inputs(includes=parameters.keys(), **default_om_list_args) parameter_data = {val.pop('prom_name'): val for key, val in data} for parameter_name, parameter_units in parameters.items(): if parameter_units is None: From ffe4114acda28bf108293ee3a0af3adb6027bb1a Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Tue, 23 Jan 2024 12:06:47 -0500 Subject: [PATCH 150/188] Update aviary/xdsm/climb_xdsm.py Co-authored-by: crecine <51181861+crecine@users.noreply.github.com> --- aviary/xdsm/climb_xdsm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/xdsm/climb_xdsm.py b/aviary/xdsm/climb_xdsm.py index cd775b221..4bf95c1ab 100644 --- a/aviary/xdsm/climb_xdsm.py +++ b/aviary/xdsm/climb_xdsm.py @@ -54,7 +54,7 @@ x.add_input("specific_energy", [Dynamic.Mission.MASS]) x.add_input("alt_rate", ["TAS_rate"]) -# make connections6 +# make connections x.connect("atmos", "fc", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) # x.connect("atmos", "prop", [Dynamic.Mission.TEMPERATURE, Dynamic.Mission.STATIC_PRESSURE]) x.connect("atmos", "constraints", ["rho"]) From e0bd272f09c608b5e866364e38104e4fa79e8436 Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Tue, 23 Jan 2024 09:27:00 -0800 Subject: [PATCH 151/188] adding deepcopy to prevent intermittent testflo failure --- aviary/validation_cases/benchmark_tests/test_0_iters.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index baa403fad..023c7e92a 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -49,7 +49,8 @@ class HEZeroItersTestCase(BaseProblemPhaseTestCase): @require_pyoptsparse(optimizer="IPOPT") def test_zero_iters_height_energy(self): local_phase_info = deepcopy(height_energy_phase_info) - self.build_and_run_problem(inputs, local_phase_info) + local_inputs = deepcopy(inputs) + self.build_and_run_problem(local_inputs, local_phase_info) @use_tempdirs From 60bd15010ae3f293247e19f8fcc176b859056b43 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Tue, 23 Jan 2024 15:20:55 -0600 Subject: [PATCH 152/188] Began to tease apart initial guessing for GASP missions --- aviary/interface/methods_for_level2.py | 6 +- aviary/utils/process_input_decks.py | 66 ++++++++----------- .../benchmark_tests/test_0_iters.py | 3 +- .../benchmark_tests/test_bench_FwFm.py | 2 +- .../benchmark_tests/test_bench_GwGm.py | 10 +-- 5 files changed, 39 insertions(+), 48 deletions(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 028f05b27..d9a972284 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -39,7 +39,7 @@ from aviary.subsystems.premission import CorePreMission from aviary.mission.gasp_based.ode.breguet_cruise_ode import BreguetCruiseODESolution from aviary.utils.functions import set_aviary_initial_values, Null, create_opts2vals, add_opts2vals, promote_aircraft_and_mission_vars -from aviary.utils.process_input_decks import create_vehicle, update_GASP_options +from aviary.utils.process_input_decks import create_vehicle, update_GASP_options, initial_guessing from aviary.utils.preprocessors import preprocess_crewpayload from aviary.interface.utils.check_phase_info import check_phase_info from aviary.utils.aviary_values import AviaryValues @@ -170,8 +170,8 @@ def load_inputs(self, aviary_inputs, phase_info=None, engine_builder=None): self.mass_method = mass_method = aviary_inputs.get_val(Settings.MASS_METHOD) if mission_method is TWO_DEGREES_OF_FREEDOM or mass_method is GASP: - aviary_inputs, initial_guesses = update_GASP_options(aviary_inputs, - initial_guesses) + aviary_inputs = update_GASP_options(aviary_inputs) + initial_guesses = initial_guessing(aviary_inputs, initial_guesses) self.aviary_inputs = aviary_inputs self.initial_guesses = initial_guesses diff --git a/aviary/utils/process_input_decks.py b/aviary/utils/process_input_decks.py index 4f7ea1161..ce8257965 100644 --- a/aviary/utils/process_input_decks.py +++ b/aviary/utils/process_input_decks.py @@ -52,13 +52,23 @@ def create_vehicle(vehicle_deck=''): aircraft_values = get_option_defaults(engine=False) # TODO temporary, needed until debug_mode retired in favor of new verbosity flag + # TODO remove all hardcoded GASP values here, find appropriate place for them aircraft_values.set_val('debug_mode', val=False) + 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') + aircraft_values.set_val('problem_type', val=ProblemType.SIZING) + aircraft_values.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False) + aircraft_values.set_val( + Aircraft.Design.RESERVE_FUEL_ADDITIONAL, val=4998, units='lbm') if isinstance(vehicle_deck, AviaryValues): aircraft_values.update(vehicle_deck) + initial_guesses = {} else: vehicle_deck = get_path(vehicle_deck) - parse_inputs(vehicle_deck, aircraft_values) + aircraft_values, initial_guesses = parse_inputs(vehicle_deck, aircraft_values) return aircraft_values, initial_guesses @@ -77,6 +87,18 @@ def parse_inputs(vehicle_deck, aircraft_values: AviaryValues(), meta_data=_MetaD ------- tuple: Updated aircraft values and initial guesses. """ + initial_guesses = { + # initial_guesses is a dictionary that contains values used to initialize the trajectory + 'actual_takeoff_mass': 0, + 'rotation_mass': .99, + 'operating_empty_mass': 0, + 'fuel_burn_per_passenger_mile': 0.1, + 'cruise_mass_final': 0, + 'flight_duration': 0, + 'time_to_climb': 0, + 'climb_range': 0, + 'reserves': 0 + } guess_names = list(initial_guesses.keys()) with open(vehicle_deck, newline='') as f_in: @@ -132,7 +154,7 @@ def parse_inputs(vehicle_deck, aircraft_values: AviaryValues(), meta_data=_MetaD # e.g. aero preprocessor, mass preprocessor, 2DOF preprocessor, etc. -def update_GASP_options(aircraft_values: AviaryValues(), initial_guesses): +def update_GASP_options(aircraft_values: AviaryValues()): """ Updates options based on the current values in aircraft_values. This function also handles special cases and prints debug information if the debug mode is active. @@ -140,25 +162,11 @@ def update_GASP_options(aircraft_values: AviaryValues(), initial_guesses): Parameters ---------- aircraft_values (AviaryValues): An instance of AviaryValues containing current aircraft values. - initial_guesses (dict): A dictionary of initial guesses for various parameters. Returns ------- tuple: Updated aircraft values and initial guesses. """ - GASP_defaults = AviaryValues() - GASP_defaults.set_val('INGASP.JENGSZ', val=4) - GASP_defaults.set_val('test_mode', val=False) - GASP_defaults.set_val('use_surrogates', val=True) - GASP_defaults.set_val('mass_defect', val=10000, units='lbm') - GASP_defaults.set_val('problem_type', val=ProblemType.SIZING) - GASP_defaults.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False) - - # overwrite GASP_defaults with values from aircraft_values, then replace - # aircraft_values with this merged set - GASP_defaults.update(aircraft_values) - aircraft_values = GASP_defaults - # update the options that depend on variables update_dependent_options(aircraft_values, dependent_options) @@ -181,18 +189,13 @@ def update_GASP_options(aircraft_values: AviaryValues(), initial_guesses): aircraft_values.set_val( Aircraft.Wing.FOLD_DIMENSIONAL_LOCATION_SPECIFIED, val=False) - initial_guessing(aircraft_values) - if aircraft_values.get_val('debug_mode'): print('\nOptions') for key in get_keys(aircraft_values): val, units = aircraft_values.get_item(key) - print(key, val) - print('\nInitial Guesses') - for key, value in initial_guesses.items(): - print(key, value) + print(key, val, units) - return aircraft_values, initial_guesses + return aircraft_values def update_dependent_options(aircraft_values: AviaryValues(), dependent_options): @@ -227,7 +230,7 @@ def update_dependent_options(aircraft_values: AviaryValues(), dependent_options) return aircraft_values -def initial_guessing(aircraft_values: AviaryValues()): +def initial_guessing(aircraft_values: AviaryValues(), initial_guesses): """ Sets initial guesses for various aircraft parameters based on the current problem type, aircraft values, and other factors. It calculates and sets values like takeoff mass, cruise mass, flight duration, etc. @@ -336,7 +339,7 @@ def initial_guessing(aircraft_values: AviaryValues()): initial_guesses['climb_range'] = initial_guesses['time_to_climb'] / \ (60 * 60) * (avg_speed_guess * np.cos(gamma_guess)) - return aircraft_values, initial_guesses + return initial_guesses dependent_options = [ @@ -378,16 +381,3 @@ def initial_guessing(aircraft_values: AviaryValues()): [Aircraft.VerticalTail.VOLUME_COEFFICIENT, { 'val': 0, 'relation': '==', 'target': Aircraft.Design.COMPUTE_VTAIL_VOLUME_COEFF, 'result': True, 'alternate': False}], ] - -initial_guesses = { - # initial_guesses is a dictionary that contains values used to initialize the trajectory - 'actual_takeoff_mass': 0, - 'rotation_mass': .99, - 'operating_empty_mass': 0, - 'fuel_burn_per_passenger_mile': 0.1, - 'cruise_mass_final': 0, - 'flight_duration': 0, - 'time_to_climb': 0, - 'climb_range': 0, - 'reserves': 0 -} diff --git a/aviary/validation_cases/benchmark_tests/test_0_iters.py b/aviary/validation_cases/benchmark_tests/test_0_iters.py index baa403fad..023c7e92a 100644 --- a/aviary/validation_cases/benchmark_tests/test_0_iters.py +++ b/aviary/validation_cases/benchmark_tests/test_0_iters.py @@ -49,7 +49,8 @@ class HEZeroItersTestCase(BaseProblemPhaseTestCase): @require_pyoptsparse(optimizer="IPOPT") def test_zero_iters_height_energy(self): local_phase_info = deepcopy(height_energy_phase_info) - self.build_and_run_problem(inputs, local_phase_info) + local_inputs = deepcopy(inputs) + self.build_and_run_problem(local_inputs, local_phase_info) @use_tempdirs diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index 365291916..124635e5c 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -262,7 +262,7 @@ def setUp(self): self.expected_dict = expected_dict @require_pyoptsparse(optimizer="IPOPT") - def bench_test_swap_4_FwFm(self): + def test_bench_FwFm(self): phase_info = { "pre_mission": {"include_takeoff": True, "optimize_mass": True}, "climb": { diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py index b6e6b7eb5..33ccb75a3 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py @@ -13,7 +13,7 @@ class ProblemPhaseTestCase(unittest.TestCase): @require_pyoptsparse(optimizer="IPOPT") - def bench_test_swap_2_GwGm(self): + def test_bench_GwGm(self): local_phase_info = deepcopy(phase_info) prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwGm.csv', local_phase_info, optimizer='IPOPT') @@ -22,16 +22,16 @@ def bench_test_swap_2_GwGm(self): # There are no truth values for these. assert_near_equal(prob.get_val(Mission.Design.GROSS_MASS), - 181654., tolerance=rtol) + 174039., tolerance=rtol) assert_near_equal(prob.get_val(Aircraft.Design.OPERATING_MASS), - 101555., tolerance=rtol) + 95509, tolerance=rtol) assert_near_equal(prob.get_val(Mission.Summary.TOTAL_FUEL_MASS), - 44098., tolerance=rtol) + 42529., tolerance=rtol) assert_near_equal(prob.get_val('landing.' + Mission.Landing.GROUND_DISTANCE), - 2637.86, tolerance=rtol) + 2634.8, tolerance=rtol) assert_near_equal(prob.get_val("traj.desc2.timeseries.states:distance")[-1], 3675.0, tolerance=rtol) From 679225d301b1d6a29e440b7af91ac56bcac5a2a7 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Tue, 23 Jan 2024 16:15:27 -0600 Subject: [PATCH 153/188] Bench fix --- aviary/interface/methods_for_level2.py | 1 - aviary/mission/gasp_based/phases/time_integration_phases.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 9dd6ca174..d11cc6d43 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -980,7 +980,6 @@ def add_phases(self, phase_info_parameterization=None): descent_phases = create_2dof_based_descent_phases( self.ode_args, - cruise_alt=self.cruise_alt, cruise_mach=self.cruise_mach) descent_estimation = descent_range_and_fuel( diff --git a/aviary/mission/gasp_based/phases/time_integration_phases.py b/aviary/mission/gasp_based/phases/time_integration_phases.py index b0b53c5ca..a972070cd 100644 --- a/aviary/mission/gasp_based/phases/time_integration_phases.py +++ b/aviary/mission/gasp_based/phases/time_integration_phases.py @@ -125,7 +125,7 @@ def __init__( ode_args={}, simupy_args={}, ): - control_names = None + controls = None super().__init__( AscentODE(analysis_scheme=AnalysisScheme.SHOOTING, alpha_mode=alpha_mode, **ode_args), @@ -143,7 +143,7 @@ def __init__( # state_units=['lbm','nmi','ft'], alternate_state_rate_names={ Dynamic.Mission.MASS: Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL}, - control_names=control_names, + controls=controls, **simupy_args, ) From 9f3b687d9026e7806097c844b0f098a0c7739796 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Tue, 23 Jan 2024 16:21:16 -0600 Subject: [PATCH 154/188] Fixed takeoff connection logic --- aviary/interface/methods_for_level2.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 606756977..bba0223a3 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -2406,12 +2406,12 @@ def _add_post_mission_takeoff_systems(self): self.model.connect(Mission.Takeoff.GROUND_DISTANCE, f'traj.{first_flight_phase_name}.initial_states:distance') - if self.phase_info[first_flight_phase_name].get('optimize_mach', False): - if self.phase_info[first_flight_phase_name].get('use_polynomial_control', True): - control_type_string = 'polynomial_control_values' - else: - control_type_string = 'control_values' + if self.phase_info[first_flight_phase_name]['user_options'].get('use_polynomial_control', True): + control_type_string = 'polynomial_control_values' + else: + control_type_string = 'control_values' + if self.phase_info[first_flight_phase_name]['user_options'].get('optimize_mach', False): # Create an ExecComp to compute the difference in mach mach_diff_comp = om.ExecComp( 'mach_resid_for_connecting_takeoff = final_mach - initial_mach') @@ -2427,7 +2427,7 @@ def _add_post_mission_takeoff_systems(self): self.model.add_constraint( 'mach_diff_comp.mach_resid_for_connecting_takeoff', equals=0.0) - if self.phase_info[first_flight_phase_name].get('optimize_altitude', False): + if self.phase_info[first_flight_phase_name]['user_options'].get('optimize_altitude', False): # Similar steps for altitude difference alt_diff_comp = om.ExecComp( 'altitude_resid_for_connecting_takeoff = final_altitude - initial_altitude', units='ft') From bfd4c9e62e4169abf5754749e762c357f28a315b Mon Sep 17 00:00:00 2001 From: johnjasa Date: Tue, 23 Jan 2024 16:37:05 -0600 Subject: [PATCH 155/188] updating bench --- .../mission/gasp_based/ode/flight_path_ode.py | 7 +++--- .../benchmark_tests/test_bench_FwFm.py | 17 +++++++++---- .../benchmark_tests/test_bench_FwGm.py | 24 +++++++++++++++++++ .../benchmark_tests/test_bench_GwFm.py | 15 +++++++++--- .../benchmark_tests/test_bench_GwGm.py | 24 +++++++++++++++++++ 5 files changed, 76 insertions(+), 11 deletions(-) diff --git a/aviary/mission/gasp_based/ode/flight_path_ode.py b/aviary/mission/gasp_based/ode/flight_path_ode.py index 1e757b0d7..1ec3fab63 100644 --- a/aviary/mission/gasp_based/ode/flight_path_ode.py +++ b/aviary/mission/gasp_based/ode/flight_path_ode.py @@ -8,9 +8,6 @@ from aviary.mission.gasp_based.ode.base_ode import BaseODE from aviary.mission.gasp_based.ode.flight_path_eom import FlightPathEOM from aviary.mission.gasp_based.ode.params import ParamPort -from aviary.subsystems.aerodynamics.gasp_based.gaspaero import (CruiseAero, - LowSpeedAero) -from aviary.subsystems.propulsion.propulsion_mission import PropulsionMission from aviary.subsystems.propulsion.propulsion_builder import PropulsionBuilderBase from aviary.variable_info.variables import Aircraft, Dynamic, Mission from aviary.mission.ode.specific_energy_rate import SpecificEnergyRate @@ -285,7 +282,9 @@ def setup(self): 'alpha_comp', 'prop_group', 'eoms', - 'mass_trigger' + 'mass_trigger', + 'SPECIFIC_ENERGY_RATE_EXCESS', + 'ALTITUDE_RATE_MAX', ] + debug_comp) diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py index 124635e5c..26a9c672d 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwFm.py @@ -261,8 +261,6 @@ def setUp(self): self.expected_dict = expected_dict - @require_pyoptsparse(optimizer="IPOPT") - def test_bench_FwFm(self): phase_info = { "pre_mission": {"include_takeoff": True, "optimize_mass": True}, "climb": { @@ -349,8 +347,19 @@ def test_bench_FwFm(self): }, } + self.phase_info = phase_info + + @require_pyoptsparse(optimizer="IPOPT") + def test_bench_FwFm(self): + prob = run_aviary( + 'models/test_aircraft/aircraft_for_bench_FwFm.csv', self.phase_info, max_iter=50, optimizer='IPOPT') + + compare_against_expected_values(prob, self.expected_dict) + + @require_pyoptsparse(optimizer="SNOPT") + def test_bench_FwFm_SNOPT(self): prob = run_aviary( - 'models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info, max_iter=50, optimizer='IPOPT') + 'models/test_aircraft/aircraft_for_bench_FwFm.csv', self.phase_info, max_iter=50, optimizer='SNOPT') compare_against_expected_values(prob, self.expected_dict) @@ -358,4 +367,4 @@ def test_bench_FwFm(self): if __name__ == '__main__': test = ProblemPhaseTestCase() test.setUp() - test.bench_test_swap_4_FwFm() + test.test_bench_FwFm_SNOPT() diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py index 437e0eee7..6119cf699 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py @@ -36,6 +36,30 @@ def bench_test_swap_3_FwGm(self): assert_near_equal(prob.get_val("traj.desc2.timeseries.states:distance")[-1], 3675.0, tolerance=rtol) + @require_pyoptsparse(optimizer="SNOPT") + def bench_test_swap_3_FwGm_SNOPT(self): + local_phase_info = deepcopy(phase_info) + prob = run_aviary('models/test_aircraft/aircraft_for_bench_FwGm.csv', + local_phase_info, optimizer='SNOPT') + + rtol = 1e-2 + + # There are no truth values for these. + assert_near_equal(prob.get_val(Mission.Design.GROSS_MASS), + 186418., tolerance=rtol) + + assert_near_equal(prob.get_val(Aircraft.Design.OPERATING_MASS), + 104530., tolerance=rtol) + + assert_near_equal(prob.get_val(Mission.Summary.TOTAL_FUEL_MASS), + 44032., tolerance=rtol) + + assert_near_equal(prob.get_val('landing.' + Mission.Landing.GROUND_DISTANCE), + 2528., tolerance=rtol) + + assert_near_equal(prob.get_val("traj.desc2.timeseries.states:distance")[-1], + 3675.0, tolerance=rtol) + if __name__ == "__main__": # unittest.main() diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py index 129d71978..ae9dd722c 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py @@ -267,8 +267,6 @@ def setUp(self): self.expected_dict = expected_dict - @require_pyoptsparse(optimizer="IPOPT") - def bench_test_swap_1_GwFm(self): phase_info = { "pre_mission": {"include_takeoff": True, "optimize_mass": True}, "climb": { @@ -355,11 +353,22 @@ def bench_test_swap_1_GwFm(self): }, } - prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwFm.csv', phase_info, + self.phase_info = phase_info + + @require_pyoptsparse(optimizer="IPOPT") + def bench_test_swap_1_GwFm(self): + prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwFm.csv', self.phase_info, max_iter=50, optimizer='IPOPT') compare_against_expected_values(prob, self.expected_dict) + @require_pyoptsparse(optimizer="SNOPT") + def bench_test_swap_1_GwFm_SNOPT(self): + prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwFm.csv', self.phase_info, + max_iter=50, optimizer='SNOPT') + + compare_against_expected_values(prob, self.expected_dict) + if __name__ == '__main__': test = ProblemPhaseTestCase() diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py index 33ccb75a3..6547dd59b 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py @@ -36,6 +36,30 @@ def test_bench_GwGm(self): assert_near_equal(prob.get_val("traj.desc2.timeseries.states:distance")[-1], 3675.0, tolerance=rtol) + @require_pyoptsparse(optimizer="SNOPT") + def test_bench_GwGm_SNOPT(self): + local_phase_info = deepcopy(phase_info) + prob = run_aviary('models/test_aircraft/aircraft_for_bench_GwGm.csv', + local_phase_info, optimizer='SNOPT') + + rtol = 0.01 + + # There are no truth values for these. + assert_near_equal(prob.get_val(Mission.Design.GROSS_MASS), + 174039., tolerance=rtol) + + assert_near_equal(prob.get_val(Aircraft.Design.OPERATING_MASS), + 95509, tolerance=rtol) + + assert_near_equal(prob.get_val(Mission.Summary.TOTAL_FUEL_MASS), + 42529., tolerance=rtol) + + assert_near_equal(prob.get_val('landing.' + Mission.Landing.GROUND_DISTANCE), + 2634.8, tolerance=rtol) + + assert_near_equal(prob.get_val("traj.desc2.timeseries.states:distance")[-1], + 3675.0, tolerance=rtol) + if __name__ == '__main__': # unittest.main() From 6d7125cd43db5a095147c5d2c916ca7afa141fd4 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Wed, 24 Jan 2024 11:34:04 -0500 Subject: [PATCH 156/188] Changed height of iframe --- aviary/visualization/dashboard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index 6cbcad632..23b8a71b0 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -90,7 +90,7 @@ def create_report_frame(format, text_filepath): # f'') # iframe_css = "width=1200px height=1200px overflow=scroll margin=0px padding=0px border=20px frameBorder=20px scrolling=yes" iframe_css = 'max-width=1200px max-height=1200px overflow="scroll" margin=0px padding=0px border=20px frameBorder=20px scrolling="yes"' - iframe_css = 'width=1200px height=1200px overflow-x="scroll" overflow="scroll" margin=0px padding=0px border=20px frameBorder=20px scrolling="yes"' + iframe_css = 'width=1200px height=800px overflow-x="scroll" overflow="scroll" margin=0px padding=0px border=20px frameBorder=20px scrolling="yes"' report_pane = pn.pane.HTML( f'' ) elif format in ['markdown', 'text']: From 4e5121b5478e1f256cb641c2b3b3cd01a284bbbd Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 24 Jan 2024 11:04:45 -0600 Subject: [PATCH 157/188] PR feedback --- aviary/utils/process_input_decks.py | 7 +++++-- aviary/validation_cases/benchmark_tests/test_bench_FwGm.py | 2 +- aviary/validation_cases/benchmark_tests/test_bench_GwFm.py | 2 +- aviary/validation_cases/benchmark_tests/test_bench_GwGm.py | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/aviary/utils/process_input_decks.py b/aviary/utils/process_input_decks.py index ce8257965..0250a2a2f 100644 --- a/aviary/utils/process_input_decks.py +++ b/aviary/utils/process_input_decks.py @@ -60,8 +60,6 @@ def create_vehicle(vehicle_deck=''): aircraft_values.set_val('mass_defect', val=10000, units='lbm') aircraft_values.set_val('problem_type', val=ProblemType.SIZING) aircraft_values.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False) - aircraft_values.set_val( - Aircraft.Design.RESERVE_FUEL_ADDITIONAL, val=4998, units='lbm') if isinstance(vehicle_deck, AviaryValues): aircraft_values.update(vehicle_deck) @@ -339,6 +337,11 @@ def initial_guessing(aircraft_values: AviaryValues(), initial_guesses): initial_guesses['climb_range'] = initial_guesses['time_to_climb'] / \ (60 * 60) * (avg_speed_guess * np.cos(gamma_guess)) + if aircraft_values.get_val('debug_mode'): + print('\nInitial Guesses') + for key, value in initial_guesses.items(): + print(key, value) + return initial_guesses diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py index 6119cf699..c8c9dae3c 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py @@ -64,4 +64,4 @@ def bench_test_swap_3_FwGm_SNOPT(self): if __name__ == "__main__": # unittest.main() test = ProblemPhaseTestCase() - test.bench_test_swap_3_FwGm() + test.bench_test_swap_3_FwGm_SNOPT() diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py index ae9dd722c..7270f242e 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwFm.py @@ -373,4 +373,4 @@ def bench_test_swap_1_GwFm_SNOPT(self): if __name__ == '__main__': test = ProblemPhaseTestCase() test.setUp() - test.bench_test_swap_1_GwFm() + test.bench_test_swap_1_GwFm_SNOPT() diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py index 6547dd59b..5a194e8c7 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py @@ -64,4 +64,4 @@ def test_bench_GwGm_SNOPT(self): if __name__ == '__main__': # unittest.main() test = ProblemPhaseTestCase() - test.bench_test_swap_2_GwGm() + test.test_bench_GwGm_SNOPT() From 57d86fd5c711311141b9d7d817be9bc2630de4a3 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 24 Jan 2024 12:19:58 -0600 Subject: [PATCH 158/188] removed dymos prefix --- .../onboarding_ext_subsystem.ipynb | 6 +++--- .../default_phase_info/height_energy.py | 1 - aviary/interface/methods_for_level2.py | 16 +++++----------- aviary/interface/test/test_phase_info.py | 10 +++++----- aviary/utils/report.py | 6 +++--- .../benchmark_tests/test_bench_FwGm.py | 4 ++-- .../benchmark_tests/test_bench_GwGm.py | 4 ++-- .../test_full_mission_solved_ode.py | 7 ++----- aviary/validation_cases/benchmark_utils.py | 8 ++++---- 9 files changed, 26 insertions(+), 36 deletions(-) diff --git a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb index c5a9a12b4..7d6d6df6e 100644 --- a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb +++ b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb @@ -315,7 +315,7 @@ "# user defined outputs\n", "print('Battery MASS', prob.get_val(Aircraft.Battery.MASS))\n", "print('Cell Max', prob.get_val(Aircraft.Battery.Cell.MASS))\n", - "masses_descent = prob.get_val('traj.descent.timeseries.states:mass', units='kg')\n", + "masses_descent = prob.get_val('traj.descent.timeseries.mass', units='kg')\n", "print(f\"Final Descent Mass: {masses_descent[-1]}\")\n", "\n", "print('done')" @@ -359,7 +359,7 @@ "metadata": {}, "outputs": [], "source": [ - "masses_descent = prob.get_val('traj.descent.timeseries.states:mass', units='kg')\n", + "masses_descent = prob.get_val('traj.descent.timeseries.mass', units='kg')\n", "print(f\"Final Descent Mass: {masses_descent[-1]}\")" ] }, @@ -381,7 +381,7 @@ "\n", "```\n", "soc_cruise = prob.get_val(\n", - " 'traj.climb.timeseries.states:mission:battery:state_of_charge')\n", + " 'traj.climb.timeseries.mission:battery:state_of_charge')\n", "print(f\"State of Charge: {soc_cruise[-1]}\")\n", "```\n", "\n", diff --git a/aviary/interface/default_phase_info/height_energy.py b/aviary/interface/default_phase_info/height_energy.py index e42c67172..a51c812bc 100644 --- a/aviary/interface/default_phase_info/height_energy.py +++ b/aviary/interface/default_phase_info/height_energy.py @@ -123,7 +123,6 @@ def phase_info_parameterization(phase_info, post_mission_info, aviary_inputs): # Range old_range_cruise, range_units = post_mission_info['target_range'] range_cruise = aviary_inputs.get_val(Mission.Design.RANGE, units=range_units) - print(old_range_cruise, range_cruise) if range_cruise != old_range_cruise: new_val = post_mission_info['target_range'][0] * range_cruise / old_range_cruise post_mission_info['target_range'] = (new_val, range_units) diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 0a49eebe5..eeb6e6b69 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -607,8 +607,6 @@ def _get_2dof_phase(self, phase_name): opt=False, lower=0.0, upper=1.0 ) - phase.timeseries_options['use_prefix'] = True - return phase def _add_groundroll_eq_constraint(self, phase): @@ -728,8 +726,6 @@ def _get_height_energy_phase(self, phase_name, phase_idx): initial_ref=user_options.get_val("initial_ref", 's'), ) - phase.timeseries_options['use_prefix'] = True - return phase def _get_solved_phase(self, phase_name): @@ -883,8 +879,6 @@ def _get_solved_phase(self, phase_name): rate_targets=['dh_dr'], rate2_targets=['d2h_dr2'], opt=phase_options['opt'], upper=40.e3, ref=30.e3, lower=-1.) - phase.timeseries_options['use_prefix'] = True - return phase def add_phases(self, phase_info_parameterization=None): @@ -1150,7 +1144,7 @@ def add_post_mission_systems(self, include_landing=True): self.post_mission.add_subsystem('fuel_burn', ecomp, promotes_outputs=['fuel_burned']) - self.model.connect(f"traj.{phases[0]}.timeseries.states:mass", + self.model.connect(f"traj.{phases[0]}.timeseries.mass", "fuel_burn.initial_mass", src_indices=[0]) self.model.connect(f"traj.{phases[-1]}.states:mass", "fuel_burn.mass_final", src_indices=[-1]) @@ -1188,7 +1182,7 @@ def add_post_mission_systems(self, include_landing=True): ("range_resid", Mission.Constraints.RANGE_RESIDUAL)], ) - self.model.connect(f"traj.{phases[-1]}.timeseries.states:distance", + self.model.connect(f"traj.{phases[-1]}.timeseries.distance", "range_constraint.actual_range", src_indices=[-1]) self.model.add_constraint( Mission.Constraints.RANGE_RESIDUAL, equals=0.0, ref=1.e2) @@ -1415,17 +1409,17 @@ def add_linkage_constraint(self, phase_a, phase_b, var_a, var_b, connected, self.model.connect("traj.ascent.timeseries.time", "h_fit.time_cp") self.model.connect( - "traj.ascent.timeseries.states:altitude", "h_fit.h_cp") + "traj.ascent.timeseries.altitude", "h_fit.h_cp") self.model.connect( - "traj.desc2.timeseries.states:mass", + "traj.desc2.timeseries.mass", "landing.mass", src_indices=[-1], flat_src_indices=True, ) connect_map = { - "traj.desc2.timeseries.states:distance": Mission.Summary.RANGE, + "traj.desc2.timeseries.distance": Mission.Summary.RANGE, "traj.desc2.states:mass": Mission.Landing.TOUCHDOWN_MASS, } else: diff --git a/aviary/interface/test/test_phase_info.py b/aviary/interface/test/test_phase_info.py index 4933fafc5..685414215 100644 --- a/aviary/interface/test/test_phase_info.py +++ b/aviary/interface/test/test_phase_info.py @@ -113,11 +113,11 @@ def test_phase_info_parameterization_two_dof(self): prob.run_model() - assert_near_equal(prob.get_val("traj.desc2.timeseries.input_values:states:distance", units='km')[-1], + assert_near_equal(prob.get_val("traj.desc2.timeseries.input_values:distance", units='km')[-1], 5000.0) - assert_near_equal(prob.get_val("traj.climb2.timeseries.input_values:states:altitude", units='ft')[-1], + assert_near_equal(prob.get_val("traj.climb2.timeseries.input_values:altitude", units='ft')[-1], 31000.0) - assert_near_equal(prob.get_val("traj.groundroll.timeseries.input_values:states:mass", units='lbm')[0], + assert_near_equal(prob.get_val("traj.groundroll.timeseries.input_values:mass", units='lbm')[0], 120000.0) assert_near_equal(prob.get_val("traj.cruise.rhs.mach")[0], 0.6) @@ -152,9 +152,9 @@ def test_phase_info_parameterization_height_energy(self): range_resid = prob.get_val(Mission.Constraints.RANGE_RESIDUAL, units='km')[-1] assert_near_equal(range_resid, 5000.0 - 1.e-3) - assert_near_equal(prob.get_val("traj.cruise.timeseries.polynomial_controls:altitude", units='ft')[0], + assert_near_equal(prob.get_val("traj.cruise.timeseries.altitude", units='ft')[0], 31000.0) - assert_near_equal(prob.get_val("traj.cruise.timeseries.polynomial_controls:mach")[0], + assert_near_equal(prob.get_val("traj.cruise.timeseries.mach")[0], 0.6) diff --git a/aviary/utils/report.py b/aviary/utils/report.py index c0076e17e..2e4c07b74 100644 --- a/aviary/utils/report.py +++ b/aviary/utils/report.py @@ -108,7 +108,7 @@ def report_gasp_comparison(prob, rtol=0.1, remote=False, file=None): "flight distance (NM)", 3675.0, prob.get_val( - "traj.desc2.timeseries.states:distance", units="NM", get_remote=remote + "traj.desc2.timeseries.distance", units="NM", get_remote=remote )[-1][0], ), # ROC @ 49 seconds to get from 456.3 ft to 500 ft minus liftoff time @@ -234,10 +234,10 @@ def report_benchmark_comparison( # check_val = no_size_yes_pyCycle if base == 'FLOPS': check_val = FLOPS_base - distance_name = 'traj.descent.timeseries.states:distance' + distance_name = 'traj.descent.timeseries.distance' landing_dist_name = Mission.Landing.GROUND_DISTANCE else: - distance_name = "traj.desc2.timeseries.states:distance" + distance_name = "traj.desc2.timeseries.distance" landing_dist_name = 'landing.'+Mission.Landing.GROUND_DISTANCE expected_vals = [ diff --git a/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py b/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py index c8c9dae3c..81cd4f4c2 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_FwGm.py @@ -33,7 +33,7 @@ def bench_test_swap_3_FwGm(self): assert_near_equal(prob.get_val('landing.' + Mission.Landing.GROUND_DISTANCE), 2528., tolerance=rtol) - assert_near_equal(prob.get_val("traj.desc2.timeseries.states:distance")[-1], + assert_near_equal(prob.get_val("traj.desc2.timeseries.distance")[-1], 3675.0, tolerance=rtol) @require_pyoptsparse(optimizer="SNOPT") @@ -57,7 +57,7 @@ def bench_test_swap_3_FwGm_SNOPT(self): assert_near_equal(prob.get_val('landing.' + Mission.Landing.GROUND_DISTANCE), 2528., tolerance=rtol) - assert_near_equal(prob.get_val("traj.desc2.timeseries.states:distance")[-1], + assert_near_equal(prob.get_val("traj.desc2.timeseries.distance")[-1], 3675.0, tolerance=rtol) diff --git a/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py b/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py index 5a194e8c7..db7bde97d 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_GwGm.py @@ -33,7 +33,7 @@ def test_bench_GwGm(self): assert_near_equal(prob.get_val('landing.' + Mission.Landing.GROUND_DISTANCE), 2634.8, tolerance=rtol) - assert_near_equal(prob.get_val("traj.desc2.timeseries.states:distance")[-1], + assert_near_equal(prob.get_val("traj.desc2.timeseries.distance")[-1], 3675.0, tolerance=rtol) @require_pyoptsparse(optimizer="SNOPT") @@ -57,7 +57,7 @@ def test_bench_GwGm_SNOPT(self): assert_near_equal(prob.get_val('landing.' + Mission.Landing.GROUND_DISTANCE), 2634.8, tolerance=rtol) - assert_near_equal(prob.get_val("traj.desc2.timeseries.states:distance")[-1], + assert_near_equal(prob.get_val("traj.desc2.timeseries.distance")[-1], 3675.0, tolerance=rtol) diff --git a/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py b/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py index e1894f237..372a67974 100644 --- a/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py +++ b/aviary/validation_cases/benchmark_tests/test_full_mission_solved_ode.py @@ -5,7 +5,6 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal from openmdao.utils.testing_utils import require_pyoptsparse, use_tempdirs -from packaging import version from aviary.mission.gasp_based.ode.params import ParamPort from aviary.variable_info.enums import SpeedType @@ -465,8 +464,6 @@ def run_mission(optimizer): traj.add_phase(phase_name, phase) - phase.timeseries_options['use_prefix'] = True - traj.add_linkage_constraint(phase_a='ascent_to_gear_retract', phase_b='ascent_to_flap_retract', var_a='time', @@ -641,9 +638,9 @@ def run_mission(optimizer): if phase_name == "groundroll": ranges.extend( - p.get_val(f"traj.{phase_name}.timeseries.states:distance", units="m")[0]) + p.get_val(f"traj.{phase_name}.timeseries.distance", units="m")[0]) ranges.extend( - p.get_val(f"traj.{phase_name}.timeseries.states:distance", units="m")[-1]) + p.get_val(f"traj.{phase_name}.timeseries.distance", units="m")[-1]) masses.extend( p.get_val(f"traj.{phase_name}.timeseries.mass", units="lbm")[0]) diff --git a/aviary/validation_cases/benchmark_utils.py b/aviary/validation_cases/benchmark_utils.py index 8ec135445..2cdd81c98 100644 --- a/aviary/validation_cases/benchmark_utils.py +++ b/aviary/validation_cases/benchmark_utils.py @@ -24,16 +24,16 @@ def compare_against_expected_values(prob, expected_dict): times.extend(prob.get_val(f'traj.{phase}.timeseries.time', units='s')) try: altitudes.extend(prob.get_val( - f'traj.{phase}.timeseries.polynomial_controls:altitude', units='m')) + f'traj.{phase}.timeseries.altitude', units='m')) except KeyError: altitudes.extend(prob.get_val( - f'traj.{phase}.timeseries.controls:altitude', units='m')) + f'traj.{phase}.timeseries.altitude', units='m')) velocities.extend(prob.get_val( f'traj.{phase}.timeseries.velocity', units='m/s')) masses.extend( - prob.get_val(f'traj.{phase}.timeseries.states:mass', units='kg')) + prob.get_val(f'traj.{phase}.timeseries.mass', units='kg')) ranges.extend( - prob.get_val(f'traj.{phase}.timeseries.states:distance', units='m')) + prob.get_val(f'traj.{phase}.timeseries.distance', units='m')) times = np.array(times) altitudes = np.array(altitudes) From ff54bd942048e6965ab6c56332364b8a20438f29 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 24 Jan 2024 12:25:36 -0600 Subject: [PATCH 159/188] Removed unnecessary file --- .../phases/benchmark/test_bench_accel.py | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py diff --git a/aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py b/aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py deleted file mode 100644 index 6d53ac5d4..000000000 --- a/aviary/mission/gasp_based/phases/benchmark/test_bench_accel.py +++ /dev/null @@ -1,34 +0,0 @@ -import unittest - -from openmdao.utils.assert_utils import assert_near_equal -from openmdao.utils.testing_utils import require_pyoptsparse - -from aviary.mission.gasp_based.phases.run_phases.run_accel import run_accel - - -@require_pyoptsparse(optimizer="SNOPT") -class AccelPhaseTestCase(unittest.TestCase): - def bench_test_accel(self): - - prob = run_accel() - - TAS = prob.get_val("accel.timeseries.TAS", units="kn") - weight = prob.get_val("accel.timeseries.mass", units="lbm") - distance = prob.get_val("accel.timeseries.distance", units="ft") - time = prob.get_val("accel.timeseries.time", units="s") - - assert_near_equal(TAS[0], 185, 1e-4) - assert_near_equal(TAS[-1], 251.82436866, 1e-4) - - assert_near_equal(weight[0], 174974, 1e-4) - assert_near_equal(weight[-1], 174886.73023817, 1e-4) - - assert_near_equal(distance[0], 0, 1e-5) - assert_near_equal(distance[-1], 7519.70802292, 1e-5) - - assert_near_equal(time[0], 0, 1e-3) - assert_near_equal(time[-1], 20.36335559, 1e-4) - - -if __name__ == "__main__": - unittest.main() From c00112e4c2f2e95d867140a639203ae393ef55e9 Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Wed, 24 Jan 2024 13:45:02 -0500 Subject: [PATCH 160/188] removed XDSM and spec-tests --- aviary/docs/_toc.yml | 1 - .../docs/developer_guide/codebase_overview.md | 1 - aviary/docs/getting_started/installation.md | 10 +- .../getting_started/onboarding_level1.ipynb | 4 +- aviary/docs/misc_resources/using_XDSM.md | 55 --- .../phases/test/test_simplified_landing.py | 16 - .../phases/test/test_simplified_takeoff.py | 17 - .../test/test_climb_constraints.py | 15 - .../test/test_flight_constraints.py | 6 - .../gasp_based/ode/test/test_accel_eom.py | 8 - .../gasp_based/ode/test/test_accel_ode.py | 10 +- .../gasp_based/ode/test/test_ascent_eom.py | 8 - .../gasp_based/ode/test/test_ascent_ode.py | 7 - .../gasp_based/ode/test/test_climb_eom.py | 8 - .../gasp_based/ode/test/test_climb_ode.py | 14 +- .../gasp_based/ode/test/test_descent_eom.py | 8 - .../gasp_based/ode/test/test_descent_ode.py | 20 +- .../ode/test/test_groundroll_eom.py | 8 - .../ode/test/test_groundroll_ode.py | 7 - .../gasp_based/ode/test/test_rotation_eom.py | 8 - .../gasp_based/ode/test/test_rotation_ode.py | 7 - .../gasp_based/phases/test/test_breguet.py | 6 - .../phases/test/test_landing_components.py | 16 - .../phases/test/test_landing_group.py | 9 +- .../phases/test/test_taxi_component.py | 6 - .../gasp_based/phases/test/test_taxi_group.py | 9 +- .../gasp_based/test/test_flight_conditions.py | 22 - .../gasp_based/flaps_model/test/test_Clmax.py | 8 - .../test/test_basic_calculations.py | 8 - .../flaps_model/test/test_increments.py | 8 - .../flaps_model/test/test_metamodel.py | 22 - .../gasp_based/test/test_table_based.py | 9 - .../gasp_based/test/test_empennage.py | 25 - .../gasp_based/test/test_size_group.py | 13 - .../geometry/gasp_based/test/test_wing.py | 22 - .../mass/gasp_based/test/test_design_load.py | 15 - .../test/test_equipment_and_useful_load.py | 8 - .../mass/gasp_based/test/test_fixed.py | 7 - .../mass/gasp_based/test/test_fuel.py | 15 - .../gasp_based/test/test_mass_summation.py | 8 - .../mass/gasp_based/test/test_wing.py | 15 - aviary/utils/test_utils/IO_test_util.py | 144 ------ aviary/xdsm/__init__.py | 0 aviary/xdsm/accel_xdsm.py | 59 --- aviary/xdsm/ascent_xdsm.py | 69 --- aviary/xdsm/climb_xdsm.py | 90 ---- aviary/xdsm/computed_aero_xdsm.py | 172 ------- aviary/xdsm/cruise_xdsm.py | 64 --- aviary/xdsm/descent1_xdsm.py | 74 --- aviary/xdsm/descent2_xdsm.py | 62 --- aviary/xdsm/design_load_xdsm.py | 40 -- aviary/xdsm/empennage_size_xdsm.py | 80 ---- aviary/xdsm/engineDeck_xdsm.py | 46 -- .../equipment_and_useful_load_mass_xdsm.py | 42 -- aviary/xdsm/fixed_mass_xdsm.py | 219 --------- aviary/xdsm/flaps_xdsm.py | 107 ----- aviary/xdsm/fuel_mass_xdsm.py | 137 ------ aviary/xdsm/fuselage_size_xdsm.py | 48 -- aviary/xdsm/groundroll_xdsm.py | 90 ---- aviary/xdsm/landing_xdsm.py | 123 ----- aviary/xdsm/mass_and_sizing_basic_xdsm.py | 282 ----------- aviary/xdsm/mass_and_sizing_both_xdsm.py | 302 ------------ ...izing_converter_configuration_test_xdsm.py | 215 --------- ...ss_and_sizing_large_single_aisle_1_xdsm.py | 213 --------- aviary/xdsm/mass_basic_xdsm.py | 202 -------- aviary/xdsm/mass_large_single_aisle_1_xdsm.py | 178 ------- aviary/xdsm/propulsion_engine_xdsm.py | 64 --- aviary/xdsm/rotation_xdsm.py | 77 --- aviary/xdsm/run_all.py | 58 --- aviary/xdsm/size_basic_xdsm.py | 128 ----- aviary/xdsm/size_both1_xdsm.py | 130 ------ aviary/xdsm/size_both2_xdsm.py | 130 ------ aviary/xdsm/statics_xdsm.py | 442 ------------------ aviary/xdsm/taxi_xdsm.py | 30 -- aviary/xdsm/wing_mass_xdsm.py | 56 --- aviary/xdsm/wing_size_xdsm.py | 42 -- 76 files changed, 8 insertions(+), 4696 deletions(-) delete mode 100644 aviary/docs/misc_resources/using_XDSM.md delete mode 100644 aviary/xdsm/__init__.py delete mode 100644 aviary/xdsm/accel_xdsm.py delete mode 100644 aviary/xdsm/ascent_xdsm.py delete mode 100644 aviary/xdsm/climb_xdsm.py delete mode 100644 aviary/xdsm/computed_aero_xdsm.py delete mode 100644 aviary/xdsm/cruise_xdsm.py delete mode 100644 aviary/xdsm/descent1_xdsm.py delete mode 100644 aviary/xdsm/descent2_xdsm.py delete mode 100644 aviary/xdsm/design_load_xdsm.py delete mode 100644 aviary/xdsm/empennage_size_xdsm.py delete mode 100644 aviary/xdsm/engineDeck_xdsm.py delete mode 100644 aviary/xdsm/equipment_and_useful_load_mass_xdsm.py delete mode 100644 aviary/xdsm/fixed_mass_xdsm.py delete mode 100644 aviary/xdsm/flaps_xdsm.py delete mode 100644 aviary/xdsm/fuel_mass_xdsm.py delete mode 100644 aviary/xdsm/fuselage_size_xdsm.py delete mode 100644 aviary/xdsm/groundroll_xdsm.py delete mode 100644 aviary/xdsm/landing_xdsm.py delete mode 100644 aviary/xdsm/mass_and_sizing_basic_xdsm.py delete mode 100644 aviary/xdsm/mass_and_sizing_both_xdsm.py delete mode 100644 aviary/xdsm/mass_and_sizing_converter_configuration_test_xdsm.py delete mode 100644 aviary/xdsm/mass_and_sizing_large_single_aisle_1_xdsm.py delete mode 100644 aviary/xdsm/mass_basic_xdsm.py delete mode 100644 aviary/xdsm/mass_large_single_aisle_1_xdsm.py delete mode 100644 aviary/xdsm/propulsion_engine_xdsm.py delete mode 100644 aviary/xdsm/rotation_xdsm.py delete mode 100644 aviary/xdsm/run_all.py delete mode 100644 aviary/xdsm/size_basic_xdsm.py delete mode 100644 aviary/xdsm/size_both1_xdsm.py delete mode 100644 aviary/xdsm/size_both2_xdsm.py delete mode 100644 aviary/xdsm/statics_xdsm.py delete mode 100644 aviary/xdsm/taxi_xdsm.py delete mode 100644 aviary/xdsm/wing_mass_xdsm.py delete mode 100644 aviary/xdsm/wing_size_xdsm.py diff --git a/aviary/docs/_toc.yml b/aviary/docs/_toc.yml index fa6b72ba4..a0714e8eb 100644 --- a/aviary/docs/_toc.yml +++ b/aviary/docs/_toc.yml @@ -86,6 +86,5 @@ parts: - file: misc_resources/feature_comparison sections: - file: misc_resources/comparison_to_flops - - file: misc_resources/using_XDSM - file: misc_resources/planned_future_features - file: _srcdocs/index diff --git a/aviary/docs/developer_guide/codebase_overview.md b/aviary/docs/developer_guide/codebase_overview.md index b24cb859d..8193dae01 100644 --- a/aviary/docs/developer_guide/codebase_overview.md +++ b/aviary/docs/developer_guide/codebase_overview.md @@ -13,4 +13,3 @@ Within the Aviary repository and package, the codebase is structured as follows: - `utils` contains utility functions for use in Aviary code, examples, and tests - `validation_cases` contains validation cases for testing and benchmarking Aviary - `visualization` is where the Aviary dashboard is located -- `xdsm` contains diagrams to help developers and users of Aviary understand how systems are connected together diff --git a/aviary/docs/getting_started/installation.md b/aviary/docs/getting_started/installation.md index d8d4fea7d..50e79246b 100644 --- a/aviary/docs/getting_started/installation.md +++ b/aviary/docs/getting_started/installation.md @@ -65,7 +65,6 @@ dependencies: - pip: - parameterized - testflo - - pyxdsm - jupyter-book - mdolab-baseclasses - sqlitedict @@ -75,7 +74,7 @@ dependencies: In this file, the `name` can be anything you like. The version of python is not limited to 3.9, but we recommend that you stay with this version because it is the version that we use to fully test Aviary and that it is required for some packages later on. For example, if you are going to add `OpenVSP` to your environment, you will find that you need this version. -In the list, we see the popular Python packages for scientific computations: `numpy`, `scipy`, `matplotlib` and `pandas`. Aviary follows a standard source code formatting convention. `autopep8` provides an easy way to check your source code for this purpose. `jupyter` and `jupyter-book` are used to create Aviary manual. `parameterized` and `testflo` are for Aviary testing. `pyxdsm` is used to create XDSM diagrams. Aviary uses a lot of packages developed by [MDOLab](https://mdolab.engin.umich.edu/). So, we want to include its base classes. OpenMDAO records data in SQLite database and that is what `sqlitedict` comes for. `f90nml` is A Python module and command line tool for parsing Fortran namelist files. `bokeh` is an interactive visualization library for modern web browsers. It is needed to generate Aviary output (traj_results_report.html). +In the list, we see the popular Python packages for scientific computations: `numpy`, `scipy`, `matplotlib` and `pandas`. Aviary follows a standard source code formatting convention. `autopep8` provides an easy way to check your source code for this purpose. `jupyter` and `jupyter-book` are used to create Aviary manual. `parameterized` and `testflo` are for Aviary testing. Aviary uses a lot of packages developed by [MDOLab](https://mdolab.engin.umich.edu/). So, we want to include its base classes. OpenMDAO records data in SQLite database and that is what `sqlitedict` comes for. `f90nml` is A Python module and command line tool for parsing Fortran namelist files. `bokeh` is an interactive visualization library for modern web browsers. It is needed to generate Aviary output (traj_results_report.html). Since we are going to depend on `OpenMDAO` and `dymos`, we could have included them in the `pip` list. We leave them out because we will install the developer version later. In this way, we will get the latest working copies that Aviary depends on. But we do not intend to make changes to them. @@ -228,13 +227,6 @@ $ cd Aviary $ pip install -e . ``` -Before we run tests on Aviary, we need to build XDSM diagrams first: - -``` -% cd aviary/xdsm/ -% python run_all.py -``` - When it is done, let us run test: ``` diff --git a/aviary/docs/getting_started/onboarding_level1.ipynb b/aviary/docs/getting_started/onboarding_level1.ipynb index 853ed37e9..44cd459c0 100644 --- a/aviary/docs/getting_started/onboarding_level1.ipynb +++ b/aviary/docs/getting_started/onboarding_level1.ipynb @@ -523,10 +523,10 @@ "source": [ "### File `n2.html`\n", "\n", - "N2 is a powerful tool in OpenMDAO. It is an N-squared diagram in the shape of a matrix, representing functional or physical interfaces between system elements. It can be used to systematically identify, define, tabulate, design, and analyze functional and physical interfaces.\n", + "[N2](https://openmdao.org/newdocs/versions/latest/features/model_visualization/n2_details/n2_details.html), sometimes referred to as an eXtended Design Structure Matrix (XDSM), is a powerful tool for understanding your model in OpenMDAO. It is an N-squared diagram in the shape of a matrix representing functional or physical interfaces between system elements. It can be used to systematically identify, define, tabulate, design, and analyze functional and physical interfaces.\n", "\n", "```{note}\n", - "We *strongly* recommend that you understand N2 diagrams well, especially if you are debugging a model or adding external subsystems. Here is a [doc page](https://openmdao.github.io/PracticalMDO/Notebooks/ModelConstruction/using_n2.html) featuring an informative video on how to use N2 diagrams effectively.\n", + "We *strongly* recommend that you understand N2 diagrams well, especially if you are debugging a model or adding external subsystems. Here is a [doc page](https://openmdao.github.io/PracticalMDO/Notebooks/ModelConstruction/using_n2.html) featuring an informative video on how to use N2 diagrams effectively. MDO lab has another resource for learning about N2 and [XDSM](https://mdolab-pyxdsm.readthedocs-hosted.com/).\n", "```\n", "\n", " Here is a screenshot of an N2 diagram after we run `aviary run_mission models/test_aircraft/aircraft_for_bench_GwGm.csv`.\n", diff --git a/aviary/docs/misc_resources/using_XDSM.md b/aviary/docs/misc_resources/using_XDSM.md deleted file mode 100644 index 189004772..000000000 --- a/aviary/docs/misc_resources/using_XDSM.md +++ /dev/null @@ -1,55 +0,0 @@ -# Using XDSM - -Aviary has two ways to visualize its structures. One way is the OpenMDAO [N2 Diagram](https://openmdao.org/newdocs/versions/latest/features/model_visualization/n2_details/n2_details.html). Another is the [XDSM](https://mdolab-pyxdsm.readthedocs-hosted.com/) from MDO Lab. In this page, we explain how XDSM diagrams are organized in Aviary. - -## What is XDSM? - -The [Practical MDO](https://openmdao.github.io/PracticalMDO/) website has a [fantastic post on understanding XDSM diagrams](https://openmdao.github.io/PracticalMDO/Notebooks/ModelConstruction/understanding_xdsm_diagrams.html). This lesson also includes a [helpful video](https://www.youtube.com/watch?v=yutKRwIL3BA). - -## Creation of all XDSM diagrams - -All the XDSM files reside in `xdsm` directory. And all of their names end with `_xdsm.py`: - -```bash -...... -descent1_xdsm.py -descent2_xdsm.py -design_load_xdsm.py -empennage_size_xdsm.py -...... -``` - -There is a particular python file `run_all.py` in `xdsm` folder. Using `run_all.py` in your Aviary environment, you can generate all the XDSM diagrams: - -```bash -python run_all.py -``` - -If everything runs correctly, you will see a list of `.pdf` files (e.g. `accel_xdsm.pdf`) and some `sub-folders` (e.g. `accel_specs`). Those sub-folders are created for [unit testing](https://docs.python.org/3/library/unit test.html). - -## The Aviary rules - -Readers should read about basic XDSM from MDO Lab [website](https://mdolab-pyxdsm.readthedocs-hosted.com/). Besides those, Aviary has its own rules. Let's take a look at a sample XDSM diagram: - -![Sample Aviary XDSM](images/sample_aviary_xdsm.PNG) - -Let us use the above example to discuss how Aviary uses XDSMs: - -1. All XDSM diagram files end with `_xdsm.py` in `xdsm` folder. -2. Some XDSM diagrams are coupled with sub-folders with names ending with `_specs`. They correspond to related Aviary unit tests. Search keyword [assert_match_spec](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/utils/test_utils/IO_test_util.py) for a specific unit test. -3. Single components have rectangular shape (e.g. `MyComp1`). -4. Groups of components have rectangular shape with chopped corners (e.g. `MyGroup`). -5. System input on the top-left corner is shown as a group (e.g. `Group Object (Input)`). This is a special symbol for the whole diagram (which is a group). -6. The components linked to unit tests are in bold. A `_specs` folder contains the data to be validated. -7. Components with feedback variables are shown in pink red background (e.g. `MyComp2` with feedback variable `var_feedback`). In this case, components are not run only sequentially, but in a loop. Usually, a nonlinear solver is required for the coupled subsystem. -8. Conditional variables, components, and groups are grayed out (e.g. `opt_Input_value`). Sometimes, a component or a component group can be left off. They are shown using gray color indicating they are conditional. Users can configure the appropriate Python file to hide them in the diagram. -9. Array of components and groups are shown as stacks (e.g. `MyComps`). A stack of components is a set of systems that are not connected to each other. Usually they can be run in parallel. -10. "InputValues" represents a list of input variables if the user set `simplified = True` when an XDSM diagram is generated. Otherwise, a complete list of variables are shown. Sometimes this list can be too long. We give an option for users to simplify the display of input variables. -11. Variables like "aircraft:wing:\*" are lists of some variables in `Aircraft.Wing` class. We display them this way to make the XDSM diagram easy to read. Sometimes, these lists can be very long and it is impractical to show all of them. If "aircraft:wing:\*" is an input to a group, it is possible that this group has its own XDSM diagram. -12. In the source code of some of the XDSM diagrams, there are boolean variables to control the inputs/outputs of variables, components, and groups (e.g. `simplified` or `show_outputs`). Users can set them themselves and regenerate those diagrams with different appearances. The next section shows how to regenerate a single diagram instead of all. - -## Unit Testing - -All XDSM diagrams within Aviary are tested against the actual Aviary code. -This means that all of the inputs and outputs for each component and group are checked against the XDSM diagram. -If you modify Aviary, you should run the unit tests to ensure that the XDSM diagrams are still valid and update the XDSM diagrams if necessary. diff --git a/aviary/mission/flops_based/phases/test/test_simplified_landing.py b/aviary/mission/flops_based/phases/test/test_simplified_landing.py index 11df1420e..3485dfd36 100644 --- a/aviary/mission/flops_based/phases/test/test_simplified_landing.py +++ b/aviary/mission/flops_based/phases/test/test_simplified_landing.py @@ -49,14 +49,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) - # def test_spec(self): - - # subsystem = self.prob.model - - # assert_match_spec( - # subsystem, "landing_specs/landing_calcs.json" - # ) - class LandingGroupTest(unittest.TestCase): def setUp(self): @@ -98,14 +90,6 @@ def test_case1(self): out_stream=None, excludes=['*.USatm'], method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) - # def test_spec(self): - - # subsystem = self.prob.model - - # assert_match_spec( - # subsystem, "landing_specs/landing_group.json" - # ) - if __name__ == "__main__": unittest.main() diff --git a/aviary/mission/flops_based/phases/test/test_simplified_takeoff.py b/aviary/mission/flops_based/phases/test/test_simplified_takeoff.py index 472a5bcc0..57be758c9 100644 --- a/aviary/mission/flops_based/phases/test/test_simplified_takeoff.py +++ b/aviary/mission/flops_based/phases/test/test_simplified_takeoff.py @@ -2,9 +2,6 @@ Test file to test the outputs, derivatives, and IO of each sample component/group. The name of this file needs to start with 'test' so that the testflo command will find and run the file. - -Before this file is run, the sample_XDSM.py file in the XDSM folder must be run in -order to generate the spec files which are used in the test_spec tests. """ import unittest @@ -53,14 +50,6 @@ def test_case1(self): partial_data, atol=1e-12, rtol=1e-12 ) # check the partial derivatives - # def test_spec(self): - - # subsystem = self.prob.model - - # assert_match_spec( - # subsystem, "takeoff_specs/vstall.json" - # ) - class FinalConditionsTest(unittest.TestCase): def setUp(self): @@ -113,12 +102,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) - # def test_spec(self): - - # subsystem = self.prob.model - - # assert_match_spec(subsystem, "takeoff_specs/final_conds.json") - class TakeoffGroupTest(unittest.TestCase): def setUp(self): diff --git a/aviary/mission/gasp_based/ode/constraints/test/test_climb_constraints.py b/aviary/mission/gasp_based/ode/constraints/test/test_climb_constraints.py index af4f9cb16..1b675c514 100644 --- a/aviary/mission/gasp_based/ode/constraints/test/test_climb_constraints.py +++ b/aviary/mission/gasp_based/ode/constraints/test/test_climb_constraints.py @@ -8,7 +8,6 @@ from aviary.mission.gasp_based.ode.constraints.speed_constraints import \ SpeedConstraints -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Dynamic @@ -43,13 +42,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) - @skipIfMissingXDSM('climb_specs/speeds.json') - def test_speed_constraints_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "climb_specs/speeds.json") - class SpeedConstraintTestCase2(unittest.TestCase): def setUp(self): @@ -82,13 +74,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) - @skipIfMissingXDSM('descent_specs/speeds.json') - def test_speed_constraints_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "descent1_specs/speeds.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/mission/gasp_based/ode/constraints/test/test_flight_constraints.py b/aviary/mission/gasp_based/ode/constraints/test/test_flight_constraints.py index 6a32352ae..2d37c0bab 100644 --- a/aviary/mission/gasp_based/ode/constraints/test/test_flight_constraints.py +++ b/aviary/mission/gasp_based/ode/constraints/test/test_flight_constraints.py @@ -8,7 +8,6 @@ from aviary.mission.gasp_based.ode.constraints.flight_constraints import \ FlightConstraints -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft, Dynamic @@ -50,11 +49,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=3e-11, rtol=1e-12) - @skipIfMissingXDSM('climb_specs/constraints.json') - def test_flight_constraints_spec(self): - subsystem = self.prob.model - assert_match_spec(subsystem, "climb_specs/constraints.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/mission/gasp_based/ode/test/test_accel_eom.py b/aviary/mission/gasp_based/ode/test/test_accel_eom.py index 61950cbc4..4b3308162 100644 --- a/aviary/mission/gasp_based/ode/test/test_accel_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_accel_eom.py @@ -7,7 +7,6 @@ assert_near_equal) from aviary.mission.gasp_based.ode.accel_eom import AccelerationRates -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Dynamic @@ -56,13 +55,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) - @skipIfMissingXDSM('accel_specs/eom.json') - def test_accel_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "accel_specs/eom.json") - if __name__ == "__main__": unittest.main() 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 98a613b58..ed71fda96 100644 --- a/aviary/mission/gasp_based/ode/test/test_accel_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_accel_ode.py @@ -6,9 +6,7 @@ from aviary.mission.gasp_based.ode.accel_ode import AccelODE from aviary.variable_info.options import get_option_defaults -from aviary.utils.test_utils.IO_test_util import (assert_match_spec, - check_prob_outputs, - skipIfMissingXDSM) +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 @@ -45,12 +43,6 @@ def test_accel(self): ) assert_check_partials(partial_data, rtol=1e-10) - @skipIfMissingXDSM('statics_specs/accelerate.json') - def test_accel_spec(self): - """Test accel ODE spec""" - subsystem = self.prob.model - assert_match_spec(subsystem, "statics_specs/accelerate.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/mission/gasp_based/ode/test/test_ascent_eom.py b/aviary/mission/gasp_based/ode/test/test_ascent_eom.py index d13beee6c..c6f19ea29 100644 --- a/aviary/mission/gasp_based/ode/test/test_ascent_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_ascent_eom.py @@ -6,7 +6,6 @@ from openmdao.utils.assert_utils import assert_check_partials from aviary.mission.gasp_based.ode.ascent_eom import AscentEOM -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft, Dynamic @@ -41,13 +40,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) - @skipIfMissingXDSM('ascent_specs/eom.json') - def test_ascent_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "ascent_specs/eom.json") - if __name__ == "__main__": unittest.main() 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 540899d70..4b972bbb3 100644 --- a/aviary/mission/gasp_based/ode/test/test_ascent_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_ascent_ode.py @@ -5,7 +5,6 @@ from openmdao.utils.assert_utils import assert_check_partials from aviary.mission.gasp_based.ode.ascent_ode import AscentODE -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.interface.default_phase_info.two_dof import default_mission_subsystems from aviary.variable_info.options import get_option_defaults @@ -31,12 +30,6 @@ def test_ascent_partials(self): ) assert_check_partials(partial_data, atol=1e-8, rtol=1e-8) - @skipIfMissingXDSM('statics_specs/ascent.json') - def test_ascent_spec(self): - """Test ascent ODE spec""" - subsystem = self.prob.model - assert_match_spec(subsystem, "statics_specs/ascent.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/mission/gasp_based/ode/test/test_climb_eom.py b/aviary/mission/gasp_based/ode/test/test_climb_eom.py index 940f0a7cb..dea987d97 100644 --- a/aviary/mission/gasp_based/ode/test/test_climb_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_climb_eom.py @@ -7,7 +7,6 @@ assert_near_equal) from aviary.mission.gasp_based.ode.climb_eom import ClimbRates -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Dynamic @@ -62,13 +61,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) - @skipIfMissingXDSM('climb_specs/eom.json') - def test_climb_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "climb_specs/eom.json") - if __name__ == "__main__": unittest.main() 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 5a895cd11..47eb53f5f 100644 --- a/aviary/mission/gasp_based/ode/test/test_climb_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_climb_ode.py @@ -6,9 +6,7 @@ from openmdao.utils.assert_utils import assert_check_partials from aviary.mission.gasp_based.ode.climb_ode import ClimbODE -from aviary.utils.test_utils.IO_test_util import (assert_match_spec, - check_prob_outputs, - skipIfMissingXDSM) +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 @@ -95,16 +93,6 @@ def test_end_of_climb(self): } check_prob_outputs(self.prob, testvals, 1e-1) # TODO tighten - @skipIfMissingXDSM('statics_specs/climb1.json') - def test_climb1_spec(self): - """Test climb1 phase spec""" - assert_match_spec(self.sys, "statics_specs/climb1.json") - - @skipIfMissingXDSM('statics_specs/climb2.json') - def test_climb2_spec(self): - """Test climb2 phase spec""" - assert_match_spec(self.sys, "statics_specs/climb2.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/mission/gasp_based/ode/test/test_descent_eom.py b/aviary/mission/gasp_based/ode/test/test_descent_eom.py index b1885749a..34c974895 100644 --- a/aviary/mission/gasp_based/ode/test/test_descent_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_descent_eom.py @@ -7,7 +7,6 @@ assert_near_equal) from aviary.mission.gasp_based.ode.descent_eom import DescentRates -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Dynamic @@ -64,13 +63,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) - @skipIfMissingXDSM('descent1_specs/eom.json') - def test_descent_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "descent1_specs/eom.json") - if __name__ == "__main__": unittest.main() 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 262871768..7d642f6e8 100644 --- a/aviary/mission/gasp_based/ode/test/test_descent_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_descent_ode.py @@ -9,9 +9,7 @@ from aviary.mission.gasp_based.ode.descent_ode import DescentODE from aviary.variable_info.options import get_option_defaults -from aviary.utils.test_utils.IO_test_util import (assert_match_spec, - check_prob_outputs, - skipIfMissingXDSM) +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 @@ -96,22 +94,6 @@ def test_low_alt(self): ) assert_check_partials(partial_data, atol=1e-8, rtol=1e-8) - @skipIfMissingXDSM('statics_specs/descent1.json') - def test_descent1_ode_spec(self): - """Test descent1 phase spec""" - self.sys.options["input_speed_type"] = SpeedType.MACH - self.prob.setup() - subsystem = self.prob.model - assert_match_spec(subsystem, "statics_specs/descent1.json") - - @skipIfMissingXDSM('statics_specs/descent2.json') - def test_descent2_ode_spec(self): - """Test descent2 phase spec""" - self.sys.options["input_speed_type"] = SpeedType.EAS - self.prob.setup() - subsystem = self.prob.model - assert_match_spec(subsystem, "statics_specs/descent2.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/mission/gasp_based/ode/test/test_groundroll_eom.py b/aviary/mission/gasp_based/ode/test/test_groundroll_eom.py index af344571c..bcb055227 100644 --- a/aviary/mission/gasp_based/ode/test/test_groundroll_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_groundroll_eom.py @@ -6,7 +6,6 @@ from openmdao.utils.assert_utils import assert_check_partials from aviary.mission.gasp_based.ode.groundroll_eom import GroundrollEOM -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft, Dynamic @@ -43,13 +42,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) - @skipIfMissingXDSM('groundroll_specs/eom.json') - def test_groundroll_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "groundroll_specs/eom.json") - if __name__ == "__main__": unittest.main() 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 d70a26b4b..147eb0fa9 100644 --- a/aviary/mission/gasp_based/ode/test/test_groundroll_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_groundroll_ode.py @@ -5,7 +5,6 @@ from openmdao.utils.assert_utils import assert_check_partials from aviary.mission.gasp_based.ode.groundroll_ode import GroundrollODE -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.options import get_option_defaults from aviary.interface.default_phase_info.two_dof import default_mission_subsystems @@ -31,12 +30,6 @@ def test_groundroll_partials(self): ) assert_check_partials(partial_data, atol=1e-8, rtol=1e-8) - @skipIfMissingXDSM('statics_specs/groundroll.json') - def test_groundroll_spec(self): - """Test groundroll ODE spec""" - subsystem = self.prob.model - assert_match_spec(subsystem, "statics_specs/groundroll.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/mission/gasp_based/ode/test/test_rotation_eom.py b/aviary/mission/gasp_based/ode/test/test_rotation_eom.py index 3d48f22a8..f8a30e4c1 100644 --- a/aviary/mission/gasp_based/ode/test/test_rotation_eom.py +++ b/aviary/mission/gasp_based/ode/test/test_rotation_eom.py @@ -6,7 +6,6 @@ from openmdao.utils.assert_utils import assert_check_partials from aviary.mission.gasp_based.ode.rotation_eom import RotationEOM -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft, Dynamic @@ -41,13 +40,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) - @skipIfMissingXDSM('rotation_specs/eom.json') - def test_rotation_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "rotation_specs/eom.json") - if __name__ == "__main__": unittest.main() 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 891c21b20..ecad9de8b 100644 --- a/aviary/mission/gasp_based/ode/test/test_rotation_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_rotation_ode.py @@ -5,7 +5,6 @@ from openmdao.utils.assert_utils import assert_check_partials from aviary.mission.gasp_based.ode.rotation_ode import RotationODE -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM 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 @@ -35,12 +34,6 @@ def test_rotation_partials(self): ) assert_check_partials(partial_data, atol=1e-8, rtol=1e-8) - @skipIfMissingXDSM('statics_specs/rotation.json') - def test_rotation_spec(self): - """Test rotation ODE spec""" - subsystem = self.prob.model - assert_match_spec(subsystem, "statics_specs/rotation.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/mission/gasp_based/phases/test/test_breguet.py b/aviary/mission/gasp_based/phases/test/test_breguet.py index 23b4238ab..0f5e208d7 100644 --- a/aviary/mission/gasp_based/phases/test/test_breguet.py +++ b/aviary/mission/gasp_based/phases/test/test_breguet.py @@ -8,7 +8,6 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.mission.gasp_based.phases.breguet import RangeComp -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Dynamic @@ -46,11 +45,6 @@ def test_case1(self): partial_data = self.prob.check_partials(method="cs") # , out_stream=None) assert_check_partials(partial_data, atol=tol, rtol=tol) - @skipIfMissingXDSM('cruise_specs/breguet_eom.json') - def test_climb_spec(self): - subsystem = self.prob.model - assert_match_spec(subsystem, "cruise_specs/breguet_eom.json") - class TestBreguetPartials(unittest.TestCase): def setUp(self): diff --git a/aviary/mission/gasp_based/phases/test/test_landing_components.py b/aviary/mission/gasp_based/phases/test/test_landing_components.py index ee3cd40da..173e593d8 100644 --- a/aviary/mission/gasp_based/phases/test/test_landing_components.py +++ b/aviary/mission/gasp_based/phases/test/test_landing_components.py @@ -8,7 +8,6 @@ from aviary.mission.gasp_based.phases.landing_components import ( GlideConditionComponent, LandingAltitudeComponent, LandingGroundRollComponent) -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft, Mission @@ -38,11 +37,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) - @skipIfMissingXDSM('landing_specs/landing_alt.json') - def test_alt_spec(self): - subsystem = self.prob.model - assert_match_spec(subsystem, "landing_specs/landing_alt.json") - class GlideTestCase(unittest.TestCase): def setUp(self): @@ -116,11 +110,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-10, rtol=1e-12) - @skipIfMissingXDSM('landing_specs/glide.json') - def test_alt_spec(self): - subsystem = self.prob.model - assert_match_spec(subsystem, "landing_specs/glide.json") - class GroundRollTestCase(unittest.TestCase): def setUp(self): @@ -168,11 +157,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=5e-12, rtol=1e-12) - @skipIfMissingXDSM('landing_specs/groundroll.json') - def test_alt_spec(self): - subsystem = self.prob.model - assert_match_spec(subsystem, "landing_specs/groundroll.json") - if __name__ == "__main__": unittest.main() 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 4d3339362..6ed7c3265 100644 --- a/aviary/mission/gasp_based/phases/test/test_landing_group.py +++ b/aviary/mission/gasp_based/phases/test/test_landing_group.py @@ -9,9 +9,7 @@ from aviary.mission.gasp_based.phases.landing_group import LandingSegment from aviary.variable_info.options import get_option_defaults -from aviary.utils.test_utils.IO_test_util import (assert_match_spec, - check_prob_outputs, - skipIfMissingXDSM) +from aviary.utils.test_utils.IO_test_util import check_prob_outputs from aviary.variable_info.variables import Dynamic, Mission @@ -55,11 +53,6 @@ def test_dland(self): ) assert_check_partials(partial_data, atol=1e-6, rtol=1e-6) - @skipIfMissingXDSM('statics_specs/landing.json') - def test_dland_spec(self): - subsystem = self.prob.model - assert_match_spec(subsystem, "statics_specs/landing.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/mission/gasp_based/phases/test/test_taxi_component.py b/aviary/mission/gasp_based/phases/test/test_taxi_component.py index 37e3a0e56..01339e7be 100644 --- a/aviary/mission/gasp_based/phases/test/test_taxi_component.py +++ b/aviary/mission/gasp_based/phases/test/test_taxi_component.py @@ -7,7 +7,6 @@ from aviary.utils.aviary_values import AviaryValues from aviary.mission.gasp_based.phases.taxi_component import TaxiFuelComponent -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Dynamic, Mission @@ -33,11 +32,6 @@ def test_fuel_consumed(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) - @skipIfMissingXDSM('taxi_specs/fuel.json') - def test_fuel_spec(self): - subsystem = self.prob.model - assert_match_spec(subsystem, "taxi_specs/fuel.json") - if __name__ == "__main__": unittest.main() 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 4d3339362..6ed7c3265 100644 --- a/aviary/mission/gasp_based/phases/test/test_taxi_group.py +++ b/aviary/mission/gasp_based/phases/test/test_taxi_group.py @@ -9,9 +9,7 @@ from aviary.mission.gasp_based.phases.landing_group import LandingSegment from aviary.variable_info.options import get_option_defaults -from aviary.utils.test_utils.IO_test_util import (assert_match_spec, - check_prob_outputs, - skipIfMissingXDSM) +from aviary.utils.test_utils.IO_test_util import check_prob_outputs from aviary.variable_info.variables import Dynamic, Mission @@ -55,11 +53,6 @@ def test_dland(self): ) assert_check_partials(partial_data, atol=1e-6, rtol=1e-6) - @skipIfMissingXDSM('statics_specs/landing.json') - def test_dland_spec(self): - subsystem = self.prob.model - assert_match_spec(subsystem, "statics_specs/landing.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/mission/gasp_based/test/test_flight_conditions.py b/aviary/mission/gasp_based/test/test_flight_conditions.py index 6cc358937..b99db957a 100644 --- a/aviary/mission/gasp_based/test/test_flight_conditions.py +++ b/aviary/mission/gasp_based/test/test_flight_conditions.py @@ -7,7 +7,6 @@ assert_near_equal) from aviary.mission.gasp_based.flight_conditions import FlightConditions -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.enums import SpeedType from aviary.variable_info.variables import Dynamic @@ -48,13 +47,6 @@ def test_case1(self): assert_check_partials(partial_data, atol=1e-8, rtol=1e-8) - @skipIfMissingXDSM('accel_specs/fc.json') - def test_fc_spec1(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "accel_specs/fc.json") - class FlightConditionsTestCase2(unittest.TestCase): def setUp(self): @@ -91,13 +83,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-8, rtol=1e-8) - @skipIfMissingXDSM('climb_specs/fc.json') - def test_fc_spec2(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "climb_specs/fc.json") - class FlightConditionsTestCase3(unittest.TestCase): def setUp(self): @@ -135,13 +120,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-8, rtol=1e-8) - @skipIfMissingXDSM('cruise_specs/fc.json') - def test_fc_spec3(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "cruise_specs/fc.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_Clmax.py b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_Clmax.py index 793185e94..cc96894ec 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_Clmax.py +++ b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_Clmax.py @@ -7,7 +7,6 @@ from aviary.subsystems.aerodynamics.gasp_based.flaps_model.Cl_max import \ CLmaxCalculation -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft, Dynamic """ @@ -75,13 +74,6 @@ def test_case(self): data, atol=6400, rtol=0.007 ) # large to account for large magnitude value, discrepancies are acceptable - @skipIfMissingXDSM('flaps_specs/CL_max.json') - def test_CLmax_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "flaps_specs/CL_max.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_basic_calculations.py b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_basic_calculations.py index ce2223692..16a7e427d 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_basic_calculations.py +++ b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_basic_calculations.py @@ -7,7 +7,6 @@ from aviary.subsystems.aerodynamics.gasp_based.flaps_model.basic_calculations import \ BasicFlapsCalculations -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft """ @@ -85,13 +84,6 @@ def test_case(self): data = self.prob.check_partials(out_stream=None, method="fd") assert_check_partials(data, atol=1e-6, rtol=4e-6) - @skipIfMissingXDSM('flaps_specs/basic.json') - def test_basic_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "flaps_specs/basic.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_increments.py b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_increments.py index 87b97a474..8e9fa1ebb 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_increments.py +++ b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_increments.py @@ -6,7 +6,6 @@ from aviary.subsystems.aerodynamics.gasp_based.flaps_model.L_and_D_increments import \ LiftAndDragIncrements -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft """ @@ -57,13 +56,6 @@ def test_case(self): data = self.prob.check_partials(out_stream=None, method="fd") assert_check_partials(data, atol=1e-4, rtol=1e-4) - @skipIfMissingXDSM('flaps_specs/increments.json') - def test_increment_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "flaps_specs/increments.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_metamodel.py b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_metamodel.py index 725b5ae60..84581a8ea 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_metamodel.py +++ b/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_metamodel.py @@ -7,7 +7,6 @@ from aviary.subsystems.aerodynamics.gasp_based.flaps_model.meta_model import \ MetaModelGroup -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.enums import FlapType from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Dynamic @@ -109,13 +108,6 @@ def test_case(self): data = self.prob.check_partials(out_stream=None, method="fd") assert_check_partials(data, atol=1e-4, rtol=1e-4) - @skipIfMissingXDSM('flaps_specs/tables.json') - def test_lookup_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "flaps_specs/tables.json") - class MetaModelTestCaseSingleSlotted(unittest.TestCase): def setUp(self): @@ -155,13 +147,6 @@ def test_case(self): data = self.prob.check_partials(out_stream=None, method="fd") assert_check_partials(data, atol=1e-4, rtol=1e-4) - @skipIfMissingXDSM('flaps_specs/tables.json') - def test_lookup_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "flaps_specs/tables.json") - class MetaModelTestCaseFowler(unittest.TestCase): def setUp(self): @@ -191,13 +176,6 @@ def test_case(self): data = self.prob.check_partials(out_stream=None, method="fd") assert_check_partials(data, atol=1e-4, rtol=1e-4) - @skipIfMissingXDSM('flaps_specs/tables.json') - def test_lookup_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "flaps_specs/tables.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/subsystems/aerodynamics/gasp_based/test/test_table_based.py b/aviary/subsystems/aerodynamics/gasp_based/test/test_table_based.py index bc449e2da..a70027ff0 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/test/test_table_based.py +++ b/aviary/subsystems/aerodynamics/gasp_based/test/test_table_based.py @@ -10,7 +10,6 @@ from aviary.subsystems.aerodynamics.gasp_based.table_based import ( CruiseAero, LowSpeedAero) -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft, Dynamic @@ -88,14 +87,6 @@ class TestLowSpeedAero(unittest.TestCase): ground_data = pkg_resources.resource_filename( "aviary", f"subsystems/aerodynamics/gasp_based/data/large_single_aisle_1_aero_ground.txt") - @skipIfMissingXDSM('rotation_specs/aero.json') - def test_spec(self): - comp = LowSpeedAero(free_aero_data=self.free_data, - flaps_aero_data=self.flaps_data, - ground_aero_data=self.ground_data, - extrapolate=True) - assert_match_spec(comp, "rotation_specs/aero.json") - @unittest.skipIf(version.parse(openmdao.__version__) < version.parse("3.26"), "Older version of OpenMDAO does not properly skip Metamodel.") def test_groundroll(self): diff --git a/aviary/subsystems/geometry/gasp_based/test/test_empennage.py b/aviary/subsystems/geometry/gasp_based/test/test_empennage.py index 12bbaec6a..8b5cf6ad1 100644 --- a/aviary/subsystems/geometry/gasp_based/test/test_empennage.py +++ b/aviary/subsystems/geometry/gasp_based/test/test_empennage.py @@ -7,7 +7,6 @@ from aviary.subsystems.geometry.gasp_based.empennage import (EmpennageSize, TailSize, TailVolCoef) -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft @@ -185,16 +184,6 @@ def test_large_sinle_aisle_1_defaults(self): self.prob[Aircraft.VerticalTail.MOMENT_ARM], 49.87526, tol ) # note: slightly different from GASP output value, likely numerical diff.s, this value is from Kenny - @skipIfMissingXDSM('size_both1_specs/empennage.json') - def test_io_emp_spec_defaults(self): - self.prob.model.emp.options["aviary_options"] = get_option_defaults() - - self.prob.setup(check=False, force_alloc_complex=True) - - subsystem = self.prob.model - - assert_match_spec(subsystem, "size_both1_specs/empennage.json") - def test_large_sinle_aisle_1_calc_volcoefs(self): options = get_option_defaults() options.set_val(Aircraft.Design.COMPUTE_HTAIL_VOLUME_COEFF, @@ -218,20 +207,6 @@ def test_large_sinle_aisle_1_calc_volcoefs(self): self.prob[Aircraft.VerticalTail.VOLUME_COEFFICIENT], 0.11623, tol ) # not actual GASP value - @skipIfMissingXDSM('size_both2_specs/empennage.json') - def test_io_emp_spec_vol_coefs(self): - options = get_option_defaults() - options.set_val(Aircraft.Design.COMPUTE_HTAIL_VOLUME_COEFF, - val=True, units='unitless') - options.set_val(Aircraft.Design.COMPUTE_VTAIL_VOLUME_COEFF, - val=True, units='unitless') - self.prob.model.emp.options["aviary_options"] = options - self.prob.setup(check=False, force_alloc_complex=True) - - subsystem = self.prob.model - - assert_match_spec(subsystem, "size_both2_specs/empennage.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/subsystems/geometry/gasp_based/test/test_size_group.py b/aviary/subsystems/geometry/gasp_based/test/test_size_group.py index b2418dd5e..5b22cfe1c 100644 --- a/aviary/subsystems/geometry/gasp_based/test/test_size_group.py +++ b/aviary/subsystems/geometry/gasp_based/test/test_size_group.py @@ -6,7 +6,6 @@ from aviary.subsystems.geometry.gasp_based.size_group import SizeGroup from aviary.variable_info.options import get_option_defaults -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft, Mission # this is the GASP test case, input and output values based on large single aisle 1 v3 without bug fix @@ -159,12 +158,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=2e-12, rtol=1e-12) - @skipIfMissingXDSM('mass_and_sizing_basic_specs/size.json') - def test_io_wing_group_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "mass_and_sizing_basic_specs/size.json") class SizeGroupTestCase2(unittest.TestCase): @@ -390,12 +383,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=3e-10, rtol=1e-12) - @skipIfMissingXDSM('mass_and_sizing_both_specs/size.json') - def test_io_wing_group_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "mass_and_sizing_both_specs/size.json") class SizeGroupTestCase3(unittest.TestCase): diff --git a/aviary/subsystems/geometry/gasp_based/test/test_wing.py b/aviary/subsystems/geometry/gasp_based/test/test_wing.py index 7a706e2d8..0154e0d1f 100644 --- a/aviary/subsystems/geometry/gasp_based/test/test_wing.py +++ b/aviary/subsystems/geometry/gasp_based/test/test_wing.py @@ -8,7 +8,6 @@ WingParameters, WingSize) from aviary.variable_info.options import get_option_defaults -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft, Mission @@ -310,13 +309,6 @@ def setUp(self): self.prob.setup(check=False, force_alloc_complex=True) - @skipIfMissingXDSM('size_basic_specs/wing.json') - def test_io_wing_group_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "size_basic_specs/wing.json") - def test_case1(self): self.prob.run_model() @@ -394,13 +386,6 @@ def setUp(self): self.prob.setup(check=False, force_alloc_complex=True) - @skipIfMissingXDSM('size_both1_specs/wing.json') - def test_io_wing_group_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "size_both1_specs/wing.json") - def test_case1(self): self.prob.run_model() @@ -563,13 +548,6 @@ def setUp(self): self.prob.setup(check=False, force_alloc_complex=True) - @skipIfMissingXDSM('size_both2_specs/wing.json') - def test_io_wing_group_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "size_both2_specs/wing.json") - class WingGroupTestCase5(unittest.TestCase): def setUp(self): diff --git a/aviary/subsystems/mass/gasp_based/test/test_design_load.py b/aviary/subsystems/mass/gasp_based/test/test_design_load.py index 6f374712d..29af24256 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_design_load.py +++ b/aviary/subsystems/mass/gasp_based/test/test_design_load.py @@ -9,7 +9,6 @@ LoadParameters, LoadSpeeds) from aviary.variable_info.options import get_option_defaults -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft, Mission @@ -880,13 +879,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-7, rtol=2e-7) - @skipIfMissingXDSM('mass_and_sizing_basic_specs/design_load.json') - def test_io_fixed_group_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "mass_and_sizing_basic_specs/design_load.json") - # this is the large single aisle 1 V3 test case class DesignLoadGroupTestCase2smooth(unittest.TestCase): @@ -932,13 +924,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-7, rtol=2e-7) - @skipIfMissingXDSM('mass_and_sizing_basic_specs/design_load.json') - def test_io_fixed_group_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "mass_and_sizing_basic_specs/design_load.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/subsystems/mass/gasp_based/test/test_equipment_and_useful_load.py b/aviary/subsystems/mass/gasp_based/test/test_equipment_and_useful_load.py index 0762fe771..392e23325 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_equipment_and_useful_load.py +++ b/aviary/subsystems/mass/gasp_based/test/test_equipment_and_useful_load.py @@ -7,7 +7,6 @@ from aviary.subsystems.mass.gasp_based.equipment_and_useful_load import \ EquipAndUsefulLoadMass from aviary.variable_info.options import get_option_defaults -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.enums import GASPEngineType from aviary.variable_info.variables import Aircraft, Mission @@ -605,13 +604,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=8e-12, rtol=1e-12) - @skipIfMissingXDSM('mass_and_sizing_basic_specs/equip.json') - def test_io_equip_and_useful_group_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "mass_and_sizing_basic_specs/equip.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/subsystems/mass/gasp_based/test/test_fixed.py b/aviary/subsystems/mass/gasp_based/test/test_fixed.py index 562f15fae..8c6a746b8 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_fixed.py +++ b/aviary/subsystems/mass/gasp_based/test/test_fixed.py @@ -14,7 +14,6 @@ PayloadMass, TailMass) from aviary.utils.aviary_values import AviaryValues, get_keys from aviary.variable_info.options import get_option_defaults -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft, Mission @@ -1116,12 +1115,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=3e-11, rtol=1e-12) - @skipIfMissingXDSM('mass_and_sizing_both_specs/fixed_mass.json') - def test_io_fixed_group_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "mass_and_sizing_both_specs/fixed_mass.json") class FixedMassGroupTestCase2(unittest.TestCase): diff --git a/aviary/subsystems/mass/gasp_based/test/test_fuel.py b/aviary/subsystems/mass/gasp_based/test/test_fuel.py index fe3c123f8..099be4d60 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_fuel.py +++ b/aviary/subsystems/mass/gasp_based/test/test_fuel.py @@ -10,7 +10,6 @@ FuelSysAndFullFuselageMass, FuselageAndStructMass) from aviary.variable_info.options import get_option_defaults -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft, Mission @@ -611,13 +610,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=2e-11, rtol=1e-12) - @skipIfMissingXDSM('mass_and_sizing_basic_specs/fuel_mass.json') - def test_io_fuel_group_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "mass_and_sizing_basic_specs/fuel_mass.json") - class FuelMassGroupTestCase3( unittest.TestCase @@ -746,13 +738,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=3e-9, rtol=6e-11) - @skipIfMissingXDSM('mass_and_sizing_basic_specs/fuel_mass.json') - def test_io_fuel_group_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "mass_and_sizing_basic_specs/fuel_mass.json") - if __name__ == "__main__": unittest.main() 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 c1e8a6d6a..41a0f90c4 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_mass_summation.py +++ b/aviary/subsystems/mass/gasp_based/test/test_mass_summation.py @@ -8,7 +8,6 @@ from aviary.subsystems.mass.gasp_based.mass_premission import MassPremission from aviary.utils.aviary_values import get_items from aviary.variable_info.options import get_option_defaults, is_option -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.models.large_single_aisle_1.V3_bug_fixed_IO import ( V3_bug_fixed_non_metadata, V3_bug_fixed_options) from aviary.variable_info.variables import Aircraft, Mission @@ -158,13 +157,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=3e-10, rtol=1e-12) - @skipIfMissingXDSM('statics_specs/mass.json') - def test_mass_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "statics_specs/mass.json") - class MassSummationTestCase2(unittest.TestCase): """ diff --git a/aviary/subsystems/mass/gasp_based/test/test_wing.py b/aviary/subsystems/mass/gasp_based/test/test_wing.py index 7a275644c..956ca4339 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_wing.py +++ b/aviary/subsystems/mass/gasp_based/test/test_wing.py @@ -8,7 +8,6 @@ WingMassSolve, WingMassTotal) from aviary.variable_info.options import get_option_defaults -from aviary.utils.test_utils.IO_test_util import assert_match_spec, skipIfMissingXDSM from aviary.variable_info.variables import Aircraft, Mission @@ -271,13 +270,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-8, rtol=1e-8) - @skipIfMissingXDSM('mass_and_sizing_basic_specs/wing_mass.json') - def test_io_equip_and_useful_group_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "mass_and_sizing_basic_specs/wing_mass.json") - class WingMassGroupTestCase2(unittest.TestCase): def setUp(self): @@ -472,13 +464,6 @@ def test_case1(self): partial_data = self.prob.check_partials(out_stream=None, method="cs") assert_check_partials(partial_data, atol=1e-8, rtol=1e-8) - @skipIfMissingXDSM('mass_and_sizing_both_specs/wing_mass.json') - def test_io_equip_and_useful_group_spec(self): - - subsystem = self.prob.model - - assert_match_spec(subsystem, "mass_and_sizing_both_specs/wing_mass.json") - if __name__ == "__main__": unittest.main() diff --git a/aviary/utils/test_utils/IO_test_util.py b/aviary/utils/test_utils/IO_test_util.py index b4aacde5b..0ec0c6d38 100644 --- a/aviary/utils/test_utils/IO_test_util.py +++ b/aviary/utils/test_utils/IO_test_util.py @@ -1,150 +1,6 @@ -import json -import os -from unittest import skipIf - import openmdao.api as om from openmdao.utils.assert_utils import assert_near_equal -XDSM_PATH = os.path.abspath(os.path.join(__file__, "../../..", "xdsm")) - - -def skipIfMissingXDSM(filename): - return skipIf(not os.path.isfile(os.path.join(XDSM_PATH, filename)), "`"+filename+"` does not exist") - - -def _load_spec(spec_path, path_prefix=XDSM_PATH): - with open(os.path.join(path_prefix, spec_path), "rb") as f: - spec_data = json.load(f) - - spec_data["inputs"] = set(spec_data["inputs"]) - spec_data["outputs"] = set(spec_data["outputs"]) - return spec_data - - -def assert_match_spec(system, spec_path, path_prefix=XDSM_PATH): - - spec_data = _load_spec(spec_path, path_prefix) - - prob = om.Problem() - prob.model = system - - prob.setup() - prob.final_setup() - - sys_inputs = prob.model.list_inputs(out_stream=None, prom_name=True) - sys_outputs = prob.model.list_outputs(out_stream=None, prom_name=True) - - input_set = set([inp[1]["prom_name"] for inp in sys_inputs]) - output_set = set([out[1]["prom_name"] for out in sys_outputs]) - - # this checks if there are any vars in the spec, that aren't in the model - missing_inputs = spec_data["inputs"] - input_set - if len(missing_inputs) > 0: - raise ValueError( - f"inputs {missing_inputs} are in {spec_path}, but are missing in the provided system." - ) - - # filter the inputs into connected and unconnected sets - connect_dict = system._conn_global_abs_in2out - unconnected_inputs = set() - connected_inputs = set() - for abs_name, in_data in sys_inputs: - if abs_name in connect_dict and (not "auto_ivc" in connect_dict[abs_name]): - connected_inputs.add(in_data["prom_name"]) - else: - unconnected_inputs.add(in_data["prom_name"]) - - # now we need to check if there are any unconnected inputs - # in the model that aren't in the spec - extra_inputs = unconnected_inputs - spec_data["inputs"] - if len(extra_inputs) > 0: - raise ValueError( - f"unconnected inputs {extra_inputs} are in your model, but are missing as inputs in the {spec_path} spec." - ) - - # last we need to check if any of the spec inputs have - # internal connections (e.g. from stray IVCs) - blocked_inputs = connected_inputs.intersection(spec_data["inputs"]) - if len(blocked_inputs) > 0: - raise ValueError( - f"inputs {blocked_inputs} are connected inside your model, but are listed as required" - f" inputs in the {spec_path} spec so they should be unconnected." - ) - - # check if any missing required outputs are missing from the model, based on the spec - missing_outputs = spec_data["outputs"] - output_set - if len(missing_outputs) > 0: - raise ValueError( - f"outputs {missing_outputs} are in {spec_path}, but are missing in the provided system." - ) - - -def assert_match_vals( - test_case, system, spec_path, path_prefix=XDSM_PATH, tolerance=1e-5, test_names=None -): - - spec_data = _load_spec(spec_path, path_prefix) - - if test_names: - # User passed a collection of test names to check. - verify_data = {name: system.verify_data[name] for name in test_names} - else: - # if there is just one case, then modify the dict to make auto-name the single case - try: - # Setup the verification case model - v_data_inputs = system.verify_data["inputs"] - verify_data = {"v_test1": system.verify_data} - except KeyError: # there is already more than one, use the fist one to figure things out - verify_data = system.verify_data - - for v_case_name, v_case in verify_data.items(): - v_data_inputs = v_case["inputs"] - v_data_outputs = v_case["outputs"] - - for v_name in v_data_inputs.keys(): - if not v_name in spec_data["inputs"]: - raise ValueError( - f'input value for "{v_name}" was given in verification data, ' - f'but this variable is not given in "{spec_path}"' - ) - - prob = om.Problem() - ivc = prob.model.add_subsystem("spec_inputs", om.IndepVarComp(), promotes=["*"]) - for v_name, v_val in v_data_inputs.items(): - if isinstance(v_val, (list, tuple)): - v_unit = v_val[1] - v_val = v_val[0] - else: - v_unit = None - - ivc.add_output(v_name, val=v_val, units=v_unit) - # note, can't set units, but don't want to hack it in. - # Unit data should be available from the system itself via the default-auto-ivc stuff - - prob.model.add_subsystem("sys", system, promotes=["*"]) - - prob.setup() - prob.final_setup() - - prob.run_model() - - for v_name, v_val in v_data_outputs.items(): - if isinstance(v_val, (list, tuple)): - v_unit = v_val[1] - v_val = v_val[0] - else: - v_unit = None - - try: - computed_val = prob.get_val(v_name, units=v_unit) - except KeyError: # hacky way to work around needing inputs/vs outputs - computed_val = prob.get_val(f"sys.{v_name}", units=v_unit) - - try: - assert_near_equal(computed_val, v_val, tolerance=tolerance) - except AssertionError as err: - raise ValueError(f'in case "{v_case_name}", for {v_name}: ' + str(err)) - def check_prob_outputs(prob, vals, rtol=1e-6): """Check multiple problem outputs and print all failures. diff --git a/aviary/xdsm/__init__.py b/aviary/xdsm/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/aviary/xdsm/accel_xdsm.py b/aviary/xdsm/accel_xdsm.py deleted file mode 100644 index f407abc9c..000000000 --- a/aviary/xdsm/accel_xdsm.py +++ /dev/null @@ -1,59 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, IFUNC, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -simplified = True - -# Create subsystem components -x.add_system("atmos", FUNC, [r"AtmosphereModel"]) -x.add_system("fc", FUNC, [r"\textbf{FlightConditions}"]) -x.add_system("weight", FUNC, ["MassToWeight"]) -x.add_system("aero", GROUP, ["CruiseAero", "(alpha~in)"]) -x.add_system("prop", GROUP, [r"Propulsion"]) -x.add_system("eom", FUNC, [r"\textbf{AccelEOM}"]) - -# create inputs -if simplified: - x.add_input("aero", ["aircraft:*"]) -else: - x.add_input("aero", [ - # Aircraft.Wing.AREA, - "aircraft:wing:*", - "aircraft:horizontal_tail:*", - "aircraft:vertical_tail:*", - "aircraft:fuselage:*", - "aircraft:design:*", - "aircraft:nacelle:*", - "aircraft:strut:*", - Mission.Design.LIFT_COEFFICIENT_MAX_FLAPS_UP, - ]) - -# create outputs -x.add_output("fc", ["EAS"], side="right") -x.add_output("aero", [Dynamic.Mission.LIFT, Dynamic.Mission.DRAG, "alpha"], side="right") -# for accel_ode, CruiseAero(output_alpha=True). So alpha is not an input. -x.add_output("eom", ["TAS_rate", Dynamic.Mission.DISTANCE_RATE], side="right") - -# make connections -x.add_input("atmos", [Dynamic.Mission.ALTITUDE]) -x.add_input("fc", ["TAS"]) -x.add_input("prop", [ - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.THROTTLE, - Aircraft.Engine.SCALE_FACTOR, -]) -x.add_input("weight", [Dynamic.Mission.MASS]) -x.add_input("eom", [Dynamic.Mission.MASS, "TAS"]) -x.connect("atmos", "fc", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -# x.connect("atmos", "prop", [Dynamic.Mission.TEMPERATURE, Dynamic.Mission.STATIC_PRESSURE]) -x.connect("fc", "aero", [Dynamic.Mission.MACH, Dynamic.Mission.DYNAMIC_PRESSURE]) -x.connect("fc", "prop", [Dynamic.Mission.MACH]) -x.connect("weight", "aero", ["weight/lift_req"]) -x.connect("aero", "eom", [Dynamic.Mission.DRAG]) -# x.connect("aero", "balance", [Dynamic.Mission.LIFT]) -x.connect("prop", "eom", [Dynamic.Mission.THRUST_TOTAL]) - -# Do not run spec test on aero. -x.write("accel_xdsm") -x.write_sys_specs("accel_specs") diff --git a/aviary/xdsm/ascent_xdsm.py b/aviary/xdsm/ascent_xdsm.py deleted file mode 100644 index 687870af3..000000000 --- a/aviary/xdsm/ascent_xdsm.py +++ /dev/null @@ -1,69 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -# Create subsystem components -x.add_system("atmos", GROUP, ["AtmosphereModel"]) -x.add_system("fc", FUNC, ["FlightConditions"]) -x.add_system("prop", GROUP, ["Propulsion"]) -x.add_system("aero", GROUP, ["LowSpeedAero", "(alpha~in)"]) -x.add_system("eom", GROUP, [r"\textbf{AscentEOM}"]) - -# create inputs -x.add_input("atmos", [Dynamic.Mission.ALTITUDE]) -x.add_input("fc", ["TAS"]) -x.add_input("prop", [ - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.THROTTLE, - Aircraft.Engine.SCALE_FACTOR,]) -x.add_input("aero", [ - "alpha", - "t_curr", - "dt_flaps", - "dt_gear", - "t_init_flaps", - "t_init_gear", - "aircraft:*", - # Aircraft.Wing.FLAP_DEFLECTION_TAKEOFF, - # Aircraft.Wing.HEIGHT, - # Aircraft.Wing.SPAN, - # Aircraft.Wing.AREA, - Dynamic.Mission.ALTITUDE, - Mission.Takeoff.AIRPORT_ALTITUDE, - Mission.Design.GROSS_MASS, - # 'aero_ramps:flap_factor:initial_val', - # 'aero_ramps:gear_factor:initial_val', - # 'aero_ramps:flap_factor:final_val', - # 'aero_ramps:gear_factor:final_val', -],) -x.add_input("eom", [ - "alpha", - "TAS", - Dynamic.Mission.MASS, - Dynamic.Mission.FLIGHT_PATH_ANGLE, - Aircraft.Wing.INCIDENCE, -],) - -# make connections -x.connect("atmos", "fc", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -# x.connect("atmos", "prop", [Dynamic.Mission.TEMPERATURE, Dynamic.Mission.STATIC_PRESSURE]) -x.connect("fc", "prop", [Dynamic.Mission.MACH]) -x.connect("fc", "aero", [Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.MACH]) -x.connect("prop", "eom", [Dynamic.Mission.THRUST_TOTAL]) -x.connect("aero", "eom", [Dynamic.Mission.LIFT, Dynamic.Mission.DRAG]) - -# create outputs -x.add_output("eom", [ - "TAS_rate", - Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, - Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.DISTANCE_RATE, - "alpha_rate", - "normal_force", - "fuselage_pitch", - "load_factor", -], side="right",) - -x.write("ascent_xdsm") -x.write_sys_specs("ascent_specs") diff --git a/aviary/xdsm/climb_xdsm.py b/aviary/xdsm/climb_xdsm.py deleted file mode 100644 index 764ad79ca..000000000 --- a/aviary/xdsm/climb_xdsm.py +++ /dev/null @@ -1,90 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, IFUNC, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -simplified = True - -# input_speed_type = "EAS" for both high altitude and low altitude -# analysis_scheme = COLLOCATION - -# Create subsystem components -x.add_system("atmos", FUNC, ["AtmosphereModel"]) -x.add_system("speeds", FUNC, [r"\textbf{SpeedConstraints}"]) -x.add_system("ks", FUNC, ["KSComp"]) -x.add_system("balance_speed", IFUNC, ["BalanceSpeed"]) -x.add_system("fc", FUNC, [r"\textbf{FlightConditions}"]) -x.add_system("prop", GROUP, ["Propulsion"]) -x.add_system("aero", GROUP, ["CruiseAero", "(alpha~in)"]) -x.add_system("eom", GROUP, [r"\textbf{ClimbEOM}"]) -x.add_system("balance_lift", IFUNC, ["BalanceLift"]) -x.add_system("constraints", FUNC, [r"\textbf{Constraints}"]) - -# create inputs -x.add_input("speeds", [Dynamic.Mission.MACH]) -x.add_input("constraints", [ - Dynamic.Mission.MASS, - Aircraft.Wing.AREA, - Aircraft.Wing.INCIDENCE -]) -x.add_input("balance_speed", ["EAS"]) -x.add_input("atmos", [Dynamic.Mission.ALTITUDE]) -if simplified: - x.add_input("aero", ["alpha", "aircraft:*"]) -else: - x.add_input("aero", [ - # Aircraft.Wing.AREA, - "aircraft:wing:*", - "aircraft:horizontal_tail:*", - "aircraft:vertical_tail:*", - "aircraft:fuselage:*", - "aircraft:design:*", - "aircraft:nacelle:*", - "aircraft:strut:*", - Mission.Design.LIFT_COEFFICIENT_MAX_FLAPS_UP, - ]) -x.add_input("prop", [ - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.THROTTLE, - Aircraft.Engine.SCALE_FACTOR, -]) -x.add_input("eom", [Dynamic.Mission.MASS]) - -# make connections -x.connect("atmos", "fc", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -# x.connect("atmos", "prop", [Dynamic.Mission.TEMPERATURE, Dynamic.Mission.STATIC_PRESSURE]) -x.connect("atmos", "constraints", ["rho"]) -x.connect("fc", "prop", [Dynamic.Mission.MACH]) -x.connect("fc", "aero", [Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.MACH]) -x.connect("fc", "eom", ["TAS"]) -x.connect("fc", "constraints", ["TAS"]) -x.connect("fc", "speeds", [Dynamic.Mission.MACH]) -x.connect("speeds", "ks", ["speed_constraint"]) -x.connect("ks", "balance_speed", ["KS"]) -x.connect("balance_speed", "fc", ["EAS"]) -x.connect("balance_speed", "speeds", ["EAS"]) -x.connect("aero", "eom", [Dynamic.Mission.DRAG]) -x.connect("aero", "constraints", ["CL_max"]) -x.connect("prop", "eom", [Dynamic.Mission.THRUST_TOTAL]) -x.connect("eom", "constraints", [Dynamic.Mission.FLIGHT_PATH_ANGLE]) -x.connect("aero", "balance_lift", [Dynamic.Mission.LIFT]) -x.connect("eom", "balance_lift", ["required_lift"]) -x.connect("balance_lift", "constraints", ["alpha"]) -x.connect("balance_lift", "aero", ["alpha"]) - -# create outputs -x.add_output("eom", [ - Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.DISTANCE_RATE, - "required_lift", -], side="right") -x.add_output("constraints", ["theta", "TAS_violation"], side="right") - -x.add_output("aero", [ - Dynamic.Mission.LIFT, - Dynamic.Mission.DRAG, - "CL_max", -], side="right") - -x.write("climb_xdsm") -x.write_sys_specs("climb_specs") diff --git a/aviary/xdsm/computed_aero_xdsm.py b/aviary/xdsm/computed_aero_xdsm.py deleted file mode 100644 index d660d8e9e..000000000 --- a/aviary/xdsm/computed_aero_xdsm.py +++ /dev/null @@ -1,172 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, IFUNC, IGROUP, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -# src = "subsystems/flops_based/computed_aero_group.py" -simplified = False -show_outputs = True - -# Create subsystem components -x.add_system("mux", FUNC, ["MUX"]) -x.add_system("dynPress", FUNC, ["DynamicPressure"]) -x.add_system("lt_eq_wt", FUNC, ["LiftEqualsWeight"]) -x.add_system("deptDrag", FUNC, ["LiftDependentDrag"]) -x.add_system("induDrag", FUNC, ["InducedDrag"]) -x.add_system("compDrag", FUNC, ["CompressibilityDrag"]) -x.add_system("skinFric", FUNC, ["SkinFriction"]) -x.add_system("skinDrag", FUNC, ["SkinFrictionDrag"]) -x.add_system("cmpdDrag", GROUP, ["ComputedDrag"]) -x.add_system("buffLift", FUNC, ["BuffetLift"]) - -if simplified: - x.add_input("mux", ["InputValues"]) - x.add_input("dynPress", ["InputValues"]) - x.add_input("lt_eq_wt", ["InputValues"]) - x.add_input("deptDrag", ["InputValues"]) - x.add_input("induDrag", ["InputValues"]) - x.add_input("compDrag", ["InputValues"]) - x.add_input("skinFric", ["InputValues"]) - x.add_input("skinDrag", ["InputValues"]) - x.add_input("cmpdDrag", ["InputValues"]) - x.add_input("buffLift", ["InputValues"]) -else: - # Wing - x.add_input("mux", [ - Aircraft.Wing.WETTED_AREA, - Aircraft.Wing.FINENESS, - Aircraft.Wing.CHARACTERISTIC_LENGTH, - Aircraft.Wing.LAMINAR_FLOW_UPPER, - Aircraft.Wing.LAMINAR_FLOW_LOWER, - # Tail - Aircraft.HorizontalTail.WETTED_AREA, - Aircraft.HorizontalTail.FINENESS, - Aircraft.HorizontalTail.CHARACTERISTIC_LENGTH, - Aircraft.HorizontalTail.LAMINAR_FLOW_UPPER, - Aircraft.HorizontalTail.LAMINAR_FLOW_LOWER, - # Vertical Tail - Aircraft.VerticalTail.WETTED_AREA, - Aircraft.VerticalTail.FINENESS, - Aircraft.VerticalTail.CHARACTERISTIC_LENGTH, - Aircraft.VerticalTail.LAMINAR_FLOW_UPPER, - Aircraft.VerticalTail.LAMINAR_FLOW_LOWER, - # Fuselage - Aircraft.Fuselage.WETTED_AREA, - Aircraft.Fuselage.FINENESS, - Aircraft.Fuselage.CHARACTERISTIC_LENGTH, - Aircraft.Fuselage.LAMINAR_FLOW_UPPER, - Aircraft.Fuselage.LAMINAR_FLOW_LOWER, - # Engine - Aircraft.Nacelle.WETTED_AREA, - Aircraft.Nacelle.FINENESS, - Aircraft.Nacelle.CHARACTERISTIC_LENGTH, - Aircraft.Nacelle.LAMINAR_FLOW_UPPER, - Aircraft.Nacelle.LAMINAR_FLOW_LOWER, - ]) - - x.add_input("dynPress", [Dynamic.Mission.MACH, Dynamic.Mission.STATIC_PRESSURE]) - x.add_input("lt_eq_wt", [ - Aircraft.Wing.AREA, - Dynamic.Mission.MASS, - # Dynamic.Mission.DYNAMIC_PRESSURE, - ]) - x.add_input("deptDrag", [ - Dynamic.Mission.MACH, - # Dynamic.Mission.LIFT, - Dynamic.Mission.STATIC_PRESSURE, - Mission.Design.MACH, - Mission.Design.LIFT_COEFFICIENT, - Aircraft.Wing.AREA, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN, - Aircraft.Wing.SWEEP, - Aircraft.Wing.THICKNESS_TO_CHORD, - ]) - x.add_input("induDrag", [ - Dynamic.Mission.MACH, - # Dynamic.Mission.LIFT, - Dynamic.Mission.STATIC_PRESSURE, - Aircraft.Wing.AREA, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.SPAN_EFFICIENCY_FACTOR, - Aircraft.Wing.SWEEP, - Aircraft.Wing.TAPER_RATIO, - ]) - x.add_input("compDrag", [ - Dynamic.Mission.MACH, - Mission.Design.MACH, - Aircraft.Design.BASE_AREA, - Aircraft.Wing.AREA, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN, - Aircraft.Wing.SWEEP, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD, - Aircraft.Fuselage.CROSS_SECTION, - Aircraft.Fuselage.DIAMETER_TO_WING_SPAN, - Aircraft.Fuselage.LENGTH_TO_DIAMETER, - ]) - x.add_input("skinFric", [ - Dynamic.Mission.MACH, - Dynamic.Mission.STATIC_PRESSURE, - Dynamic.Mission.TEMPERATURE, - # "characteristic_lengths", - ]) - x.add_input("skinDrag", [ - # "skin_friction_coeff", - # "Re", - Aircraft.Wing.AREA, - ]) - x.add_input("cmpdDrag", [ - # Dynamic.Mission.DYNAMIC_PRESSURE, - Dynamic.Mission.MACH, - Aircraft.Wing.AREA, - Aircraft.Design.ZERO_LIFT_DRAG_COEFF_FACTOR, - Aircraft.Design.LIFT_DEPENDENT_DRAG_COEFF_FACTOR, - Aircraft.Design.SUBSONIC_DRAG_COEFF_FACTOR, - Aircraft.Design.SUPERSONIC_DRAG_COEFF_FACTOR, - ]) - x.add_input("buffLift", [ - Dynamic.Mission.MACH, - Mission.Design.MACH, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN, - Aircraft.Wing.SWEEP, - Aircraft.Wing.THICKNESS_TO_CHORD, - ]) - -# make connections -x.connect("mux", "skinFric", ["characteristic_lengths"]) - -x.connect("mux", "skinDrag", [ - "wetted_areas", - "fineness_ratios", - "laminar_fractions_upper", - "laminar_fractions_lower", -]) - -x.connect("dynPress", "lt_eq_wt", [Dynamic.Mission.DYNAMIC_PRESSURE]) -x.connect("dynPress", "cmpdDrag", [Dynamic.Mission.DYNAMIC_PRESSURE]) -x.connect("lt_eq_wt", "deptDrag", [Dynamic.Mission.LIFT]) -x.connect("lt_eq_wt", "induDrag", [Dynamic.Mission.LIFT]) - -x.connect("skinFric", "skinDrag", ["skin_friction_coeff", "Re"]) -x.connect("deptDrag", "cmpdDrag", ["CD/pressure_drag_coeff"]) -x.connect("induDrag", "cmpdDrag", ["induced_drag_coeff"]) -x.connect("compDrag", "cmpdDrag", ["compress_drag_coeff"]) -x.connect("skinDrag", "cmpdDrag", ["skin_friction_drag_coeff"]) - -# create outputs -if show_outputs: - x.add_output("lt_eq_wt", ["CL", Dynamic.Mission.LIFT], side="right") - # x.add_output("skinFric", ["cf_iter", "wall_temp"], side="right") # don't see why needed - x.add_output("cmpdDrag", [ - "CDI", - "CD0", - "CD/drag_coefficient", - Dynamic.Mission.DRAG, - ], side="right") - x.add_output("buffLift", ["delta_CL_Before"], side="right") # DELCLB - -x.write("computed_aero_xdsm") -x.write_sys_specs("computed_aero_specs") diff --git a/aviary/xdsm/cruise_xdsm.py b/aviary/xdsm/cruise_xdsm.py deleted file mode 100644 index 2f7b5675f..000000000 --- a/aviary/xdsm/cruise_xdsm.py +++ /dev/null @@ -1,64 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, IFUNC, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -simplified = True - -# Create subsystem components -x.add_system("atmos", FUNC, ["AtmosphereModel"]) -x.add_system("fc", FUNC, [r"\textbf{FlightConditions}"]) -x.add_system("weight", FUNC, ["MassToWeight"]) -x.add_system("aero", GROUP, ["CruiseAero", "(alpha~in)"]) -x.add_system("prop", GROUP, ["Propulsion"]) -x.add_system("thrust_bal", IFUNC, ["BalanceThrust"]) -x.add_system("breguet_eom", FUNC, [r"\textbf{BreguetEOM}"]) - -# create inputs - -if simplified: - x.add_input("aero", [Dynamic.Mission.MACH, "aircraft:*"]) -else: - x.add_input("aero", [ - # Aircraft.Wing.AREA, - "aircraft:wing:*", - "aircraft:horizontal_tail:*", - "aircraft:vertical_tail:*", - "aircraft:fuselage:*", - "aircraft:design:*", - "aircraft:nacelle:*", - "aircraft:strut:*", - Mission.Design.LIFT_COEFFICIENT_MAX_FLAPS_UP, - ]) -x.add_input("atmos", [Dynamic.Mission.ALTITUDE]) # alt_cruise -x.add_input("fc", [Dynamic.Mission.MACH]) -x.add_input("prop", [ - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MACH, - Dynamic.Mission.THROTTLE, - Aircraft.Engine.SCALE_FACTOR, -]) -x.add_input("breguet_eom", [ - Dynamic.Mission.MASS, - "cruise_distance_initial", - "cruise_time_initial", -]) -x.add_input("weight", ["mass"]) - -# make connections -x.connect("fc", "aero", [Dynamic.Mission.DYNAMIC_PRESSURE]) -x.connect("atmos", "fc", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -x.connect("weight", "aero", ["weight/lift_req"]) -x.connect("aero", "prop", ["drag/thrust_req"]) -x.connect("aero", "thrust_bal", ["thrust_req"]) -x.connect("fc", "breguet_eom", ["TAS"]) # TAS_cruise -x.connect("prop", "breguet_eom", [Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL]) -x.connect("prop", "thrust_bal", [Dynamic.Mission.THRUST_TOTAL]) -x.connect("thrust_bal", "prop", ["thrust_req"]) - -# create outputs -x.add_output("breguet_eom", [Dynamic.Mission.DISTANCE, "cruise_time"], side="right") -# x.add_output("fc", ["EAS"], side="right") - -x.write("cruise_xdsm") -x.write_sys_specs("cruise_specs") diff --git a/aviary/xdsm/descent1_xdsm.py b/aviary/xdsm/descent1_xdsm.py deleted file mode 100644 index 74e3b0f02..000000000 --- a/aviary/xdsm/descent1_xdsm.py +++ /dev/null @@ -1,74 +0,0 @@ -"""XDSM for above 10 kft""" - -from pyxdsm.XDSM import FUNC, GROUP, IFUNC, IGROUP, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -# input_speed_type = "MACH" -# analysis_scheme = "COLLOCATION" - -# Create subsystem components -x.add_system("atmos", FUNC, ["AtmosphereModel"]) -x.add_system("balance_speed", IFUNC, ["BalanceSpeed"]) -x.add_system("speeds", FUNC, [r"\textbf{SpeedConstraints}"]) -x.add_system("fc", FUNC, ["FlightConditions"]) -x.add_system("ks", FUNC, ["KSComp"]) -x.add_system("prop", GROUP, ["Propulsion"]) -x.add_system("eom", GROUP, [r"\textbf{EOM}"]) -x.add_system("balance_lift", FUNC, ["BalanceLift"]) -x.add_system("aero", IGROUP, ["CruiseAero", "(alpha~in)"]) -x.add_system("pitch", FUNC, ["Constraints"]) - -# create inputs -# x.add_input("fc", [Dynamic.Mission.MACH]) -x.add_input("atmos", [Dynamic.Mission.ALTITUDE]) -x.add_input("balance_speed", ["rhs_mass"]) -# x.add_input("aero", [Aircraft.Wing.AREA]) -x.add_input("aero", [r"aircraft:*", Dynamic.Mission.ALTITUDE]) -x.add_input("prop", [ - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.THROTTLE, - Aircraft.Engine.SCALE_FACTOR, -]) -x.add_input("eom", ["mass"]) -x.add_input("pitch", [ - Dynamic.Mission.MASS, - Aircraft.Wing.AREA, - Aircraft.Wing.INCIDENCE, -]) - -# make connections -x.connect("atmos", "fc", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -x.connect("atmos", "aero", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -x.connect("atmos", "pitch", ["rho"]) -x.connect("balance_speed", "fc", [Dynamic.Mission.MACH]) -x.connect("balance_speed", "speeds", [Dynamic.Mission.MACH]) -x.connect("balance_speed", "aero", [Dynamic.Mission.MACH]) -x.connect("balance_speed", "prop", [Dynamic.Mission.MACH]) -x.connect("speeds", "ks", ["speed_constraint"]) -x.connect("fc", "aero", [Dynamic.Mission.DYNAMIC_PRESSURE]) -x.connect("fc", "eom", ["TAS"]) -x.connect("fc", "speeds", ["EAS"]) -x.connect("fc", "pitch", ["TAS"]) -x.connect("ks", "balance_speed", ["KS"]) -x.connect("prop", "eom", [Dynamic.Mission.THRUST_TOTAL]) -x.connect("prop", "aero", [Dynamic.Mission.THRUST_TOTAL]) -x.connect("eom", "pitch", [Dynamic.Mission.FLIGHT_PATH_ANGLE]) -x.connect("eom", "balance_lift", ["required_lift"]) -x.connect("balance_lift", "aero", ["alpha"]) -x.connect("balance_lift", "eom", ["alpha"]) -x.connect("balance_lift", "pitch", ["alpha"]) -x.connect("aero", "eom", [Dynamic.Mission.DRAG]) -x.connect("aero", "pitch", ["CL_max"]) -x.connect("aero", "balance_lift", [Dynamic.Mission.LIFT]) - -# create outputs -x.add_output("eom", [ - Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.DISTANCE_RATE, - "required_lift" -], side="right") - -x.write("descent1_xdsm") -x.write_sys_specs("descent1_specs") diff --git a/aviary/xdsm/descent2_xdsm.py b/aviary/xdsm/descent2_xdsm.py deleted file mode 100644 index 20ba3f889..000000000 --- a/aviary/xdsm/descent2_xdsm.py +++ /dev/null @@ -1,62 +0,0 @@ -"""XDSM for below 10 kft""" - -from pyxdsm.XDSM import FUNC, GROUP, IFUNC, IGROUP, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -# Create subsystem components -x.add_system("atmos", FUNC, ["AtmosphereModel"]) -x.add_system("fc", FUNC, ["FlightConditions"]) -x.add_system("prop", GROUP, ["Propulsion"]) -x.add_system("eom", GROUP, ["EOM"]) -x.add_system("balance_lift", FUNC, ["BalanceLift"]) -x.add_system("aero", IGROUP, ["CruiseAero", "(alpha~in)"]) -x.add_system("pitch", FUNC, ["Constraints"]) - -# create inputs -# x.add_input("fc", ["EAS"]) -# x.add_input("aero", [Aircraft.Wing.AREA]) -x.add_input("aero", [r"aircraft:*", Dynamic.Mission.ALTITUDE]) -x.add_input("prop", [ - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.THROTTLE, - Aircraft.Engine.SCALE_FACTOR, -]) -x.add_input("eom", ["mass"]) -x.add_input("pitch", [ - Dynamic.Mission.MASS, - Aircraft.Wing.AREA, - Aircraft.Wing.INCIDENCE, -]) - -# make connections -x.add_input("fc", ["EAS"]) -x.add_input("atmos", [Dynamic.Mission.ALTITUDE]) -x.connect("atmos", "fc", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -x.connect("atmos", "aero", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -x.connect("atmos", "pitch", ["rho"]) -x.connect("fc", "aero", [Dynamic.Mission.MACH, Dynamic.Mission.DYNAMIC_PRESSURE]) -x.connect("fc", "prop", [Dynamic.Mission.MACH]) -x.connect("fc", "eom", ["TAS"]) -x.connect("fc", "pitch", ["TAS"]) -x.connect("prop", "eom", [Dynamic.Mission.THRUST_TOTAL]) -x.connect("prop", "aero", [Dynamic.Mission.THRUST_TOTAL]) -x.connect("eom", "pitch", [Dynamic.Mission.FLIGHT_PATH_ANGLE]) -x.connect("eom", "balance_lift", ["required_lift"]) -x.connect("balance_lift", "aero", ["alpha"]) -x.connect("balance_lift", "eom", ["alpha"]) -x.connect("balance_lift", "pitch", ["alpha"]) -x.connect("aero", "eom", [Dynamic.Mission.DRAG]) -x.connect("aero", "pitch", ["CL_max"]) -x.connect("aero", "balance_lift", [Dynamic.Mission.LIFT]) - -# create outputs -x.add_output("eom", [ - Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.DISTANCE_RATE, - "required_lift" -], side="right") - -x.write("descent2_xdsm") -x.write_sys_specs("descent2_specs") diff --git a/aviary/xdsm/design_load_xdsm.py b/aviary/xdsm/design_load_xdsm.py deleted file mode 100644 index cf2e37ccb..000000000 --- a/aviary/xdsm/design_load_xdsm.py +++ /dev/null @@ -1,40 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, XDSM -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -show_outputs = True - -# Create subsystem components -x.add_system("speeds", FUNC, ["LoadSpeeds"]) -x.add_system("params", FUNC, ["LoadParameters"]) -x.add_system("slope", FUNC, ["LiftCurveSlope", "(at Cruise)"]) -x.add_system("factors", FUNC, ["LoadFactors"]) - -# create inputs -x.add_input("speeds", [ - Aircraft.Design.MAX_STRUCTURAL_SPEED, - Aircraft.Wing.LOADING, -]) -x.add_input("slope", [ - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.SWEEP, Mission.Design.MACH -]) -x.add_input("factors", [Aircraft.Wing.AVERAGE_CHORD]) - -# make connections -x.connect("speeds", "params", ["max_airspeed", "vel_c"]) -x.connect("speeds", "factors", ["max_maneuver_factor", "min_dive_vel"]) -x.connect("slope", "factors", [Aircraft.Design.LIFT_CURVE_SLOPE]) -x.connect("params", "factors", ["density_ratio", "V9"]) - -### add outputs ### -if show_outputs is True: - # params - x.add_output("params", ["max_mach"], side="right") - # factors - x.add_output("factors", [Aircraft.Wing.ULTIMATE_LOAD_FACTOR], side="right") - - -x.write("design_load_xdsm") -x.write_sys_specs("design_load_specs") diff --git a/aviary/xdsm/empennage_size_xdsm.py b/aviary/xdsm/empennage_size_xdsm.py deleted file mode 100644 index 9bca74515..000000000 --- a/aviary/xdsm/empennage_size_xdsm.py +++ /dev/null @@ -1,80 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, XDSM -from aviary.variable_info.variables import Aircraft - -x = XDSM() - -compute_volume_coeff = True - -if compute_volume_coeff: - x.add_system("hvc", FUNC, [r"\textcolor{gray}{htail_vc\, (TailVolCoef)}"]) - x.add_system("vvc", FUNC, [r"\textcolor{gray}{vtail_vc\, (TailVolCoef)}"]) -x.add_system("htail", FUNC, [r"htail\, (TailSize)"]) -x.add_system("vtail", FUNC, [r"vtail\, (TailSize)"]) - -# move to EmpennageSize inputs -# x.add_input("htail", [r"chord_hor_arm", r"h_ar", r"h_tr", r"(htail_vol_coef)"]) -# x.add_input("vtail", [r"span_ver_arm", r"v_ar", r"v_tr", r"(vtail_vol_coef)"]) - -if compute_volume_coeff: - x.add_input("hvc", [ - r"\textcolor{gray}{"+Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION+"}", - r"\textcolor{gray}{"+Aircraft.Fuselage.LENGTH+"}", - r"\textcolor{gray}{"+Aircraft.Fuselage.AVG_DIAMETER+"}", - r"\textcolor{gray}{"+Aircraft.Wing.AREA+"}", - r"\textcolor{gray}{"+Aircraft.Wing.AVERAGE_CHORD+"}", - ]) - x.add_input("vvc", [ - r"\textcolor{gray}{"+Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION+"}", - r"\textcolor{gray}{"+Aircraft.Fuselage.LENGTH+"}", - r"\textcolor{gray}{"+Aircraft.Fuselage.AVG_DIAMETER+"}", - r"\textcolor{gray}{"+Aircraft.Wing.AREA+"}", - r"\textcolor{gray}{"+Aircraft.Wing.SPAN+"}", - ]) -in_htail_array = [ - Aircraft.HorizontalTail.MOMENT_RATIO, - Aircraft.HorizontalTail.ASPECT_RATIO, - Aircraft.HorizontalTail.TAPER_RATIO, - Aircraft.Wing.AREA, - Aircraft.Wing.AVERAGE_CHORD, -] -if not compute_volume_coeff: - in_htail_array.append( - r"\textcolor{gray}{"+Aircraft.HorizontalTail.VOLUME_COEFFICIENT+"}") -x.add_input("htail", in_htail_array) -in_vtail_array = [ - Aircraft.VerticalTail.MOMENT_RATIO, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.VerticalTail.TAPER_RATIO, - Aircraft.Wing.AREA, - Aircraft.Wing.SPAN, -] -if not compute_volume_coeff: - in_vtail_array.append( - r"\textcolor{gray}{"+Aircraft.VerticalTail.VOLUME_COEFFICIENT+"}") -x.add_input("vtail", in_vtail_array) - -# make connections -if compute_volume_coeff: - x.connect("hvc", "htail", [ - r"\textcolor{gray}{"+Aircraft.HorizontalTail.VOLUME_COEFFICIENT+"}"]) - x.connect("vvc", "vtail", [ - r"\textcolor{gray}{"+Aircraft.VerticalTail.VOLUME_COEFFICIENT+"}"]) - -# create outputs -x.add_output("htail", [ - Aircraft.HorizontalTail.AREA, - Aircraft.HorizontalTail.SPAN, - Aircraft.HorizontalTail.ROOT_CHORD, - Aircraft.HorizontalTail.AVERAGE_CHORD, - Aircraft.HorizontalTail.MOMENT_ARM, -], side="right") -x.add_output("vtail", [ - Aircraft.VerticalTail.AREA, - Aircraft.VerticalTail.SPAN, - Aircraft.VerticalTail.ROOT_CHORD, - Aircraft.VerticalTail.AVERAGE_CHORD, - Aircraft.VerticalTail.MOMENT_ARM -], side="right") - -x.write("empennage_size_xdsm") -# x.write_sys_specs("empennage_size_specs") diff --git a/aviary/xdsm/engineDeck_xdsm.py b/aviary/xdsm/engineDeck_xdsm.py deleted file mode 100644 index 88b09dbdf..000000000 --- a/aviary/xdsm/engineDeck_xdsm.py +++ /dev/null @@ -1,46 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, METAMODEL, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic - -x = XDSM() - -use_hybrid_throttle = False -# use_thrust = False - -x.add_system('engine', METAMODEL, ['Engine~Interpolator'], stack=True) -x.add_system('scaling', FUNC, [r'Engine~Scaling'], stack=True) - -# create inputs -engine_inputs = [ - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MACH, - Dynamic.Mission.THROTTLE, -] -if use_hybrid_throttle: - engine_inputs.append(r"\textcolor{gray}{"+Dynamic.Mission.HYBRID_THROTTLE+"}") -x.add_input('engine', engine_inputs) - -x.add_input("scaling", [ - Dynamic.Mission.MACH, - Aircraft.Engine.SCALE_FACTOR, -]) - -# make connections -x.connect("engine", "scaling", [ - 'thrust_net_unscaled', - 'thrust_net_max_unscaled', - 'fuel_flow_rate_unscaled', - 'electric_power_unscaled', - 'nox_rate_unscaled', -], stack=True) - -# create outputs -x.add_output("scaling", [ - Dynamic.Mission.THRUST, - Dynamic.Mission.THRUST_MAX, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, - Dynamic.Mission.ELECTRIC_POWER, - Dynamic.Mission.NOX_RATE -], stack=True, side='right') - -x.write("engineDeck_xdsm") -# x.write_sys_specs("engineDeck_specs") diff --git a/aviary/xdsm/equipment_and_useful_load_mass_xdsm.py b/aviary/xdsm/equipment_and_useful_load_mass_xdsm.py deleted file mode 100644 index dbf30f2e9..000000000 --- a/aviary/xdsm/equipment_and_useful_load_mass_xdsm.py +++ /dev/null @@ -1,42 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, XDSM -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -simplified = False -show_outputs = True - -# Create subsystem components -x.add_system("equip", FUNC, ["EquipAndUsefulMass"]) - -### make input connections ### -if simplified is True: - # FixedEquipMass - x.add_input("equip", ["InputValues"]) -else: - x.add_input("equip", [ - Mission.Design.GROSS_MASS, - Aircraft.Design.EQUIPMENT_MASS_COEFFICIENTS, - Aircraft.Fuselage.LENGTH, - Aircraft.Wing.SPAN, - Aircraft.LandingGear.TOTAL_MASS, - Aircraft.Controls.TOTAL_MASS, - Aircraft.HorizontalTail.AREA, - Aircraft.VerticalTail.AREA, - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Fuel.WING_FUEL_FRACTION, - Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS, - Aircraft.Wing.AREA, - ]) - -### add outputs ### -if show_outputs is True: - x.add_output("equip", [ - Aircraft.Design.FIXED_USEFUL_LOAD, - Aircraft.Design.FIXED_EQUIPMENT_MASS, - ], side="right") - -x.write("equipment_and_useful_load_mass_xdsm") -x.write_sys_specs("equipment_and_useful_load_mass_specs") diff --git a/aviary/xdsm/fixed_mass_xdsm.py b/aviary/xdsm/fixed_mass_xdsm.py deleted file mode 100644 index 56c318755..000000000 --- a/aviary/xdsm/fixed_mass_xdsm.py +++ /dev/null @@ -1,219 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, XDSM -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -simplified = False -show_outputs = True -has_hybrid_system = False -has_propellers = False - -# Create subsystem components -x.add_system("params", FUNC, ["MassParameters"]) -x.add_system("payload", FUNC, ["PayloadMass"]) -x.add_system("tail", FUNC, ["TailMass"]) -x.add_system("HL", FUNC, ["HighLiftMass"]) -x.add_system("controls", FUNC, ["ControlMass"]) -x.add_system("gear", FUNC, ["GearMass"]) -if has_hybrid_system: - x.add_system("aug", FUNC, [r"\textcolor{gray}{ElectricAugmentationMass}"]) -x.add_system("engine", FUNC, ["EngineMass"]) - -### make input connections ### -if simplified is True: - x.add_input("params", ["InputValues"]) - x.add_input("payload", ["InputValues"]) - x.add_input("tail", ["InputValues"]) - x.add_input("HL", ["InputValues"]) - x.add_input("controls", ["InputValues"]) - x.add_input("gear", ["InputValues"]) - if has_hybrid_system: - x.add_input("aug", [r"\textcolor{gray}{InputValues}"]) - x.add_input("engine", ["InputValues"]) -else: - x.add_input("params", [ - Aircraft.Wing.SPAN, - Aircraft.Wing.SWEEP, # SweepC4 - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.ASPECT_RATIO, - "max_mach", - Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS, # StrutX - Aircraft.LandingGear.MAIN_GEAR_LOCATION, - ]) - x.add_input("payload", [ - # Aircraft.CrewPayload.PASSENGER_MASS_WITH_BAGS, # PaxMass. This is an option - Aircraft.CrewPayload.CARGO_MASS, # CargoMass - ]) - x.add_input("tail", [ - Aircraft.Wing.SWEEP, - Mission.Design.GROSS_MASS, # GrossMassInitial - "min_dive_vel", - Aircraft.Wing.SPAN, - Aircraft.VerticalTail.TAPER_RATIO, # TaperRatioVtail - Aircraft.VerticalTail.ASPECT_RATIO, # ARVtail - Aircraft.VerticalTail.SWEEP, # QuarterSweepTail - Aircraft.VerticalTail.SPAN, # SpanVtail - Aircraft.HorizontalTail.MASS_COEFFICIENT, # CoefHtail - Aircraft.Fuselage.LENGTH, - Aircraft.HorizontalTail.SPAN, - Aircraft.LandingGear.TAIL_HOOK_MASS_SCALER, - Aircraft.HorizontalTail.TAPER_RATIO, # TaperRatioHtail - Aircraft.VerticalTail.MASS_COEFFICIENT, # CoefVtail - Aircraft.HorizontalTail.AREA, # HtailArea - Aircraft.HorizontalTail.MOMENT_ARM, # HtailMomArm - Aircraft.HorizontalTail.THICKNESS_TO_CHORD, # TcRatioRootHtail - Aircraft.HorizontalTail.ROOT_CHORD, # RootChordHtail - Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, # TailLoc - Aircraft.VerticalTail.AREA, - Aircraft.VerticalTail.MOMENT_ARM, # VtailMomArm - Aircraft.VerticalTail.THICKNESS_TO_CHORD, # TcRatioRootVtail - Aircraft.VerticalTail.ROOT_CHORD, # RootChordVtail - # "CMassTrendHighLift", - ]) - x.add_input("HL", [ - "density", - Aircraft.Wing.SWEEP, - # "GrossMassInitial", - # "minDiveVel", - Aircraft.Wing.AREA, - Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT, # CMassTrendHighLift - # "wing_area", - # "num_flaps", - Aircraft.Wing.SLAT_CHORD_RATIO, # slat_chord_ratio - Aircraft.Wing.FLAP_CHORD_RATIO, # flap_chord_ratio - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.FLAP_SPAN_RATIO, # flap_span_ratio - Aircraft.Wing.SLAT_SPAN_RATIO, # slat_span_ratio - Aircraft.Wing.LOADING, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, # tc_ratio_root - Aircraft.Wing.SPAN, - Aircraft.Fuselage.AVG_DIAMETER, # cabin_width - Aircraft.Wing.CENTER_CHORD, - Mission.Landing.LIFT_COEFFICIENT_MAX, # CL_max_flaps_landing - ]) - x.add_input("controls", [ - Aircraft.Wing.SURFACE_CONTROL_MASS_COEFFICIENT, - Mission.Design.GROSS_MASS, # GrossMassInitial - "min_dive_vel", - Aircraft.Wing.AREA, - # "CMassTrendWingControl", - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, # ULF - Aircraft.Design.COCKPIT_CONTROL_MASS_COEFFICIENT, # CMassTrendCockpitControl - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS, # StabAugMass - Aircraft.Controls.COCKPIT_CONTROL_MASS_SCALER, # CK15 - Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, # CK18 - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS_SCALER, # CK19 - Aircraft.Controls.CONTROL_MASS_INCREMENT, # DeltaControlMass - ]) - x.add_input("gear", [ - Aircraft.Wing.MOUNTING_TYPE, - Mission.Design.GROSS_MASS, # GrossMassInitial - Aircraft.LandingGear.MASS_COEFFICIENT, # CGearMass - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, # CMainGear - Aircraft.Nacelle.CLEARANCE_RATIO, # ClearanceRatio - Aircraft.Nacelle.AVG_DIAMETER, # NacelleDiam - ]) - - if has_hybrid_system: - x.add_input("aug", [ - r"\textcolor{gray}{motor_power}", # MotorPowerKw - r"\textcolor{gray}{motor_voltage}", # MotorVoltage - r"\textcolor{gray}{max_amp_per_wire}", # MaxAmpPerWire - r"\textcolor{gray}{safety_factor}", # SafetyFactor - r"\textcolor{gray}{" - + Aircraft.Electrical.HYBRID_CABLE_LENGTH + "}", # CableLen - r"\textcolor{gray}{wire_area}", - r"\textcolor{gray}{rho_wire}", - r"\textcolor{gray}{battery_energy}", - r"\textcolor{gray}{motor_eff}", - r"\textcolor{gray}{inverter_eff}", - r"\textcolor{gray}{transmission_eff}", - r"\textcolor{gray}{battery_eff}", - r"\textcolor{gray}{rho_battery}", - r"\textcolor{gray}{motor_spec_mass}", - r"\textcolor{gray}{inverter_spec_mass}", - r"\textcolor{gray}{TMS_spec_mass}", - ]) - # engine - engine_inputs = [ - Aircraft.Engine.MASS_SPECIFIC, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Nacelle.MASS_SPECIFIC, - Aircraft.Nacelle.SURFACE_AREA, - Aircraft.Engine.PYLON_FACTOR, - Aircraft.Engine.ADDITIONAL_MASS_FRACTION, - Aircraft.Engine.MASS_SCALER, - Aircraft.Propulsion.MISC_MASS_SCALER, - Aircraft.Engine.WING_LOCATIONS, - Aircraft.LandingGear.MAIN_GEAR_LOCATION, - ] - if has_hybrid_system: - engine_inputs.append(r"\textcolor{gray}{aug_mass}") - if has_propellers: - engine_inputs.append(r"\textcolor{gray}{prop_mass}") - x.add_input("engine", engine_inputs) - -### make component connections ### -x.connect("gear", "engine", ["main_gear_mass"]) -if has_hybrid_system: - x.connect("aug", "engine", [r"\textcolor{gray}{aug_mass}"]) - -### add outputs ### -if show_outputs is True: - x.add_output("params", [ - Aircraft.Wing.MATERIAL_FACTOR, # CMaterial - "c_strut_braced", - "c_gear_loc", - Aircraft.Engine.POSITION_FACTOR, # CEngPos - "half_sweep", - ], side="right") - - x.add_output("payload", [ - Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, - "payload_mass_des", - "payload_mass_max", - ], side="right") - - x.add_output("tail", [ - "loc_MAC_vtail", - Aircraft.HorizontalTail.MASS, - Aircraft.VerticalTail.MASS - ], side="right") - - x.add_output("HL", [ - Aircraft.Wing.HIGH_LIFT_MASS, - "flap_mass", - "slat_mass", - ], side="right") - - x.add_output("controls", [ - Aircraft.Controls.TOTAL_MASS, - Aircraft.Wing.SURFACE_CONTROL_MASS, - ], side="right") - - x.add_output("gear", [ - Aircraft.LandingGear.TOTAL_MASS, - "main_gear_mass", - ], side="right") - - if has_hybrid_system: - x.add_output("aug", [ - r"\textcolor{gray}{aug_mass}", - ], side="right") - - # engine - engine_outputs = [ - "eng_comb_mass", - "wing_mounted_mass", - "pylon_mass", - Aircraft.Propulsion.TOTAL_ENGINE_MASS, - Aircraft.Nacelle.MASS, - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, - Aircraft.Engine.ADDITIONAL_MASS, - ] - if has_propellers: - engine_outputs.append(r"\textcolor{gray}{prop_mass_all}") - x.add_output("engine", engine_outputs, side="right") - -x.write("fixed_mass_xdsm") -x.write_sys_specs("fixed_mass_specs") diff --git a/aviary/xdsm/flaps_xdsm.py b/aviary/xdsm/flaps_xdsm.py deleted file mode 100644 index 37b997f58..000000000 --- a/aviary/xdsm/flaps_xdsm.py +++ /dev/null @@ -1,107 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, IGROUP, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic - -x = XDSM() - -simplified = False # for testflo run, it must be False - -# Create subsystem components -x.add_system("basic", GROUP, [r"\textbf{BasicFlapsCalculations}"]) -x.add_system("CL_max", FUNC, [r"\textbf{CLmaxCalculation}"]) -x.add_system("tables", IGROUP, [r"\textbf{LookupTables}"]) -x.add_system("increments", FUNC, [r"\textbf{LiftAndDragIncrements}"]) - -# create inputs -if simplified is True: - x.add_input("basic", ["InputValues"]) - x.add_input("CL_max", ["InputValues"]) - x.add_input("tables", ["InputValues"]) - x.add_input("increments", ["InputValues"]) -else: - x.add_input("basic", [ - Aircraft.Wing.SWEEP, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.FLAP_CHORD_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.CENTER_CHORD, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Aircraft.Wing.SPAN, - Aircraft.Wing.SLAT_CHORD_RATIO, - "slat_defl", - Aircraft.Wing.OPTIMUM_SLAT_DEFLECTION, - "flap_defl", - Aircraft.Wing.OPTIMUM_FLAP_DEFLECTION, - Aircraft.Wing.ROOT_CHORD, - Aircraft.Fuselage.LENGTH, - Aircraft.Wing.LEADING_EDGE_SWEEP, - ]) - x.add_input("CL_max", [ - Aircraft.Wing.FLAP_LIFT_INCREMENT_OPTIMUM, - Aircraft.Wing.LOADING, - Dynamic.Mission.STATIC_PRESSURE, - Aircraft.Wing.AVERAGE_CHORD, - Aircraft.Wing.MAX_LIFT_REF, - Aircraft.Wing.SLAT_LIFT_INCREMENT_OPTIMUM, - "fus_lift", # fuselage lift increment - "kinematic_viscosity", - Dynamic.Mission.TEMPERATURE, - Dynamic.Mission.SPEED_OF_SOUND, - ]) - x.add_input("tables", [ - Aircraft.Wing.FLAP_CHORD_RATIO, - Aircraft.Wing.FLAP_SPAN_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED, - "flap_defl", - ]) - x.add_input("increments", [ - Aircraft.Wing.FLAP_DRAG_INCREMENT_OPTIMUM, - Aircraft.Wing.FLAP_LIFT_INCREMENT_OPTIMUM, - ]) - -# make connections -x.connect("basic", "increments", ["VLAM8", "VDEL4", "VDEL5"]) -x.connect("basic", "CL_max", ["VLAM8", "VLAM9", "VLAM12"]) -x.connect("basic", "tables", [ - "slat_defl_ratio", - "flap_defl_ratio", - "body_to_span_ratio", - Aircraft.Wing.SLAT_SPAN_RATIO, - "chord_to_body_ratio", -]) -x.connect("CL_max", "tables", ["reynolds", Dynamic.Mission.MACH]) -x.connect("tables", "increments", [ - "VDEL1", - "VDEL2", - "VDEL3", - "VLAM3", - "VLAM4", - "VLAM5", - "VLAM6", - "VLAM7", - "VLAM13", - "VLAM14", -]) -x.connect("tables", "CL_max", [ - "VLAM1", - "VLAM2", - "VLAM3", - "VLAM4", - "VLAM5", - "VLAM6", - "VLAM7", - "VLAM10", - "VLAM11", - "VLAM13", - "VLAM14", - "fus_lift", -]) - -# create outputs -x.add_output("increments", ["delta_CL", "delta_CD"], side="right") -x.add_output("CL_max", ["CL_max"], side="right") - -x.write("flaps_xdsm") -x.write_sys_specs("flaps_specs") diff --git a/aviary/xdsm/fuel_mass_xdsm.py b/aviary/xdsm/fuel_mass_xdsm.py deleted file mode 100644 index cb82f5bdb..000000000 --- a/aviary/xdsm/fuel_mass_xdsm.py +++ /dev/null @@ -1,137 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, IFUNC, XDSM -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -simplified = True -show_outputs = True - -# Create subsystem components -x.add_system("sys_and_fus", FUNC, ["FuelSysAndFullFuselageMass"]) -x.add_system("fus_and_struct", FUNC, ["FuselageAndStructMass"]) -x.add_system("fuel", FUNC, ["FuelMass"]) -x.add_system("fuel_and_oem", FUNC, ["FuelAndOEMOutputs"]) -x.add_system("body", IFUNC, ["BodyTankCalculations"]) - -### make input connections ### -if simplified is True: - x.add_input("sys_and_fus", ["InputValues"]) - x.add_input("fus_and_struct", ["InputValues"]) - x.add_input("fuel", ["InputValues"]) - x.add_input("fuel_and_oem", ["InputValues"]) -else: - x.add_input("sys_and_fus", [ - "wing_mounted_mass", - Mission.Design.GROSS_MASS, # GrossMassInitial - Aircraft.Wing.MASS, # TotalWingMass - Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, # CK21 - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, # CMassTrendFuelSys - Aircraft.Fuel.DENSITY, # RhoFuel - Aircraft.Fuel.FUEL_MARGIN, # FuelMargin - ]) - - x.add_input("fus_and_struct", [ - Aircraft.Wing.MASS, # TotalWingMass - Aircraft.Fuselage.MASS_COEFFICIENT, # CFuselage - Aircraft.Fuselage.WETTED_AREA, # FusSA - Aircraft.Fuselage.AVG_DIAMETER, # CabinWidth - Aircraft.TailBoom.LENGTH, # CabinLenTailboom - "pylon_len", - "min_dive_vel", - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, # PDiffFus - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, # ULF - "MAT", - Aircraft.Wing.MASS_SCALER, # CK8 - Aircraft.HorizontalTail.MASS_SCALER, # CK9 - Aircraft.HorizontalTail.MASS, # HtailMass - Aircraft.VerticalTail.MASS_SCALER, # CK10 - Aircraft.VerticalTail.MASS, # VtailMass - Aircraft.Fuselage.MASS_SCALER, # CK11 - Aircraft.LandingGear.TOTAL_MASS_SCALER, # CK12 - Aircraft.LandingGear.TOTAL_MASS, # LandingGearMass - Aircraft.Engine.POD_MASS_SCALER, # CK14 - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, # SecMass - Aircraft.Design.STRUCTURAL_MASS_INCREMENT, # DeltaStructMass - ]) - - x.add_input("fuel", [ - "eng_comb_mass", - "payload_mass_des", - "payload_mass_max", - Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, # PayloadMass - Mission.Design.GROSS_MASS, # GrossMassInitial - Aircraft.Controls.TOTAL_MASS, # ControlMass - Aircraft.Design.FIXED_EQUIPMENT_MASS, # FixedEquipMass - Aircraft.Design.FIXED_USEFUL_LOAD, # UsefulMass - Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, # CK21 - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, # CMassTrendFuelSys - Aircraft.Fuel.DENSITY, # RhoFuel - Aircraft.Fuel.FUEL_MARGIN, # FuelMargin - ]) - - x.add_input("fuel_and_oem", [ - Aircraft.Fuel.DENSITY, # RhoFuel - Mission.Design.GROSS_MASS, # GrossMassInitial - # Aircraft.Propulsion.MASS, - Aircraft.Controls.TOTAL_MASS, # ControlMass - # Aircraft.Design.STRUCTURE_MASS, - Aircraft.Design.FIXED_EQUIPMENT_MASS, # FixedEquipMass - Aircraft.Design.FIXED_USEFUL_LOAD, # UsefulMass - Mission.Design.FUEL_MASS_REQUIRED, - Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, # GeometricFuelVol - Aircraft.Fuel.FUEL_MARGIN, # FuelMargin - Aircraft.Fuel.TOTAL_CAPACITY, - ]) - - x.add_input("body", [ - Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, # GeometricFuelVol - Aircraft.Fuel.DENSITY, # RhoFuel - Mission.Design.GROSS_MASS # GrossMassInitial - ]) - -### make component connections ### -x.connect("sys_and_fus", "fus_and_struct", ["fus_mass_full"]) # FusMassFull -x.connect("sys_and_fus", "fuel", [Aircraft.Fuel.FUEL_SYSTEM_MASS]) -x.connect("fus_and_struct", "fuel", [Aircraft.Design.STRUCTURE_MASS]) -x.connect("fus_and_struct", "fuel_and_oem", [Aircraft.Design.STRUCTURE_MASS]) -x.connect("fuel", "sys_and_fus", [Mission.Design.FUEL_MASS]) # FuelMassDes -x.connect("fuel", "fuel_and_oem", [ - Aircraft.Propulsion.MASS, - Mission.Design.FUEL_MASS_REQUIRED, # ReqFuelMass -]) -x.connect("fuel", "body", [ - "fuel_mass_min", # FuelMassMin - Mission.Design.FUEL_MASS_REQUIRED, # ReqFuelMass - Mission.Design.FUEL_MASS, # FuelMassDes -]) -x.connect("fuel_and_oem", "body", [ - Aircraft.Fuel.WING_VOLUME_DESIGN, # DesignFuelVol - Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, # MaxWingfuelVol - "max_wingfuel_mass", # MaxWingfuelMass - Aircraft.Design.OPERATING_MASS, -]) -x.connect("body", "sys_and_fus", ["wingfuel_mass_min"]) # WingfuelMassMin -x.connect("body", "fuel_and_oem", [Aircraft.Fuel.TOTAL_CAPACITY]) # MaxFuelAvail - -### add outputs ### -if show_outputs is True: - # fus_and_struct - x.add_output("fus_and_struct", [Aircraft.Fuselage.MASS], side="right") - - # fuel_and_oem - x.add_output("fuel_and_oem", [ - "OEM_wingfuel_mass", - "OEM_fuel_vol", - "payload_mass_max_fuel", # PayloadMassMaxFuel - "volume_wingfuel_mass", # VolumeWingfuelMass - ], side="right") - - # body - x.add_output("body", [ - Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY, # ExtraFuelMass - "extra_fuel_volume", # ExtraFuelVolume - "max_extra_fuel_mass", # MaxExtraFuelMass - ], side="right") - -x.write("fuel_mass_xdsm") -x.write_sys_specs("fuel_mass_specs") diff --git a/aviary/xdsm/fuselage_size_xdsm.py b/aviary/xdsm/fuselage_size_xdsm.py deleted file mode 100644 index 41ba303ec..000000000 --- a/aviary/xdsm/fuselage_size_xdsm.py +++ /dev/null @@ -1,48 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, XDSM -from aviary.variable_info.variables import Aircraft - -x = XDSM() - -# Create subsystem components -x.add_system("fus_parameters", FUNC, ["FuselageParameters"]) -x.add_system("fus_size", FUNC, ["FuselageSize"]) - -# create inputs -x.add_input("fus_parameters", [ - # Aircraft.Fuselage.NUM_SEATS_ABREAST, # option - # Aircraft.Fuselage.SEAT_WIDTH, # option - # Aircraft.Fuselage.NUM_AISLES, # option - # Aircraft.Fuselage.AISLE_WIDTH, # option - # Aircraft.Fuselage.SEAT_PITCH, # option - Aircraft.Fuselage.DELTA_DIAMETER, - Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, -]) -x.add_input("fus_size", [ - Aircraft.Fuselage.NOSE_FINENESS, - Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, - Aircraft.Fuselage.TAIL_FINENESS, - Aircraft.Fuselage.WETTED_AREA_FACTOR, -]) - -# make connections -x.connect("fus_parameters", "fus_size", [ - "cabin_height", - "cabin_len", - "nose_height", -]) - -# create outputs -x.add_output("fus_parameters", [ - Aircraft.Fuselage.AVG_DIAMETER, - "cabin_height", - "cabin_len", - "nose_height", -], side="right") -x.add_output("fus_size", [ - Aircraft.Fuselage.LENGTH, - Aircraft.Fuselage.WETTED_AREA, - Aircraft.TailBoom.LENGTH, -], side="right") - -x.write("fuselage_size_xdsm") -# x.write_sys_specs("fuselage_size_specs") diff --git a/aviary/xdsm/groundroll_xdsm.py b/aviary/xdsm/groundroll_xdsm.py deleted file mode 100644 index c032279f2..000000000 --- a/aviary/xdsm/groundroll_xdsm.py +++ /dev/null @@ -1,90 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -with_EXE_Comps = False - -# Create subsystem components -x.add_system("atmos", FUNC, ["USatm"]) -x.add_system("fc", FUNC, ["FlightConditions"]) -x.add_system("ialpha", FUNC, ["InitAlpha"]) -x.add_system("prop", GROUP, ["Propulsion"]) -x.add_system("aero", GROUP, ["LowspeedAero"]) -x.add_system("eom", GROUP, [r"\textbf{EOM}"]) -if with_EXE_Comps: - x.add_system("exec", FUNC, ["Exec"]) - x.add_system("exec2", FUNC, ["Exec2"]) - x.add_system("exec3", FUNC, ["Exec3"]) - -# create inputs -x.add_input("atmos", [Dynamic.Mission.ALTITUDE]) -x.add_input("fc", ["TAS"]) -x.add_input("ialpha", ["i_wing"]) -x.add_input("eom", [ - "mass", - "TAS", - Dynamic.Mission.FLIGHT_PATH_ANGLE, - Aircraft.Wing.INCIDENCE, -]) -x.add_input("aero", [ - "t_curr", - "dt_flaps", - "dt_gear", - "t_init_flaps", - "t_init_gear", - "aircraft:*", - # Aircraft.Wing.FLAP_DEFLECTION_TAKEOFF, # flap_defl - # Aircraft.Wing.HEIGHT, - # Aircraft.Wing.SPAN, - # Aircraft.Wing.AREA, - Dynamic.Mission.ALTITUDE, - Mission.Takeoff.AIRPORT_ALTITUDE, - Mission.Design.GROSS_MASS, - # 'aero_ramps.flap_factor:initial_val', - # 'aero_ramps.gear_factor:initial_val', - # 'aero_ramps.flap_factor:final_val', - # 'aero_ramps.gear_factor:final_val', -]) -x.add_input("prop", [ - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.THROTTLE, - Aircraft.Engine.SCALE_FACTOR, -]) - - -# make connections -x.connect("atmos", "fc", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -x.connect("fc", "prop", [Dynamic.Mission.MACH]) -x.connect("fc", "aero", [Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.MACH]) -x.connect("prop", "eom", [Dynamic.Mission.THRUST_TOTAL]) -x.connect("aero", "eom", [Dynamic.Mission.LIFT, Dynamic.Mission.DRAG]) -x.connect("ialpha", "aero", ["alpha"]) -x.connect("ialpha", "eom", ["alpha"]) -if with_EXE_Comps: - x.add_input("exec", ["TAS"]) - x.connect("eom", "exec", ["TAS_rate"]) - x.connect("eom", "exec2", ["TAS_rate"]) - x.connect("prop", "exec2", ["fuel_flow_rate_negative_total"]) # mass_rate - x.connect("exec2", "exec3", ["dt_dv"]) - -# create outputs -eom_output_list = [ - Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, - Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.DISTANCE_RATE, - "alpha_rate", - "normal_force", - "fuselage_pitch", -] -if not with_EXE_Comps: - eom_output_list.append("TAS_rate") -x.add_output("eom", eom_output_list, side="right") - -if with_EXE_Comps: - x.add_output("exec", ["over_a",], side="right") - x.add_output("exec3", ["dmss_dv",], side="right") -x.add_output("fc", ["EAS",], side="right") - -x.write("groundroll_xdsm") -x.write_sys_specs("groundroll_specs") diff --git a/aviary/xdsm/landing_xdsm.py b/aviary/xdsm/landing_xdsm.py deleted file mode 100644 index bf0a456f9..000000000 --- a/aviary/xdsm/landing_xdsm.py +++ /dev/null @@ -1,123 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, METAMODEL, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -show_outputs = True - -# Create subsystem components -x.add_system("landing_alt", FUNC, [r"\textbf{LandingAlt}"]) -x.add_system("atmos_approach", FUNC, ["ApproachAtmosphere"]) -x.add_system("fc_approach", FUNC, ["ApproachFlightConditions"]) -x.add_system("prop_approach", GROUP, ["ApproachPropulsion"]) -x.add_system("aero_approach", GROUP, ["ApproachLowSpeedAero", "(alpha~in)"]) -x.add_system("glide", FUNC, [r"\textbf{GlideCondition}"]) -x.add_system("atmos_touchdown", FUNC, ["TouchdownAtmosphere"]) -x.add_system("fc_touchdown", FUNC, ["TouchdownFlightConditions"]) -x.add_system("aero_touchdown", GROUP, ["TouchdownLowSpeedAero"]) -x.add_system("groundroll", FUNC, [r"\textbf{GroundRoll}"]) - -# create inputs -x.add_input("landing_alt", [ - Mission.Landing.OBSTACLE_HEIGHT, - Mission.Landing.AIRPORT_ALTITUDE, -]) -x.add_input("fc_approach", [Mission.Landing.INITIAL_MACH]) -x.add_input("prop_approach", [ - Dynamic.Mission.THROTTLE, - Mission.Landing.INITIAL_MACH, -]) -x.add_input("aero_approach", [ - "aero_app.alpha", - "t_init_flaps", - "t_init_gear", - Mission.Landing.INITIAL_MACH, - Mission.Landing.AIRPORT_ALTITUDE, - Mission.Design.GROSS_MASS, - Mission.Landing.LIFT_COEFFICIENT_FLAP_INCREMENT, # dCL_flaps_model - Mission.Landing.DRAG_COEFFICIENT_FLAP_INCREMENT, # dCD_flaps_model - # "flap_defl", # Aircraft.Wing.FLAP_DEFLECTION_LANDING - "aircraft:*", -]) -x.add_input("glide", [ - Mission.Landing.MAXIMUM_SINK_RATE, - Mission.Landing.GLIDE_TO_STALL_RATIO, - Mission.Landing.MAXIMUM_FLARE_LOAD_FACTOR, - Mission.Landing.TOUCHDOWN_SINK_RATE, - Mission.Landing.BRAKING_DELAY, - Dynamic.Mission.MASS, - Aircraft.Wing.AREA, -]) -x.add_input("atmos_touchdown", [Mission.Landing.AIRPORT_ALTITUDE]) -x.add_input("aero_touchdown", [ - Aircraft.Wing.INCIDENCE, - Mission.Landing.AIRPORT_ALTITUDE, - Aircraft.Wing.AREA, - Aircraft.Wing.HEIGHT, - Aircraft.Wing.SPAN, - Mission.Design.GROSS_MASS, - Aircraft.Wing.FLAP_DEFLECTION_LANDING, # flap_defl -]) -x.add_input("groundroll", ["mass"]) - -# make connections -x.connect("landing_alt", "atmos_approach", [Mission.Landing.INITIAL_ALTITUDE]) -x.connect("landing_alt", "prop_approach", [Mission.Landing.INITIAL_ALTITUDE]) -x.connect("landing_alt", "aero_approach", [Mission.Landing.INITIAL_ALTITUDE]) -x.connect("landing_alt", "glide", [Mission.Landing.INITIAL_ALTITUDE]) - -x.connect("atmos_approach", "fc_approach", [ - "rho_app", - "speed_of_sound_app", # Dynamic.Mission.SPEED_OF_SOUND -]) -# x.connect("atmos_approach", "prop_approach", ["T_app", "P_app"]) -x.connect("atmos_approach", "glide", ["rho_app"]) - -x.connect("fc_approach", "aero_approach", [ - "dynamic_pressure_app", # Dynamic.Mission.DYNAMIC_PRESSURE -]) - -x.connect("prop_approach", "groundroll", ["thrust_idle"]) - -x.connect("aero_approach", "glide", ["CL_max"]) -x.connect("aero_approach", "groundroll", ["CL_max"]) - -x.connect("glide", "groundroll", [ - Mission.Landing.STALL_VELOCITY, - "TAS_touchdown", - "density_ratio", - "wing_loading_land", - "glide_distance", - "tr_distance", # transition distance - "delay_distance", -]) -x.connect("glide", "fc_touchdown", ["TAS_touchdown"]) - -x.connect("atmos_touchdown", "fc_touchdown", [ - "rho_touchdown", - "speed_of_sound_touchdown", -]) - -x.connect("fc_touchdown", "aero_touchdown", [ - "mach_touchdown", - "dynamic_pressure_touchdown", -]) - -x.connect("aero_touchdown", "groundroll", ["touchdown_CD", "touchdown_CL"]) - -# create outputs -if show_outputs: - x.add_output("glide", [ - Mission.Landing.INITIAL_VELOCITY, - "theta", - "flare_alt", - ], side="right") - x.add_output("groundroll", [ - # Mission.Landing.INITIAL_VELOCITY, - "ground_roll_distance", - Mission.Landing.GROUND_DISTANCE, - "average_acceleration", # ABAR - ], side="right") - -x.write("landing_xdsm") -x.write_sys_specs("landing_specs") diff --git a/aviary/xdsm/mass_and_sizing_basic_xdsm.py b/aviary/xdsm/mass_and_sizing_basic_xdsm.py deleted file mode 100644 index 3d93f5d1c..000000000 --- a/aviary/xdsm/mass_and_sizing_basic_xdsm.py +++ /dev/null @@ -1,282 +0,0 @@ -""" -This XDSM is for the case with no strut, no fold, volume coefficients input, no -augmented system -""" - -from pyxdsm.XDSM import FUNC, GROUP, IGROUP, XDSM -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -simplified = False -# HAS_FOLD = False -# HAS_STRUT = False -HAS_PROPELLERS = True -# has_hybrid_system = False # see fixed_mass_xdsm.py - -# Create subsystem components -x.add_system("size", GROUP, [r"\textbf{SizeGroup}"]) -x.add_system("design_load", GROUP, [r"\textbf{DesignLoadGroup}"]) -x.add_system("fixed_mass", GROUP, ["FixedMassGroup"]) -x.add_system("equip", FUNC, [r"\textbf{EquipAndUsefulMass}"]) -x.add_system("wing_mass", IGROUP, [r"\textbf{WingMassGroup}"]) -x.add_system("fuel_mass", IGROUP, [r"\textbf{FuelMassGroup}"]) - -### make input connections ### - -# size -size_inputs = [ - # connect inputs: - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.SWEEP, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Mission.Design.GROSS_MASS, - Aircraft.Wing.LOADING, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.HorizontalTail.TAPER_RATIO, - Aircraft.Fuel.WING_FUEL_FRACTION, - Aircraft.VerticalTail.TAPER_RATIO, - # direct inputs: - Aircraft.Fuselage.DELTA_DIAMETER, - Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, - Aircraft.Fuselage.NOSE_FINENESS, - Aircraft.Fuselage.TAIL_FINENESS, - Aircraft.Fuselage.WETTED_AREA_FACTOR, - Aircraft.Wing.THICKNESS_TO_CHORD_TIP, - Aircraft.HorizontalTail.MOMENT_RATIO, - Aircraft.VerticalTail.MOMENT_RATIO, - Aircraft.HorizontalTail.ASPECT_RATIO, - Aircraft.Engine.REFERENCE_DIAMETER, - Aircraft.Engine.SCALE_FACTOR, - Aircraft.Nacelle.CORE_DIAMETER_RATIO, - Aircraft.Nacelle.FINENESS, - Aircraft.HorizontalTail.VOLUME_COEFFICIENT, - Aircraft.VerticalTail.VOLUME_COEFFICIENT, - # Aircraft.Engine.WING_LOCATIONS, -] -if simplified: - x.add_input("size", ["InputValues"]) -else: - x.add_input("size", size_inputs) - -# design_load -if simplified: - x.add_input("design_load", ["InputValues"]) -else: - x.add_input("design_load", [ - # connect input: - Aircraft.Wing.LOADING, - # direct input: - Aircraft.Design.MAX_STRUCTURAL_SPEED, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.SWEEP, - Mission.Design.MACH - ]) - -# fixed_mass -fixed_input = [ - # connect inputs: - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.SWEEP, - Mission.Design.GROSS_MASS, - Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.HorizontalTail.TAPER_RATIO, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Engine.WING_LOCATIONS, - Aircraft.VerticalTail.TAPER_RATIO, - # direct inputs: - Aircraft.CrewPayload.CARGO_MASS, - Aircraft.VerticalTail.SWEEP, - Aircraft.HorizontalTail.MASS_COEFFICIENT, - Aircraft.LandingGear.TAIL_HOOK_MASS_SCALER, - Aircraft.VerticalTail.MASS_COEFFICIENT, - Aircraft.HorizontalTail.THICKNESS_TO_CHORD, - Aircraft.VerticalTail.THICKNESS_TO_CHORD, - Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT, - Aircraft.Wing.SURFACE_CONTROL_MASS_COEFFICIENT, - Aircraft.Design.COCKPIT_CONTROL_MASS_COEFFICIENT, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS, - Aircraft.Controls.COCKPIT_CONTROL_MASS_SCALER, - Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS_SCALER, - Aircraft.Controls.CONTROL_MASS_INCREMENT, - Aircraft.LandingGear.MASS_COEFFICIENT, - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, - Aircraft.Engine.MASS_SPECIFIC, - Aircraft.Nacelle.MASS_SPECIFIC, - Aircraft.Engine.PYLON_FACTOR, - Aircraft.Engine.ADDITIONAL_MASS_FRACTION, - Aircraft.Engine.MASS_SCALER, - Aircraft.Propulsion.MISC_MASS_SCALER, - Aircraft.LandingGear.MAIN_GEAR_LOCATION, - # Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Wing.MOUNTING_TYPE, - Aircraft.Nacelle.CLEARANCE_RATIO, -] -if HAS_PROPELLERS: - fixed_input.append( - r"\textcolor{gray}{engine.prop_mass}") # direct input: mass of one propeller. Note: should output "prop_mass_all" -if simplified: - x.add_input("fixed_mass", ["InputValues"]) -else: - x.add_input("fixed_mass", fixed_input) - -# equip -if simplified: - x.add_input("equip", ["InputValues"]) -else: - x.add_input("equip", [ - Mission.Design.GROSS_MASS, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, - Aircraft.Fuel.WING_FUEL_FRACTION, - Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS, - # direct input: - Aircraft.Design.EQUIPMENT_MASS_COEFFICIENTS, - ]) - -# wing_mass -wing_inputs = [ - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Mission.Design.GROSS_MASS, - # direct input: - Aircraft.Wing.MASS_COEFFICIENT, -] -if simplified: - x.add_input("wing_mass", ["InputValues"]) -else: - x.add_input("wing_mass", wing_inputs) - -# fuel_mass -if simplified: - x.add_input("fuel_mass", ["InputValues"]) -else: - x.add_input("fuel_mass", [ - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, - Mission.Design.GROSS_MASS, - # direct input - Aircraft.Fuel.FUEL_MARGIN, - Aircraft.Fuselage.MASS_COEFFICIENT, - "fus_and_struct.pylon_len", - "fus_and_struct.MAT", - Aircraft.Wing.MASS_SCALER, - Aircraft.HorizontalTail.MASS_SCALER, - Aircraft.VerticalTail.MASS_SCALER, - Aircraft.Fuselage.MASS_SCALER, - Aircraft.LandingGear.TOTAL_MASS_SCALER, - Aircraft.Engine.POD_MASS_SCALER, - Aircraft.Design.STRUCTURAL_MASS_INCREMENT, - Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, - Aircraft.Fuel.DENSITY, - # Mission.Design.FUEL_MASS_REQUIRED, - # Aircraft.Fuel.TOTAL_CAPACITY, - ]) - -# make connections -x.connect("size", "design_load", [Aircraft.Wing.AVERAGE_CHORD]) - -wing_inputs = [Aircraft.Wing.SPAN] -x.connect("size", "wing_mass", wing_inputs) - -if simplified: - x.connect("size", "fixed_mass", ["aircraft:*"]) -else: - x.connect("size", "fixed_mass", [ - Aircraft.Fuselage.LENGTH, - Aircraft.Wing.SPAN, - Aircraft.Wing.AREA, - Aircraft.VerticalTail.AREA, - Aircraft.HorizontalTail.AREA, - Aircraft.VerticalTail.SPAN, - Aircraft.HorizontalTail.SPAN, - Aircraft.HorizontalTail.MOMENT_ARM, - Aircraft.HorizontalTail.ROOT_CHORD, - Aircraft.VerticalTail.MOMENT_ARM, - Aircraft.VerticalTail.ROOT_CHORD, - Aircraft.Nacelle.SURFACE_AREA, - Aircraft.Nacelle.AVG_DIAMETER, - ]) -x.connect("size", "equip", [ - Aircraft.Fuselage.LENGTH, - Aircraft.Wing.SPAN, - Aircraft.HorizontalTail.AREA, - Aircraft.VerticalTail.AREA, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.Wing.AREA, -]) -if simplified: - x.connect("size", "fuel_mass", ["aircraft:*"]) -else: - x.connect("size", "fuel_mass", [ - Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, - Aircraft.Fuselage.WETTED_AREA, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.TailBoom.LENGTH, - ]) - -x.connect("design_load", "fixed_mass", [ - "max_mach", - "min_dive_vel", - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, -]) -x.connect("design_load", "wing_mass", [Aircraft.Wing.ULTIMATE_LOAD_FACTOR]) -x.connect("design_load", "fuel_mass", [ - "min_dive_vel", - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, -]) - -if simplified: - x.connect("fixed_mass", "wing_mass", [ - "aircraft:*", - "c_strut_braced", - "c_gear_loc", - "half_sweep", - ] - ) -else: - x.connect("fixed_mass", "wing_mass", [ - Aircraft.Wing.MATERIAL_FACTOR, - "c_strut_braced", - "c_gear_loc", - Aircraft.Engine.POSITION_FACTOR, - "half_sweep", - Aircraft.Wing.HIGH_LIFT_MASS, - ]) -if simplified: - x.connect("fixed_mass", "fuel_mass", [ - "aircraft:*", - "payload_mass_des", - "payload_mass_max", - "wing_mounted_mass", - "eng_comb_mass", - ]) -else: - x.connect("fixed_mass", "fuel_mass", [ - Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, - "payload_mass_des", - "payload_mass_max", - Aircraft.HorizontalTail.MASS, - Aircraft.VerticalTail.MASS, - Aircraft.Controls.TOTAL_MASS, - Aircraft.LandingGear.TOTAL_MASS, - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, - "wing_mounted_mass", - "eng_comb_mass", - ]) -x.connect("fixed_mass", "equip", [ - Aircraft.Controls.TOTAL_MASS, - Aircraft.LandingGear.TOTAL_MASS -]) -x.connect("equip", "fuel_mass", [ - Aircraft.Design.FIXED_EQUIPMENT_MASS, - Aircraft.Design.FIXED_USEFUL_LOAD, -]) -x.connect("wing_mass", "fuel_mass", [Aircraft.Wing.MASS]) - -x.write("mass_and_sizing_basic_xdsm") -x.write_sys_specs("mass_and_sizing_basic_specs") diff --git a/aviary/xdsm/mass_and_sizing_both_xdsm.py b/aviary/xdsm/mass_and_sizing_both_xdsm.py deleted file mode 100644 index 08f1b8d00..000000000 --- a/aviary/xdsm/mass_and_sizing_both_xdsm.py +++ /dev/null @@ -1,302 +0,0 @@ -""" -This XDSM is for the case with both a fold and a strut, volume coefficients input, no -augmented system, no propeller, and a low wing -""" - -from pyxdsm.XDSM import FUNC, GROUP, IGROUP, XDSM -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -simplified = False -HAS_FOLD = True -HAS_STRUT = True -# HAS_PROPELLERS = False -# has_hybrid_system = False # see fixed_mass_xdsm.py - -# Create subsystem components -x.add_system("size", GROUP, [r"\textbf{SizeGroup}"]) -x.add_system("design_load", GROUP, ["DesignLoadGroup"]) -x.add_system("fixed_mass", GROUP, [r"\textbf{FixedMassGroup}"]) -x.add_system("equip", FUNC, ["EquipAndUsefulMass"]) -x.add_system("wing_mass", IGROUP, [r"\textbf{WingMassGroup}"]) -x.add_system("fuel_mass", IGROUP, ["FuelMassGroup"]) - -### make input connections ### - -size_inputs = [ - # connect inputs: - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.SWEEP, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Mission.Design.GROSS_MASS, - Aircraft.Wing.LOADING, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.HorizontalTail.TAPER_RATIO, - Aircraft.Fuel.WING_FUEL_FRACTION, - Aircraft.VerticalTail.TAPER_RATIO, - # direct inputs: - Aircraft.Fuselage.DELTA_DIAMETER, - Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, - Aircraft.Fuselage.NOSE_FINENESS, - Aircraft.Fuselage.TAIL_FINENESS, - Aircraft.Fuselage.WETTED_AREA_FACTOR, - Aircraft.Wing.THICKNESS_TO_CHORD_TIP, - Aircraft.HorizontalTail.MOMENT_RATIO, - Aircraft.VerticalTail.MOMENT_RATIO, - Aircraft.HorizontalTail.ASPECT_RATIO, - Aircraft.Engine.REFERENCE_DIAMETER, - Aircraft.Nacelle.CORE_DIAMETER_RATIO, - Aircraft.Nacelle.FINENESS, - Aircraft.HorizontalTail.VOLUME_COEFFICIENT, - Aircraft.VerticalTail.VOLUME_COEFFICIENT, - # Aircraft.Engine.WING_LOCATIONS, -] -if HAS_FOLD: - size_inputs.append( - r"\textcolor{gray}{"+Aircraft.Engine.SCALE_FACTOR+"}") # connect inputs - size_inputs.append( - r"\textcolor{gray}{"+Aircraft.Wing.FOLDED_SPAN+"}") # connect inputs -if HAS_STRUT: - size_inputs.append( - r"\textcolor{gray}{"+Aircraft.Strut.ATTACHMENT_LOCATION+"}") # connect inputs - size_inputs.append( - r"\textcolor{gray}{"+Aircraft.Strut.AREA_RATIO+"}") # direct inputs -if simplified: - x.add_input("size", ["InputValues"]) -else: - x.add_input("size", size_inputs) -if simplified: - x.add_input("design_load", ["InputValues"]) -else: - x.add_input("design_load", [ - # connect input: - Aircraft.Wing.LOADING, - # direct input: - Aircraft.Design.MAX_STRUCTURAL_SPEED, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.SWEEP, - Mission.Design.MACH - ]) -fixed_input = [ - # HL connect inputs: - "density", - Aircraft.Wing.LOADING, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.Wing.FLAP_CHORD_RATIO, - Aircraft.Wing.SLAT_CHORD_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Aircraft.Wing.CENTER_CHORD, - Aircraft.Wing.FLAP_SPAN_RATIO, - Aircraft.Wing.SLAT_SPAN_RATIO, - Mission.Landing.LIFT_COEFFICIENT_MAX, - # connect inputs: - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.SWEEP, - Mission.Design.GROSS_MASS, - Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.HorizontalTail.TAPER_RATIO, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Engine.WING_LOCATIONS, - Aircraft.VerticalTail.TAPER_RATIO, - # direct inputs: - Aircraft.CrewPayload.CARGO_MASS, - Aircraft.VerticalTail.SWEEP, - Aircraft.HorizontalTail.MASS_COEFFICIENT, - Aircraft.LandingGear.TAIL_HOOK_MASS_SCALER, - Aircraft.VerticalTail.MASS_COEFFICIENT, - Aircraft.HorizontalTail.THICKNESS_TO_CHORD, - Aircraft.VerticalTail.THICKNESS_TO_CHORD, - Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT, - Aircraft.Wing.SURFACE_CONTROL_MASS_COEFFICIENT, - Aircraft.Design.COCKPIT_CONTROL_MASS_COEFFICIENT, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS, - Aircraft.Controls.COCKPIT_CONTROL_MASS_SCALER, - Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS_SCALER, - Aircraft.Controls.CONTROL_MASS_INCREMENT, - Aircraft.LandingGear.MASS_COEFFICIENT, - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, - Aircraft.Engine.MASS_SPECIFIC, - Aircraft.Nacelle.MASS_SPECIFIC, - Aircraft.Engine.PYLON_FACTOR, - Aircraft.Engine.ADDITIONAL_MASS_FRACTION, - Aircraft.Engine.MASS_SCALER, - Aircraft.Propulsion.MISC_MASS_SCALER, - Aircraft.LandingGear.MAIN_GEAR_LOCATION, - # Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Wing.MOUNTING_TYPE, - Aircraft.Nacelle.CLEARANCE_RATIO, -] -if HAS_STRUT: - fixed_input.append( - r"\textcolor{gray}{"+Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS+"}") -if simplified: - x.add_input("fixed_mass", ["InputValues"]) -else: - x.add_input("fixed_mass", fixed_input) -if simplified: - x.add_input("equip", ["InputValues"]) -else: - x.add_input("equip", [ - Mission.Design.GROSS_MASS, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, - Aircraft.Fuel.WING_FUEL_FRACTION, - Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS, - # direct input: - Aircraft.Design.EQUIPMENT_MASS_COEFFICIENTS, - ]) -wing_inputs = [ - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Mission.Design.GROSS_MASS, - # direct input: - Aircraft.Wing.MASS_COEFFICIENT, -] -if HAS_FOLD: - wing_inputs.append(r"\textcolor{gray}{"+Aircraft.Wing.FOLD_MASS_COEFFICIENT+"}") -if HAS_STRUT: - wing_inputs.append(r"\textcolor{gray}{"+Aircraft.Strut.MASS_COEFFICIENT+"}") -if simplified: - x.add_input("wing_mass", ["InputValues"]) -else: - x.add_input("wing_mass", wing_inputs) -if simplified: - x.add_input("fuel_mass", ["InputValues"]) -else: - x.add_input("fuel_mass", [ - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, - Mission.Design.GROSS_MASS, - # direct input - Aircraft.Fuel.FUEL_MARGIN, - Aircraft.Fuselage.MASS_COEFFICIENT, - "pylon_len", - "MAT", - Aircraft.Wing.MASS_SCALER, - Aircraft.HorizontalTail.MASS_SCALER, - Aircraft.VerticalTail.MASS_SCALER, - Aircraft.Fuselage.MASS_SCALER, - Aircraft.LandingGear.TOTAL_MASS_SCALER, - Aircraft.Engine.POD_MASS_SCALER, - Aircraft.Design.STRUCTURAL_MASS_INCREMENT, - Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, - Aircraft.Fuel.DENSITY, - # Mission.Design.FUEL_MASS_REQUIRED, - # Aircraft.Fuel.TOTAL_CAPACITY, - ]) - -# make connections -x.connect("size", "design_load", [Aircraft.Wing.AVERAGE_CHORD]) - -wing_inputs = [Aircraft.Wing.SPAN] -if HAS_FOLD: - wing_inputs.append(r"\textcolor{gray}{"+Aircraft.Wing.AREA+"}") - wing_inputs.append(r"\textcolor{gray}{"+Aircraft.Wing.FOLDING_AREA+"}") -if simplified: - x.connect("size", "wing_mass", ["aircraft:*"]) -else: - x.connect("size", "wing_mass", wing_inputs) - -if simplified: - x.connect("size", "fixed_mass", ["aircraft:*"]) -else: - x.connect("size", "fixed_mass", [ - Aircraft.Fuselage.LENGTH, - Aircraft.Wing.SPAN, - Aircraft.Wing.AREA, - Aircraft.VerticalTail.AREA, - Aircraft.HorizontalTail.AREA, - Aircraft.VerticalTail.SPAN, - Aircraft.HorizontalTail.SPAN, - Aircraft.HorizontalTail.MOMENT_ARM, - Aircraft.HorizontalTail.ROOT_CHORD, - Aircraft.VerticalTail.MOMENT_ARM, - Aircraft.VerticalTail.ROOT_CHORD, - Aircraft.Nacelle.SURFACE_AREA, - Aircraft.Nacelle.AVG_DIAMETER, - ]) -x.connect("size", "equip", [ - Aircraft.Fuselage.LENGTH, - Aircraft.Wing.SPAN, - Aircraft.HorizontalTail.AREA, - Aircraft.VerticalTail.AREA, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.Wing.AREA, -]) -if simplified: - x.connect("size", "fuel_mass", ["aircraft:*"]) -else: - x.connect("size", "fuel_mass", [ - Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, - Aircraft.Fuselage.WETTED_AREA, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.TailBoom.LENGTH, - ]) - -x.connect("design_load", "fixed_mass", [ - "max_mach", - "min_dive_vel", - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, -]) -x.connect("design_load", "wing_mass", [ - Aircraft.Wing.ULTIMATE_LOAD_FACTOR -]) -x.connect("design_load", "fuel_mass", [ - "min_dive_vel", - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, -]) - -if simplified: - x.connect("fixed_mass", "wing_mass", [ - "aircraft:*", - "c_strut_braced", - "c_gear_loc", - "half_sweep", - ]) -else: - x.connect("fixed_mass", "wing_mass", [ - Aircraft.Wing.MATERIAL_FACTOR, - "c_strut_braced", - "c_gear_loc", - Aircraft.Engine.POSITION_FACTOR, - "half_sweep", - Aircraft.Wing.HIGH_LIFT_MASS, - ]) -if simplified: - x.connect("fixed_mass", "fuel_mass", [ - "aircraft:*", - "payload_mass_des", - "payload_mass_max", - "wing_mounted_mass", - "eng_comb_mass", - ]) -else: - x.connect("fixed_mass", "fuel_mass", [ - Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, - "payload_mass_des", - "payload_mass_max", - Aircraft.HorizontalTail.MASS, - Aircraft.VerticalTail.MASS, - Aircraft.Controls.TOTAL_MASS, - Aircraft.LandingGear.TOTAL_MASS, - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, - "wing_mounted_mass", - "eng_comb_mass", - ]) -x.connect("fixed_mass", "equip", [ - Aircraft.Controls.TOTAL_MASS, - Aircraft.LandingGear.TOTAL_MASS, -]) -x.connect("equip", "fuel_mass", [ - Aircraft.Design.FIXED_EQUIPMENT_MASS, - Aircraft.Design.FIXED_USEFUL_LOAD, -]) -x.connect("wing_mass", "fuel_mass", [Aircraft.Wing.MASS]) - -x.write("mass_and_sizing_both_xdsm") -x.write_sys_specs("mass_and_sizing_both_specs") diff --git a/aviary/xdsm/mass_and_sizing_converter_configuration_test_xdsm.py b/aviary/xdsm/mass_and_sizing_converter_configuration_test_xdsm.py deleted file mode 100644 index d932a2407..000000000 --- a/aviary/xdsm/mass_and_sizing_converter_configuration_test_xdsm.py +++ /dev/null @@ -1,215 +0,0 @@ -""" -This XDSM is for the case with a strut but no fold, volume coefficients calculated, -no augmented system -""" - -from pyxdsm.XDSM import FUNC, GROUP, IGROUP, XDSM - -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -simplified = False - -# Create subsystem components -x.add_system("size", GROUP, ["SizeGroup"]) -x.add_system("design_load", GROUP, ["DesignLoadGroup"]) -x.add_system("fixed_mass", GROUP, ["FixedMassGroup"]) -x.add_system("equip", FUNC, ["FixedEquipAndUsefulMass"]) -x.add_system("wing_mass", IGROUP, ["WingMassGroup"]) -x.add_system("fuel_mass", IGROUP, ["FuelMassGroup"]) - -### make input connections ### - -if simplified is True: - x.add_input("size", ["InputValues"]) - x.add_input("design_load", ["InputValues"]) - x.add_input("fixed_mass", ["InputValues"]) - x.add_input("equip", ["InputValues"]) - x.add_input("wing_mass", ["InputValues"]) - x.add_input("fuel_mass", ["InputValues"]) -else: - x.add_input("size", [ - Aircraft.Engine.SCALE_FACTOR, - Aircraft.Fuselage.DELTA_DIAMETER, - Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, - Aircraft.Fuselage.NOSE_FINENESS, - Aircraft.Fuselage.TAIL_FINENESS, - Aircraft.Fuselage.WETTED_AREA_FACTOR, - Aircraft.Wing.THICKNESS_TO_CHORD_TIP, - Aircraft.HorizontalTail.MOMENT_RATIO, - Aircraft.VerticalTail.MOMENT_RATIO, - Aircraft.HorizontalTail.ASPECT_RATIO, - Aircraft.Engine.REFERENCE_DIAMETER, - Aircraft.Nacelle.CORE_DIAMETER_RATIO, - Aircraft.Nacelle.FINENESS, - Aircraft.Strut.AREA_RATIO, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.SWEEP, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Mission.Design.GROSS_MASS, - Aircraft.Wing.LOADING, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.HorizontalTail.TAPER_RATIO, - Aircraft.Fuel.WING_FUEL_FRACTION, - Aircraft.VerticalTail.TAPER_RATIO, - Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS, - Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, - ]) - x.add_input("design_load", [ - Aircraft.Wing.LOADING, - Aircraft.Design.MAX_STRUCTURAL_SPEED, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.SWEEP, - Mission.Design.MACH, - ]) - x.add_input("fixed_mass", [ - Aircraft.CrewPayload.CARGO_MASS, - Aircraft.VerticalTail.SWEEP, - Aircraft.HorizontalTail.MASS_COEFFICIENT, - Aircraft.LandingGear.TAIL_HOOK_MASS_SCALER, - Aircraft.VerticalTail.MASS_COEFFICIENT, - Aircraft.HorizontalTail.THICKNESS_TO_CHORD, - Aircraft.VerticalTail.THICKNESS_TO_CHORD, - Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT, - Aircraft.Wing.SURFACE_CONTROL_MASS_COEFFICIENT, - Aircraft.Design.COCKPIT_CONTROL_MASS_COEFFICIENT, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS, - Aircraft.Controls.COCKPIT_CONTROL_MASS_SCALER, - Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS_SCALER, - Aircraft.Controls.CONTROL_MASS_INCREMENT, - Aircraft.LandingGear.MASS_COEFFICIENT, - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, - Aircraft.Engine.MASS_SPECIFIC, - Aircraft.Nacelle.MASS_SPECIFIC, - Aircraft.Engine.PYLON_FACTOR, - Aircraft.Engine.ADDITIONAL_MASS_FRACTION, - Aircraft.Engine.MASS_SCALER, - Aircraft.Propulsion.MISC_MASS_SCALER, - Aircraft.LandingGear.MAIN_GEAR_LOCATION, - "(prop_mass)", - "("+Aircraft.Nacelle.CLEARANCE_RATIO+")", - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.SWEEP, - Mission.Design.GROSS_MASS, - Aircraft.Strut.ATTACHMENT_LOCATION, - Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.HorizontalTail.TAPER_RATIO, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Engine.WING_LOCATIONS, - Aircraft.VerticalTail.TAPER_RATIO, - ]) - x.add_input("equip", [ - Mission.Design.GROSS_MASS, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, - Aircraft.Fuel.WING_FUEL_FRACTION, - Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS, - Aircraft.Design.EQUIPMENT_MASS_COEFFICIENTS, - ]) - x.add_input("wing_mass", [ - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Mission.Design.GROSS_MASS, - Aircraft.Wing.MASS_COEFFICIENT, - Aircraft.Strut.MASS_COEFFICIENT, - ]) - x.add_input("fuel_mass", [ - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, - Mission.Design.GROSS_MASS, - Aircraft.Fuel.FUEL_MARGIN, - Aircraft.Fuselage.MASS_COEFFICIENT, - "pylon_len", - "MAT", - Aircraft.Wing.MASS_SCALER, - Aircraft.HorizontalTail.MASS_SCALER, - Aircraft.VerticalTail.MASS_SCALER, - Aircraft.Fuselage.MASS_SCALER, - Aircraft.LandingGear.TOTAL_MASS_SCALER, - Aircraft.Engine.POD_MASS_SCALER, - Aircraft.Design.STRUCTURAL_MASS_INCREMENT, - Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, - Aircraft.Fuel.DENSITY, - ]) - -# make connection -x.connect("size", "design_load", [Aircraft.Wing.AVERAGE_CHORD]) -x.connect("size", "wing_mass", [Aircraft.Wing.SPAN]) -x.connect("size", "fixed_mass", [ - Aircraft.Fuselage.LENGTH, - Aircraft.Wing.SPAN, - Aircraft.Wing.AREA, - Aircraft.VerticalTail.AREA, - Aircraft.HorizontalTail.AREA, - Aircraft.VerticalTail.SPAN, - Aircraft.HorizontalTail.SPAN, - Aircraft.HorizontalTail.MOMENT_ARM, - Aircraft.HorizontalTail.ROOT_CHORD, - Aircraft.VerticalTail.MOMENT_ARM, - Aircraft.VerticalTail.ROOT_CHORD, - Aircraft.Nacelle.SURFACE_AREA, - Aircraft.Nacelle.AVG_DIAMETER, -]) -x.connect("size", "equip", [ - Aircraft.Fuselage.LENGTH, - Aircraft.Wing.SPAN, - Aircraft.HorizontalTail.AREA, - Aircraft.VerticalTail.AREA, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.Wing.AREA, -]) -x.connect("size", "fuel_mass", [ - Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, - Aircraft.Fuselage.WETTED_AREA, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.TailBoom.LENGTH, -]) - -x.connect("design_load", "fixed_mass", [ - "max_mach", - "min_dive_vel", - Aircraft.Wing.ULTIMATE_LOAD_FACTOR -]) -x.connect("design_load", "wing_mass", [Aircraft.Wing.ULTIMATE_LOAD_FACTOR]) -x.connect("design_load", "fuel_mass", [ - "min_dive_vel", - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, -]) - -x.connect("fixed_mass", "wing_mass", [ - Aircraft.Wing.MATERIAL_FACTOR, - "c_strut_braced", - "c_gear_loc", - Aircraft.Engine.POSITION_FACTOR, - "half_sweep", - Aircraft.Wing.HIGH_LIFT_MASS, -]) -x.connect("fixed_mass", "fuel_mass", [ - Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, - "payload_mass_des", - "payload_mass_max", - Aircraft.HorizontalTail.MASS, - Aircraft.VerticalTail.MASS, - Aircraft.Controls.TOTAL_MASS, - Aircraft.LandingGear.TOTAL_MASS, - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, - "wing_mounted_mass", - "eng_comb_mass", -]) -x.connect("fixed_mass", "equip", [ - Aircraft.Controls.TOTAL_MASS, - Aircraft.LandingGear.TOTAL_MASS, -]) -x.connect("equip", "fuel_mass", [ - Aircraft.Design.FIXED_EQUIPMENT_MASS, - Aircraft.Design.FIXED_USEFUL_LOAD, -]) -x.connect("wing_mass", "fuel_mass", [Aircraft.Wing.MASS]) - -x.write("mass_and_sizing_converter_configuration_test_xdsm") -x.write_sys_specs("mass_and_sizing_strut_specs") diff --git a/aviary/xdsm/mass_and_sizing_large_single_aisle_1_xdsm.py b/aviary/xdsm/mass_and_sizing_large_single_aisle_1_xdsm.py deleted file mode 100644 index edbcf8d1a..000000000 --- a/aviary/xdsm/mass_and_sizing_large_single_aisle_1_xdsm.py +++ /dev/null @@ -1,213 +0,0 @@ -""" -This XDSM is for the case with no strut, no fold, volume coefficients input, no -augmented system -""" - -from pyxdsm.XDSM import FUNC, GROUP, IGROUP, XDSM -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -simplified = False - -# Create subsystem components -x.add_system("size", GROUP, ["SizeGroup"]) -x.add_system("design_load", GROUP, ["DesignLoadGroup"]) -x.add_system("fixed_mass", GROUP, ["FixedMassGroup"]) -x.add_system("equip", FUNC, ["FixedEquipAndUsefulMass"]) -x.add_system("wing_mass", IGROUP, ["WingMassGroup"]) -x.add_system("fuel_mass", IGROUP, ["FuelMassGroup"]) - -### make input connections ### - -if simplified is True: - x.add_input("size", ["InputValues"]) - x.add_input("design_load", ["InputValues"]) - x.add_input("fixed_mass", ["InputValues"]) - x.add_input("equip", ["InputValues"]) - x.add_input("wing_mass", ["InputValues"]) - x.add_input("fuel_mass", ["InputValues"]) -else: - x.add_input("size", [ - Aircraft.Fuselage.DELTA_DIAMETER, - Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, - Aircraft.Fuselage.NOSE_FINENESS, - Aircraft.Fuselage.TAIL_FINENESS, - Aircraft.Fuselage.WETTED_AREA_FACTOR, - Aircraft.Wing.THICKNESS_TO_CHORD_TIP, - Aircraft.HorizontalTail.MOMENT_RATIO, - Aircraft.VerticalTail.MOMENT_RATIO, - Aircraft.HorizontalTail.ASPECT_RATIO, - Aircraft.Engine.REFERENCE_DIAMETER, - Aircraft.Engine.REFERENCE_SLS_THRUST, - Aircraft.Engine.SCALE_FACTOR, - Aircraft.Nacelle.CORE_DIAMETER_RATIO, - Aircraft.Nacelle.FINENESS, - Aircraft.HorizontalTail.VOLUME_COEFFICIENT, - Aircraft.VerticalTail.VOLUME_COEFFICIENT, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.SWEEP, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Mission.Design.GROSS_MASS, - Aircraft.Wing.LOADING, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.HorizontalTail.TAPER_RATIO, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Engine.SCALE_FACTOR, - Aircraft.Fuel.WING_FUEL_FRACTION, - Aircraft.VerticalTail.TAPER_RATIO, - ]) - x.add_input("design_load", [ - Aircraft.Design.MAX_STRUCTURAL_SPEED, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.SWEEP, - Mission.Design.MACH, - Aircraft.Wing.LOADING, - ]) - x.add_input("fixed_mass", [ - Aircraft.CrewPayload.CARGO_MASS, - Aircraft.VerticalTail.SWEEP, - Aircraft.HorizontalTail.MASS_COEFFICIENT, - Aircraft.LandingGear.TAIL_HOOK_MASS_SCALER, - Aircraft.VerticalTail.MASS_COEFFICIENT, - Aircraft.HorizontalTail.THICKNESS_TO_CHORD, - Aircraft.VerticalTail.THICKNESS_TO_CHORD, - Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT, - Aircraft.Wing.SURFACE_CONTROL_MASS_COEFFICIENT, - Aircraft.Design.COCKPIT_CONTROL_MASS_COEFFICIENT, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS, - Aircraft.Controls.COCKPIT_CONTROL_MASS_SCALER, - Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS_SCALER, - Aircraft.Controls.CONTROL_MASS_INCREMENT, - Aircraft.LandingGear.MASS_COEFFICIENT, - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, - Aircraft.Engine.MASS_SPECIFIC, - Aircraft.Nacelle.MASS_SPECIFIC, - Aircraft.Engine.PYLON_FACTOR, - Aircraft.Engine.ADDITIONAL_MASS_FRACTION, - Aircraft.Engine.MASS_SCALER, - Aircraft.Engine.SCALE_FACTOR, - Aircraft.Propulsion.MISC_MASS_SCALER, - Aircraft.LandingGear.MAIN_GEAR_LOCATION, - Aircraft.Nacelle.CLEARANCE_RATIO, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.SWEEP, - Mission.Design.GROSS_MASS, - Aircraft.Strut.ATTACHMENT_LOCATION, - Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.HorizontalTail.TAPER_RATIO, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Engine.SCALE_FACTOR, - Aircraft.Engine.WING_LOCATIONS, - Aircraft.VerticalTail.TAPER_RATIO, - ]) - x.add_input("equip", [ - Aircraft.Design.EQUIPMENT_MASS_COEFFICIENTS, - Mission.Design.GROSS_MASS, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, - Aircraft.Fuel.WING_FUEL_FRACTION, - ]) - x.add_input("wing_mass", [ - Aircraft.Wing.MASS_COEFFICIENT, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Mission.Design.GROSS_MASS, - ]) - x.add_input("fuel_mass", [ - Aircraft.Fuel.FUEL_MARGIN, - Aircraft.Fuselage.MASS_COEFFICIENT, - "fus_and_struct.pylon_len", - "fus_and_struct.MAT", - Aircraft.Wing.MASS_SCALER, - Aircraft.HorizontalTail.MASS_SCALER, - Aircraft.VerticalTail.MASS_SCALER, - Aircraft.Fuselage.MASS_SCALER, - Aircraft.LandingGear.TOTAL_MASS_SCALER, - Aircraft.Engine.POD_MASS_SCALER, - Aircraft.Design.STRUCTURAL_MASS_INCREMENT, - Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, - Aircraft.Fuel.DENSITY, - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, - Mission.Design.GROSS_MASS, - ]) - -# make connections -x.connect("size", "design_load", [Aircraft.Wing.AVERAGE_CHORD]) -x.connect("size", "wing_mass", [Aircraft.Wing.SPAN]) -x.connect("size", "fixed_mass", [ - Aircraft.Fuselage.LENGTH, - Aircraft.Wing.SPAN, - Aircraft.Wing.AREA, - Aircraft.VerticalTail.AREA, - Aircraft.HorizontalTail.AREA, - Aircraft.VerticalTail.SPAN, - Aircraft.HorizontalTail.SPAN, - Aircraft.HorizontalTail.MOMENT_ARM, - Aircraft.HorizontalTail.ROOT_CHORD, - Aircraft.VerticalTail.MOMENT_ARM, - Aircraft.VerticalTail.ROOT_CHORD, - Aircraft.Nacelle.SURFACE_AREA, - Aircraft.Nacelle.AVG_DIAMETER, -]) -x.connect("size", "equip", [ - Aircraft.Fuselage.LENGTH, - Aircraft.Wing.SPAN, - Aircraft.HorizontalTail.AREA, - Aircraft.VerticalTail.AREA, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.Wing.AREA, -]) -x.connect("size", "fuel_mass", [ - Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, - Aircraft.Fuselage.WETTED_AREA, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.TailBoom.LENGTH, -]) - -x.connect("design_load", "fixed_mass", [ - "max_mach", - "min_dive_vel", - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, -]) -x.connect("design_load", "wing_mass", [Aircraft.Wing.ULTIMATE_LOAD_FACTOR]) -x.connect("design_load", "fuel_mass", [ - "min_dive_vel", Aircraft.Wing.ULTIMATE_LOAD_FACTOR]) - -x.connect("fixed_mass", "wing_mass", [ - Aircraft.Wing.MATERIAL_FACTOR, - "c_strut_braced", - "c_gear_loc", - Aircraft.Engine.POSITION_FACTOR, - "half_sweep", - Aircraft.Wing.HIGH_LIFT_MASS, -]) -x.connect("fixed_mass", "fuel_mass", [ - Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, - "payload_mass_des", - "payload_mass_max", - Aircraft.HorizontalTail.MASS, - Aircraft.VerticalTail.MASS, - Aircraft.Controls.TOTAL_MASS, - Aircraft.LandingGear.TOTAL_MASS, - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, - "wing_mounted_mass", - "eng_comb_mass", -]) -x.connect("fixed_mass", "equip", [ - Aircraft.Controls.TOTAL_MASS, - Aircraft.LandingGear.TOTAL_MASS, -]) -x.connect("equip", "fuel_mass", [ - Aircraft.Design.FIXED_EQUIPMENT_MASS, - Aircraft.Design.FIXED_USEFUL_LOAD, -]) -x.connect("wing_mass", "fuel_mass", [Aircraft.Wing.MASS]) - -x.write("mass_and_sizing_large_single_aisle_1_xdsm") -# x.write_sys_specs("mass_and_sizing_large_single_aisle_1_specs") diff --git a/aviary/xdsm/mass_basic_xdsm.py b/aviary/xdsm/mass_basic_xdsm.py deleted file mode 100644 index 969c522b6..000000000 --- a/aviary/xdsm/mass_basic_xdsm.py +++ /dev/null @@ -1,202 +0,0 @@ -""" -This XDSM is for the case with no strut, no fold, volume coefficients input, no -augmented system -""" - -from pyxdsm.XDSM import FUNC, GROUP, IGROUP, XDSM -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -simplified = True - -# Create subsystem components -x.add_system("design_load", GROUP, ["DesignLoadGroup"]) -x.add_system("fixed_mass", GROUP, ["FixedMassGroup"]) -x.add_system("equip", FUNC, ["FixedEquipAndUsefulMass"]) -x.add_system("wing_mass", GROUP, ["WingMassGroup"]) -x.add_system("fuel_mass", GROUP, ["FuelMassGroup"]) - -### make input connections ### - -# design_load -if simplified: - x.add_input("design_load", ["InputValues"]) -else: - x.add_input("design_load", [ - Aircraft.Wing.LOADING, - Aircraft.Design.MAX_STRUCTURAL_SPEED, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.SWEEP, - Mission.Design.MACH, - Aircraft.Wing.AVERAGE_CHORD, - ]) - -# fixed_mass -if simplified: - x.add_input("fixed_mass", ["InputValues"]) -else: - x.add_input("fixed_mass", [ - Aircraft.CrewPayload.CARGO_MASS, - Aircraft.VerticalTail.SWEEP, - Aircraft.HorizontalTail.MASS_COEFFICIENT, - Aircraft.LandingGear.TAIL_HOOK_MASS_SCALER, - Aircraft.VerticalTail.MASS_COEFFICIENT, - Aircraft.HorizontalTail.THICKNESS_TO_CHORD, - Aircraft.VerticalTail.THICKNESS_TO_CHORD, - Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT, - Aircraft.Wing.SURFACE_CONTROL_MASS_COEFFICIENT, - Aircraft.Design.COCKPIT_CONTROL_MASS_COEFFICIENT, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS, - Aircraft.Controls.COCKPIT_CONTROL_MASS_SCALER, - Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS_SCALER, - Aircraft.Controls.CONTROL_MASS_INCREMENT, - Aircraft.LandingGear.MASS_COEFFICIENT, - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, - Aircraft.Engine.MASS_SPECIFIC, - Aircraft.Nacelle.MASS_SPECIFIC, - Aircraft.Engine.PYLON_FACTOR, - Aircraft.Engine.ADDITIONAL_MASS_FRACTION, - Aircraft.Engine.MASS_SCALER, - Aircraft.Propulsion.MISC_MASS_SCALER, - Aircraft.LandingGear.MAIN_GEAR_LOCATION, - "(prop_mass)", - "("+Aircraft.Nacelle.CLEARANCE_RATIO+")", - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.SWEEP, - Mission.Design.GROSS_MASS, - Aircraft.Strut.ATTACHMENT_LOCATION, - Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.HorizontalTail.TAPER_RATIO, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Engine.WING_LOCATIONS, - Aircraft.VerticalTail.TAPER_RATIO, - Aircraft.Fuselage.LENGTH, - Aircraft.Wing.SPAN, - Aircraft.Wing.AREA, - Aircraft.VerticalTail.AREA, - Aircraft.HorizontalTail.AREA, - Aircraft.VerticalTail.SPAN, - Aircraft.HorizontalTail.SPAN, - Aircraft.HorizontalTail.MOMENT_ARM, - Aircraft.HorizontalTail.ROOT_CHORD, - Aircraft.VerticalTail.MOMENT_ARM, - Aircraft.VerticalTail.ROOT_CHORD, - Aircraft.Nacelle.SURFACE_AREA, - Aircraft.Nacelle.AVG_DIAMETER, - ]) - -# equip -if simplified: - x.add_input("equip", ["InputValues"]) -else: - x.connect("equip", [ - Aircraft.Design.EQUIPMENT_MASS_COEFFICIENTS, - Mission.Design.GROSS_MASS, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, - Aircraft.Fuel.WING_FUEL_FRACTION, - Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS, - Aircraft.Fuselage.LENGTH, - Aircraft.Wing.SPAN, - Aircraft.HorizontalTail.AREA, - Aircraft.VerticalTail.AREA, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.Wing.AREA, - ]) - -# wing_mass -if simplified: - x.add_input("wing_mass", ["InputValues"]) -else: - x.add_input("wing_mass", [ - Aircraft.Wing.MASS_COEFFICIENT, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Mission.Design.GROSS_MASS, - Aircraft.Wing.SPAN, - ]) - -# fuel_mass -if simplified: - x.add_input("fuel_mass", ["InputValues"]) -else: - x.add_input("fuel_mass", [ - Aircraft.Fuel.FUEL_MARGIN, - Aircraft.Fuselage.MASS_COEFFICIENT, - "fus_and_struct.pylon_len", - "fus_and_struct.MAT", - Aircraft.Wing.MASS_SCALER, - Aircraft.HorizontalTail.MASS_SCALER, - Aircraft.VerticalTail.MASS_SCALER, - Aircraft.Fuselage.MASS_SCALER, - Aircraft.LandingGear.TOTAL_MASS_SCALER, - Aircraft.Engine.POD_MASS_SCALER, - Aircraft.Design.STRUCTURAL_MASS_INCREMENT, - Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, - Aircraft.Fuel.DENSITY, - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, - Mission.Design.GROSS_MASS, - Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, - Aircraft.Fuselage.WETTED_AREA, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.TailBoom.LENGTH, - ]) - - -x.connect("design_load", "fixed_mass", [ - "max_mach", - "min_dive_vel", - Aircraft.Wing.ULTIMATE_LOAD_FACTOR -]) -x.connect("design_load", "wing_mass", [Aircraft.Wing.ULTIMATE_LOAD_FACTOR]) -x.connect("design_load", "fuel_mass", [ - "min_dive_vel", - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, -]) - -x.connect("fixed_mass", "wing_mass", [ - Aircraft.Wing.MATERIAL_FACTOR, - "c_strut_braced", - "c_gear_loc", - Aircraft.Engine.POSITION_FACTOR, - "half_sweep", - Aircraft.Wing.HIGH_LIFT_MASS, -]) -if simplified: - x.connect("fixed_mass", "fuel_mass", [ - "aircraft:*", - "payload_mass_des", - "payload_mass_max", - "wing_mounted_mass", - "eng_comb_mass", - ]) -else: - x.connect("fixed_mass", "fuel_mass", [ - Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, - "payload_mass_des", - "payload_mass_max", - Aircraft.HorizontalTail.MASS, - Aircraft.VerticalTail.MASS, - Aircraft.Controls.TOTAL_MASS, - Aircraft.LandingGear.TOTAL_MASS, - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, - "wing_mounted_mass", - "eng_comb_mass", - ]) -x.connect("fixed_mass", "equip", [ - Aircraft.Controls.TOTAL_MASS, - Aircraft.LandingGear.TOTAL_MASS -]) -x.connect("equip", "fuel_mass", [ - Aircraft.Design.FIXED_EQUIPMENT_MASS, - Aircraft.Design.FIXED_USEFUL_LOAD -]) -x.connect("wing_mass", "fuel_mass", [Aircraft.Wing.MASS]) - -x.write("mass_basic_xdsm") -# x.write_sys_specs("mass_basic_specs") diff --git a/aviary/xdsm/mass_large_single_aisle_1_xdsm.py b/aviary/xdsm/mass_large_single_aisle_1_xdsm.py deleted file mode 100644 index f8e517ee4..000000000 --- a/aviary/xdsm/mass_large_single_aisle_1_xdsm.py +++ /dev/null @@ -1,178 +0,0 @@ -"""Mass for large single aisle""" - -from pyxdsm.XDSM import GROUP, XDSM -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -x.add_system("mass", GROUP, [r"\textbf{MassSummation}"]) -x.add_input("mass", [ - Aircraft.HorizontalTail.TAPER_RATIO, - Aircraft.HorizontalTail.MOMENT_RATIO, - Aircraft.HorizontalTail.ASPECT_RATIO, - Aircraft.VerticalTail.MOMENT_RATIO, - Aircraft.VerticalTail.TAPER_RATIO, - Aircraft.Engine.REFERENCE_DIAMETER, - Aircraft.Nacelle.CORE_DIAMETER_RATIO, - Aircraft.Nacelle.FINENESS, - Aircraft.Fuselage.DELTA_DIAMETER, - Aircraft.Fuselage.NOSE_FINENESS, - Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, - Aircraft.Fuselage.TAIL_FINENESS, - Aircraft.Fuselage.WETTED_AREA_FACTOR, - Aircraft.Wing.LOADING, - Aircraft.Wing.THICKNESS_TO_CHORD_TIP, - Aircraft.Design.MAX_STRUCTURAL_SPEED, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.SWEEP, - Mission.Design.MACH, - Aircraft.Design.EQUIPMENT_MASS_COEFFICIENTS, - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Fuel.WING_FUEL_FRACTION, - Aircraft.Wing.SWEEP, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS, - Aircraft.CrewPayload.CARGO_MASS, - Aircraft.Engine.MASS_SPECIFIC, - Aircraft.Nacelle.MASS_SPECIFIC, - Aircraft.Engine.PYLON_FACTOR, - Aircraft.Engine.ADDITIONAL_MASS_FRACTION, - Aircraft.Engine.MASS_SCALER, - Aircraft.Engine.SCALE_FACTOR, - Aircraft.Propulsion.MISC_MASS_SCALER, - Aircraft.Engine.WING_LOCATIONS, - Aircraft.LandingGear.MAIN_GEAR_LOCATION, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.VerticalTail.SWEEP, - Aircraft.HorizontalTail.MASS_COEFFICIENT, - Aircraft.LandingGear.TAIL_HOOK_MASS_SCALER, - Aircraft.VerticalTail.MASS_COEFFICIENT, - Aircraft.HorizontalTail.THICKNESS_TO_CHORD, - Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, - Aircraft.VerticalTail.THICKNESS_TO_CHORD, - Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT, - Aircraft.Wing.SURFACE_CONTROL_MASS_COEFFICIENT, - Aircraft.Design.COCKPIT_CONTROL_MASS_COEFFICIENT, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS, - Aircraft.Controls.COCKPIT_CONTROL_MASS_SCALER, - Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS_SCALER, - Aircraft.Controls.CONTROL_MASS_INCREMENT, - Aircraft.LandingGear.MASS_COEFFICIENT, - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, - Aircraft.Wing.MOUNTING_TYPE, - Aircraft.Fuel.DENSITY, - Aircraft.Fuel.FUEL_MARGIN, - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, - Aircraft.Fuselage.MASS_COEFFICIENT, - "fuel_mass.fus_and_struct.pylon_len", - "fuel_mass.fus_and_struct.MAT", - Aircraft.Wing.MASS_SCALER, - Aircraft.HorizontalTail.MASS_SCALER, - Aircraft.VerticalTail.MASS_SCALER, - Aircraft.Fuselage.MASS_SCALER, - Aircraft.LandingGear.TOTAL_MASS_SCALER, - Aircraft.Engine.POD_MASS_SCALER, - Aircraft.Design.STRUCTURAL_MASS_INCREMENT, - Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, - Mission.Design.GROSS_MASS, - Aircraft.Wing.MASS_COEFFICIENT, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Aircraft.HorizontalTail.VOLUME_COEFFICIENT, - Aircraft.VerticalTail.VOLUME_COEFFICIENT, - Aircraft.Nacelle.CLEARANCE_RATIO, - Aircraft.Wing.FLAP_CHORD_RATIO, - Aircraft.Wing.FLAP_SPAN_RATIO, - Aircraft.Wing.SLAT_CHORD_RATIO, - Aircraft.Wing.SLAT_SPAN_RATIO, - Mission.Landing.LIFT_COEFFICIENT_MAX, - "density", - Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS, -]) - -x.add_output("mass", [ - Aircraft.HorizontalTail.AREA, - Aircraft.HorizontalTail.SPAN, - Aircraft.HorizontalTail.ROOT_CHORD, - Aircraft.HorizontalTail.MOMENT_ARM, - Aircraft.HorizontalTail.AVERAGE_CHORD, - Aircraft.VerticalTail.AREA, - Aircraft.VerticalTail.SPAN, - Aircraft.VerticalTail.ROOT_CHORD, - Aircraft.VerticalTail.MOMENT_ARM, - Aircraft.VerticalTail.AVERAGE_CHORD, - Aircraft.Nacelle.AVG_LENGTH, - Aircraft.Nacelle.SURFACE_AREA, - Aircraft.Fuselage.AVG_DIAMETER, - "size.fuselage.cabin_height", - "size.fuselage.cabin_len", - "size.fuselage.nose_height", - Aircraft.Fuselage.LENGTH, - Aircraft.Fuselage.WETTED_AREA, - Aircraft.TailBoom.LENGTH, - Aircraft.Wing.AREA, - Aircraft.Wing.SPAN, - Aircraft.Wing.CENTER_CHORD, - Aircraft.Wing.AVERAGE_CHORD, - Aircraft.Wing.ROOT_CHORD, - Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED, - Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, - "max_airspeed", - "vel_c", - "max_maneuver_factor", - "min_dive_vel", - "max_mach", - "density_ratio", - "V9", - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, - Aircraft.Design.FIXED_USEFUL_LOAD, - Aircraft.Design.FIXED_EQUIPMENT_MASS, - Aircraft.Wing.MATERIAL_FACTOR, - "c_strut_braced", - "c_gear_loc", - Aircraft.Engine.POSITION_FACTOR, - "half_sweep", - Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, - "payload_mass_des", - "payload_mass_max", - Aircraft.Propulsion.TOTAL_ENGINE_MASS, - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, - "eng_comb_mass", - "wing_mounted_mass", - "fixed_mass.tail.loc_MAC_vtail", - Aircraft.HorizontalTail.MASS, - Aircraft.VerticalTail.MASS, - Aircraft.Wing.HIGH_LIFT_MASS, - Aircraft.Controls.TOTAL_MASS, - Aircraft.LandingGear.TOTAL_MASS, - "fixed_mass.main_gear_mass", - Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY, - "fuel_mass.body_tank.extra_fuel_volume", - "fuel_mass.body_tank.max_extra_fuel_mass", - "fuel_mass.wingfuel_mass_min", - Aircraft.Fuel.TOTAL_CAPACITY, - "fuel_mass.fuel_and_oem.OEM_wingfuel_mass", - "fuel_mass.fuel_and_oem.OEM_fuel_vol", - Aircraft.Fuel.WING_VOLUME_DESIGN, - Aircraft.Design.OPERATING_MASS, - "fuel_mass.fuel_and_oem.payload_mass_max_fuel", - "fuel_mass.fuel_and_oem.volume_wingfuel_mass", - "fuel_mass.max_wingfuel_mass", - Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, - "fuel_mass.fus_mass_full", - Aircraft.Fuel.FUEL_SYSTEM_MASS, - Aircraft.Design.STRUCTURE_MASS, - Aircraft.Fuselage.MASS, - Mission.Design.FUEL_MASS, - Aircraft.Propulsion.MASS, - Mission.Design.FUEL_MASS_REQUIRED, - "fuel_mass.fuel_mass_min", - "wing_mass.isolated_wing_mass", - Aircraft.Wing.MASS, - Aircraft.Nacelle.AVG_DIAMETER, -], side="right") - -x.write("mass_large_single_aisle_1_xdsm") -x.write_sys_specs("mass_large_single_aisle_1_specs") diff --git a/aviary/xdsm/propulsion_engine_xdsm.py b/aviary/xdsm/propulsion_engine_xdsm.py deleted file mode 100644 index 7b38e400a..000000000 --- a/aviary/xdsm/propulsion_engine_xdsm.py +++ /dev/null @@ -1,64 +0,0 @@ -from pyxdsm.XDSM import XDSM, GROUP, FUNC, METAMODEL -from aviary.variable_info.variables import Aircraft, Mission, Dynamic - -x = XDSM() - -use_hybrid_throttle = False - -x.add_system("engine", METAMODEL, ["Engine~Interpolator"], stack=True) -x.add_system("scaling", FUNC, ["Engine~Scaling"], stack=True) -x.add_system("mux", FUNC, ["Performance~Mux"]) -x.add_system("sum", FUNC, ["Propulsion~Sum"]) - -# create inputs -prop_eng_inputs = [ - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MACH, - Dynamic.Mission.THROTTLE, -] -if use_hybrid_throttle: - prop_eng_inputs.append(r"\textcolor{gray}{"+Dynamic.Mission.HYBRID_THROTTLE+"}") -x.add_input("engine", prop_eng_inputs) - -x.add_input("scaling", [ - Dynamic.Mission.MACH, - Aircraft.Engine.SCALE_FACTOR, -] -) - -# make connections -x.connect("engine", "scaling", [ - 'thrust_net_unscaled', - 'thrust_net_max_unscaled', - 'fuel_flow_rate_unscaled', - 'electric_power_unscaled', - 'nox_rate_unscaled', -], stack=True) - -x.connect("scaling", "mux", [ - Dynamic.Mission.THRUST, - Dynamic.Mission.THRUST_MAX, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, - Dynamic.Mission.ELECTRIC_POWER, - Dynamic.Mission.NOX_RATE, -], stack=True) - -x.connect("mux", "sum", [ - Dynamic.Mission.THRUST, - Dynamic.Mission.THRUST_MAX, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE, - Dynamic.Mission.ELECTRIC_POWER, - Dynamic.Mission.NOX_RATE, -]) - -# create outputs -x.add_output("engine", [Dynamic.Mission.TEMPERATURE_ENGINE_T4], side="right") -x.add_output("sum", [ - Dynamic.Mission.THRUST_MAX_TOTAL, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - Dynamic.Mission.ELECTRIC_POWER_TOTAL, - Dynamic.Mission.NOX_RATE_TOTAL, -], side="right") - -x.write("propulsion_engine_xdsm") -# x.write_sys_specs("propulsion_engine_specs") diff --git a/aviary/xdsm/rotation_xdsm.py b/aviary/xdsm/rotation_xdsm.py deleted file mode 100644 index e812b41ed..000000000 --- a/aviary/xdsm/rotation_xdsm.py +++ /dev/null @@ -1,77 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -simplified = False - -# Create subsystem components -x.add_system("atmos", FUNC, ["USatm"]) -x.add_system("fc", FUNC, ["FlightConditions"]) -x.add_system("prop", GROUP, ["Propulsion"]) -x.add_system("aero", GROUP, [r"\textbf{Aerodynamics}"]) -x.add_system("eom", GROUP, [r"\textbf{EOM}"]) - -# create inputs -x.add_input("atmos", [Dynamic.Mission.ALTITUDE]) -x.add_input("fc", ["TAS"]) - -if simplified: - x.add_input("prop", ["InputValues"]) -else: - x.add_input("prop", [ - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MACH, - Dynamic.Mission.THROTTLE - ]) - -if simplified: - x.add_input("aero", ["InputValues"]) -else: - x.add_input("aero", [ - "airport_alt", - Dynamic.Mission.ALTITUDE, - Aircraft.Wing.HEIGHT, - Aircraft.Wing.SPAN, - "alpha", - "flap_defl", - Mission.Design.GROSS_MASS, - Aircraft.Wing.AREA, - "t_init_gear", - "t_curr", - "dt_gear", - "t_init_flaps", - "dt_flaps", - ]) - -if simplified: - x.add_input("eom", ["InputValues"]) -else: - x.add_input("eom", [ - Dynamic.Mission.MASS, - "TAS", - Dynamic.Mission.FLIGHT_PATH_ANGLE, - Aircraft.Wing.INCIDENCE, - "alpha", - ]) - -# make connections -x.connect("atmos", "fc", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -x.connect("fc", "prop", [Dynamic.Mission.MACH]) -x.connect("fc", "aero", [Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.MACH]) -x.connect("prop", "eom", [Dynamic.Mission.THRUST_TOTAL]) -x.connect("aero", "eom", [Dynamic.Mission.LIFT, Dynamic.Mission.DRAG]) - -# create outputs -x.add_output("eom", [ - "TAS_rate", - Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, - Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.DISTANCE_RATE, - "alpha_rate", - "normal_force", - "fuselage_pitch", -], side="right") - -x.write("rotation_xdsm") -x.write_sys_specs("rotation_specs") diff --git a/aviary/xdsm/run_all.py b/aviary/xdsm/run_all.py deleted file mode 100644 index 2cc4249fc..000000000 --- a/aviary/xdsm/run_all.py +++ /dev/null @@ -1,58 +0,0 @@ -import glob -import os -import subprocess -from importlib import import_module -from pathlib import Path - - -os.chdir(Path(__file__).parents[0]) - -for file_name in glob.iglob("*xdsm.py"): - xdsm = import_module(file_name[:-3]) - # remove the grayed out text decoration in spec files - spec_name = file_name[:-7] + "specs" - for item in xdsm.x.systems: - spec = item.spec_name - try: - str_line = "" - with open(spec_name + "/" + spec + ".json", "r") as fr: - for line in fr: - if "textcolor{gray}" in line: - str_line += line.replace( - "\\\\textcolor{gray}{", "").replace("}", "") - else: - str_line += line - with open(spec_name + "/" + spec + ".json", "w") as fw: - fw.write(str_line) - except: - pass - -# go through all *xdsm.py files again and replace "_" by "\_" -print("post-processing") -for file_name in glob.iglob("*xdsm.py"): - file_name = file_name[:-3] - print(f"post-processing {file_name}.tikz and {file_name}.tex") - # backup .tikz files, assuming Python 3.3+ - os.replace(f"{file_name}.tikz", f"{file_name}_save.tikz") - str_line = "" - # replace "_" by "\_" in .tikz files - with open(file_name+"_save.tikz", "r") as fr: - for line in fr: - if "begin{array}" in line: - index_begin = line.index("begin{array}") - str_line += line[:index_begin] + line[index_begin:].replace("_", "\\_") - else: - str_line += line - # save updated .tikz files - with open(file_name+".tikz", "w") as fw: - fw.write(str_line) - - # generate .pdf file again - cmd = f"pdflatex {file_name}.tex" - try: - output = subprocess.check_output(cmd.split()) - except subprocess.CalledProcessError as err: - print("Command '{}' failed. Return code: {}".format(cmd, err.returncode)) - os.remove(file_name+".log") - os.remove(file_name+".aux") - os.remove(file_name+"_save.tikz") diff --git a/aviary/xdsm/size_basic_xdsm.py b/aviary/xdsm/size_basic_xdsm.py deleted file mode 100644 index 2ad60f3f6..000000000 --- a/aviary/xdsm/size_basic_xdsm.py +++ /dev/null @@ -1,128 +0,0 @@ -"""This XDSM is for the case with no fold and no strut""" - -from pyxdsm.XDSM import FUNC, GROUP, XDSM -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -HAS_FOLD = False -HAS_STRUT = False -compute_volume_coeff = True # see empennage_size_xdsm.py - -x.add_system("fuselage", GROUP, ["FuselageGroup"]) -x.add_input("fuselage", [ - Aircraft.Fuselage.DELTA_DIAMETER, - Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, - Aircraft.Fuselage.NOSE_FINENESS, - Aircraft.Fuselage.TAIL_FINENESS, - Aircraft.Fuselage.WETTED_AREA_FACTOR, -]) -x.add_output("fuselage", [ - Aircraft.Fuselage.WETTED_AREA, - Aircraft.TailBoom.LENGTH, - "cabin_height", - "cabin_len", - "nose_height", -], side="right") - -x.add_system("wing", GROUP, [r"\textbf{WingGroup}"]) -wing_inputs = [ - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.SWEEP, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Aircraft.Wing.THICKNESS_TO_CHORD_TIP, - Mission.Design.GROSS_MASS, - Aircraft.Wing.LOADING, -] -if HAS_FOLD: - wing_inputs.append(r"\textcolor{gray}{"+Aircraft.Wing.FOLDED_SPAN+"}") -else: - wing_inputs.append(r"\textcolor{gray}{"+Aircraft.Fuel.WING_FUEL_FRACTION+"}") -if HAS_STRUT: - wing_inputs.append(r"\textcolor{gray}{"+Aircraft.Strut.ATTACHMENT_LOCATION+"}") - wing_inputs.append(r"\textcolor{gray}{"+Aircraft.Strut.AREA_RATIO+"}") -x.add_input("wing", wing_inputs) -wing_outputs = [ - Aircraft.Wing.CENTER_CHORD, - Aircraft.Wing.ROOT_CHORD, - Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED, - Aircraft.Wing.LEADING_EDGE_SWEEP, - Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, -] -if HAS_FOLD: - wing_outputs.append("fold.nonfolded_taper_ratio") - wing_outputs.append(Aircraft.Wing.FOLDING_AREA) - wing_outputs.append("fold.nonfolded_wing_area") - wing_outputs.append("fold.tc_ratio_mean_folded") - wing_outputs.append("fold.nonfolded_AR") -if HAS_STRUT: - wing_outputs.append(Aircraft.Strut.LENGTH) - wing_outputs.append(Aircraft.Strut.CHORD) - wing_outputs.append("strut.strut_y") -x.add_output("wing", wing_outputs, side="right") - -x.add_system("empennage", GROUP, ["EmpennageSize"]) - -emp_inputs = [ - Aircraft.HorizontalTail.MOMENT_RATIO, - Aircraft.VerticalTail.MOMENT_RATIO, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.HorizontalTail.ASPECT_RATIO, - Aircraft.VerticalTail.TAPER_RATIO, - Aircraft.HorizontalTail.TAPER_RATIO, -] -if compute_volume_coeff: - emp_inputs.append( - r"\textcolor{gray}{"+Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION+"}") -else: - emp_inputs.append( - r"\textcolor{gray}{"+Aircraft.HorizontalTail.VOLUME_COEFFICIENT+"}") - emp_inputs.append(r"\textcolor{gray}{"+Aircraft.VerticalTail.VOLUME_COEFFICIENT+"}") -x.add_input("empennage", emp_inputs) -x.add_output("empennage", [ - Aircraft.VerticalTail.AREA, - Aircraft.HorizontalTail.AREA, - Aircraft.VerticalTail.SPAN, - Aircraft.HorizontalTail.SPAN, - Aircraft.VerticalTail.ROOT_CHORD, - Aircraft.HorizontalTail.ROOT_CHORD, - Aircraft.VerticalTail.AREA, - Aircraft.VerticalTail.AVERAGE_CHORD, - Aircraft.HorizontalTail.AVERAGE_CHORD, - Aircraft.VerticalTail.MOMENT_ARM, - Aircraft.HorizontalTail.MOMENT_ARM, -], side="right") -x.connect("wing", "empennage", [ - Aircraft.Wing.SPAN, - Aircraft.Wing.AREA, - Aircraft.Wing.AVERAGE_CHORD -]) - -if compute_volume_coeff: - x.connect("fuselage", "empennage", [ - Aircraft.Fuselage.LENGTH, Aircraft.Fuselage.AVG_DIAMETER]) - -x.add_system("engine", FUNC, ["EngineSize"]) -x.add_input("engine", [ - Aircraft.Engine.REFERENCE_DIAMETER, - Aircraft.Engine.SCALE_FACTOR, - Aircraft.Nacelle.CORE_DIAMETER_RATIO, - Aircraft.Nacelle.FINENESS, -]) -x.add_output("engine", [ - Aircraft.Nacelle.AVG_DIAMETER, - Aircraft.Nacelle.AVG_LENGTH, - Aircraft.Nacelle.SURFACE_AREA, -], side="right") - -x.add_system("cable_size", FUNC, ["CableSize"]) -x.add_input("cable_size", [Aircraft.Engine.WING_LOCATIONS]) -x.add_output("cable_size", [Aircraft.Electrical.HYBRID_CABLE_LENGTH], side="right") - -x.connect("fuselage", "wing", [Aircraft.Fuselage.AVG_DIAMETER]) -x.connect("fuselage", "cable_size", [Aircraft.Fuselage.AVG_DIAMETER]) -x.connect("wing", "cable_size", [Aircraft.Wing.SPAN]) - -x.write("size_basic_xdsm") -x.write_sys_specs("size_basic_specs") diff --git a/aviary/xdsm/size_both1_xdsm.py b/aviary/xdsm/size_both1_xdsm.py deleted file mode 100644 index f898ce74f..000000000 --- a/aviary/xdsm/size_both1_xdsm.py +++ /dev/null @@ -1,130 +0,0 @@ -""" -This XDSM is for the case with a fold and a strut, fold location based on strut -location. It also is the case where tail volume coefficients are NOT computed. -""" - -from pyxdsm.XDSM import FUNC, GROUP, XDSM -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -# Do not change the following flags. Otherwise, unittest will fail. -HAS_FOLD = True -HAS_STRUT = True -compute_volume_coeff = False # see empennage_size_xdsm.py - -x.add_system("fuselage", GROUP, ["FuselageGroup"]) -x.add_input("fuselage", [ - Aircraft.Fuselage.DELTA_DIAMETER, - Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, - Aircraft.Fuselage.NOSE_FINENESS, - Aircraft.Fuselage.TAIL_FINENESS, - Aircraft.Fuselage.WETTED_AREA_FACTOR, -]) -x.add_output("fuselage", [ - Aircraft.Fuselage.WETTED_AREA, - Aircraft.TailBoom.LENGTH, - "cabin_height", - "cabin_len", - "nose_height", -], side="right") - -x.add_system("wing", GROUP, [r"\textbf{WingGroup}"]) -wing_inputs = [ - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.SWEEP, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Aircraft.Wing.THICKNESS_TO_CHORD_TIP, - Mission.Design.GROSS_MASS, - Aircraft.Wing.LOADING, - Aircraft.Fuel.WING_FUEL_FRACTION, -] -if HAS_FOLD: - wing_inputs.append(r"\textcolor{gray}{"+Aircraft.Wing.FOLDED_SPAN+"}") -if HAS_STRUT: - wing_inputs.append(r"\textcolor{gray}{"+Aircraft.Strut.ATTACHMENT_LOCATION+"}") - wing_inputs.append(r"\textcolor{gray}{"+Aircraft.Strut.AREA_RATIO+"}") -x.add_input("wing", wing_inputs) -wing_outputs = [ - Aircraft.Wing.CENTER_CHORD, - Aircraft.Wing.ROOT_CHORD, - Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED, - Aircraft.Wing.LEADING_EDGE_SWEEP, - Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, -] -if HAS_FOLD: - wing_outputs.append("fold.nonfolded_taper_ratio") - wing_outputs.append(Aircraft.Wing.FOLDING_AREA) - wing_outputs.append("fold.nonfolded_wing_area") - wing_outputs.append("fold.tc_ratio_mean_folded") - wing_outputs.append("fold.nonfolded_AR") -if HAS_STRUT: - wing_outputs.append(Aircraft.Strut.LENGTH) - wing_outputs.append(Aircraft.Strut.CHORD) -x.add_output("wing", wing_outputs, side="right") - -x.add_system("empennage", GROUP, [r"\textbf{EmpennageSize}"]) - -emp_inputs = [ - Aircraft.HorizontalTail.MOMENT_RATIO, - Aircraft.VerticalTail.MOMENT_RATIO, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.HorizontalTail.ASPECT_RATIO, - Aircraft.VerticalTail.TAPER_RATIO, - Aircraft.HorizontalTail.TAPER_RATIO, -] -if compute_volume_coeff: - emp_inputs.append( - r"\textcolor{gray}{"+Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION+"}") -else: - emp_inputs.append( - r"\textcolor{gray}{"+Aircraft.HorizontalTail.VOLUME_COEFFICIENT+"}") - emp_inputs.append( - r"\textcolor{gray}{"+Aircraft.VerticalTail.VOLUME_COEFFICIENT+"}") -x.add_input("empennage", emp_inputs) -x.add_output("empennage", [ - Aircraft.VerticalTail.AREA, - Aircraft.HorizontalTail.AREA, - Aircraft.VerticalTail.SPAN, - Aircraft.HorizontalTail.SPAN, - Aircraft.VerticalTail.ROOT_CHORD, - Aircraft.HorizontalTail.ROOT_CHORD, - Aircraft.VerticalTail.AREA, - Aircraft.VerticalTail.AVERAGE_CHORD, - Aircraft.HorizontalTail.AVERAGE_CHORD, - Aircraft.VerticalTail.MOMENT_ARM, - Aircraft.HorizontalTail.MOMENT_ARM, -], side="right") -x.connect("wing", "empennage", [ - Aircraft.Wing.SPAN, - Aircraft.Wing.AREA, - Aircraft.Wing.AVERAGE_CHORD -]) -if compute_volume_coeff: - x.connect("fuselage", "empennage", [ - Aircraft.Fuselage.LENGTH, Aircraft.Fuselage.AVG_DIAMETER]) - -x.add_system("engine", FUNC, ["EngineSize"]) -x.add_input("engine", [ - Aircraft.Engine.REFERENCE_DIAMETER, - Aircraft.Engine.SCALE_FACTOR, - Aircraft.Nacelle.CORE_DIAMETER_RATIO, - Aircraft.Nacelle.FINENESS, -]) -x.add_output("engine", [ - Aircraft.Nacelle.AVG_DIAMETER, - Aircraft.Nacelle.AVG_LENGTH, - Aircraft.Nacelle.SURFACE_AREA, -], side="right") - -x.add_system("cable_size", FUNC, ["CableSize"]) -x.add_input("cable_size", [Aircraft.Engine.WING_LOCATIONS]) -x.add_output("cable_size", [Aircraft.Electrical.HYBRID_CABLE_LENGTH], side="right") - -x.connect("fuselage", "wing", [Aircraft.Fuselage.AVG_DIAMETER]) -x.connect("fuselage", "cable_size", [Aircraft.Fuselage.AVG_DIAMETER]) -x.connect("wing", "cable_size", [Aircraft.Wing.SPAN]) - -x.write("size_both1_xdsm") -x.write_sys_specs("size_both1_specs") diff --git a/aviary/xdsm/size_both2_xdsm.py b/aviary/xdsm/size_both2_xdsm.py deleted file mode 100644 index a0affe55d..000000000 --- a/aviary/xdsm/size_both2_xdsm.py +++ /dev/null @@ -1,130 +0,0 @@ -""" -This XDSM is for the case with a fold and a strut, fold location not based on strut -location. It also is the case where tail volume coefficients ARE computed. -""" - -from pyxdsm.XDSM import FUNC, GROUP, XDSM -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -# Do not change the following flags. Otherwise, unittest will fail. -HAS_FOLD = True -HAS_STRUT = True -compute_volume_coeff = True # see empennage_size_xdsm.py - -x.add_system("fuselage", GROUP, ["FuselageGroup"]) -x.add_input("fuselage", [ - Aircraft.Fuselage.DELTA_DIAMETER, - Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, - Aircraft.Fuselage.NOSE_FINENESS, - Aircraft.Fuselage.TAIL_FINENESS, - Aircraft.Fuselage.WETTED_AREA_FACTOR, -]) -x.add_output("fuselage", [ - Aircraft.Fuselage.WETTED_AREA, - Aircraft.TailBoom.LENGTH, - "cabin_height", - "cabin_len", - "nose_height", -], side="right") - -x.add_system("wing", GROUP, [r"\textbf{WingGroup}"]) -wing_inputs = [ - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.SWEEP, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Aircraft.Wing.THICKNESS_TO_CHORD_TIP, - Mission.Design.GROSS_MASS, - Aircraft.Wing.LOADING, - Aircraft.Fuel.WING_FUEL_FRACTION, -] -if HAS_FOLD: - wing_inputs.append(r"\textcolor{gray}{"+Aircraft.Wing.FOLDED_SPAN+"}") -if HAS_STRUT: - wing_inputs.append(r"\textcolor{gray}{"+Aircraft.Strut.ATTACHMENT_LOCATION+"}") - wing_inputs.append(r"\textcolor{gray}{"+Aircraft.Strut.AREA_RATIO+"}") -x.add_input("wing", wing_inputs) -wing_outputs = [ - Aircraft.Wing.CENTER_CHORD, - Aircraft.Wing.ROOT_CHORD, - Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED, - Aircraft.Wing.LEADING_EDGE_SWEEP, - Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, -] -if HAS_FOLD: - wing_outputs.append("fold.nonfolded_taper_ratio") - wing_outputs.append(Aircraft.Wing.FOLDING_AREA) - wing_outputs.append("fold.nonfolded_wing_area") - wing_outputs.append("fold.tc_ratio_mean_folded") - wing_outputs.append("fold.nonfolded_AR") -if HAS_STRUT: - wing_outputs.append(Aircraft.Strut.LENGTH) - wing_outputs.append(Aircraft.Strut.CHORD) - wing_outputs.append("strut.strut_y") -x.add_output("wing", wing_outputs, side="right") - -x.add_system("empennage", GROUP, [r"\textbf{EmpennageSize}"]) - -emp_inputs = [ - Aircraft.HorizontalTail.MOMENT_RATIO, - Aircraft.VerticalTail.MOMENT_RATIO, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.HorizontalTail.ASPECT_RATIO, - Aircraft.VerticalTail.TAPER_RATIO, - Aircraft.HorizontalTail.TAPER_RATIO, -] -if compute_volume_coeff: - emp_inputs.append( - r"\textcolor{gray}{"+Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION+"}") -else: - emp_inputs.append( - r"\textcolor{gray}{"+Aircraft.HorizontalTail.VOLUME_COEFFICIENT+"}") - emp_inputs.append(r"\textcolor{gray}{"+Aircraft.VerticalTail.VOLUME_COEFFICIENT+"}") -x.add_input("empennage", emp_inputs) -x.add_output("empennage", [ - Aircraft.VerticalTail.AREA, - Aircraft.HorizontalTail.AREA, - Aircraft.VerticalTail.SPAN, - Aircraft.HorizontalTail.SPAN, - Aircraft.VerticalTail.ROOT_CHORD, - Aircraft.HorizontalTail.ROOT_CHORD, - Aircraft.VerticalTail.AREA, - Aircraft.VerticalTail.AVERAGE_CHORD, - Aircraft.HorizontalTail.AVERAGE_CHORD, - Aircraft.VerticalTail.MOMENT_ARM, - Aircraft.HorizontalTail.MOMENT_ARM, -], side="right") -x.connect("wing", "empennage", [ - Aircraft.Wing.SPAN, - Aircraft.Wing.AREA, - Aircraft.Wing.AVERAGE_CHORD, -]) -if compute_volume_coeff: - x.connect("fuselage", "empennage", [ - Aircraft.Fuselage.LENGTH, Aircraft.Fuselage.AVG_DIAMETER]) - -x.add_system("engine", FUNC, ["EngineSize"]) -x.add_input("engine", [ - Aircraft.Engine.REFERENCE_DIAMETER, - Aircraft.Engine.SCALE_FACTOR, - Aircraft.Nacelle.CORE_DIAMETER_RATIO, - Aircraft.Nacelle.FINENESS, -]) -x.add_output("engine", [ - Aircraft.Nacelle.AVG_DIAMETER, - Aircraft.Nacelle.AVG_LENGTH, - Aircraft.Nacelle.SURFACE_AREA, -], side="right") - -x.add_system("cable_size", FUNC, ["CableSize"]) -x.add_input("cable_size", [Aircraft.Engine.WING_LOCATIONS]) -x.add_output("cable_size", [Aircraft.Electrical.HYBRID_CABLE_LENGTH], side="right") - -x.connect("fuselage", "wing", [Aircraft.Fuselage.AVG_DIAMETER]) -x.connect("fuselage", "cable_size", [Aircraft.Fuselage.AVG_DIAMETER]) -x.connect("wing", "cable_size", [Aircraft.Wing.SPAN]) - -x.write("size_both2_xdsm") -x.write_sys_specs("size_both2_specs") diff --git a/aviary/xdsm/statics_xdsm.py b/aviary/xdsm/statics_xdsm.py deleted file mode 100644 index 2d5c5eed5..000000000 --- a/aviary/xdsm/statics_xdsm.py +++ /dev/null @@ -1,442 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, IFUNC, OPT, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -simplified = False - -# Create subsystem components -if simplified is False: - x.add_system("shared", GROUP, ["SharedInputs"]) -else: - x.add_system("inputs", GROUP, ["Inputs"]) -x.add_system("opt", OPT, ["Optimizer"]) -x.add_system(Dynamic.Mission.MASS, GROUP, [r"\textbf{MassSummation}"]) -x.add_system("xform", FUNC, ["EventXform"]) -x.add_system("dymos", GROUP, ["Dymos"]) -x.add_system("taxi", GROUP, ["Taxi"]) -x.add_system("groundroll", GROUP, [r"\textbf{GroundRoll}"]) -x.add_system("rotation", GROUP, [r"\textbf{Rotation}"]) -x.add_system("ascent", GROUP, [r"\textbf{InitialAscent}"]) -x.add_system("accelerate", GROUP, [r"\textbf{Accelerate}"]) -x.add_system("climb1", GROUP, [r"\textbf{ClimbTo10kFt}"]) -x.add_system("climb2", GROUP, [r"\textbf{ClimbToCruise}"]) -x.add_system("poly", IFUNC, ["PolynomialFit"]) -x.add_system("cruise", GROUP, [r"\textbf{BreguetRange}"]) -x.add_system("descent1", GROUP, [r"\textbf{DescentTo10kFt}"]) -x.add_system("descent2", GROUP, [r"\textbf{DescentTo1kFt}"]) -x.add_system("landing", GROUP, [r"\textbf{Landing}"]) -x.add_system("fuelburn", FUNC, ["FuelBurn"]) -x.add_system("mass_diff", FUNC, ["MassDifference"]) -x.add_system(Dynamic.Mission.DISTANCE, FUNC, ["RangeConstraint"]) - -if simplified is False: - # independent vars input to ParamPort, common to all phases - ivc_params = [ - Aircraft.Wing.INCIDENCE, - Aircraft.Wing.HEIGHT, - Mission.Summary.FUEL_FLOW_SCALER, - Mission.Takeoff.AIRPORT_ALTITUDE, - Mission.Landing.AIRPORT_ALTITUDE, - Aircraft.Wing.FLAP_DEFLECTION_TAKEOFF, - Aircraft.Wing.FLAP_DEFLECTION_LANDING, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Aircraft.Wing.THICKNESS_TO_CHORD_TIP, - Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, - Aircraft.Wing.SWEEP, - Aircraft.HorizontalTail.SWEEP, - Aircraft.HorizontalTail.MOMENT_RATIO, - Aircraft.Wing.MOUNTING_TYPE, - Aircraft.Design.STATIC_MARGIN, - Aircraft.Design.CG_DELTA, - Aircraft.Wing.FORM_FACTOR, - Aircraft.Fuselage.FORM_FACTOR, - Aircraft.Nacelle.FORM_FACTOR, - Aircraft.VerticalTail.FORM_FACTOR, - Aircraft.HorizontalTail.FORM_FACTOR, - Aircraft.Wing.FUSELAGE_INTERFERENCE_FACTOR, - Aircraft.Strut.FUSELAGE_INTERFERENCE_FACTOR, - Aircraft.Design.DRAG_COEFFICIENT_INCREMENT, - Aircraft.Fuselage.FLAT_PLATE_AREA_INCREMENT, - Aircraft.Wing.CENTER_DISTANCE, - Aircraft.Wing.MIN_PRESSURE_LOCATION, - Aircraft.Wing.MAX_THICKNESS_LOCATION, - Aircraft.Strut.AREA_RATIO, - Aircraft.Wing.ZERO_LIFT_ANGLE, - Aircraft.Design.SUPERCRITICAL_DIVERGENCE_SHIFT, - Aircraft.Wing.FLAP_CHORD_RATIO, - Mission.Design.LIFT_COEFFICIENT_MAX_FLAPS_UP, - Mission.Takeoff.LIFT_COEFFICIENT_MAX, - Mission.Landing.LIFT_COEFFICIENT_MAX, - Mission.Takeoff.LIFT_COEFFICIENT_FLAP_INCREMENT, - Mission.Landing.LIFT_COEFFICIENT_FLAP_INCREMENT, - Mission.Takeoff.DRAG_COEFFICIENT_FLAP_INCREMENT, - Mission.Landing.DRAG_COEFFICIENT_FLAP_INCREMENT, - Aircraft.Strut.CHORD, # normally would be output by sizing - Mission.Summary.GROSS_MASS, - ] - - # ParamPort inputs from mass/sizing - sizing_params = [ - Aircraft.Wing.AREA, - Aircraft.Wing.SPAN, - Aircraft.Wing.AVERAGE_CHORD, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.HorizontalTail.AVERAGE_CHORD, - Aircraft.HorizontalTail.AREA, - Aircraft.HorizontalTail.SPAN, - Aircraft.VerticalTail.AVERAGE_CHORD, - Aircraft.VerticalTail.AREA, - Aircraft.VerticalTail.SPAN, - Aircraft.Fuselage.LENGTH, - Aircraft.Nacelle.AVG_LENGTH, - Aircraft.Fuselage.WETTED_AREA, - Aircraft.Nacelle.SURFACE_AREA, - Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED, - # Aircraft.Strut.CHORD, - ] - - # Connect shared inputs - x.connect("shared", "taxi", ivc_params) - x.connect("shared", "groundroll", ivc_params) - x.connect("shared", "rotation", ivc_params) - x.connect("shared", "ascent", ivc_params) - x.connect("shared", "accelerate", ivc_params) - x.connect("shared", "climb1", ivc_params) - x.connect("shared", "climb2", ivc_params) - x.connect("shared", "cruise", ivc_params) - x.connect("shared", "descent1", ivc_params) - x.connect("shared", "descent2", ivc_params) - x.connect("shared", "landing", ivc_params) - -else: - x.connect("inputs", Dynamic.Mission.MASS, ["InputValue"]) - x.connect("inputs", "taxi", ["InputValue"]) - x.connect("inputs", "groundroll", ["InputValue"]) - x.connect("inputs", "rotation", ["InputValue"]) - x.connect("inputs", "ascent", ["InputValue"]) - x.connect("inputs", "accelerate", ["InputValue"]) - x.connect("inputs", "climb1", ["InputValue"]) - x.connect("inputs", "climb2", ["InputValue"]) - x.connect("inputs", "cruise", ["InputValue"]) - x.connect("inputs", "descent1", ["InputValue"]) - x.connect("inputs", "descent2", ["InputValue"]) - x.connect("inputs", "landing", ["InputValue"]) - -# Connect mass -x.connect( - Dynamic.Mission.MASS, - "mass_diff", - [Aircraft.Design.OPERATING_MASS, Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS], -) - -x.connect("opt", Dynamic.Mission.MASS, [Mission.Design.GROSS_MASS]) -x.connect("opt", "taxi", [Mission.Design.GROSS_MASS]) -x.connect("opt", "landing", [Mission.Design.GROSS_MASS]) -x.connect("fuelburn", "mass_diff", [Mission.Design.FUEL_MASS_REQUIRED]) - -# Connect sizing calculated values -if simplified is False: - x.connect(Dynamic.Mission.MASS, "taxi", sizing_params) - x.connect(Dynamic.Mission.MASS, "groundroll", sizing_params) - x.connect(Dynamic.Mission.MASS, "rotation", sizing_params) - x.connect(Dynamic.Mission.MASS, "ascent", sizing_params) - x.connect(Dynamic.Mission.MASS, "accelerate", sizing_params) - x.connect(Dynamic.Mission.MASS, "climb1", sizing_params) - x.connect(Dynamic.Mission.MASS, "climb2", sizing_params) - x.connect(Dynamic.Mission.MASS, "cruise", sizing_params) - x.connect(Dynamic.Mission.MASS, "descent1", sizing_params) - x.connect(Dynamic.Mission.MASS, "descent2", sizing_params) - x.connect(Dynamic.Mission.MASS, "landing", sizing_params) - -# Connect miscellaneous -x.connect("xform", "dymos", ["t_init_gear", "t_init_flaps"]) -x.connect("xform", "ascent", ["t_init_gear", "t_init_flaps"]) -x.connect("xform", "poly", ["t_init_gear", "t_init_flaps"]) - -if simplified is False: - # Create inputs - x.add_input( - Dynamic.Mission.MASS, - [ - Aircraft.HorizontalTail.TAPER_RATIO, - Aircraft.HorizontalTail.MOMENT_RATIO, - Aircraft.HorizontalTail.ASPECT_RATIO, - Aircraft.VerticalTail.MOMENT_RATIO, - Aircraft.VerticalTail.TAPER_RATIO, - Aircraft.Engine.REFERENCE_DIAMETER, - Aircraft.Nacelle.CORE_DIAMETER_RATIO, - Aircraft.Nacelle.FINENESS, - Aircraft.Fuselage.DELTA_DIAMETER, - Aircraft.Fuselage.NOSE_FINENESS, - Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, - Aircraft.Fuselage.TAIL_FINENESS, - Aircraft.Fuselage.WETTED_AREA_FACTOR, - Aircraft.Wing.LOADING, - Aircraft.Wing.THICKNESS_TO_CHORD_TIP, - Aircraft.Design.MAX_STRUCTURAL_SPEED, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.SWEEP, - Mission.Design.MACH, - Aircraft.Design.EQUIPMENT_MASS_COEFFICIENTS, - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, - Aircraft.Fuel.WING_FUEL_FRACTION, - Aircraft.Wing.SWEEP, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS, - Aircraft.CrewPayload.CARGO_MASS, - Aircraft.Engine.MASS_SPECIFIC, - Aircraft.Nacelle.MASS_SPECIFIC, - Aircraft.Engine.PYLON_FACTOR, - Aircraft.Engine.ADDITIONAL_MASS_FRACTION, - Aircraft.Engine.SCALE_FACTOR, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Engine.MASS_SCALER, - Aircraft.Propulsion.MISC_MASS_SCALER, - Aircraft.Engine.WING_LOCATIONS, - Aircraft.LandingGear.MAIN_GEAR_LOCATION, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.VerticalTail.SWEEP, - Aircraft.HorizontalTail.MASS_COEFFICIENT, - Aircraft.LandingGear.TAIL_HOOK_MASS_SCALER, - Aircraft.VerticalTail.MASS_COEFFICIENT, - Aircraft.HorizontalTail.THICKNESS_TO_CHORD, - Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, - Aircraft.VerticalTail.THICKNESS_TO_CHORD, - Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT, - Aircraft.Wing.SURFACE_CONTROL_MASS_COEFFICIENT, - Aircraft.Design.COCKPIT_CONTROL_MASS_COEFFICIENT, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS, - Aircraft.Controls.COCKPIT_CONTROL_MASS_SCALER, - Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS_SCALER, - Aircraft.Controls.CONTROL_MASS_INCREMENT, - Aircraft.LandingGear.MASS_COEFFICIENT, - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, - Aircraft.Wing.MOUNTING_TYPE, - Aircraft.Fuel.DENSITY, - Aircraft.Fuel.FUEL_MARGIN, - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, - Aircraft.Fuselage.MASS_COEFFICIENT, - "fuel_mass.fus_and_struct.pylon_len", - "fuel_mass.fus_and_struct.MAT", - Aircraft.Wing.MASS_SCALER, - Aircraft.HorizontalTail.MASS_SCALER, - Aircraft.VerticalTail.MASS_SCALER, - Aircraft.Fuselage.MASS_SCALER, - Aircraft.LandingGear.TOTAL_MASS_SCALER, - Aircraft.Engine.POD_MASS_SCALER, - Aircraft.Design.STRUCTURAL_MASS_INCREMENT, - Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, - Mission.Design.GROSS_MASS, - Aircraft.Wing.MASS_COEFFICIENT, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Aircraft.HorizontalTail.VOLUME_COEFFICIENT, - Aircraft.VerticalTail.VOLUME_COEFFICIENT, - Aircraft.Nacelle.CLEARANCE_RATIO, - Aircraft.Wing.FLAP_CHORD_RATIO, - Aircraft.Wing.FLAP_SPAN_RATIO, - Aircraft.Wing.SLAT_CHORD_RATIO, - Aircraft.Wing.SLAT_SPAN_RATIO, - Mission.Landing.LIFT_COEFFICIENT_MAX, - "density", - Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS, - ], - ) - - aero_in = [ - 'aero_ramps.flap_factor:final_val', - 'aero_ramps.gear_factor:final_val', - 'aero_ramps.flap_factor:initial_val', - 'aero_ramps.gear_factor:initial_val', - ] - - # common propulsion inputs that are set internally but propagate up to IVC - prop_in = [ - Aircraft.Engine.SCALE_FACTOR, - ] - - x.add_input("taxi", ['throttle', - 'propulsion.vectorize_performance.t4_0', - 'propulsion.aircraft:engine:scale_factor']) - x.add_input("groundroll", - ["dt_flaps", - "dt_gear", - "t_init_gear", - "t_init_flaps", - Dynamic.Mission.FLIGHT_PATH_ANGLE, - Dynamic.Mission.ALTITUDE] + aero_in + - [ - 'throttle', - 'vectorize_performance.t4_0', - 'aircraft:engine:scale_factor', - ], - ) - x.add_input("rotation", - ["dt_flaps", "dt_gear", "t_init_gear", "t_init_flaps"] + - aero_in + prop_in + - ['throttle', 'vectorize_performance.t4_0'] - ) - x.add_input("ascent", ["dt_flaps", - "dt_gear", - 'vectorize_performance.t4_0', - 'throttle'] + aero_in + prop_in) - x.add_input("accelerate", ['throttle', - 'vectorize_performance.t4_0'] + prop_in) - x.add_input("climb1", ["speed_bal.rhs:EAS", - 'vectorize_performance.t4_0', - 'throttle'] + prop_in) - x.add_input("climb2", ["speed_bal.rhs:EAS", - 'vectorize_performance.t4_0', - 'throttle'] + prop_in) - x.add_input( - "cruise", - [ - 'prop_initial.prop.vectorize_performance.t4_0', - 'prop_final.prop.vectorize_performance.t4_0', - 'prop_final.prop.aircraft:engine:scale_factor', - 'prop_initial.prop.aircraft:engine:scale_factor' - ] - ) - x.add_input("descent1", ["speed_bal.rhs:mach", - 'aircraft:engine:scale_factor', - 'throttle', - 'vectorize_performance.t4_0']) - x.add_input("descent2", ["EAS", - 'aircraft:engine:scale_factor', - 'vectorize_performance.t4_0', - 'throttle']) - x.add_input( - "landing", - [ - Mission.Landing.AIRPORT_ALTITUDE, - Mission.Landing.OBSTACLE_HEIGHT, - Mission.Landing.INITIAL_MACH, - "alpha", - Mission.Landing.MAXIMUM_SINK_RATE, - Mission.Landing.GLIDE_TO_STALL_RATIO, - Mission.Landing.MAXIMUM_FLARE_LOAD_FACTOR, - Mission.Landing.TOUCHDOWN_SINK_RATE, - Mission.Landing.BRAKING_DELAY, - "dt_flaps", - "dt_gear", - "t_init_flaps_app", - "t_init_gear_app", - "t_init_flaps_td", - "t_init_gear_td", - "t_curr", - 'aero_ramps.flap_factor:final_val', - 'aero_ramps.gear_factor:final_val', - 'aero_ramps.flap_factor:initial_val', - 'aero_ramps.gear_factor:initial_val', - Dynamic.Mission.THROTTLE, - 'vectorize_performance.t4_0', - 'aircraft:engine:scale_factor' - ] - - ) - x.add_input("fuelburn", [Aircraft.Fuel.FUEL_MARGIN, Mission.Summary.GROSS_MASS]) - x.add_input(Dynamic.Mission.DISTANCE, [Mission.Design.RANGE]) - -# Create outputs -x.add_output("landing", [Mission.Landing.GROUND_DISTANCE], side="right") - -# Create phase continuities -x.connect("dymos", "groundroll", [Dynamic.Mission.MASS, "TAS", "t_curr"]) -x.connect("dymos", "rotation", [Dynamic.Mission.MASS, "TAS", - "alpha", Dynamic.Mission.FLIGHT_PATH_ANGLE, "t_curr", Dynamic.Mission.ALTITUDE]) -x.connect("dymos", "ascent", [Dynamic.Mission.MASS, Dynamic.Mission.ALTITUDE, - "TAS", Dynamic.Mission.FLIGHT_PATH_ANGLE, "t_curr", "alpha"]) -x.connect("dymos", "accelerate", [Dynamic.Mission.ALTITUDE, "TAS", Dynamic.Mission.MASS]) -x.connect("dymos", "climb1", [Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS]) -x.connect("dymos", "climb2", [Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS]) -x.connect("dymos", "poly", ["time_cp", "h_cp"]) -x.connect("dymos", "descent2", [Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS]) -x.connect("dymos", "landing", [Dynamic.Mission.MASS]) -x.connect("taxi", "groundroll", [Dynamic.Mission.MASS]) -x.connect("dymos", - "cruise", - [Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MACH, - "mass_initial", - "cruise_time_initial", - "cruise_distance_initial"], - ) -x.connect("dymos", "descent1", [Dynamic.Mission.ALTITUDE, Dynamic.Mission.MASS]) -x.connect("dymos", "fuelburn", [Mission.Landing.TOUCHDOWN_MASS]) -x.connect("dymos", Dynamic.Mission.DISTANCE, [Mission.Summary.RANGE]) -x.connect("cruise", "dymos", ["cruise_time_final", "cruise_distance_final"]) - -# Add Design Variables -x.connect( - "opt", - "dymos", - [ - "cruise_mass_final", - "ascent:t_initial", - Mission.Takeoff.ASCENT_DURATION, - Mission.Design.GROSS_MASS, - ], -) -x.connect( - "opt", - "xform", - [ - "tau_gear", - "tau_flaps", - "ascent:t_initial", - Mission.Takeoff.ASCENT_DURATION, - ], -) -x.connect("opt", "groundroll", [Mission.Design.GROSS_MASS]) -x.connect("opt", "rotation", [Mission.Design.GROSS_MASS]) -x.connect("opt", "ascent", [Mission.Design.GROSS_MASS]) -x.connect("opt", "accelerate", [Mission.Design.GROSS_MASS]) -x.connect("opt", "climb1", [Mission.Design.GROSS_MASS]) -x.connect("opt", "climb2", [Mission.Design.GROSS_MASS]) -x.connect("opt", "cruise", [Mission.Design.GROSS_MASS, "mass_final"]) -x.connect("opt", "descent1", [Mission.Design.GROSS_MASS]) -x.connect("opt", "descent2", [Mission.Design.GROSS_MASS]) -x.connect("opt", "mass_diff", [Mission.Design.GROSS_MASS]) - -# Add Constraints -x.connect("dymos", "opt", [r"\mathcal{R}"]) -x.connect("mass_diff", "opt", [Mission.Constraints.MASS_RESIDUAL]) -x.connect(Dynamic.Mission.DISTANCE, "opt", [Mission.Constraints.RANGE_RESIDUAL]) -x.connect("poly", "opt", ["h_init_gear", "h_init_flaps"]) - -# Connect State Rates -x.connect( - "groundroll", "dymos", [ - "TAS_rate", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) -x.connect("rotation", - "dymos", - ["TAS_rate", - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - Dynamic.Mission.DISTANCE_RATE, - "alpha_rate"]) -x.connect("ascent", - "dymos", - ["TAS_rate", - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - Dynamic.Mission.DISTANCE_RATE, - Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], - ) -x.connect( - "accelerate", "dymos", [ - "TAS_rate", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) -x.connect("climb1", "dymos", [Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) -x.connect("climb2", "dymos", [Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) -x.connect("descent1", "dymos", [Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) -x.connect("descent2", "dymos", [Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) - -x.write("statics_xdsm") -x.write_sys_specs("statics_specs") diff --git a/aviary/xdsm/taxi_xdsm.py b/aviary/xdsm/taxi_xdsm.py deleted file mode 100644 index 28799da36..000000000 --- a/aviary/xdsm/taxi_xdsm.py +++ /dev/null @@ -1,30 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -# Create subsystem components -x.add_system("atmos", FUNC, ["USatm"]) -x.add_system("prop", GROUP, ["prop"]) -x.add_system("fuel", GROUP, [r"\textbf{taxifuel}"]) - -# create inputs -x.add_input("atmos", ["airport_alt"]) -x.add_input("prop", [ - Dynamic.Mission.THROTTLE, - Dynamic.Mission.ALTITUDE, -]) -x.add_input("fuel", [Mission.Summary.GROSS_MASS]) - -# make connections -x.connect("atmos", "prop", [ - Dynamic.Mission.TEMPERATURE, - Dynamic.Mission.STATIC_PRESSURE -]) -x.connect("prop", "fuel", [Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL]) - -# create output -x.add_output("fuel", ["mass"], side="right") - -x.write("taxi_xdsm") -x.write_sys_specs("taxi_specs") diff --git a/aviary/xdsm/wing_mass_xdsm.py b/aviary/xdsm/wing_mass_xdsm.py deleted file mode 100644 index 548a4f499..000000000 --- a/aviary/xdsm/wing_mass_xdsm.py +++ /dev/null @@ -1,56 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, IFUNC, XDSM -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -HAS_STRUT = True -HAS_FOLD = True - -# Create subsystem components -x.add_system("wing_mass_solve", IFUNC, ["WingMassSolve"]) -x.add_system("tot_wing_mass", FUNC, ["WingMassTotal"]) - -# add inputs -x.add_input("wing_mass_solve", [ - Mission.Design.GROSS_MASS, - Aircraft.Wing.HIGH_LIFT_MASS, - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, - Aircraft.Wing.MASS_COEFFICIENT, - Aircraft.Wing.MATERIAL_FACTOR, - Aircraft.Engine.POSITION_FACTOR, - Aircraft.Wing.SPAN, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - r"\textcolor{gray}{c_strut_braced}", - "c_gear_loc", - "half_sweep", -]) -mass_inputs = [] -if HAS_STRUT: - mass_inputs.append( - r"\textcolor{gray}{aircraft:strut:mass_coefficient}", - ) -if HAS_FOLD: - mass_inputs.append(r"\textcolor{gray}{aircraft:wing:area}") - mass_inputs.append(r"\textcolor{gray}{aircraft:wing:folding_area}") - mass_inputs.append(r"\textcolor{gray}{aircraft:wing:fold_mass_coefficient}") - -if HAS_STRUT or HAS_FOLD: - x.add_input("tot_wing_mass", mass_inputs) - -# connect up tot_wing_mass -x.connect("wing_mass_solve", "tot_wing_mass", ["isolated_wing_mass"]) - -mass_output = [Aircraft.Wing.MASS] -if HAS_STRUT: - mass_output.append( - r"\textcolor{gray}{aircraft:strut:mass}", - ) -if HAS_FOLD: - mass_output.append( - r"\textcolor{gray}{aircraft:wing:fold_mass}", - ) -x.add_output("tot_wing_mass", mass_output, side="right") - -x.write("wing_mass_xdsm") -x.write_sys_specs("wing_mass_specs") diff --git a/aviary/xdsm/wing_size_xdsm.py b/aviary/xdsm/wing_size_xdsm.py deleted file mode 100644 index 00477eb4c..000000000 --- a/aviary/xdsm/wing_size_xdsm.py +++ /dev/null @@ -1,42 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, XDSM -from aviary.variable_info.variables import Aircraft, Mission - -x = XDSM() - -# DIMENSIONAL_LOCATION_SPECIFIED = False -# This file assume HAS_FOLD = False and HAS_STRUT = False -# Otherwise, see wing_size_with_strut_fold_xdsm.py - -# Create subsystem components -x.add_system("wing_size", FUNC, ["WingSize"]) -x.add_system("wing_parameters", FUNC, ["WingParameters"]) - -# x.add_input("wing_size", [r"gross_wt_initial", r"wing_loading"]) -x.add_input("wing_size", [ - Mission.Design.GROSS_MASS, - Aircraft.Wing.LOADING, - Aircraft.Wing.ASPECT_RATIO, -]) - -# x.add_input("wing_parameters", [r"sweep_c4", r"(fuel_vol_frac)"]) -x.add_input("wing_parameters", [ - Aircraft.Wing.SWEEP, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Aircraft.Wing.THICKNESS_TO_CHORD_TIP, - Aircraft.Fuselage.AVG_DIAMETER, -]) - -x.connect("wing_size", "wing_parameters", [Aircraft.Wing.AREA, Aircraft.Wing.SPAN]) - -x.add_output("wing_parameters", [ - Aircraft.Wing.CENTER_CHORD, - Aircraft.Wing.AVERAGE_CHORD, - Aircraft.Wing.ROOT_CHORD, - Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED, - Aircraft.Wing.LEADING_EDGE_SWEEP, -], side="right") - -x.write("wing_size_xdsm") -# x.write_sys_specs("wing_size_specs") From a9fac7c351fedd3c907aa23e03227dceebce5540 Mon Sep 17 00:00:00 2001 From: Eliot Aretskin-Hariton Date: Wed, 24 Jan 2024 13:51:30 -0500 Subject: [PATCH 161/188] fixed conflicts by removing remaing xdsm --- aviary/xdsm/climb_xdsm.py | 102 -------- aviary/xdsm/descent1_xdsm.py | 85 ------- aviary/xdsm/descent2_xdsm.py | 73 ------ aviary/xdsm/statics_xdsm.py | 450 ----------------------------------- 4 files changed, 710 deletions(-) delete mode 100644 aviary/xdsm/climb_xdsm.py delete mode 100644 aviary/xdsm/descent1_xdsm.py delete mode 100644 aviary/xdsm/descent2_xdsm.py delete mode 100644 aviary/xdsm/statics_xdsm.py diff --git a/aviary/xdsm/climb_xdsm.py b/aviary/xdsm/climb_xdsm.py deleted file mode 100644 index 4bf95c1ab..000000000 --- a/aviary/xdsm/climb_xdsm.py +++ /dev/null @@ -1,102 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, IFUNC, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -simplified = True - -# input_speed_type = "EAS" for both high altitude and low altitude -# analysis_scheme = COLLOCATION - -# Create subsystem components -x.add_system("atmos", FUNC, ["AtmosphereModel"]) -x.add_system("speeds", FUNC, [r"\textbf{SpeedConstraints}"]) -x.add_system("ks", FUNC, ["KSComp"]) -x.add_system("balance_speed", IFUNC, ["BalanceSpeed"]) -x.add_system("fc", FUNC, [r"\textbf{FlightConditions}"]) -x.add_system("prop", GROUP, ["Propulsion"]) -x.add_system("aero", GROUP, ["CruiseAero", "(alpha~in)"]) -x.add_system("eom", GROUP, [r"\textbf{ClimbEOM}"]) -x.add_system("balance_lift", IFUNC, ["BalanceLift"]) -x.add_system("constraints", FUNC, [r"\textbf{Constraints}"]) -x.add_system('specific_energy', FUNC, ["specific_energy"]) -x.add_system('alt_rate', FUNC, ["alt_rate"]) - -# create inputs -x.add_input("speeds", [Dynamic.Mission.MACH]) -x.add_input("constraints", [ - Dynamic.Mission.MASS, - Aircraft.Wing.AREA, - Aircraft.Wing.INCIDENCE -]) -x.add_input("balance_speed", ["EAS"]) -x.add_input("atmos", [Dynamic.Mission.ALTITUDE]) -if simplified: - x.add_input("aero", ["alpha", "aircraft:*"]) -else: - x.add_input("aero", [ - # Aircraft.Wing.AREA, - "aircraft:wing:*", - "aircraft:horizontal_tail:*", - "aircraft:vertical_tail:*", - "aircraft:fuselage:*", - "aircraft:design:*", - "aircraft:nacelle:*", - "aircraft:strut:*", - Mission.Design.LIFT_COEFFICIENT_MAX_FLAPS_UP, - ]) -x.add_input("prop", [ - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.THROTTLE, - Aircraft.Engine.SCALE_FACTOR, -]) -x.add_input("eom", [Dynamic.Mission.MASS]) -x.add_input("specific_energy", [Dynamic.Mission.MASS]) -x.add_input("alt_rate", ["TAS_rate"]) - -# make connections -x.connect("atmos", "fc", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -# x.connect("atmos", "prop", [Dynamic.Mission.TEMPERATURE, Dynamic.Mission.STATIC_PRESSURE]) -x.connect("atmos", "constraints", ["rho"]) -x.connect("fc", "prop", [Dynamic.Mission.MACH]) -x.connect("fc", "aero", [Dynamic.Mission.DYNAMIC_PRESSURE, Dynamic.Mission.MACH]) -x.connect("fc", "eom", ["TAS"]) -x.connect("fc", "constraints", ["TAS"]) -x.connect("fc", "speeds", [Dynamic.Mission.MACH]) -x.connect("speeds", "ks", ["speed_constraint"]) -x.connect("ks", "balance_speed", ["KS"]) -x.connect("balance_speed", "fc", ["EAS"]) -x.connect("balance_speed", "speeds", ["EAS"]) -x.connect("aero", "eom", [Dynamic.Mission.DRAG]) -x.connect("aero", "constraints", ["CL_max"]) -x.connect("prop", "eom", [Dynamic.Mission.THRUST_TOTAL]) -x.connect("eom", "constraints", [Dynamic.Mission.FLIGHT_PATH_ANGLE]) -x.connect("aero", "balance_lift", [Dynamic.Mission.LIFT]) -x.connect("eom", "balance_lift", ["required_lift"]) -x.connect("balance_lift", "constraints", ["alpha"]) -x.connect("balance_lift", "aero", ["alpha"]) -x.connect("fc", "specific_energy", ["TAS"]) -x.connect("aero", "specific_energy", [Dynamic.Mission.DRAG]) -x.connect("prop", "specific_energy", [Dynamic.Mission.THRUST_MAX_TOTAL]) -x.connect("specific_energy", "alt_rate", [Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS]) -x.connect("fc", "alt_rate", ["TAS"]) - - -# create outputs -x.add_output("eom", [ - Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.DISTANCE_RATE, - "required_lift", -], side="right") -x.add_output("constraints", ["theta", "TAS_violation"], side="right") - -x.add_output("aero", [ - Dynamic.Mission.LIFT, - Dynamic.Mission.DRAG, - "CL_max", -], side="right") - -x.add_output("alt_rate", [Dynamic.Mission.ALTITUDE_RATE_MAX], side="right") - -x.write("climb_xdsm") -x.write_sys_specs("climb_specs") diff --git a/aviary/xdsm/descent1_xdsm.py b/aviary/xdsm/descent1_xdsm.py deleted file mode 100644 index a405f9b93..000000000 --- a/aviary/xdsm/descent1_xdsm.py +++ /dev/null @@ -1,85 +0,0 @@ -"""XDSM for above 10 kft""" - -from pyxdsm.XDSM import FUNC, GROUP, IFUNC, IGROUP, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -# input_speed_type = "MACH" -# analysis_scheme = "COLLOCATION" - -# Create subsystem components -x.add_system("atmos", FUNC, ["AtmosphereModel"]) -x.add_system("balance_speed", IFUNC, ["BalanceSpeed"]) -x.add_system("speeds", FUNC, [r"\textbf{SpeedConstraints}"]) -x.add_system("fc", FUNC, ["FlightConditions"]) -x.add_system("ks", FUNC, ["KSComp"]) -x.add_system("prop", GROUP, ["Propulsion"]) -x.add_system("eom", GROUP, [r"\textbf{EOM}"]) -x.add_system("balance_lift", FUNC, ["BalanceLift"]) -x.add_system("aero", IGROUP, ["CruiseAero", "(alpha~in)"]) -x.add_system("pitch", FUNC, ["Constraints"]) -x.add_system('specific_energy', FUNC, ["specific_energy"]) -x.add_system('alt_rate', FUNC, ["alt_rate"]) - -# create inputs -# x.add_input("fc", [Dynamic.Mission.MACH]) -x.add_input("atmos", [Dynamic.Mission.ALTITUDE]) -x.add_input("balance_speed", ["rhs_mass"]) -# x.add_input("aero", [Aircraft.Wing.AREA]) -x.add_input("aero", [r"aircraft:*", Dynamic.Mission.ALTITUDE]) -x.add_input("prop", [ - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.THROTTLE, - Aircraft.Engine.SCALE_FACTOR, -]) -x.add_input("eom", ["mass"]) -x.add_input("pitch", [ - Dynamic.Mission.MASS, - Aircraft.Wing.AREA, - Aircraft.Wing.INCIDENCE, -]) -x.add_input("specific_energy", [Dynamic.Mission.MASS]) -x.add_input("alt_rate", ["TAS_rate"]) - -# make connections -x.connect("atmos", "fc", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -x.connect("atmos", "aero", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -x.connect("atmos", "pitch", ["rho"]) -x.connect("balance_speed", "fc", [Dynamic.Mission.MACH]) -x.connect("balance_speed", "speeds", [Dynamic.Mission.MACH]) -x.connect("balance_speed", "aero", [Dynamic.Mission.MACH]) -x.connect("balance_speed", "prop", [Dynamic.Mission.MACH]) -x.connect("speeds", "ks", ["speed_constraint"]) -x.connect("fc", "aero", [Dynamic.Mission.DYNAMIC_PRESSURE]) -x.connect("fc", "eom", ["TAS"]) -x.connect("fc", "speeds", ["EAS"]) -x.connect("fc", "pitch", ["TAS"]) -x.connect("ks", "balance_speed", ["KS"]) -x.connect("prop", "eom", [Dynamic.Mission.THRUST_TOTAL]) -x.connect("prop", "aero", [Dynamic.Mission.THRUST_TOTAL]) -x.connect("eom", "pitch", [Dynamic.Mission.FLIGHT_PATH_ANGLE]) -x.connect("eom", "balance_lift", ["required_lift"]) -x.connect("balance_lift", "aero", ["alpha"]) -x.connect("balance_lift", "eom", ["alpha"]) -x.connect("balance_lift", "pitch", ["alpha"]) -x.connect("aero", "eom", [Dynamic.Mission.DRAG]) -x.connect("aero", "pitch", ["CL_max"]) -x.connect("aero", "balance_lift", [Dynamic.Mission.LIFT]) -x.connect("fc", "specific_energy", ["TAS"]) -x.connect("aero", "specific_energy", [Dynamic.Mission.DRAG]) -x.connect("prop", "specific_energy", [Dynamic.Mission.THRUST_MAX_TOTAL]) -x.connect("specific_energy", "alt_rate", [Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS]) -x.connect("fc", "alt_rate", ["TAS"]) - -# create outputs -x.add_output("eom", [ - Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.DISTANCE_RATE, - "required_lift" -], side="right") - -x.add_output("alt_rate", [Dynamic.Mission.ALTITUDE_RATE_MAX], side="right") - -x.write("descent1_xdsm") -x.write_sys_specs("descent1_specs") diff --git a/aviary/xdsm/descent2_xdsm.py b/aviary/xdsm/descent2_xdsm.py deleted file mode 100644 index f23e9cd45..000000000 --- a/aviary/xdsm/descent2_xdsm.py +++ /dev/null @@ -1,73 +0,0 @@ -"""XDSM for below 10 kft""" - -from pyxdsm.XDSM import FUNC, GROUP, IFUNC, IGROUP, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -# Create subsystem components -x.add_system("atmos", FUNC, ["AtmosphereModel"]) -x.add_system("fc", FUNC, ["FlightConditions"]) -x.add_system("prop", GROUP, ["Propulsion"]) -x.add_system("eom", GROUP, ["EOM"]) -x.add_system("balance_lift", FUNC, ["BalanceLift"]) -x.add_system("aero", IGROUP, ["CruiseAero", "(alpha~in)"]) -x.add_system("pitch", FUNC, ["Constraints"]) -x.add_system('specific_energy', FUNC, ["specific_energy"]) -x.add_system('alt_rate', FUNC, ["alt_rate"]) - -# create inputs -# x.add_input("fc", ["EAS"]) -# x.add_input("aero", [Aircraft.Wing.AREA]) -x.add_input("aero", [r"aircraft:*", Dynamic.Mission.ALTITUDE]) -x.add_input("prop", [ - Dynamic.Mission.ALTITUDE, - Dynamic.Mission.THROTTLE, - Aircraft.Engine.SCALE_FACTOR, -]) -x.add_input("eom", ["mass"]) -x.add_input("pitch", [ - Dynamic.Mission.MASS, - Aircraft.Wing.AREA, - Aircraft.Wing.INCIDENCE, -]) -x.add_input("specific_energy", [Dynamic.Mission.MASS]) -x.add_input("alt_rate", ["TAS_rate"]) - -# make connections -x.add_input("fc", ["EAS"]) -x.add_input("atmos", [Dynamic.Mission.ALTITUDE]) -x.connect("atmos", "fc", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -x.connect("atmos", "aero", ["rho", Dynamic.Mission.SPEED_OF_SOUND]) -x.connect("atmos", "pitch", ["rho"]) -x.connect("fc", "aero", [Dynamic.Mission.MACH, Dynamic.Mission.DYNAMIC_PRESSURE]) -x.connect("fc", "prop", [Dynamic.Mission.MACH]) -x.connect("fc", "eom", ["TAS"]) -x.connect("fc", "pitch", ["TAS"]) -x.connect("prop", "eom", [Dynamic.Mission.THRUST_TOTAL]) -x.connect("prop", "aero", [Dynamic.Mission.THRUST_TOTAL]) -x.connect("eom", "pitch", [Dynamic.Mission.FLIGHT_PATH_ANGLE]) -x.connect("eom", "balance_lift", ["required_lift"]) -x.connect("balance_lift", "aero", ["alpha"]) -x.connect("balance_lift", "eom", ["alpha"]) -x.connect("balance_lift", "pitch", ["alpha"]) -x.connect("aero", "eom", [Dynamic.Mission.DRAG]) -x.connect("aero", "pitch", ["CL_max"]) -x.connect("aero", "balance_lift", [Dynamic.Mission.LIFT]) -x.connect("fc", "specific_energy", ["TAS"]) -x.connect("aero", "specific_energy", [Dynamic.Mission.DRAG]) -x.connect("prop", "specific_energy", [Dynamic.Mission.THRUST_MAX_TOTAL]) -x.connect("specific_energy", "alt_rate", [Dynamic.Mission.SPECIFIC_ENERGY_RATE_EXCESS]) -x.connect("fc", "alt_rate", ["TAS"]) - -# create outputs -x.add_output("eom", [ - Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.DISTANCE_RATE, - "required_lift" -], side="right") - -x.add_output("alt_rate", [Dynamic.Mission.ALTITUDE_RATE_MAX], side="right") - -x.write("descent2_xdsm") -x.write_sys_specs("descent2_specs") diff --git a/aviary/xdsm/statics_xdsm.py b/aviary/xdsm/statics_xdsm.py deleted file mode 100644 index 69920ccfe..000000000 --- a/aviary/xdsm/statics_xdsm.py +++ /dev/null @@ -1,450 +0,0 @@ -from pyxdsm.XDSM import FUNC, GROUP, IFUNC, OPT, XDSM -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -x = XDSM() - -simplified = False - -# Create subsystem components -if simplified is False: - x.add_system("shared", GROUP, ["SharedInputs"]) -else: - x.add_system("inputs", GROUP, ["Inputs"]) -x.add_system("opt", OPT, ["Optimizer"]) -x.add_system(Dynamic.Mission.MASS, GROUP, [r"\textbf{MassSummation}"]) -x.add_system("xform", FUNC, ["EventXform"]) -x.add_system("dymos", GROUP, ["Dymos"]) -x.add_system("taxi", GROUP, ["Taxi"]) -x.add_system("groundroll", GROUP, [r"\textbf{GroundRoll}"]) -x.add_system("rotation", GROUP, [r"\textbf{Rotation}"]) -x.add_system("ascent", GROUP, [r"\textbf{InitialAscent}"]) -x.add_system("accelerate", GROUP, [r"\textbf{Accelerate}"]) -x.add_system("climb1", GROUP, [r"\textbf{ClimbTo10kFt}"]) -x.add_system("climb2", GROUP, [r"\textbf{ClimbToCruise}"]) -x.add_system("poly", IFUNC, ["PolynomialFit"]) -x.add_system("cruise", GROUP, [r"\textbf{BreguetRange}"]) -x.add_system("descent1", GROUP, [r"\textbf{DescentTo10kFt}"]) -x.add_system("descent2", GROUP, [r"\textbf{DescentTo1kFt}"]) -x.add_system("landing", GROUP, [r"\textbf{Landing}"]) -x.add_system("fuelburn", FUNC, ["FuelBurn"]) -x.add_system("mass_diff", FUNC, ["MassDifference"]) -x.add_system(Dynamic.Mission.DISTANCE, FUNC, ["RangeConstraint"]) - -if simplified is False: - # independent vars input to ParamPort, common to all phases - ivc_params = [ - Aircraft.Wing.INCIDENCE, - Aircraft.Wing.HEIGHT, - Mission.Summary.FUEL_FLOW_SCALER, - Mission.Takeoff.AIRPORT_ALTITUDE, - Mission.Landing.AIRPORT_ALTITUDE, - Aircraft.Wing.FLAP_DEFLECTION_TAKEOFF, - Aircraft.Wing.FLAP_DEFLECTION_LANDING, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Aircraft.Wing.THICKNESS_TO_CHORD_TIP, - Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, - Aircraft.Wing.SWEEP, - Aircraft.HorizontalTail.SWEEP, - Aircraft.HorizontalTail.MOMENT_RATIO, - Aircraft.Wing.MOUNTING_TYPE, - Aircraft.Design.STATIC_MARGIN, - Aircraft.Design.CG_DELTA, - Aircraft.Wing.FORM_FACTOR, - Aircraft.Fuselage.FORM_FACTOR, - Aircraft.Nacelle.FORM_FACTOR, - Aircraft.VerticalTail.FORM_FACTOR, - Aircraft.HorizontalTail.FORM_FACTOR, - Aircraft.Wing.FUSELAGE_INTERFERENCE_FACTOR, - Aircraft.Strut.FUSELAGE_INTERFERENCE_FACTOR, - Aircraft.Design.DRAG_COEFFICIENT_INCREMENT, - Aircraft.Fuselage.FLAT_PLATE_AREA_INCREMENT, - Aircraft.Wing.CENTER_DISTANCE, - Aircraft.Wing.MIN_PRESSURE_LOCATION, - Aircraft.Wing.MAX_THICKNESS_LOCATION, - Aircraft.Strut.AREA_RATIO, - Aircraft.Wing.ZERO_LIFT_ANGLE, - Aircraft.Design.SUPERCRITICAL_DIVERGENCE_SHIFT, - Aircraft.Wing.FLAP_CHORD_RATIO, - Mission.Design.LIFT_COEFFICIENT_MAX_FLAPS_UP, - Mission.Takeoff.LIFT_COEFFICIENT_MAX, - Mission.Landing.LIFT_COEFFICIENT_MAX, - Mission.Takeoff.LIFT_COEFFICIENT_FLAP_INCREMENT, - Mission.Landing.LIFT_COEFFICIENT_FLAP_INCREMENT, - Mission.Takeoff.DRAG_COEFFICIENT_FLAP_INCREMENT, - Mission.Landing.DRAG_COEFFICIENT_FLAP_INCREMENT, - Aircraft.Strut.CHORD, # normally would be output by sizing - Mission.Summary.GROSS_MASS, - ] - - # ParamPort inputs from mass/sizing - sizing_params = [ - Aircraft.Wing.AREA, - Aircraft.Wing.SPAN, - Aircraft.Wing.AVERAGE_CHORD, - Aircraft.Fuselage.AVG_DIAMETER, - Aircraft.HorizontalTail.AVERAGE_CHORD, - Aircraft.HorizontalTail.AREA, - Aircraft.HorizontalTail.SPAN, - Aircraft.VerticalTail.AVERAGE_CHORD, - Aircraft.VerticalTail.AREA, - Aircraft.VerticalTail.SPAN, - Aircraft.Fuselage.LENGTH, - Aircraft.Nacelle.AVG_LENGTH, - Aircraft.Fuselage.WETTED_AREA, - Aircraft.Nacelle.SURFACE_AREA, - Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED, - # Aircraft.Strut.CHORD, - ] - - # Connect shared inputs - x.connect("shared", "taxi", ivc_params) - x.connect("shared", "groundroll", ivc_params) - x.connect("shared", "rotation", ivc_params) - x.connect("shared", "ascent", ivc_params) - x.connect("shared", "accelerate", ivc_params) - x.connect("shared", "climb1", ivc_params) - x.connect("shared", "climb2", ivc_params) - x.connect("shared", "cruise", ivc_params) - x.connect("shared", "descent1", ivc_params) - x.connect("shared", "descent2", ivc_params) - x.connect("shared", "landing", ivc_params) - -else: - x.connect("inputs", Dynamic.Mission.MASS, ["InputValue"]) - x.connect("inputs", "taxi", ["InputValue"]) - x.connect("inputs", "groundroll", ["InputValue"]) - x.connect("inputs", "rotation", ["InputValue"]) - x.connect("inputs", "ascent", ["InputValue"]) - x.connect("inputs", "accelerate", ["InputValue"]) - x.connect("inputs", "climb1", ["InputValue"]) - x.connect("inputs", "climb2", ["InputValue"]) - x.connect("inputs", "cruise", ["InputValue"]) - x.connect("inputs", "descent1", ["InputValue"]) - x.connect("inputs", "descent2", ["InputValue"]) - x.connect("inputs", "landing", ["InputValue"]) - -# Connect mass -x.connect( - Dynamic.Mission.MASS, - "mass_diff", - [Aircraft.Design.OPERATING_MASS, Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS], -) - -x.connect("opt", Dynamic.Mission.MASS, [Mission.Design.GROSS_MASS]) -x.connect("opt", "taxi", [Mission.Design.GROSS_MASS]) -x.connect("opt", "landing", [Mission.Design.GROSS_MASS]) -x.connect("fuelburn", "mass_diff", [Mission.Design.FUEL_MASS_REQUIRED]) - -# Connect sizing calculated values -if simplified is False: - x.connect(Dynamic.Mission.MASS, "taxi", sizing_params) - x.connect(Dynamic.Mission.MASS, "groundroll", sizing_params) - x.connect(Dynamic.Mission.MASS, "rotation", sizing_params) - x.connect(Dynamic.Mission.MASS, "ascent", sizing_params) - x.connect(Dynamic.Mission.MASS, "accelerate", sizing_params) - x.connect(Dynamic.Mission.MASS, "climb1", sizing_params) - x.connect(Dynamic.Mission.MASS, "climb2", sizing_params) - x.connect(Dynamic.Mission.MASS, "cruise", sizing_params) - x.connect(Dynamic.Mission.MASS, "descent1", sizing_params) - x.connect(Dynamic.Mission.MASS, "descent2", sizing_params) - x.connect(Dynamic.Mission.MASS, "landing", sizing_params) - -# Connect miscellaneous -x.connect("xform", "dymos", ["t_init_gear", "t_init_flaps"]) -x.connect("xform", "ascent", ["t_init_gear", "t_init_flaps"]) -x.connect("xform", "poly", ["t_init_gear", "t_init_flaps"]) - -if simplified is False: - # Create inputs - x.add_input( - Dynamic.Mission.MASS, - [ - Aircraft.HorizontalTail.TAPER_RATIO, - Aircraft.HorizontalTail.MOMENT_RATIO, - Aircraft.HorizontalTail.ASPECT_RATIO, - Aircraft.VerticalTail.MOMENT_RATIO, - Aircraft.VerticalTail.TAPER_RATIO, - Aircraft.Engine.REFERENCE_DIAMETER, - Aircraft.Nacelle.CORE_DIAMETER_RATIO, - Aircraft.Nacelle.FINENESS, - Aircraft.Fuselage.DELTA_DIAMETER, - Aircraft.Fuselage.NOSE_FINENESS, - Aircraft.Fuselage.PILOT_COMPARTMENT_LENGTH, - Aircraft.Fuselage.TAIL_FINENESS, - Aircraft.Fuselage.WETTED_AREA_FACTOR, - Aircraft.Wing.LOADING, - Aircraft.Wing.THICKNESS_TO_CHORD_TIP, - Aircraft.Design.MAX_STRUCTURAL_SPEED, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Wing.SWEEP, - Mission.Design.MACH, - Aircraft.Design.EQUIPMENT_MASS_COEFFICIENTS, - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, - Aircraft.Fuel.WING_FUEL_FRACTION, - Aircraft.Wing.SWEEP, - Aircraft.Wing.ASPECT_RATIO, - Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS, - Aircraft.CrewPayload.CARGO_MASS, - Aircraft.Engine.MASS_SPECIFIC, - Aircraft.Nacelle.MASS_SPECIFIC, - Aircraft.Engine.PYLON_FACTOR, - Aircraft.Engine.ADDITIONAL_MASS_FRACTION, - Aircraft.Engine.SCALE_FACTOR, - Aircraft.Engine.SCALED_SLS_THRUST, - Aircraft.Engine.MASS_SCALER, - Aircraft.Propulsion.MISC_MASS_SCALER, - Aircraft.Engine.WING_LOCATIONS, - Aircraft.LandingGear.MAIN_GEAR_LOCATION, - Aircraft.VerticalTail.ASPECT_RATIO, - Aircraft.VerticalTail.SWEEP, - Aircraft.HorizontalTail.MASS_COEFFICIENT, - Aircraft.LandingGear.TAIL_HOOK_MASS_SCALER, - Aircraft.VerticalTail.MASS_COEFFICIENT, - Aircraft.HorizontalTail.THICKNESS_TO_CHORD, - Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, - Aircraft.VerticalTail.THICKNESS_TO_CHORD, - Aircraft.Wing.HIGH_LIFT_MASS_COEFFICIENT, - Aircraft.Wing.SURFACE_CONTROL_MASS_COEFFICIENT, - Aircraft.Design.COCKPIT_CONTROL_MASS_COEFFICIENT, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS, - Aircraft.Controls.COCKPIT_CONTROL_MASS_SCALER, - Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, - Aircraft.Controls.STABILITY_AUGMENTATION_SYSTEM_MASS_SCALER, - Aircraft.Controls.CONTROL_MASS_INCREMENT, - Aircraft.LandingGear.MASS_COEFFICIENT, - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, - Aircraft.Wing.MOUNTING_TYPE, - Aircraft.Fuel.DENSITY, - Aircraft.Fuel.FUEL_MARGIN, - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, - Aircraft.Fuselage.MASS_COEFFICIENT, - "fuel_mass.fus_and_struct.pylon_len", - "fuel_mass.fus_and_struct.MAT", - Aircraft.Wing.MASS_SCALER, - Aircraft.HorizontalTail.MASS_SCALER, - Aircraft.VerticalTail.MASS_SCALER, - Aircraft.Fuselage.MASS_SCALER, - Aircraft.LandingGear.TOTAL_MASS_SCALER, - Aircraft.Engine.POD_MASS_SCALER, - Aircraft.Design.STRUCTURAL_MASS_INCREMENT, - Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, - Mission.Design.GROSS_MASS, - Aircraft.Wing.MASS_COEFFICIENT, - Aircraft.Wing.TAPER_RATIO, - Aircraft.Wing.THICKNESS_TO_CHORD_ROOT, - Aircraft.HorizontalTail.VOLUME_COEFFICIENT, - Aircraft.VerticalTail.VOLUME_COEFFICIENT, - Aircraft.Nacelle.CLEARANCE_RATIO, - Aircraft.Wing.FLAP_CHORD_RATIO, - Aircraft.Wing.FLAP_SPAN_RATIO, - Aircraft.Wing.SLAT_CHORD_RATIO, - Aircraft.Wing.SLAT_SPAN_RATIO, - Mission.Landing.LIFT_COEFFICIENT_MAX, - "density", - Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS, - ], - ) - - aero_in = [ - 'aero_ramps.flap_factor:final_val', - 'aero_ramps.gear_factor:final_val', - 'aero_ramps.flap_factor:initial_val', - 'aero_ramps.gear_factor:initial_val', - ] - - # common propulsion inputs that are set internally but propagate up to IVC - prop_in = [ - Aircraft.Engine.SCALE_FACTOR, - ] - - x.add_input("taxi", ['throttle', - 'propulsion.vectorize_performance.t4_0', - 'propulsion.aircraft:engine:scale_factor']) - x.add_input("groundroll", - ["dt_flaps", - "dt_gear", - "t_init_gear", - "t_init_flaps", - Dynamic.Mission.FLIGHT_PATH_ANGLE, - Dynamic.Mission.ALTITUDE] + aero_in + - [ - 'throttle', - 'vectorize_performance.t4_0', - 'aircraft:engine:scale_factor', - ], - ) - x.add_input("rotation", - ["dt_flaps", "dt_gear", "t_init_gear", "t_init_flaps"] + - aero_in + prop_in + - ['throttle', 'vectorize_performance.t4_0'] - ) - x.add_input("ascent", ["dt_flaps", - "dt_gear", - 'vectorize_performance.t4_0', - 'throttle'] + aero_in + prop_in) - x.add_input("accelerate", ['throttle', - 'vectorize_performance.t4_0'] + prop_in) - x.add_input("climb1", ["speed_bal.rhs:EAS", - 'vectorize_performance.t4_0', - 'throttle'] + prop_in) - x.add_input("climb2", ["speed_bal.rhs:EAS", - 'vectorize_performance.t4_0', - 'throttle'] + prop_in) - x.add_input( - "cruise", - [ - 'prop_initial.prop.vectorize_performance.t4_0', - 'prop_final.prop.vectorize_performance.t4_0', - 'prop_final.prop.aircraft:engine:scale_factor', - 'prop_initial.prop.aircraft:engine:scale_factor' - ] - ) - x.add_input("descent1", ["speed_bal.rhs:mach", - 'aircraft:engine:scale_factor', - 'throttle', - 'vectorize_performance.t4_0']) - x.add_input("descent2", ["EAS", - 'aircraft:engine:scale_factor', - 'vectorize_performance.t4_0', - 'throttle']) - x.add_input( - "landing", - [ - Mission.Landing.AIRPORT_ALTITUDE, - Mission.Landing.OBSTACLE_HEIGHT, - Mission.Landing.INITIAL_MACH, - "alpha", - Mission.Landing.MAXIMUM_SINK_RATE, - Mission.Landing.GLIDE_TO_STALL_RATIO, - Mission.Landing.MAXIMUM_FLARE_LOAD_FACTOR, - Mission.Landing.TOUCHDOWN_SINK_RATE, - Mission.Landing.BRAKING_DELAY, - "dt_flaps", - "dt_gear", - "t_init_flaps_app", - "t_init_gear_app", - "t_init_flaps_td", - "t_init_gear_td", - "t_curr", - 'aero_ramps.flap_factor:final_val', - 'aero_ramps.gear_factor:final_val', - 'aero_ramps.flap_factor:initial_val', - 'aero_ramps.gear_factor:initial_val', - Dynamic.Mission.THROTTLE, - 'vectorize_performance.t4_0', - 'aircraft:engine:scale_factor' - ] - - ) - x.add_input("fuelburn", [Aircraft.Fuel.FUEL_MARGIN, Mission.Summary.GROSS_MASS]) - x.add_input(Dynamic.Mission.DISTANCE, [Mission.Design.RANGE]) - -# Create outputs -x.add_output("landing", [Mission.Landing.GROUND_DISTANCE], side="right") -x.add_output("climb1", [Dynamic.Mission.ALTITUDE_RATE_MAX], side="right") -x.add_output("climb2", [Dynamic.Mission.ALTITUDE_RATE_MAX], side="right") -x.add_output("descent2", [Dynamic.Mission.ALTITUDE_RATE_MAX], side="right") -x.add_output("descent1", [Dynamic.Mission.ALTITUDE_RATE_MAX], side="right") - -# Create phase continuities -x.connect("dymos", "groundroll", [Dynamic.Mission.MASS, "TAS", "t_curr"]) -x.connect("dymos", "rotation", [Dynamic.Mission.MASS, "TAS", - "alpha", Dynamic.Mission.FLIGHT_PATH_ANGLE, "t_curr", Dynamic.Mission.ALTITUDE]) -x.connect("dymos", "ascent", [Dynamic.Mission.MASS, Dynamic.Mission.ALTITUDE, - "TAS", Dynamic.Mission.FLIGHT_PATH_ANGLE, "t_curr", "alpha"]) -x.connect("dymos", "accelerate", [Dynamic.Mission.ALTITUDE, "TAS", Dynamic.Mission.MASS]) -x.connect("dymos", "climb1", [Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MASS, "TAS_rate"]) -x.connect("dymos", "climb2", [Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MASS, "TAS_rate"]) -x.connect("dymos", "poly", ["time_cp", "h_cp"]) -x.connect("dymos", "descent2", [Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MASS, "TAS_rate"]) -x.connect("dymos", "landing", [Dynamic.Mission.MASS]) -x.connect("taxi", "groundroll", [Dynamic.Mission.MASS]) -x.connect("dymos", - "cruise", - [Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MACH, - "mass_initial", - "cruise_time_initial", - "cruise_distance_initial"], - ) -x.connect("dymos", "descent1", [Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MASS, "TAS_rate"]) -x.connect("dymos", "fuelburn", [Mission.Landing.TOUCHDOWN_MASS]) -x.connect("dymos", Dynamic.Mission.DISTANCE, [Mission.Summary.RANGE]) -x.connect("cruise", "dymos", ["cruise_time_final", "cruise_distance_final"]) - -# Add Design Variables -x.connect( - "opt", - "dymos", - [ - "cruise_mass_final", - "ascent:t_initial", - Mission.Takeoff.ASCENT_DURATION, - Mission.Design.GROSS_MASS, - ], -) -x.connect( - "opt", - "xform", - [ - "tau_gear", - "tau_flaps", - "ascent:t_initial", - Mission.Takeoff.ASCENT_DURATION, - ], -) -x.connect("opt", "groundroll", [Mission.Design.GROSS_MASS]) -x.connect("opt", "rotation", [Mission.Design.GROSS_MASS]) -x.connect("opt", "ascent", [Mission.Design.GROSS_MASS]) -x.connect("opt", "accelerate", [Mission.Design.GROSS_MASS]) -x.connect("opt", "climb1", [Mission.Design.GROSS_MASS]) -x.connect("opt", "climb2", [Mission.Design.GROSS_MASS]) -x.connect("opt", "cruise", [Mission.Design.GROSS_MASS, "mass_final"]) -x.connect("opt", "descent1", [Mission.Design.GROSS_MASS]) -x.connect("opt", "descent2", [Mission.Design.GROSS_MASS]) -x.connect("opt", "mass_diff", [Mission.Design.GROSS_MASS]) - -# Add Constraints -x.connect("dymos", "opt", [r"\mathcal{R}"]) -x.connect("mass_diff", "opt", [Mission.Constraints.MASS_RESIDUAL]) -x.connect(Dynamic.Mission.DISTANCE, "opt", [Mission.Constraints.RANGE_RESIDUAL]) -x.connect("poly", "opt", ["h_init_gear", "h_init_flaps"]) - -# Connect State Rates -x.connect( - "groundroll", "dymos", [ - "TAS_rate", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) -x.connect("rotation", - "dymos", - ["TAS_rate", - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - Dynamic.Mission.DISTANCE_RATE, - "alpha_rate"]) -x.connect("ascent", - "dymos", - ["TAS_rate", - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - Dynamic.Mission.DISTANCE_RATE, - Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE], - ) -x.connect( - "accelerate", "dymos", [ - "TAS_rate", Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) -x.connect("climb1", "dymos", [Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) -x.connect("climb2", "dymos", [Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) -x.connect("descent1", "dymos", [Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) -x.connect("descent2", "dymos", [Dynamic.Mission.ALTITUDE_RATE, - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, Dynamic.Mission.DISTANCE_RATE]) - -x.write("statics_xdsm") -x.write_sys_specs("statics_specs") From c631d76f07570b000b4e1d2bf22ea58b603e1986 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 24 Jan 2024 13:25:54 -0600 Subject: [PATCH 162/188] Tests and benches pass --- aviary/interface/default_phase_info/two_dof.py | 7 ------- aviary/interface/methods_for_level2.py | 4 +--- aviary/interface/utils/check_phase_info.py | 5 ----- aviary/mission/gasp_based/phases/accel_phase.py | 3 --- aviary/mission/gasp_based/phases/climb_phase.py | 3 --- aviary/mission/gasp_based/phases/descent_phase.py | 6 ------ aviary/mission/gasp_based/phases/rotation_phase.py | 5 +---- aviary/subsystems/aerodynamics/gasp_based/gaspaero.py | 10 ++++------ 8 files changed, 6 insertions(+), 37 deletions(-) diff --git a/aviary/interface/default_phase_info/two_dof.py b/aviary/interface/default_phase_info/two_dof.py index 4fbe64475..1e1ffd101 100644 --- a/aviary/interface/default_phase_info/two_dof.py +++ b/aviary/interface/default_phase_info/two_dof.py @@ -132,7 +132,6 @@ 'fix_initial': False, 'alt': (500, 'ft'), 'EAS_constraint_eq': (250, 'kn'), - 'time_initial_bounds': ((5, 1000), 's'), 'duration_bounds': ((1, 200), 's'), 'duration_ref': (1000, 's'), 'TAS_lower': (150, 'kn'), @@ -164,7 +163,6 @@ 'mach_cruise': 0.8, 'target_mach': False, 'final_alt': (10.e3, 'ft'), - 'time_initial_bounds': ((20, 200), 's'), 'duration_bounds': ((30, 300), 's'), 'duration_ref': (1000, 's'), 'alt_lower': (400, 'ft'), @@ -196,7 +194,6 @@ 'target_mach': True, 'final_alt': (37.5e3, 'ft'), 'required_available_climb_rate': (0.1, 'ft/min'), - 'time_initial_bounds': ((10, 700), 's'), 'duration_bounds': ((200, 17_000), 's'), 'duration_ref': (5000, 's'), 'alt_lower': (9000, 'ft'), @@ -244,8 +241,6 @@ 'mach_cruise': 0.8, 'input_speed_type': SpeedType.MACH, 'final_alt': (10.e3, 'ft'), - 'time_initial_bounds': ((1000, 35_000), 's'), - 'time_initial_ref': (10_000, 's'), 'duration_bounds': ((300., 900.), 's'), 'duration_ref': (1000, 's'), 'alt_lower': (1000, 'ft'), @@ -282,8 +277,6 @@ 'mach_cruise': 0.80, 'input_speed_type': SpeedType.EAS, 'final_alt': (1000, 'ft'), - 'time_initial_bounds': ((2000, 50_000), 's'), - 'time_initial_ref': (15000, 's'), 'duration_bounds': ((100., 5000), 's'), 'duration_ref': (500, 's'), 'alt_lower': (500, 'ft'), diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index eeb6e6b69..0f8c1737c 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -604,7 +604,7 @@ def _get_2dof_phase(self, phase_name): if 'cruise' not in phase_name: phase.add_control( Dynamic.Mission.THROTTLE, targets=Dynamic.Mission.THROTTLE, units='unitless', - opt=False, lower=0.0, upper=1.0 + opt=False, ) return phase @@ -1453,8 +1453,6 @@ def connect_with_common_params(self, source, target): for source, target in connect_map.items(): connect_with_common_params(self, source, target) - self.model.set_input_defaults(Mission.Takeoff.ASCENT_DURATION, val=30.0) - def add_driver(self, optimizer=None, use_coloring=None, max_iter=50, debug_print=False): """ Add an optimization driver to the Aviary problem. diff --git a/aviary/interface/utils/check_phase_info.py b/aviary/interface/utils/check_phase_info.py index eb9251d94..f35307a3a 100644 --- a/aviary/interface/utils/check_phase_info.py +++ b/aviary/interface/utils/check_phase_info.py @@ -75,8 +75,6 @@ def check_phase_info(phase_info, mission_method): 'mach_cruise': float, 'input_speed_type': SpeedType, 'final_alt': tuple, - 'time_initial_bounds': tuple, - 'time_initial_ref': tuple, 'alt_constraint_ref': tuple, } @@ -119,7 +117,6 @@ def check_phase_info(phase_info, mission_method): 'accel': { 'alt': tuple, 'EAS_constraint_eq': tuple, - 'time_initial_bounds': tuple, **common_duration, 'duration_ref': tuple, **common_TAS, @@ -133,7 +130,6 @@ def check_phase_info(phase_info, mission_method): 'mach_cruise': float, 'target_mach': bool, 'final_alt': tuple, - 'time_initial_bounds': tuple, **common_duration, **common_alt, **common_mass, @@ -146,7 +142,6 @@ def check_phase_info(phase_info, mission_method): 'target_mach': bool, 'final_alt': tuple, 'required_available_climb_rate': tuple, - 'time_initial_bounds': tuple, **common_duration, **common_alt, **common_mass, diff --git a/aviary/mission/gasp_based/phases/accel_phase.py b/aviary/mission/gasp_based/phases/accel_phase.py index 4aeda9499..95a5034a7 100644 --- a/aviary/mission/gasp_based/phases/accel_phase.py +++ b/aviary/mission/gasp_based/phases/accel_phase.py @@ -72,7 +72,6 @@ def build_phase(self, aviary_options: AviaryValues = None): # Extracting and setting options fix_initial = user_options.get_val('fix_initial') EAS_constraint_eq = user_options.get_val('EAS_constraint_eq', units='kn') - time_initial_bounds = user_options.get_val('time_initial_bounds', units='s') duration_bounds = user_options.get_val('duration_bounds', units='s') duration_ref = user_options.get_val('duration_ref', units='s') TAS_lower = user_options.get_val('TAS_lower', units='kn') @@ -94,7 +93,6 @@ def build_phase(self, aviary_options: AviaryValues = None): phase.set_time_options( fix_initial=fix_initial, - initial_bounds=time_initial_bounds, duration_bounds=duration_bounds, units="s", duration_ref=duration_ref, @@ -165,7 +163,6 @@ def build_phase(self, aviary_options: AviaryValues = None): # Adding metadata for the AccelPhase AccelPhase._add_meta_data('fix_initial', val=False) AccelPhase._add_meta_data('EAS_constraint_eq', val=250, units='kn') -AccelPhase._add_meta_data('time_initial_bounds', val=(0, 0), units='s') AccelPhase._add_meta_data('duration_bounds', val=(0, 0), units='s') AccelPhase._add_meta_data('duration_ref', val=1, units='s') AccelPhase._add_meta_data('TAS_lower', val=0, units='kn') diff --git a/aviary/mission/gasp_based/phases/climb_phase.py b/aviary/mission/gasp_based/phases/climb_phase.py index 85a90b0c0..7c70ab399 100644 --- a/aviary/mission/gasp_based/phases/climb_phase.py +++ b/aviary/mission/gasp_based/phases/climb_phase.py @@ -82,7 +82,6 @@ def build_phase(self, aviary_options: AviaryValues = None): final_alt = user_options.get_val('final_alt', units='ft') required_available_climb_rate = user_options.get_val( 'required_available_climb_rate', units='ft/min') - time_initial_bounds = user_options.get_val('time_initial_bounds', units='s') duration_bounds = user_options.get_val('duration_bounds', units='s') duration_ref = user_options.get_val('duration_ref', units='s') alt_lower = user_options.get_val('alt_lower', units='ft') @@ -103,7 +102,6 @@ def build_phase(self, aviary_options: AviaryValues = None): phase.set_time_options( fix_initial=fix_initial, - initial_bounds=time_initial_bounds, duration_bounds=duration_bounds, duration_ref=duration_ref, units="s", @@ -213,7 +211,6 @@ def _extra_ode_init_kwargs(self): ClimbPhase._add_meta_data('target_mach', val=False) ClimbPhase._add_meta_data('final_alt', val=0) ClimbPhase._add_meta_data('required_available_climb_rate', val=None, units='ft/min') -ClimbPhase._add_meta_data('time_initial_bounds', val=(0, 0), units='s') ClimbPhase._add_meta_data('duration_bounds', val=(0, 0), units='s') ClimbPhase._add_meta_data('duration_ref', val=1, units='s') ClimbPhase._add_meta_data('alt_lower', val=0, units='ft') diff --git a/aviary/mission/gasp_based/phases/descent_phase.py b/aviary/mission/gasp_based/phases/descent_phase.py index c1982bc6a..bfc7a3ac1 100644 --- a/aviary/mission/gasp_based/phases/descent_phase.py +++ b/aviary/mission/gasp_based/phases/descent_phase.py @@ -44,12 +44,10 @@ def build_phase(self, aviary_options: AviaryValues = None): # Retrieve user options values user_options = self.user_options - time_initial_bounds = user_options.get_val('time_initial_bounds', units='s') duration_bounds = user_options.get_val('duration_bounds', units='s') fix_initial = user_options.get_val('fix_initial') input_initial = user_options.get_val('input_initial') duration_ref = user_options.get_val('duration_ref', units='s') - time_initial_ref = user_options.get_val('time_initial_ref', units='s') alt_lower = user_options.get_val('alt_lower', units='ft') alt_upper = user_options.get_val('alt_upper', units='ft') alt_ref = user_options.get_val('alt_ref', units='ft') @@ -72,13 +70,11 @@ def build_phase(self, aviary_options: AviaryValues = None): # Time options phase.set_time_options( - initial_bounds=time_initial_bounds, duration_bounds=duration_bounds, fix_initial=fix_initial, input_initial=input_initial, units="s", duration_ref=duration_ref, - initial_ref=time_initial_ref, ) # Add states @@ -172,8 +168,6 @@ def _extra_ode_init_kwargs(self): DescentPhase._add_meta_data('mach_cruise', val=0) DescentPhase._add_meta_data('input_speed_type', val=SpeedType.MACH) DescentPhase._add_meta_data('final_alt', val=0, units='ft') -DescentPhase._add_meta_data('time_initial_bounds', val=(0, 0), units='s') -DescentPhase._add_meta_data('time_initial_ref', val=1, units='s') DescentPhase._add_meta_data('duration_bounds', val=(0, 0), units='s') DescentPhase._add_meta_data('duration_ref', val=1, units='s') DescentPhase._add_meta_data('alt_lower', val=0, units='ft') diff --git a/aviary/mission/gasp_based/phases/rotation_phase.py b/aviary/mission/gasp_based/phases/rotation_phase.py index 75cad6a37..f50776037 100644 --- a/aviary/mission/gasp_based/phases/rotation_phase.py +++ b/aviary/mission/gasp_based/phases/rotation_phase.py @@ -1,4 +1,5 @@ import numpy as np +from dymos.utils.misc import _unspecified from aviary.mission.phase_builder_base import ( PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) @@ -46,7 +47,6 @@ def build_phase(self, aviary_options: AviaryValues = None): # Retrieve user options values user_options = self.user_options fix_initial = user_options.get_val('fix_initial') - initial_ref = user_options.get_val('initial_ref', units='s') duration_bounds = user_options.get_val('duration_bounds', units='s') duration_ref = user_options.get_val('duration_ref', units='s') angle_lower = user_options.get_val('angle_lower', units='rad') @@ -72,13 +72,11 @@ def build_phase(self, aviary_options: AviaryValues = None): normal_ref = user_options.get_val('normal_ref', units='lbf') normal_ref0 = user_options.get_val('normal_ref0', units='lbf') - # Set time options phase.set_time_options( fix_initial=fix_initial, fix_duration=False, units="s", targets="t_curr", - initial_ref=initial_ref, duration_bounds=duration_bounds, duration_ref=duration_ref, ) @@ -167,7 +165,6 @@ def build_phase(self, aviary_options: AviaryValues = None): # Adding metadata for the RotationPhase RotationPhase._add_meta_data('fix_initial', val=False) -RotationPhase._add_meta_data('initial_ref', val=1, units='s') RotationPhase._add_meta_data('duration_bounds', val=(1, 100), units='s') RotationPhase._add_meta_data('duration_ref', val=1, units='s') RotationPhase._add_meta_data('angle_lower', val=0.0, units='rad') # rad diff --git a/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py b/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py index a0fb90a81..0ff9b7ceb 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py +++ b/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py @@ -1044,7 +1044,7 @@ def compute(self, inputs, outputs): outputs["CD"] = cd0 + cdi + delcdm -class LiftCoef(om.ExplicitComponent): +class LiftCoeff(om.ExplicitComponent): """GASP lift coefficient calculation for low-speed near-ground flight""" def initialize(self): @@ -1117,7 +1117,6 @@ def setup_partials(self): self.declare_partials("CL_base", ["*"], method="cs") self.declare_partials("CL_base", dynvars, rows=ar, cols=ar, method="cs") - self.declare_partials("CL_base", ["CL_max_flaps"], val=0) self.declare_partials("dCL_flaps_full", ["dCL_flaps_model"], method="cs") self.declare_partials( @@ -1125,7 +1124,6 @@ def setup_partials(self): self.declare_partials("alpha_stall", ["*"], method="cs") self.declare_partials("alpha_stall", dynvars, rows=ar, cols=ar, method="cs") - # self.declare_partials("alpha_stall", ["lift_ratio"], val=0) self.declare_partials("CL_max", ["CL_max_flaps"], method="cs") self.declare_partials("CL_max", ["lift_ratio"], rows=ar, cols=ar, method="cs") @@ -1180,7 +1178,7 @@ def compute(self, inputs, outputs): outputs["CL_max"] = CL_max_flaps * (1 + lift_ratio) -class LiftCoefClean(om.ExplicitComponent): +class LiftCoeffClean(om.ExplicitComponent): """Clean wing lift coefficient for high-speed flight""" def initialize(self): @@ -1297,7 +1295,7 @@ def setup(self): self.add_subsystem("lift2cl", CLFromLift(num_nodes=nn), promotes=["*"]) self.add_subsystem( "lift_coef", - LiftCoefClean(output_alpha=self.options["output_alpha"], num_nodes=nn), + LiftCoeffClean(output_alpha=self.options["output_alpha"], num_nodes=nn), promotes=["*"], ) self.add_subsystem("drag_coef", DragCoefClean(num_nodes=nn), promotes=["*"]) @@ -1379,7 +1377,7 @@ def setup(self): # alpha be useful? an issue is ground effects depend on alpha self.add_subsystem( "lift_coef", - LiftCoef(num_nodes=nn), + LiftCoeff(num_nodes=nn), promotes_inputs=["*"], promotes_outputs=["*"] ) From f9686eaf1e5766a46674fba44e36914e66cc0342 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 24 Jan 2024 13:39:11 -0600 Subject: [PATCH 163/188] Fixing CI --- .github/workflows/test_workflow.yml | 11 ----------- .../geometry/gasp_based/test/test_size_group.py | 2 -- aviary/subsystems/mass/gasp_based/test/test_fixed.py | 1 - 3 files changed, 14 deletions(-) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 8b0fa1e9e..c35c96721 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -220,17 +220,6 @@ jobs: path: ${{ matrix.NAME }}_environment.yml retention-days: 5 - - name: Generate specs - if: matrix.MAKE_DOCS == 0 && matrix.RUN_BENCHES == 0 - shell: bash -l {0} - run: | - echo "=============================================================" - echo "Generate specs" - echo "=============================================================" - cd aviary/xdsm - python run_all.py - cd ../.. - - name: Run tests if: matrix.MAKE_DOCS == 0 && matrix.RUN_BENCHES == 0 shell: bash -l {0} diff --git a/aviary/subsystems/geometry/gasp_based/test/test_size_group.py b/aviary/subsystems/geometry/gasp_based/test/test_size_group.py index 5b22cfe1c..9549599df 100644 --- a/aviary/subsystems/geometry/gasp_based/test/test_size_group.py +++ b/aviary/subsystems/geometry/gasp_based/test/test_size_group.py @@ -159,7 +159,6 @@ def test_case1(self): assert_check_partials(partial_data, atol=2e-12, rtol=1e-12) - class SizeGroupTestCase2(unittest.TestCase): def setUp(self): @@ -384,7 +383,6 @@ def test_case1(self): assert_check_partials(partial_data, atol=3e-10, rtol=1e-12) - class SizeGroupTestCase3(unittest.TestCase): def setUp(self): diff --git a/aviary/subsystems/mass/gasp_based/test/test_fixed.py b/aviary/subsystems/mass/gasp_based/test/test_fixed.py index 8c6a746b8..295517684 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_fixed.py +++ b/aviary/subsystems/mass/gasp_based/test/test_fixed.py @@ -1116,7 +1116,6 @@ def test_case1(self): assert_check_partials(partial_data, atol=3e-11, rtol=1e-12) - class FixedMassGroupTestCase2(unittest.TestCase): def setUp(self): From 78ade111073b2d127c5f4deccf4d224116c1bee4 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 24 Jan 2024 13:42:01 -0600 Subject: [PATCH 164/188] Removed more XDSM reqs --- .github/workflows/test_workflow.yml | 11 +---------- .gitignore | 3 --- README.md | 6 ------ environment.yml | 1 - setup.py | 2 +- 5 files changed, 2 insertions(+), 21 deletions(-) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index c35c96721..b1328c9da 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -133,7 +133,7 @@ jobs: echo "=============================================================" conda install numpy=${{ matrix.NUMPY }} scipy=${{ matrix.SCIPY }} -q -y conda install matplotlib pandas panel hvplot -q -y - pip install testflo pyxdsm -q + pip install testflo -q - name: Install pyOptSparse if: matrix.PYOPTSPARSE @@ -156,15 +156,6 @@ jobs: pip install git+https://github.com/OpenMDAO/build_pyoptsparse build_pyoptsparse -v -b ${{ matrix.PYOPTSPARSE }} $SNOPT - - name: Install TeX Live - shell: bash - run: | - echo "=============================================================" - echo "Install TeX Live (for pyXDSM)" - echo "=============================================================" - sudo apt-get update - sudo apt-get install texlive-pictures texlive-latex-extra -y - - name: Install OpenMDAO if: matrix.OPENMDAO shell: bash -l {0} diff --git a/.gitignore b/.gitignore index 73195354f..0b2f951ce 100644 --- a/.gitignore +++ b/.gitignore @@ -138,9 +138,6 @@ reports/ *.tex *.tikz -# Generated by XDSM files -*_specs/ - #VSCode user settings .vscode/ diff --git a/README.md b/README.md index 00c013282..230c56f12 100644 --- a/README.md +++ b/README.md @@ -36,12 +36,6 @@ Otherwise you can build the docs locally: 3. Run the command `sh build_book.sh` from your command prompt of choice 4. Navigate to the built html: `/Aviary/aviary/docs/\_build/html/intro.html` -## Visualization - -To create XDSM visualizations of some of the Aviary code, you can run the `run_all.py` utility script within the `aviary/xdsm` directory. -This is not strictly necessary but is used in some of the unit tests. -This requires installing Aviary with the `[test]` or `[all]` options as described above. - ## Validation This code has been validated using output and data from the GASP and FLOPS codes themselves. The GASP-based weight calculations in this code include in their comments which versions of the GASP standalone weights module were used in validation. The aero and EOM subsystem validations were based on runs of the entire GASP and FLOPS code as they stood in the summer of 2021 and the summer of 2022 respectively. diff --git a/environment.yml b/environment.yml index 101843014..0193e042e 100644 --- a/environment.yml +++ b/environment.yml @@ -134,7 +134,6 @@ dependencies: - openmdao==3.28.1.dev0 - parameterized==0.9.0 - pyoptsparse==2.9.1 - - pyxdsm==2.3.0 - requests==2.31.0 - setuptools==65.7.0 - simupy==1.1.2 diff --git a/setup.py b/setup.py index 4786b34cd..d17c512c9 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ pkgname = "aviary" extras_require = { - "test": ["testflo", "pyxdsm", "pre-commit"], + "test": ["testflo", "pre-commit"], "examples": ["openaerostruct", "ambiance"], } From 63f4ae2966b2713c3cabf1b085fb19a879c4a149 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Wed, 24 Jan 2024 16:13:36 -0600 Subject: [PATCH 165/188] more updates to remove warnings --- aviary/api.py | 5 ----- aviary/docs/getting_started/onboarding_level3.ipynb | 11 ++++++----- aviary/docs/user_guide/features/overriding.ipynb | 3 ++- aviary/interface/methods_for_level2.py | 2 +- aviary/mission/gasp_based/ode/base_ode.py | 2 ++ 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/aviary/api.py b/aviary/api.py index 28eee2ae3..d390b6789 100644 --- a/aviary/api.py +++ b/aviary/api.py @@ -143,8 +143,3 @@ from aviary.subsystems.propulsion.engine_model import EngineModel from aviary.subsystems.propulsion.propulsion_builder import PropulsionBuilderBase from aviary.subsystems.propulsion.propulsion_builder import CorePropulsionBuilder - -# Testing -# NOTE these load every FLOPS validation test case, every Avairy run -from aviary.validation_cases.validation_tests import get_flops_inputs, get_flops_outputs -from aviary.validation_cases.validation_data.flops_data.FLOPS_Test_Data import FLOPS_Test_Data diff --git a/aviary/docs/getting_started/onboarding_level3.ipynb b/aviary/docs/getting_started/onboarding_level3.ipynb index db5d76a26..49c9136b6 100644 --- a/aviary/docs/getting_started/onboarding_level3.ipynb +++ b/aviary/docs/getting_started/onboarding_level3.ipynb @@ -75,6 +75,7 @@ "import scipy.constants as _units\n", "\n", "import aviary.api as av\n", + "from aviary.validation_cases.validation_tests import get_flops_inputs\n", "\n", "\n", "prob = om.Problem(model=om.Group())\n", @@ -88,7 +89,7 @@ "# Aircraft Input Variables and Options #\n", "##########################################\n", "\n", - "aviary_inputs = av.get_flops_inputs('N3CC')\n", + "aviary_inputs = get_flops_inputs('N3CC')\n", "\n", "aviary_inputs.set_val(av.Mission.Landing.LIFT_COEFFICIENT_MAX,\n", " 2.4, units=\"unitless\")\n", @@ -525,10 +526,10 @@ "metadata": {}, "outputs": [], "source": [ - "aviary_inputs = av.get_flops_inputs('LargeSingleAisle1FLOPS')\n", - "aviary_inputs = av.get_flops_inputs('LargeSingleAisle2FLOPS')\n", - "aviary_inputs = av.get_flops_inputs('LargeSingleAisle2FLOPSdw')\n", - "aviary_inputs = av.get_flops_inputs('LargeSingleAisle2FLOPSalt')" + "aviary_inputs = get_flops_inputs('LargeSingleAisle1FLOPS')\n", + "aviary_inputs = get_flops_inputs('LargeSingleAisle2FLOPS')\n", + "aviary_inputs = get_flops_inputs('LargeSingleAisle2FLOPSdw')\n", + "aviary_inputs = get_flops_inputs('LargeSingleAisle2FLOPSalt')" ] }, { diff --git a/aviary/docs/user_guide/features/overriding.ipynb b/aviary/docs/user_guide/features/overriding.ipynb index e7f81401d..de7b9a634 100644 --- a/aviary/docs/user_guide/features/overriding.ipynb +++ b/aviary/docs/user_guide/features/overriding.ipynb @@ -46,8 +46,9 @@ "source": [ "from aviary.api import Aircraft\n", "import aviary.api as av\n", + "from aviary.validation_cases.validation_data.flops_data.FLOPS_Test_Data import FLOPS_Test_Data\n", "\n", - "aviary_inputs = av.AviaryValues(av.FLOPS_Test_Data['LargeSingleAisle1FLOPS']['inputs'])\n", + "aviary_inputs = av.AviaryValues(FLOPS_Test_Data['LargeSingleAisle1FLOPS']['inputs'])\n", "\n", "aviary_inputs.set_val(Aircraft.HorizontalTail.MASS, 2200.0, units='lbm')" ] diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 0f8c1737c..97cabb9a6 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -1437,7 +1437,7 @@ def add_linkage_constraint(self, phase_a, phase_b, var_a, var_b, connected, self.model.promotes("landing", inputs=param_list) if self.analysis_scheme is AnalysisScheme.SHOOTING: self.model.promotes("traj", inputs=param_list) - self.model.list_inputs() + # self.model.list_inputs() # self.model.promotes("traj", inputs=['ascent.ODE_group.eoms.'+Aircraft.Design.MAX_FUSELAGE_PITCH_ANGLE]) self.model.connect("taxi.mass", "vrot.mass") diff --git a/aviary/mission/gasp_based/ode/base_ode.py b/aviary/mission/gasp_based/ode/base_ode.py index 2884c1d4b..c74ba6773 100644 --- a/aviary/mission/gasp_based/ode/base_ode.py +++ b/aviary/mission/gasp_based/ode/base_ode.py @@ -72,6 +72,7 @@ def AddAlphaControl( name="alpha", val=np.full(nn, 10), # initial guess units="deg", + eq_units="unitless", lhs_name="load_factor", rhs_val=target_load_factor, upper=25., @@ -99,6 +100,7 @@ def AddAlphaControl( lhs_name="TAS_rate", rhs_name='target_tas_rate', rhs_val=target_tas_rate, + eq_units="kn/s", upper=25., lower=-2., ) From 3656d46ebc0341981ede2132b882bed6376d453f Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Wed, 24 Jan 2024 15:42:28 -0800 Subject: [PATCH 166/188] Created workflow for sending notifications to Teams --- .github/workflows/notify_teams.yml | 144 +++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 .github/workflows/notify_teams.yml diff --git a/.github/workflows/notify_teams.yml b/.github/workflows/notify_teams.yml new file mode 100644 index 000000000..3cbbb6c05 --- /dev/null +++ b/.github/workflows/notify_teams.yml @@ -0,0 +1,144 @@ +name: Notify Teams + +on: + pull_request_target: + branches: [main] + types: [opened, reopened, assigned, closed] + +env: + SMTP_SERVER: smtp.gmail.com + SMTP_PORT: 465 + EMAIL_USERNAME: ${{ secrets.EMAIL_USERNAME }} + EMAIL_PASSWORD: ${{ secrets.EMAIL_PASSWORD }} + EMAIL_FROM: GitHub Actions + EMAIL_TO: ${{ secrets.DESTINATION_EMAIL }} + # Optional priority: 'high', 'normal' (default) or 'low' + +jobs: + send_email_on_opened_pr: + if: github.event_name == 'pull_request' && github.event.action == 'opened' + runs-on: ubuntu-latest + steps: + - name: Get PR Data + run: | + echo "action=${{ github.event.action }}" >> $GITHUB_ENV + echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_ENV + echo "user=${{ github.event.pull_request.user.login }}" >> $GITHUB_ENV + echo "title=${{ github.event.pull_request.title }}" >> $GITHUB_ENV + echo "url=${{ github.event.pull_request.html_url }}" >> $GITHUB_ENV + echo "assignees=${{ join(github.event.pull_request.assignees.*.login, ',') }}" >> $GITHUB_ENV + + - name: Send Email on Opened PR + uses: dawidd6/action-send-mail@v3 + with: + server_address: ${{ env.SMTP_SERVER }} + server_port: ${{ env.SMTP_PORT }} + username: ${{ env.EMAIL_USERNAME }} + password: ${{ env.EMAIL_PASSWORD }} + to: ${{ env.EMAIL_TO }} + from: ${{ env.EMAIL_FROM }} + subject: "***Notification*** New Pull Request: ${{ env.number }}" + body: | + { + "action": "${{ env.action }}", + "number": "${{ env.number }}", + "user": "${{ env.user }}", + "title": "${{ env.title }}", + "url": "${{ env.url }}", + "assignees": "${{ env.assignees }}" + } + ignore_cert: true + nodemailerlog: true + nodemailerdebug: true + + send_email_on_reopened_pr: + if: github.event_name == 'pull_request' && github.event.action == 'reopened' + runs-on: ubuntu-latest + steps: + - name: Get PR Data + run: | + echo "action=${{ github.event.action }}" >> $GITHUB_ENV + echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_ENV + echo "user=${{ github.event.pull_request.user.login }}" >> $GITHUB_ENV + echo "title=${{ github.event.pull_request.title }}" >> $GITHUB_ENV + + - name: Send Email on Reopened PR + uses: dawidd6/action-send-mail@v3 + with: + server_address: ${{ env.SMTP_SERVER }} + server_port: ${{ env.SMTP_PORT }} + username: ${{ env.EMAIL_USERNAME }} + password: ${{ env.EMAIL_PASSWORD }} + to: ${{ env.EMAIL_TO }} + from: ${{ env.EMAIL_FROM }} + subject: "***Notification*** Reopened: ${{ env.number }}" + body: | + { + "action": "${{ env.action }}", + "number": "${{ env.number }}", + "user": "${{ env.user }}", + "title": "${{ env.title }}" + } + ignore_cert: true + nodemailerlog: true + nodemailerdebug: true + + send_email_on_updated_assignees: + if: github.event_name == 'pull_request' && github.event.action == 'assigned' + runs-on: ubuntu-latest + steps: + - name: Get Updated Assignees + run: | + echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_ENV + echo "assignees=${{ join(github.event.pull_request.assignees.*.login, ',') }}" >> $GITHUB_ENV + echo "title=${{ github.event.pull_request.title }}" >> $GITHUB_ENV + + - name: Send Email on Updated Assignees + uses: dawidd6/action-send-mail@v3 + with: + server_address: ${{ env.SMTP_SERVER }} + server_port: ${{ env.SMTP_PORT }} + username: ${{ env.EMAIL_USERNAME }} + password: ${{ env.EMAIL_PASSWORD }} + to: ${{ env.EMAIL_TO }} + from: ${{ env.EMAIL_FROM }} + subject: "***Notification*** Updated Assignees for Pull Request: ${{ env.number }}" + body: | + { + "number": "${{ env.number }}", + "assignees": "${{ env.assignees }}", + "title": "${{ env.title }}" + } + ignore_cert: true + nodemailerlog: true + nodemailerdebug: true + + send_email_on_closed_pr: + if: github.event_name == 'pull_request' && github.event.action == 'closed' + runs-on: ubuntu-latest + steps: + - name: Get PR Data + run: | + echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_ENV + echo "title=${{ github.event.pull_request.title }}" >> $GITHUB_ENV + + - name: Send Email on Updated Assignees + uses: dawidd6/action-send-mail@v3 + with: + server_address: ${{ env.SMTP_SERVER }} + server_port: ${{ env.SMTP_PORT }} + username: ${{ env.EMAIL_USERNAME }} + password: ${{ env.EMAIL_PASSWORD }} + to: ${{ env.EMAIL_TO }} + from: ${{ env.EMAIL_FROM }} + subject: "***Notification*** Closed Pull Request: ${{ env.number }}" + body: | + { + "number": "${{ env.number }}", + "title": "${{ env.title }}" + } + ignore_cert: true + nodemailerlog: true + nodemailerdebug: true + + From 06336b70f4c8311fd081a7090f8e5161fbf37588 Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Wed, 24 Jan 2024 16:24:34 -0800 Subject: [PATCH 167/188] Allow pull_request and pull_request_target --- .github/workflows/notify_teams.yml | 40 +++--------------------------- 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/.github/workflows/notify_teams.yml b/.github/workflows/notify_teams.yml index 3cbbb6c05..f821e6c20 100644 --- a/.github/workflows/notify_teams.yml +++ b/.github/workflows/notify_teams.yml @@ -16,7 +16,7 @@ env: jobs: send_email_on_opened_pr: - if: github.event_name == 'pull_request' && github.event.action == 'opened' + if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && (github.event.action == 'opened' || github.event.action == 'reopened') runs-on: ubuntu-latest steps: - name: Get PR Data @@ -37,7 +37,7 @@ jobs: password: ${{ env.EMAIL_PASSWORD }} to: ${{ env.EMAIL_TO }} from: ${{ env.EMAIL_FROM }} - subject: "***Notification*** New Pull Request: ${{ env.number }}" + subject: "***Notification*** Opened Pull Request: ${{ env.number }}" body: | { "action": "${{ env.action }}", @@ -51,40 +51,8 @@ jobs: nodemailerlog: true nodemailerdebug: true - send_email_on_reopened_pr: - if: github.event_name == 'pull_request' && github.event.action == 'reopened' - runs-on: ubuntu-latest - steps: - - name: Get PR Data - run: | - echo "action=${{ github.event.action }}" >> $GITHUB_ENV - echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_ENV - echo "user=${{ github.event.pull_request.user.login }}" >> $GITHUB_ENV - echo "title=${{ github.event.pull_request.title }}" >> $GITHUB_ENV - - - name: Send Email on Reopened PR - uses: dawidd6/action-send-mail@v3 - with: - server_address: ${{ env.SMTP_SERVER }} - server_port: ${{ env.SMTP_PORT }} - username: ${{ env.EMAIL_USERNAME }} - password: ${{ env.EMAIL_PASSWORD }} - to: ${{ env.EMAIL_TO }} - from: ${{ env.EMAIL_FROM }} - subject: "***Notification*** Reopened: ${{ env.number }}" - body: | - { - "action": "${{ env.action }}", - "number": "${{ env.number }}", - "user": "${{ env.user }}", - "title": "${{ env.title }}" - } - ignore_cert: true - nodemailerlog: true - nodemailerdebug: true - send_email_on_updated_assignees: - if: github.event_name == 'pull_request' && github.event.action == 'assigned' + if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && github.event.action == 'assigned' runs-on: ubuntu-latest steps: - name: Get Updated Assignees @@ -114,7 +82,7 @@ jobs: nodemailerdebug: true send_email_on_closed_pr: - if: github.event_name == 'pull_request' && github.event.action == 'closed' + if: (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') && github.event.action == 'closed' runs-on: ubuntu-latest steps: - name: Get PR Data From 96846c3b1a4cee816b46c9f2f80684301f8f1942 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Thu, 25 Jan 2024 09:40:08 -0500 Subject: [PATCH 168/188] Added units to the Results-Aviary Variables table in the dashboard --- aviary/visualization/assets/aviary_vars/script.js | 6 ++++++ aviary/visualization/dashboard.py | 3 +++ 2 files changed, 9 insertions(+) diff --git a/aviary/visualization/assets/aviary_vars/script.js b/aviary/visualization/assets/aviary_vars/script.js index 36d48f3ec..17ed2cbab 100755 --- a/aviary/visualization/assets/aviary_vars/script.js +++ b/aviary/visualization/assets/aviary_vars/script.js @@ -56,6 +56,12 @@ function createTabulator(tableData) width: 300, tooltip: (e, cell, onRendered) => displayValueInToolTip(e, cell, onRendered), }, + { + title: "Units", + field: "units", + width: 200, + tooltip: (e, cell, onRendered) => displayValueInToolTip(e, cell, onRendered), + }, ] }); diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index 3926a94dd..5810c945b 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -185,6 +185,7 @@ def create_aviary_variables_table_data_nested(script_name, recorder_file): "abs_name": group_name, "prom_name": outputs[var_info]["prom_name"], "value": str(outputs[var_info]["val"]), + "units": str(outputs[var_info]["units"]), } ) else: @@ -197,6 +198,7 @@ def create_aviary_variables_table_data_nested(script_name, recorder_file): "abs_name": children_name, "prom_name": outputs[children_name]["prom_name"], "value": str(outputs[children_name]["val"]), + "units": str(outputs[children_name]["units"]), } ) table_data_nested.append( # not a real var, just a group of vars so no values @@ -204,6 +206,7 @@ def create_aviary_variables_table_data_nested(script_name, recorder_file): "abs_name": group_name, "prom_name": "", "value": "", + "units": "", "_children": children_list, } ) From 2d9273ac4e74a8b19f8a05b28338360391f10922 Mon Sep 17 00:00:00 2001 From: Herb Schilling Date: Thu, 25 Jan 2024 09:45:10 -0500 Subject: [PATCH 169/188] Minor doc change --- aviary/visualization/dashboard.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aviary/visualization/dashboard.py b/aviary/visualization/dashboard.py index 26bf503a5..78675e4b0 100644 --- a/aviary/visualization/dashboard.py +++ b/aviary/visualization/dashboard.py @@ -111,7 +111,7 @@ def create_report_frame(format, text_filepath): if format == 'html': iframe_css = 'width=1200px height=800px overflow-x="scroll" overflow="scroll" margin=0px padding=0px border=20px frameBorder=20px scrolling="yes"' report_pane = pn.pane.HTML( - f'' ) + f'') elif format in ['markdown', 'text']: with open(text_filepath, "rb") as f: file_text = f.read() @@ -307,7 +307,6 @@ def dashboard(script_name, problem_recorder, driver_recorder, port): ) # TODO - use lists and functions to do this with a lot less code - ####### Model Tab ####### model_tabs_list = [] From 0f82417f584e2c60155776fcb1187e502c46d69e Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 25 Jan 2024 11:26:47 -0600 Subject: [PATCH 170/188] Opened up mass bounds --- aviary/mission/gasp_based/phases/cruise_phase.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aviary/mission/gasp_based/phases/cruise_phase.py b/aviary/mission/gasp_based/phases/cruise_phase.py index 7384fa632..c2ef8352e 100644 --- a/aviary/mission/gasp_based/phases/cruise_phase.py +++ b/aviary/mission/gasp_based/phases/cruise_phase.py @@ -89,9 +89,9 @@ def build_phase(self, aviary_options: AviaryValues = None): fix_duration=False, units="lbm", targets="mass", - initial_bounds=(10.e3, 500_000), - initial_ref=100_000, - duration_bounds=(-50000, -10), + initial_bounds=(0., 1.e7), + initial_ref=10.e3, + duration_bounds=(-1.e7, -1), duration_ref=50000, ) From 597d29b3482f2c51b0df2b01b4af4d42d5740ee5 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 25 Jan 2024 12:02:24 -0600 Subject: [PATCH 171/188] Updated ref for bench --- aviary/mission/gasp_based/phases/cruise_phase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/mission/gasp_based/phases/cruise_phase.py b/aviary/mission/gasp_based/phases/cruise_phase.py index c2ef8352e..bc69aecb0 100644 --- a/aviary/mission/gasp_based/phases/cruise_phase.py +++ b/aviary/mission/gasp_based/phases/cruise_phase.py @@ -90,7 +90,7 @@ def build_phase(self, aviary_options: AviaryValues = None): units="lbm", targets="mass", initial_bounds=(0., 1.e7), - initial_ref=10.e3, + initial_ref=100.e3, duration_bounds=(-1.e7, -1), duration_ref=50000, ) From afefd04d72cc3283b119d0a0e2255a2742c28d1f Mon Sep 17 00:00:00 2001 From: crecine <51181861+crecine@users.noreply.github.com> Date: Thu, 25 Jan 2024 10:37:32 -0800 Subject: [PATCH 172/188] Update notify_teams.yml --- .github/workflows/notify_teams.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/notify_teams.yml b/.github/workflows/notify_teams.yml index f821e6c20..235d0e915 100644 --- a/.github/workflows/notify_teams.yml +++ b/.github/workflows/notify_teams.yml @@ -90,7 +90,7 @@ jobs: echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_ENV echo "title=${{ github.event.pull_request.title }}" >> $GITHUB_ENV - - name: Send Email on Updated Assignees + - name: Send Email on Closed PR uses: dawidd6/action-send-mail@v3 with: server_address: ${{ env.SMTP_SERVER }} From 0994282e16dc90a8785c556a0d6dccdd31c2895a Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 25 Jan 2024 13:21:13 -0600 Subject: [PATCH 173/188] PR feedback --- aviary/mission/gasp_based/phases/rotation_phase.py | 1 - setup.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/aviary/mission/gasp_based/phases/rotation_phase.py b/aviary/mission/gasp_based/phases/rotation_phase.py index f50776037..4f09adaff 100644 --- a/aviary/mission/gasp_based/phases/rotation_phase.py +++ b/aviary/mission/gasp_based/phases/rotation_phase.py @@ -1,5 +1,4 @@ import numpy as np -from dymos.utils.misc import _unspecified from aviary.mission.phase_builder_base import ( PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) diff --git a/setup.py b/setup.py index 4786b34cd..718388d16 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ pkgname = "aviary" extras_require = { "test": ["testflo", "pyxdsm", "pre-commit"], - "examples": ["openaerostruct", "ambiance"], + "examples": ["openaerostruct", "ambiance", "itables"], } all_packages = [] From 7a2258643489f1a19dfeea3296e4995d0e145f76 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Thu, 25 Jan 2024 18:23:04 -0600 Subject: [PATCH 174/188] Beginning to move phase builders --- aviary/mission/flight_phase_builder_base.py | 474 ++++++++++++++++++ .../phases/detailed_landing_phases.py | 5 +- .../phases/detailed_takeoff_phases.py | 5 +- .../flops_based/phases/energy_phase.py | 9 +- aviary/mission/gasp_based/ode/climb_ode.py | 1 - .../mission/gasp_based/phases/accel_phase.py | 4 +- .../mission/gasp_based/phases/ascent_phase.py | 4 +- .../mission/gasp_based/phases/climb_phase.py | 4 +- .../mission/gasp_based/phases/cruise_phase.py | 4 +- .../mission/gasp_based/phases/desc_phase.py | 135 ----- .../gasp_based/phases/descent_phase.py | 4 +- .../gasp_based/phases/groundroll_phase.py | 4 +- .../gasp_based/phases/rotation_phase.py | 4 +- aviary/mission/initial_guess_builders.py | 191 +++++++ aviary/mission/phase_builder_base.py | 178 +------ 15 files changed, 689 insertions(+), 337 deletions(-) create mode 100644 aviary/mission/flight_phase_builder_base.py delete mode 100644 aviary/mission/gasp_based/phases/desc_phase.py create mode 100644 aviary/mission/initial_guess_builders.py diff --git a/aviary/mission/flight_phase_builder_base.py b/aviary/mission/flight_phase_builder_base.py new file mode 100644 index 000000000..f3907ae8a --- /dev/null +++ b/aviary/mission/flight_phase_builder_base.py @@ -0,0 +1,474 @@ +''' +Define utilities for building phases. + +Classes +------- + +''' +from abc import ABC +from collections import namedtuple +from collections.abc import Sequence + +import dymos as dm +import numpy as np +import openmdao.api as om + +from aviary.mission.flops_based.ode.mission_ODE import MissionODE +from aviary.utils.aviary_values import AviaryValues, get_keys + +_require_new_meta_data_class_attr_ = \ + namedtuple('_require_new_meta_data_class_attr_', ()) + + +_require_new_initial_guesses_meta_data_class_attr_ = \ + namedtuple('_require_new_initial_guesses_meta_data_class_attr_', ()) + + +class PhaseBuilderBase(ABC): + ''' + Define the interface for a phase builder. + + Attributes + ---------- + name : str ('') + object label + + core_subsystems : (None) + list of SubsystemBuilderBase objects that will be added to the phase ODE + + user_options : AviaryValues () + state/path constraint values and flags + + initial_guesses : AviaryValues () + state/path beginning values to be set on the problem + + ode_class : type (None) + advanced: the type of system defining the ODE + + transcription : "Dymos transcription object" (None) + advanced: an object providing the transcription technique of the + optimal control problem + + subsystem_options : dict (None) + dictionary of parameters to be passed to the subsystem builders + + default_name : str + class attribute: derived type customization point; the default value + for name + + default_ode_class : type + class attribute: derived type customization point; the default value + for ode_class used by build_phase + + is_analytic_phase : bool (False) + class attribute: derived type customization point; if True, build_phase + will return an AnalyticPhase instead of a Phase + + num_nodes : int (5) + class attribute: derived type customization point; the default value + for num_nodes used by build_phase, only for AnalyticPhases + + Methods + ------- + build_phase + make_default_transcription + validate_options + assign_default_options + ''' + __slots__ = ( + 'name', 'core_subsystems', 'subsystem_options', 'user_options', + 'initial_guesses', 'ode_class', 'transcription', + 'is_analytic_phase', 'num_nodes', + ) + + # region : derived type customization points + _meta_data_ = _require_new_meta_data_class_attr_() + + _initial_guesses_meta_data_ = _require_new_initial_guesses_meta_data_class_attr_() + + default_name = '' + + default_ode_class = MissionODE + # endregion : derived type customization points + + def __init__( + self, name=None, core_subsystems=None, user_options=None, initial_guesses=None, + ode_class=None, transcription=None, subsystem_options=None, is_analytic_phase=False, num_nodes=5, + ): + if name is None: + name = self.default_name + + self.name = name + + if core_subsystems is None: + core_subsystems = [] + + self.core_subsystems = core_subsystems + + if subsystem_options is None: + subsystem_options = {} + + self.subsystem_options = subsystem_options + + self.user_options = user_options + self.validate_options() + self.assign_default_options() + + if initial_guesses is None: + initial_guesses = AviaryValues() + + self.initial_guesses = initial_guesses + self.validate_initial_guesses() + + self.ode_class = ode_class + self.transcription = transcription + self.is_analytic_phase = is_analytic_phase + self.num_nodes = num_nodes + + def build_phase(self, aviary_options=None): + ''' + Return a new phase object for analysis using these constraints. + + If ode_class is None, default_ode_class is used. + + If transcription is None, the return value from calling + make_default_transcription is used. + + Parameters + ---------- + aviary_options : AviaryValues (emtpy) + collection of Aircraft/Mission specific options + + Returns + ------- + dymos.Phase + ''' + ode_class = self.ode_class + + if ode_class is None: + ode_class = self.default_ode_class + + transcription = self.transcription + + if transcription is None and not self.is_analytic_phase: + transcription = self.make_default_transcription() + + if aviary_options is None: + aviary_options = AviaryValues() + + kwargs = self._extra_ode_init_kwargs() + + kwargs = { + 'aviary_options': aviary_options, + **kwargs + } + + subsystem_options = self.subsystem_options + + if subsystem_options is not None: + kwargs['subsystem_options'] = subsystem_options + + kwargs['core_subsystems'] = self.core_subsystems + + if self.is_analytic_phase: + phase = dm.AnalyticPhase( + ode_class=ode_class, + ode_init_kwargs=kwargs, + num_nodes=self.num_nodes, + ) + else: + phase = dm.Phase( + ode_class=ode_class, transcription=transcription, + ode_init_kwargs=kwargs + ) + + # overrides should add state, controls, etc. + return phase + + def make_default_transcription(self): + ''' + Return a transcription object to be used by default in build_phase. + ''' + user_options = self.user_options + + num_segments, _ = user_options.get_item('num_segments') + order, _ = user_options.get_item('order') + + transcription = dm.Radau( + num_segments=num_segments, order=order, compressed=True) + + return transcription + + def validate_options(self): + ''' + Raise TypeError if an unsupported option is found. + + Users can call this method when updating options after initialization. + ''' + user_options = self.user_options + + if not user_options: + return # acceptable + + meta_data = self._meta_data_ + + for key in get_keys(user_options): + if key not in meta_data: + raise TypeError( + f'{self.__class__.__name__}: {self.name}:' + f' unsupported option: {key}' + ) + + def assign_default_options(self): + ''' + Update missing options with default values. + + If user_options is None, start with an empty AviaryValues. + + Users can call this method when replacing the user_options member after + initialization. + ''' + user_options = self.user_options + + if user_options is None: + user_options = self.user_options = AviaryValues() + + meta_data = self._meta_data_ + + for key in meta_data: + if key not in user_options: + item = meta_data[key] + + val = item['val'] + units = item['units'] + + user_options.set_val(key, val, units) + + def validate_initial_guesses(self): + ''' + Raise TypeError if an unsupported initial guess is found. + + Users can call this method when updating initial guesses after initialization. + ''' + initial_guesses = self.initial_guesses + + if not initial_guesses: + return # acceptable + + meta_data = self._initial_guesses_meta_data_ + + for key in get_keys(initial_guesses): + if key not in meta_data: + raise TypeError( + f'{self.__class__.__name__}: {self.name}:' + f' unsupported initial guess: {key}' + ) + + def apply_initial_guesses( + self, prob: om.Problem, traj_name, phase: dm.Phase + ): + ''' + Apply any stored initial guesses; return a list of guesses not applied. + ''' + not_applied = [] + + phase_name = self.name + meta_data = self._initial_guesses_meta_data_ + initial_guesses: AviaryValues = self.initial_guesses + + for key in meta_data: + if key in initial_guesses: + apply_initial_guess = meta_data[key]['apply_initial_guess'] + val, units = initial_guesses.get_item(key) + + apply_initial_guess(prob, traj_name, phase, phase_name, val, units) + + else: + not_applied.append(key) + + return not_applied + + def _extra_ode_init_kwargs(self): + """ + Return extra kwargs required for initializing the ODE. + """ + return {} + + def to_phase_info(self): + ''' + Return the stored settings as phase info. + + Returns + ------- + tuple + name : str + object label + phase_info : dict + stored settings + ''' + subsystem_options = self.subsystem_options # TODO: aero info? + user_options = dict(self.user_options) + initial_guesses = dict(self.initial_guesses) + + # TODO some of these may be purely programming API hooks, rather than for use + # with phase info + # - ode_class + # - transcription + # - external_subsystems + # - meta_data + + phase_info = dict( + subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses) + + return (self.name, phase_info) + + @classmethod + def from_phase_info(cls, name, phase_info: dict, core_subsystems=None, meta_data=None, transcription=None): + ''' + Return a new phase builder based on the specified phase info. + + Note, calling code is responsible for matching phase info to the correct phase + builder type, or the behavior is undefined. + + Parameters + ---------- + name : str + object label + phase_info : dict + stored settings + ''' + # loop over user_options dict entries + # if the value is not a tuple, wrap it in a tuple with the second entry of 'unitless' + for key, value in phase_info['user_options'].items(): + if not isinstance(value, tuple): + phase_info['user_options'][key] = (value, 'unitless') + + subsystem_options = phase_info.get( + 'subsystem_options', {}) # TODO: aero info? + user_options = AviaryValues(phase_info.get('user_options', ())) + initial_guesses = AviaryValues(phase_info.get('initial_guesses', ())) + external_subsystems = phase_info.get('external_subsystems', []) + # TODO core subsystems in phase info? + + # TODO some of these may be purely programming API hooks, rather than for use + # with phase info + # - ode_class + # - transcription + # - external_subsystems + # - meta_data + + phase_builder = cls( + name, subsystem_options=subsystem_options, user_options=user_options, + initial_guesses=initial_guesses, meta_data=meta_data, + core_subsystems=core_subsystems, external_subsystems=external_subsystems, transcription=transcription) + + return phase_builder + + @classmethod + def _add_meta_data(cls, name, *, val, units='unitless', desc=None): + ''' + Update supported options with a new item. + + Raises + ------ + ValueError + if a repeat option is found + ''' + meta_data = cls._meta_data_ + + if name in meta_data: + raise ValueError( + f'{cls.__name__}": meta data: repeat option: {name}' + ) + + meta_data[name] = dict(val=val, units=units, desc=desc) + + @classmethod + def _add_initial_guess_meta_data(cls, initial_guess: InitialGuess, desc=None): + ''' + Update supported initial guesses with a new item. + + Raises + ------ + ValueError + if a repeat initial guess is found + ''' + meta_data = cls._initial_guesses_meta_data_ + name = initial_guess.key + + if name in meta_data: + raise ValueError( + f'{cls.__name__}": meta data: repeat initial guess: {name}' + ) + + meta_data[name] = dict( + apply_initial_guess=initial_guess.apply_initial_guess, desc=desc) + + +_registered_phase_builder_types = [] + + +def register(phase_builder_t=None, *, check_repeats=True): + ''' + Register a new phase builder type. + + Note, this function qualifies as a class decorator for ease of use. + + Returns + ------- + ''' + if phase_builder_t is None: + def decorator(phase_builder_t): + return register(phase_builder_t, check_repeats=check_repeats) + + return decorator + + if check_repeats and (phase_builder_t in _registered_phase_builder_types): + raise ValueError('repeated phase builder type') + + _registered_phase_builder_types.append(phase_builder_t) + + return phase_builder_t + + +def phase_info_to_builder(name: str, phase_info: dict) -> PhaseBuilderBase: + ''' + Return a new phase builder based on the specified phase info. + + Note, the type of phase builder will be determined by calling + phase_builder_t.from_phase_info() for each registered type in order of registration; + the first result that is not None will be returned. If a supported phase builder type + cannot be determined, raise ValueError. + + Raises + ------ + ValueError + if a supported phase builder type cannot be determined + ''' + phase_builder_t: PhaseBuilderBase = None + + for phase_builder_t in _registered_phase_builder_types: + builder = phase_builder_t.from_phase_info(name, phase_info) + + if builder is not None: + return builder + + raise ValueError(f'unsupported phase info: {name}') + + +if __name__ == '__main__': + help(PhaseBuilderBase) + + try: + PhaseBuilderBase._add_meta_data('test', val=0, units=None, desc='test') + + except Exception as error: + print(error) + + try: + PhaseBuilderBase._add_initial_guess_meta_data( + InitialGuessTime(), desc='test initial guess') + + except Exception as error: + print(error) diff --git a/aviary/mission/flops_based/phases/detailed_landing_phases.py b/aviary/mission/flops_based/phases/detailed_landing_phases.py index 43e53a257..0f5b255c5 100644 --- a/aviary/mission/flops_based/phases/detailed_landing_phases.py +++ b/aviary/mission/flops_based/phases/detailed_landing_phases.py @@ -32,9 +32,8 @@ TakeoffTrajectory as _TakeoffTrajectory from aviary.mission.flops_based.phases.detailed_takeoff_phases import \ _init_initial_guess_meta_data -from aviary.mission.phase_builder_base import ( - InitialGuessControl, InitialGuessParameter, InitialGuessPolynomialControl, - InitialGuessState, PhaseBuilderBase) +from aviary.mission.phase_builder_base import PhaseBuilderBase +from aviary.mission.initial_guess_builders import InitialGuessControl, InitialGuessParameter, InitialGuessPolynomialControl, InitialGuessState, InitialGuessTime from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import setup_trajectory_params from aviary.variable_info.variables import Dynamic, Mission diff --git a/aviary/mission/flops_based/phases/detailed_takeoff_phases.py b/aviary/mission/flops_based/phases/detailed_takeoff_phases.py index 70e877528..ea9dc73b5 100644 --- a/aviary/mission/flops_based/phases/detailed_takeoff_phases.py +++ b/aviary/mission/flops_based/phases/detailed_takeoff_phases.py @@ -46,9 +46,8 @@ import openmdao.api as om from aviary.mission.flops_based.ode.takeoff_ode import TakeoffODE -from aviary.mission.phase_builder_base import ( - InitialGuessControl, InitialGuessParameter, InitialGuessPolynomialControl, - InitialGuessState, InitialGuessTime, PhaseBuilderBase) +from aviary.mission.phase_builder_base import PhaseBuilderBase +from aviary.mission.initial_guess_builders import InitialGuessControl, InitialGuessParameter, InitialGuessPolynomialControl, InitialGuessState, InitialGuessTime from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import setup_trajectory_params from aviary.variable_info.variables import Dynamic, Mission diff --git a/aviary/mission/flops_based/phases/energy_phase.py b/aviary/mission/flops_based/phases/energy_phase.py index 06a311e08..0b637e75a 100644 --- a/aviary/mission/flops_based/phases/energy_phase.py +++ b/aviary/mission/flops_based/phases/energy_phase.py @@ -1,8 +1,7 @@ import dymos as dm -from aviary.mission.phase_builder_base import ( - register, PhaseBuilderBase, InitialGuessControl, InitialGuessParameter, - InitialGuessPolynomialControl, InitialGuessState, InitialGuessTime) +from aviary.mission.phase_builder_base import PhaseBuilderBase, register +from aviary.mission.initial_guess_builders import InitialGuessState, InitialGuessTime, InitialGuessControl from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variable_meta_data import _MetaData @@ -428,11 +427,11 @@ def _extra_ode_init_kwargs(self): desc='initial guess for horizontal distance traveled') EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('altitude'), + InitialGuessControl('altitude'), desc='initial guess for vertical distances') EnergyPhase._add_initial_guess_meta_data( - InitialGuessState('mach'), + InitialGuessControl('mach'), desc='initial guess for speed') EnergyPhase._add_initial_guess_meta_data( diff --git a/aviary/mission/gasp_based/ode/climb_ode.py b/aviary/mission/gasp_based/ode/climb_ode.py index 71b1366ea..6a16f4153 100644 --- a/aviary/mission/gasp_based/ode/climb_ode.py +++ b/aviary/mission/gasp_based/ode/climb_ode.py @@ -11,7 +11,6 @@ from aviary.mission.gasp_based.ode.params import ParamPort from aviary.subsystems.aerodynamics.aerodynamics_builder import AerodynamicsBuilderBase from aviary.subsystems.propulsion.propulsion_builder import PropulsionBuilderBase -from aviary.subsystems.propulsion.propulsion_mission import PropulsionMission from aviary.variable_info.enums import AnalysisScheme, AlphaModes, SpeedType from aviary.variable_info.variables import Dynamic from aviary.mission.ode.specific_energy_rate import SpecificEnergyRate diff --git a/aviary/mission/gasp_based/phases/accel_phase.py b/aviary/mission/gasp_based/phases/accel_phase.py index 95a5034a7..a45822123 100644 --- a/aviary/mission/gasp_based/phases/accel_phase.py +++ b/aviary/mission/gasp_based/phases/accel_phase.py @@ -1,5 +1,5 @@ -from aviary.mission.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.mission.phase_builder_base import PhaseBuilderBase +from aviary.mission.initial_guess_builders import InitialGuessState, InitialGuessTime, InitialGuessControl from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic from aviary.mission.gasp_based.ode.accel_ode import AccelODE diff --git a/aviary/mission/gasp_based/phases/ascent_phase.py b/aviary/mission/gasp_based/phases/ascent_phase.py index 542be98af..12f0b9fe3 100644 --- a/aviary/mission/gasp_based/phases/ascent_phase.py +++ b/aviary/mission/gasp_based/phases/ascent_phase.py @@ -1,5 +1,5 @@ -from aviary.mission.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.mission.phase_builder_base import PhaseBuilderBase +from aviary.mission.initial_guess_builders import InitialGuessState, InitialGuessTime, InitialGuessControl from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic from aviary.mission.gasp_based.ode.ascent_ode import AscentODE diff --git a/aviary/mission/gasp_based/phases/climb_phase.py b/aviary/mission/gasp_based/phases/climb_phase.py index 9c8bbb034..ddb073e84 100644 --- a/aviary/mission/gasp_based/phases/climb_phase.py +++ b/aviary/mission/gasp_based/phases/climb_phase.py @@ -1,5 +1,5 @@ -from aviary.mission.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.mission.phase_builder_base import PhaseBuilderBase +from aviary.mission.initial_guess_builders import InitialGuessState, InitialGuessTime, InitialGuessControl from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic from aviary.mission.gasp_based.ode.climb_ode import ClimbODE diff --git a/aviary/mission/gasp_based/phases/cruise_phase.py b/aviary/mission/gasp_based/phases/cruise_phase.py index bc69aecb0..226782526 100644 --- a/aviary/mission/gasp_based/phases/cruise_phase.py +++ b/aviary/mission/gasp_based/phases/cruise_phase.py @@ -1,5 +1,5 @@ -from aviary.mission.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime) +from aviary.mission.phase_builder_base import PhaseBuilderBase +from aviary.mission.initial_guess_builders import InitialGuessState, InitialGuessTime from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic from aviary.mission.gasp_based.ode.breguet_cruise_ode import BreguetCruiseODESolution diff --git a/aviary/mission/gasp_based/phases/desc_phase.py b/aviary/mission/gasp_based/phases/desc_phase.py deleted file mode 100644 index 5bb549c95..000000000 --- a/aviary/mission/gasp_based/phases/desc_phase.py +++ /dev/null @@ -1,135 +0,0 @@ -import dymos as dm - -from aviary.mission.gasp_based.ode.descent_ode import DescentODE -from aviary.variable_info.enums import SpeedType -from aviary.variable_info.variables import Dynamic - - -def get_descent( - ode_args=None, - transcription=None, - fix_initial=False, - input_initial=False, - EAS_limit=0, - mach_cruise=0, - input_speed_type=SpeedType.MACH, - final_altitude=0, - time_initial_bounds=(0, 0), - time_initial_ref=1, - duration_bounds=(0, 0), - duration_ref=1, - alt_lower=0, - alt_upper=0, - alt_ref=1, - alt_ref0=0, - alt_defect_ref=None, - alt_constraint_ref=None, - mass_lower=0, - mass_upper=0, - mass_ref=1, - mass_ref0=0, - mass_defect_ref=None, - distance_lower=0, - distance_upper=0, - distance_ref=1, - distance_ref0=0, - distance_defect_ref=None, -): - ode_init_kwargs = dict( - EAS_limit=EAS_limit, - input_speed_type=input_speed_type, - mach_cruise=mach_cruise, - ) - if ode_args: - ode_init_kwargs.update(ode_args) - - desc = dm.Phase( - ode_class=DescentODE, - transcription=transcription, - ode_init_kwargs=ode_init_kwargs, - ) - - desc.set_time_options( - initial_bounds=time_initial_bounds, - duration_bounds=duration_bounds, - fix_initial=fix_initial, - input_initial=input_initial, - units="s", - duration_ref=duration_ref, - initial_ref=time_initial_ref, - ) - - desc.add_state( - Dynamic.Mission.ALTITUDE, - fix_initial=True, - fix_final=False, - lower=alt_lower, - upper=alt_upper, - units="ft", - rate_source=Dynamic.Mission.ALTITUDE_RATE, - targets=Dynamic.Mission.ALTITUDE, - ref=alt_ref, - ref0=alt_ref0, - defect_ref=alt_defect_ref, - ) - - if fix_initial and input_initial: - raise ValueError( - "ERROR in desc_phase: fix_initial and input_initial are both True" - ) - - desc.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial, - input_initial=input_initial, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - ref=mass_ref, - ref0=mass_ref0, - defect_ref=mass_defect_ref, - ) - - desc.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - input_initial=input_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="NM", - rate_source=Dynamic.Mission.DISTANCE_RATE, - ref=distance_ref, - ref0=distance_ref0, - defect_ref=distance_defect_ref, - ) - - desc.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, - loc="final", - equals=final_altitude, - units="ft", - ref=alt_constraint_ref) - - if input_speed_type is SpeedType.EAS: - desc.add_parameter("EAS", opt=False, units="kn", val=EAS_limit) - - desc.add_timeseries_output( - Dynamic.Mission.MACH, - output_name=Dynamic.Mission.MACH, - units="unitless") - desc.add_timeseries_output("EAS", output_name="EAS", units="kn") - desc.add_timeseries_output("TAS", output_name="TAS", units="kn") - desc.add_timeseries_output(Dynamic.Mission.FLIGHT_PATH_ANGLE, - output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, units="deg") - desc.add_timeseries_output("alpha", output_name="alpha", units="deg") - desc.add_timeseries_output("theta", output_name="theta", units="deg") - desc.add_timeseries_output("aero.CL", output_name="CL", units="unitless") - desc.add_timeseries_output(Dynamic.Mission.THRUST_TOTAL, - output_name=Dynamic.Mission.THRUST_TOTAL, units="lbf") - desc.add_timeseries_output("aero.CD", output_name="CD", units="unitless") - - return desc diff --git a/aviary/mission/gasp_based/phases/descent_phase.py b/aviary/mission/gasp_based/phases/descent_phase.py index 9d814fde1..a835dc575 100644 --- a/aviary/mission/gasp_based/phases/descent_phase.py +++ b/aviary/mission/gasp_based/phases/descent_phase.py @@ -1,5 +1,5 @@ -from aviary.mission.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.mission.phase_builder_base import PhaseBuilderBase +from aviary.mission.initial_guess_builders import InitialGuessState, InitialGuessTime, InitialGuessControl from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic from aviary.variable_info.enums import SpeedType diff --git a/aviary/mission/gasp_based/phases/groundroll_phase.py b/aviary/mission/gasp_based/phases/groundroll_phase.py index a7d871254..6703a9809 100644 --- a/aviary/mission/gasp_based/phases/groundroll_phase.py +++ b/aviary/mission/gasp_based/phases/groundroll_phase.py @@ -1,5 +1,5 @@ -from aviary.mission.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.mission.phase_builder_base import PhaseBuilderBase +from aviary.mission.initial_guess_builders import InitialGuessState, InitialGuessTime, InitialGuessControl from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic from aviary.mission.gasp_based.ode.groundroll_ode import GroundrollODE diff --git a/aviary/mission/gasp_based/phases/rotation_phase.py b/aviary/mission/gasp_based/phases/rotation_phase.py index 4f09adaff..36c4c0d6e 100644 --- a/aviary/mission/gasp_based/phases/rotation_phase.py +++ b/aviary/mission/gasp_based/phases/rotation_phase.py @@ -1,7 +1,7 @@ import numpy as np -from aviary.mission.phase_builder_base import ( - PhaseBuilderBase, InitialGuessState, InitialGuessTime, InitialGuessControl) +from aviary.mission.phase_builder_base import PhaseBuilderBase +from aviary.mission.initial_guess_builders import InitialGuessState, InitialGuessTime, InitialGuessControl from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic from aviary.mission.gasp_based.ode.rotation_ode import RotationODE diff --git a/aviary/mission/initial_guess_builders.py b/aviary/mission/initial_guess_builders.py new file mode 100644 index 000000000..9b8c3bbb9 --- /dev/null +++ b/aviary/mission/initial_guess_builders.py @@ -0,0 +1,191 @@ +''' +Define utilities for building phases. + +Classes +------- +InitialGuess : a utility for setting an initial guess on a problem + +InitialGuessControl : a utility for setting an initial guess for a control on a problem + +InitialGuessParameter : a utility for setting an initial guess for a parameter on a +problem + +InitialGuessPolynomialControl : a utility for setting an initial guess for a polynomial +control on a problem + +InitialGuessState : a utility for setting an initial guess for a state on a problem + +InitialGuessTime : a utility for setting guesses for initial time and duration on a +problem +''' +from abc import ABC +from collections import namedtuple +from collections.abc import Sequence + +import dymos as dm +import numpy as np +import openmdao.api as om + +from aviary.mission.flops_based.ode.mission_ODE import MissionODE +from aviary.utils.aviary_values import AviaryValues, get_keys + +_require_new_meta_data_class_attr_ = \ + namedtuple('_require_new_meta_data_class_attr_', ()) + + +_require_new_initial_guesses_meta_data_class_attr_ = \ + namedtuple('_require_new_initial_guesses_meta_data_class_attr_', ()) + + +class InitialGuess: + ''' + Define a utility for setting an initial guess on a problem. + + Attributes + ---------- + key : str + base name for the initial guess + ''' + __slots__ = ('key',) + + def __init__(self, key): + self.key = key + + def apply_initial_guess( + self, prob: om.Problem, traj_name, phase: dm.Phase, phase_name, val, units + ): + ''' + Set the initial guess on the problem. + ''' + complete_key = self._get_complete_key(traj_name, phase_name) + + # TODO: this is a short term hack in need of an appropriate long term solution + # - to interpolate, or not to interpolate: that is the question + # - the solution should probably be a value decoration (a wrapper) that is + # both lightweight and easy to check and unpack + if ( + isinstance(val, np.ndarray) + or (isinstance(val, Sequence) and not isinstance(val, str)) + ): + val = phase.interp(self.key, val) + + prob.set_val(complete_key, val, units) + + def _get_complete_key(self, traj_name, phase_name): + ''' + Compose the complete key for setting the initial guess. + ''' + _ = traj_name + _ = phase_name + + return self.key + + +class InitialGuessControl(InitialGuess): + ''' + Define a utility for setting an initial guess for a control on a problem. + + Attributes + ---------- + key : str + base name for the control + ''' + __slots__ = () + + def _get_complete_key(self, traj_name, phase_name): + ''' + Compose the complete key for setting the control initial guess. + ''' + key = f'{traj_name}.{phase_name}.controls:{self.key}' + + return key + + +class InitialGuessParameter(InitialGuess): + ''' + Define a utility for setting an initial guess for a parameter on a problem. + + Attributes + ---------- + key : str + base name for the parameter + ''' + __slots__ = () + + def _get_complete_key(self, traj_name, phase_name): + ''' + Compose the complete key for setting the parameter initial guess. + ''' + key = f'{traj_name}.{phase_name}.parameters:{self.key}' + + return key + + +class InitialGuessPolynomialControl(InitialGuess): + ''' + Define a utility for setting an initial guess for a polynomial control on a problem. + + Attributes + ---------- + key : str + base name for the polynomial control + ''' + __slots__ = () + + def _get_complete_key(self, traj_name, phase_name): + ''' + Compose the complete key for setting the polynomial control initial guess. + ''' + key = f'{traj_name}.{phase_name}.polynomial_controls:{self.key}' + + return key + + +class InitialGuessState(InitialGuess): + ''' + Define a utility for setting an initial guess for a state on a problem. + + Attributes + ---------- + key : str + base name for the state + ''' + __slots__ = () + + def _get_complete_key(self, traj_name, phase_name): + ''' + Compose the complete key for setting the state initial guess. + ''' + key = f'{traj_name}.{phase_name}.states:{self.key}' + + return key + + +class InitialGuessTime(InitialGuess): + ''' + Define a utility for setting guesses for initial time and duration on a problem. + + Attributes + ---------- + key : str ('times') + the group identifier for guesses for initial time and duration + ''' + __slots__ = () + + def __init__(self, key='times'): + super().__init__(key) + + def apply_initial_guess( + self, prob: om.Problem, traj_name, phase: dm.Phase, phase_name, val, units + ): + ''' + Set the guesses for initial time and duration on the problem. + ''' + _ = phase + + name = f'{traj_name}.{phase_name}.t_initial' + t_initial, t_duration = val + prob.set_val(name, t_initial, units) + + name = f'{traj_name}.{phase_name}.t_duration' + prob.set_val(name, t_duration, units) diff --git a/aviary/mission/phase_builder_base.py b/aviary/mission/phase_builder_base.py index a2d5a82db..3b4eb6190 100644 --- a/aviary/mission/phase_builder_base.py +++ b/aviary/mission/phase_builder_base.py @@ -3,27 +3,14 @@ Classes ------- -InitialGuess : a utility for setting an initial guess on a problem - -InitialGuessControl : a utility for setting an initial guess for a control on a problem - -InitialGuessParameter : a utility for setting an initial guess for a parameter on a -problem - -InitialGuessPolynomialControl : a utility for setting an initial guess for a polynomial -control on a problem - -InitialGuessState : a utility for setting an initial guess for a state on a problem - -InitialGuessTime : a utility for setting guesses for initial time and duration on a -problem - PhaseBuilderBase : the interface for a phase builder ''' from abc import ABC from collections import namedtuple from collections.abc import Sequence +from aviary.mission.initial_guess_builders import InitialGuess + import dymos as dm import numpy as np import openmdao.api as om @@ -39,160 +26,6 @@ namedtuple('_require_new_initial_guesses_meta_data_class_attr_', ()) -class InitialGuess: - ''' - Define a utility for setting an initial guess on a problem. - - Attributes - ---------- - key : str - base name for the initial guess - ''' - __slots__ = ('key',) - - def __init__(self, key): - self.key = key - - def apply_initial_guess( - self, prob: om.Problem, traj_name, phase: dm.Phase, phase_name, val, units - ): - ''' - Set the initial guess on the problem. - ''' - complete_key = self._get_complete_key(traj_name, phase_name) - - # TODO: this is a short term hack in need of an appropriate long term solution - # - to interpolate, or not to interpolate: that is the question - # - the solution should probably be a value decoration (a wrapper) that is - # both lightweight and easy to check and unpack - if ( - isinstance(val, np.ndarray) - or (isinstance(val, Sequence) and not isinstance(val, str)) - ): - val = phase.interp(self.key, val) - - prob.set_val(complete_key, val, units) - - def _get_complete_key(self, traj_name, phase_name): - ''' - Compose the complete key for setting the initial guess. - ''' - _ = traj_name - _ = phase_name - - return self.key - - -class InitialGuessControl(InitialGuess): - ''' - Define a utility for setting an initial guess for a control on a problem. - - Attributes - ---------- - key : str - base name for the control - ''' - __slots__ = () - - def _get_complete_key(self, traj_name, phase_name): - ''' - Compose the complete key for setting the control initial guess. - ''' - key = f'{traj_name}.{phase_name}.controls:{self.key}' - - return key - - -class InitialGuessParameter(InitialGuess): - ''' - Define a utility for setting an initial guess for a parameter on a problem. - - Attributes - ---------- - key : str - base name for the parameter - ''' - __slots__ = () - - def _get_complete_key(self, traj_name, phase_name): - ''' - Compose the complete key for setting the parameter initial guess. - ''' - key = f'{traj_name}.{phase_name}.parameters:{self.key}' - - return key - - -class InitialGuessPolynomialControl(InitialGuess): - ''' - Define a utility for setting an initial guess for a polynomial control on a problem. - - Attributes - ---------- - key : str - base name for the polynomial control - ''' - __slots__ = () - - def _get_complete_key(self, traj_name, phase_name): - ''' - Compose the complete key for setting the polynomial control initial guess. - ''' - key = f'{traj_name}.{phase_name}.polynomial_controls:{self.key}' - - return key - - -class InitialGuessState(InitialGuess): - ''' - Define a utility for setting an initial guess for a state on a problem. - - Attributes - ---------- - key : str - base name for the state - ''' - __slots__ = () - - def _get_complete_key(self, traj_name, phase_name): - ''' - Compose the complete key for setting the state initial guess. - ''' - key = f'{traj_name}.{phase_name}.states:{self.key}' - - return key - - -class InitialGuessTime(InitialGuess): - ''' - Define a utility for setting guesses for initial time and duration on a problem. - - Attributes - ---------- - key : str ('times') - the group identifier for guesses for initial time and duration - ''' - __slots__ = () - - def __init__(self, key='times'): - super().__init__(key) - - def apply_initial_guess( - self, prob: om.Problem, traj_name, phase: dm.Phase, phase_name, val, units - ): - ''' - Set the guesses for initial time and duration on the problem. - ''' - _ = phase - - name = f'{traj_name}.{phase_name}.t_initial' - t_initial, t_duration = val - prob.set_val(name, t_initial, units) - - name = f'{traj_name}.{phase_name}.t_duration' - prob.set_val(name, t_duration, units) - - class PhaseBuilderBase(ABC): ''' Define the interface for a phase builder. @@ -634,10 +467,3 @@ def phase_info_to_builder(name: str, phase_info: dict) -> PhaseBuilderBase: except Exception as error: print(error) - - try: - PhaseBuilderBase._add_initial_guess_meta_data( - InitialGuessTime(), desc='test initial guess') - - except Exception as error: - print(error) From 1cf39c11fdc49dc0d75ad4b679a69fe73bc7f578 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 26 Jan 2024 01:43:00 -0600 Subject: [PATCH 175/188] Simplifying phase builder logic --- aviary/mission/flight_phase_builder_base.py | 474 ------------------ .../mission/gasp_based/phases/accel_phase.py | 26 - .../mission/gasp_based/phases/ascent_phase.py | 30 +- .../mission/gasp_based/phases/climb_phase.py | 29 -- .../mission/gasp_based/phases/cruise_phase.py | 20 +- .../gasp_based/phases/descent_phase.py | 26 - .../gasp_based/phases/groundroll_phase.py | 26 - .../gasp_based/phases/rotation_phase.py | 26 - aviary/mission/phase_builder_base.py | 17 +- 9 files changed, 18 insertions(+), 656 deletions(-) delete mode 100644 aviary/mission/flight_phase_builder_base.py diff --git a/aviary/mission/flight_phase_builder_base.py b/aviary/mission/flight_phase_builder_base.py deleted file mode 100644 index f3907ae8a..000000000 --- a/aviary/mission/flight_phase_builder_base.py +++ /dev/null @@ -1,474 +0,0 @@ -''' -Define utilities for building phases. - -Classes -------- - -''' -from abc import ABC -from collections import namedtuple -from collections.abc import Sequence - -import dymos as dm -import numpy as np -import openmdao.api as om - -from aviary.mission.flops_based.ode.mission_ODE import MissionODE -from aviary.utils.aviary_values import AviaryValues, get_keys - -_require_new_meta_data_class_attr_ = \ - namedtuple('_require_new_meta_data_class_attr_', ()) - - -_require_new_initial_guesses_meta_data_class_attr_ = \ - namedtuple('_require_new_initial_guesses_meta_data_class_attr_', ()) - - -class PhaseBuilderBase(ABC): - ''' - Define the interface for a phase builder. - - Attributes - ---------- - name : str ('') - object label - - core_subsystems : (None) - list of SubsystemBuilderBase objects that will be added to the phase ODE - - user_options : AviaryValues () - state/path constraint values and flags - - initial_guesses : AviaryValues () - state/path beginning values to be set on the problem - - ode_class : type (None) - advanced: the type of system defining the ODE - - transcription : "Dymos transcription object" (None) - advanced: an object providing the transcription technique of the - optimal control problem - - subsystem_options : dict (None) - dictionary of parameters to be passed to the subsystem builders - - default_name : str - class attribute: derived type customization point; the default value - for name - - default_ode_class : type - class attribute: derived type customization point; the default value - for ode_class used by build_phase - - is_analytic_phase : bool (False) - class attribute: derived type customization point; if True, build_phase - will return an AnalyticPhase instead of a Phase - - num_nodes : int (5) - class attribute: derived type customization point; the default value - for num_nodes used by build_phase, only for AnalyticPhases - - Methods - ------- - build_phase - make_default_transcription - validate_options - assign_default_options - ''' - __slots__ = ( - 'name', 'core_subsystems', 'subsystem_options', 'user_options', - 'initial_guesses', 'ode_class', 'transcription', - 'is_analytic_phase', 'num_nodes', - ) - - # region : derived type customization points - _meta_data_ = _require_new_meta_data_class_attr_() - - _initial_guesses_meta_data_ = _require_new_initial_guesses_meta_data_class_attr_() - - default_name = '' - - default_ode_class = MissionODE - # endregion : derived type customization points - - def __init__( - self, name=None, core_subsystems=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, subsystem_options=None, is_analytic_phase=False, num_nodes=5, - ): - if name is None: - name = self.default_name - - self.name = name - - if core_subsystems is None: - core_subsystems = [] - - self.core_subsystems = core_subsystems - - if subsystem_options is None: - subsystem_options = {} - - self.subsystem_options = subsystem_options - - self.user_options = user_options - self.validate_options() - self.assign_default_options() - - if initial_guesses is None: - initial_guesses = AviaryValues() - - self.initial_guesses = initial_guesses - self.validate_initial_guesses() - - self.ode_class = ode_class - self.transcription = transcription - self.is_analytic_phase = is_analytic_phase - self.num_nodes = num_nodes - - def build_phase(self, aviary_options=None): - ''' - Return a new phase object for analysis using these constraints. - - If ode_class is None, default_ode_class is used. - - If transcription is None, the return value from calling - make_default_transcription is used. - - Parameters - ---------- - aviary_options : AviaryValues (emtpy) - collection of Aircraft/Mission specific options - - Returns - ------- - dymos.Phase - ''' - ode_class = self.ode_class - - if ode_class is None: - ode_class = self.default_ode_class - - transcription = self.transcription - - if transcription is None and not self.is_analytic_phase: - transcription = self.make_default_transcription() - - if aviary_options is None: - aviary_options = AviaryValues() - - kwargs = self._extra_ode_init_kwargs() - - kwargs = { - 'aviary_options': aviary_options, - **kwargs - } - - subsystem_options = self.subsystem_options - - if subsystem_options is not None: - kwargs['subsystem_options'] = subsystem_options - - kwargs['core_subsystems'] = self.core_subsystems - - if self.is_analytic_phase: - phase = dm.AnalyticPhase( - ode_class=ode_class, - ode_init_kwargs=kwargs, - num_nodes=self.num_nodes, - ) - else: - phase = dm.Phase( - ode_class=ode_class, transcription=transcription, - ode_init_kwargs=kwargs - ) - - # overrides should add state, controls, etc. - return phase - - def make_default_transcription(self): - ''' - Return a transcription object to be used by default in build_phase. - ''' - user_options = self.user_options - - num_segments, _ = user_options.get_item('num_segments') - order, _ = user_options.get_item('order') - - transcription = dm.Radau( - num_segments=num_segments, order=order, compressed=True) - - return transcription - - def validate_options(self): - ''' - Raise TypeError if an unsupported option is found. - - Users can call this method when updating options after initialization. - ''' - user_options = self.user_options - - if not user_options: - return # acceptable - - meta_data = self._meta_data_ - - for key in get_keys(user_options): - if key not in meta_data: - raise TypeError( - f'{self.__class__.__name__}: {self.name}:' - f' unsupported option: {key}' - ) - - def assign_default_options(self): - ''' - Update missing options with default values. - - If user_options is None, start with an empty AviaryValues. - - Users can call this method when replacing the user_options member after - initialization. - ''' - user_options = self.user_options - - if user_options is None: - user_options = self.user_options = AviaryValues() - - meta_data = self._meta_data_ - - for key in meta_data: - if key not in user_options: - item = meta_data[key] - - val = item['val'] - units = item['units'] - - user_options.set_val(key, val, units) - - def validate_initial_guesses(self): - ''' - Raise TypeError if an unsupported initial guess is found. - - Users can call this method when updating initial guesses after initialization. - ''' - initial_guesses = self.initial_guesses - - if not initial_guesses: - return # acceptable - - meta_data = self._initial_guesses_meta_data_ - - for key in get_keys(initial_guesses): - if key not in meta_data: - raise TypeError( - f'{self.__class__.__name__}: {self.name}:' - f' unsupported initial guess: {key}' - ) - - def apply_initial_guesses( - self, prob: om.Problem, traj_name, phase: dm.Phase - ): - ''' - Apply any stored initial guesses; return a list of guesses not applied. - ''' - not_applied = [] - - phase_name = self.name - meta_data = self._initial_guesses_meta_data_ - initial_guesses: AviaryValues = self.initial_guesses - - for key in meta_data: - if key in initial_guesses: - apply_initial_guess = meta_data[key]['apply_initial_guess'] - val, units = initial_guesses.get_item(key) - - apply_initial_guess(prob, traj_name, phase, phase_name, val, units) - - else: - not_applied.append(key) - - return not_applied - - def _extra_ode_init_kwargs(self): - """ - Return extra kwargs required for initializing the ODE. - """ - return {} - - def to_phase_info(self): - ''' - Return the stored settings as phase info. - - Returns - ------- - tuple - name : str - object label - phase_info : dict - stored settings - ''' - subsystem_options = self.subsystem_options # TODO: aero info? - user_options = dict(self.user_options) - initial_guesses = dict(self.initial_guesses) - - # TODO some of these may be purely programming API hooks, rather than for use - # with phase info - # - ode_class - # - transcription - # - external_subsystems - # - meta_data - - phase_info = dict( - subsystem_options=subsystem_options, user_options=user_options, - initial_guesses=initial_guesses) - - return (self.name, phase_info) - - @classmethod - def from_phase_info(cls, name, phase_info: dict, core_subsystems=None, meta_data=None, transcription=None): - ''' - Return a new phase builder based on the specified phase info. - - Note, calling code is responsible for matching phase info to the correct phase - builder type, or the behavior is undefined. - - Parameters - ---------- - name : str - object label - phase_info : dict - stored settings - ''' - # loop over user_options dict entries - # if the value is not a tuple, wrap it in a tuple with the second entry of 'unitless' - for key, value in phase_info['user_options'].items(): - if not isinstance(value, tuple): - phase_info['user_options'][key] = (value, 'unitless') - - subsystem_options = phase_info.get( - 'subsystem_options', {}) # TODO: aero info? - user_options = AviaryValues(phase_info.get('user_options', ())) - initial_guesses = AviaryValues(phase_info.get('initial_guesses', ())) - external_subsystems = phase_info.get('external_subsystems', []) - # TODO core subsystems in phase info? - - # TODO some of these may be purely programming API hooks, rather than for use - # with phase info - # - ode_class - # - transcription - # - external_subsystems - # - meta_data - - phase_builder = cls( - name, subsystem_options=subsystem_options, user_options=user_options, - initial_guesses=initial_guesses, meta_data=meta_data, - core_subsystems=core_subsystems, external_subsystems=external_subsystems, transcription=transcription) - - return phase_builder - - @classmethod - def _add_meta_data(cls, name, *, val, units='unitless', desc=None): - ''' - Update supported options with a new item. - - Raises - ------ - ValueError - if a repeat option is found - ''' - meta_data = cls._meta_data_ - - if name in meta_data: - raise ValueError( - f'{cls.__name__}": meta data: repeat option: {name}' - ) - - meta_data[name] = dict(val=val, units=units, desc=desc) - - @classmethod - def _add_initial_guess_meta_data(cls, initial_guess: InitialGuess, desc=None): - ''' - Update supported initial guesses with a new item. - - Raises - ------ - ValueError - if a repeat initial guess is found - ''' - meta_data = cls._initial_guesses_meta_data_ - name = initial_guess.key - - if name in meta_data: - raise ValueError( - f'{cls.__name__}": meta data: repeat initial guess: {name}' - ) - - meta_data[name] = dict( - apply_initial_guess=initial_guess.apply_initial_guess, desc=desc) - - -_registered_phase_builder_types = [] - - -def register(phase_builder_t=None, *, check_repeats=True): - ''' - Register a new phase builder type. - - Note, this function qualifies as a class decorator for ease of use. - - Returns - ------- - ''' - if phase_builder_t is None: - def decorator(phase_builder_t): - return register(phase_builder_t, check_repeats=check_repeats) - - return decorator - - if check_repeats and (phase_builder_t in _registered_phase_builder_types): - raise ValueError('repeated phase builder type') - - _registered_phase_builder_types.append(phase_builder_t) - - return phase_builder_t - - -def phase_info_to_builder(name: str, phase_info: dict) -> PhaseBuilderBase: - ''' - Return a new phase builder based on the specified phase info. - - Note, the type of phase builder will be determined by calling - phase_builder_t.from_phase_info() for each registered type in order of registration; - the first result that is not None will be returned. If a supported phase builder type - cannot be determined, raise ValueError. - - Raises - ------ - ValueError - if a supported phase builder type cannot be determined - ''' - phase_builder_t: PhaseBuilderBase = None - - for phase_builder_t in _registered_phase_builder_types: - builder = phase_builder_t.from_phase_info(name, phase_info) - - if builder is not None: - return builder - - raise ValueError(f'unsupported phase info: {name}') - - -if __name__ == '__main__': - help(PhaseBuilderBase) - - try: - PhaseBuilderBase._add_meta_data('test', val=0, units=None, desc='test') - - except Exception as error: - print(error) - - try: - PhaseBuilderBase._add_initial_guess_meta_data( - InitialGuessTime(), desc='test initial guess') - - except Exception as error: - print(error) diff --git a/aviary/mission/gasp_based/phases/accel_phase.py b/aviary/mission/gasp_based/phases/accel_phase.py index a45822123..23a3b5f71 100644 --- a/aviary/mission/gasp_based/phases/accel_phase.py +++ b/aviary/mission/gasp_based/phases/accel_phase.py @@ -3,7 +3,6 @@ from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic from aviary.mission.gasp_based.ode.accel_ode import AccelODE -from aviary.variable_info.variable_meta_data import _MetaData class AccelPhase(PhaseBuilderBase): @@ -25,34 +24,9 @@ class AccelPhase(PhaseBuilderBase): default_name = 'accel_phase' default_ode_class = AccelODE - __slots__ = ('external_subsystems', 'meta_data') - _meta_data_ = {} _initial_guesses_meta_data_ = {} - default_meta_data = _MetaData - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, subsystem_options=subsystem_options, user_options=user_options, - initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, - core_subsystems=core_subsystems, - ) - - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - def build_phase(self, aviary_options: AviaryValues = None): """ Return a new acceleration phase for analysis using these constraints. diff --git a/aviary/mission/gasp_based/phases/ascent_phase.py b/aviary/mission/gasp_based/phases/ascent_phase.py index 12f0b9fe3..b7df046d5 100644 --- a/aviary/mission/gasp_based/phases/ascent_phase.py +++ b/aviary/mission/gasp_based/phases/ascent_phase.py @@ -1,45 +1,19 @@ +import numpy as np + from aviary.mission.phase_builder_base import PhaseBuilderBase from aviary.mission.initial_guess_builders import InitialGuessState, InitialGuessTime, InitialGuessControl from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic from aviary.mission.gasp_based.ode.ascent_ode import AscentODE -from aviary.variable_info.variable_meta_data import _MetaData - -import numpy as np class AscentPhase(PhaseBuilderBase): default_name = 'ascent_phase' default_ode_class = AscentODE - __slots__ = ('external_subsystems', 'meta_data') - _meta_data_ = {} _initial_guesses_meta_data_ = {} - default_meta_data = _MetaData - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, subsystem_options=subsystem_options, user_options=user_options, - initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, - core_subsystems=core_subsystems, - ) - - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - def build_phase(self, aviary_options: AviaryValues = None): phase = super().build_phase(aviary_options) diff --git a/aviary/mission/gasp_based/phases/climb_phase.py b/aviary/mission/gasp_based/phases/climb_phase.py index ddb073e84..13ce427f7 100644 --- a/aviary/mission/gasp_based/phases/climb_phase.py +++ b/aviary/mission/gasp_based/phases/climb_phase.py @@ -3,7 +3,6 @@ from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic from aviary.mission.gasp_based.ode.climb_ode import ClimbODE -from aviary.variable_info.variable_meta_data import _MetaData class ClimbPhase(PhaseBuilderBase): @@ -25,37 +24,9 @@ class ClimbPhase(PhaseBuilderBase): default_name = 'climb_phase' default_ode_class = ClimbODE - __slots__ = ('external_subsystems', 'meta_data') - - # region : derived type customization points _meta_data_ = {} - _initial_guesses_meta_data_ = {} - default_meta_data = _MetaData - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, subsystem_options=subsystem_options, user_options=user_options, - initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, - core_subsystems=core_subsystems, - ) - - # TODO: support external_subsystems and meta_data in the base class - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - def build_phase(self, aviary_options: AviaryValues = None): """ Return a new climb phase for analysis using these constraints. diff --git a/aviary/mission/gasp_based/phases/cruise_phase.py b/aviary/mission/gasp_based/phases/cruise_phase.py index 226782526..4d29720d7 100644 --- a/aviary/mission/gasp_based/phases/cruise_phase.py +++ b/aviary/mission/gasp_based/phases/cruise_phase.py @@ -25,15 +25,9 @@ class CruisePhase(PhaseBuilderBase): default_name = 'cruise_phase' default_ode_class = BreguetCruiseODESolution - __slots__ = ('external_subsystems', 'meta_data') - - # region : derived type customization points _meta_data_ = {} - _initial_guesses_meta_data_ = {} - default_meta_data = _MetaData - def __init__( self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, ode_class=None, transcription=None, core_subsystems=None, @@ -42,21 +36,9 @@ def __init__( super().__init__( name=name, subsystem_options=subsystem_options, user_options=user_options, initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, - core_subsystems=core_subsystems, + core_subsystems=core_subsystems, is_analytic_phase=True, ) - # TODO: support external_subsystems and meta_data in the base class - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - self.is_analytic_phase = True - def build_phase(self, aviary_options: AviaryValues = None): """ Return a new climb phase for analysis using these constraints. diff --git a/aviary/mission/gasp_based/phases/descent_phase.py b/aviary/mission/gasp_based/phases/descent_phase.py index a835dc575..c34ada5f3 100644 --- a/aviary/mission/gasp_based/phases/descent_phase.py +++ b/aviary/mission/gasp_based/phases/descent_phase.py @@ -4,41 +4,15 @@ from aviary.variable_info.variables import Dynamic from aviary.variable_info.enums import SpeedType from aviary.mission.gasp_based.ode.descent_ode import DescentODE -from aviary.variable_info.variable_meta_data import _MetaData class DescentPhase(PhaseBuilderBase): default_name = 'descent_phase' default_ode_class = DescentODE - __slots__ = ('external_subsystems', 'meta_data') - _meta_data_ = {} _initial_guesses_meta_data_ = {} - default_meta_data = _MetaData - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, subsystem_options=subsystem_options, user_options=user_options, - initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, - core_subsystems=core_subsystems, - ) - - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - def build_phase(self, aviary_options: AviaryValues = None): phase = super().build_phase(aviary_options) diff --git a/aviary/mission/gasp_based/phases/groundroll_phase.py b/aviary/mission/gasp_based/phases/groundroll_phase.py index 6703a9809..52f78cb9b 100644 --- a/aviary/mission/gasp_based/phases/groundroll_phase.py +++ b/aviary/mission/gasp_based/phases/groundroll_phase.py @@ -3,41 +3,15 @@ from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic from aviary.mission.gasp_based.ode.groundroll_ode import GroundrollODE -from aviary.variable_info.variable_meta_data import _MetaData class GroundrollPhase(PhaseBuilderBase): default_name = 'groundroll_phase' default_ode_class = GroundrollODE - __slots__ = ('external_subsystems', 'meta_data') - _meta_data_ = {} _initial_guesses_meta_data_ = {} - default_meta_data = _MetaData - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, subsystem_options=subsystem_options, user_options=user_options, - initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, - core_subsystems=core_subsystems, - ) - - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - def build_phase(self, aviary_options: AviaryValues = None): phase = super().build_phase(aviary_options) diff --git a/aviary/mission/gasp_based/phases/rotation_phase.py b/aviary/mission/gasp_based/phases/rotation_phase.py index 36c4c0d6e..fa7eaec34 100644 --- a/aviary/mission/gasp_based/phases/rotation_phase.py +++ b/aviary/mission/gasp_based/phases/rotation_phase.py @@ -5,41 +5,15 @@ from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic from aviary.mission.gasp_based.ode.rotation_ode import RotationODE -from aviary.variable_info.variable_meta_data import _MetaData class RotationPhase(PhaseBuilderBase): default_name = 'rotation_phase' default_ode_class = RotationODE - __slots__ = ('external_subsystems', 'meta_data') - _meta_data_ = {} _initial_guesses_meta_data_ = {} - default_meta_data = _MetaData - - def __init__( - self, name=None, subsystem_options=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, core_subsystems=None, - external_subsystems=None, meta_data=None - ): - super().__init__( - name=name, subsystem_options=subsystem_options, user_options=user_options, - initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription, - core_subsystems=core_subsystems, - ) - - if external_subsystems is None: - external_subsystems = [] - - self.external_subsystems = external_subsystems - - if meta_data is None: - meta_data = self.default_meta_data - - self.meta_data = meta_data - def build_phase(self, aviary_options: AviaryValues = None): phase = super().build_phase(aviary_options) diff --git a/aviary/mission/phase_builder_base.py b/aviary/mission/phase_builder_base.py index 3b4eb6190..78c330455 100644 --- a/aviary/mission/phase_builder_base.py +++ b/aviary/mission/phase_builder_base.py @@ -17,6 +17,7 @@ from aviary.mission.flops_based.ode.mission_ODE import MissionODE from aviary.utils.aviary_values import AviaryValues, get_keys +from aviary.variable_info.variable_meta_data import _MetaData _require_new_meta_data_class_attr_ = \ namedtuple('_require_new_meta_data_class_attr_', ()) @@ -80,7 +81,7 @@ class attribute: derived type customization point; the default value __slots__ = ( 'name', 'core_subsystems', 'subsystem_options', 'user_options', 'initial_guesses', 'ode_class', 'transcription', - 'is_analytic_phase', 'num_nodes', + 'is_analytic_phase', 'num_nodes', 'external_subsystems', 'meta_data', ) # region : derived type customization points @@ -91,11 +92,13 @@ class attribute: derived type customization point; the default value default_name = '' default_ode_class = MissionODE + + default_meta_data = _MetaData # endregion : derived type customization points def __init__( self, name=None, core_subsystems=None, user_options=None, initial_guesses=None, - ode_class=None, transcription=None, subsystem_options=None, is_analytic_phase=False, num_nodes=5, + ode_class=None, transcription=None, subsystem_options=None, is_analytic_phase=False, num_nodes=5, external_subsystems=None, meta_data=None, ): if name is None: name = self.default_name @@ -127,6 +130,16 @@ def __init__( self.is_analytic_phase = is_analytic_phase self.num_nodes = num_nodes + if external_subsystems is None: + external_subsystems = [] + + self.external_subsystems = external_subsystems + + if meta_data is None: + meta_data = self.default_meta_data + + self.meta_data = meta_data + def build_phase(self, aviary_options=None): ''' Return a new phase object for analysis using these constraints. From 70302ce55e6dbfa8e79c83847435f4a7e9cbddf2 Mon Sep 17 00:00:00 2001 From: "Kenneth T. Moore" Date: Fri, 26 Jan 2024 11:13:52 -0500 Subject: [PATCH 176/188] Tweaked some residuals to improve nested solver performance. --- aviary/mission/flops_based/ode/mission_ODE.py | 3 ++- .../subsystems/aerodynamics/flops_based/solved_alpha_group.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/aviary/mission/flops_based/ode/mission_ODE.py b/aviary/mission/flops_based/ode/mission_ODE.py index 60cfba24e..71fe5b932 100644 --- a/aviary/mission/flops_based/ode/mission_ODE.py +++ b/aviary/mission/flops_based/ode/mission_ODE.py @@ -164,6 +164,7 @@ def setup(self): normalize=False, lower=0.0 if options['throttle_enforcement'] == 'bounded' else None, upper=1.0 if options['throttle_enforcement'] == 'bounded' else None, + res_ref=1.0e6, ), promotes_inputs=['*'], promotes_outputs=['*']) @@ -187,7 +188,7 @@ def setup(self): exec_comp_string, initial_mass={'units': 'kg'}, mass={'units': 'kg', 'shape': (nn,)}, - initial_mass_residual={'units': 'kg'}, + initial_mass_residual={'units': 'kg', 'res_ref': 1.0e5}, ) self.add_subsystem('initial_mass_residual_constraint', initial_mass_residual_constraint, diff --git a/aviary/subsystems/aerodynamics/flops_based/solved_alpha_group.py b/aviary/subsystems/aerodynamics/flops_based/solved_alpha_group.py index 984fdac77..684c93612 100644 --- a/aviary/subsystems/aerodynamics/flops_based/solved_alpha_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/solved_alpha_group.py @@ -76,7 +76,7 @@ def setup(self): promotes_outputs=[Dynamic.Mission.LIFT, Dynamic.Mission.DRAG]) balance = self.add_subsystem('balance', om.BalanceComp()) - balance.add_balance('alpha', val=np.ones(nn), units='deg') + balance.add_balance('alpha', val=np.ones(nn), units='deg', res_ref=1.0e6) self.connect('balance.alpha', 'tabular_aero.alpha') self.connect('needed_lift.lift_resid', 'balance.lhs:alpha') From 054f286b8babc8275a72a1b73c79ee0f165d6ada Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 26 Jan 2024 11:19:50 -0600 Subject: [PATCH 177/188] WIP --- .../mission/gasp_based/phases/accel_phase.py | 58 +---------- .../mission/gasp_based/phases/ascent_phase.py | 97 ++---------------- .../mission/gasp_based/phases/climb_phase.py | 58 +---------- .../gasp_based/phases/descent_phase.py | 60 +----------- .../gasp_based/phases/groundroll_phase.py | 20 +--- .../gasp_based/phases/rotation_phase.py | 38 +------ aviary/mission/phase_builder_base.py | 98 +++++++++++++++++++ 7 files changed, 122 insertions(+), 307 deletions(-) diff --git a/aviary/mission/gasp_based/phases/accel_phase.py b/aviary/mission/gasp_based/phases/accel_phase.py index 23a3b5f71..3c123cf39 100644 --- a/aviary/mission/gasp_based/phases/accel_phase.py +++ b/aviary/mission/gasp_based/phases/accel_phase.py @@ -40,7 +40,7 @@ def build_phase(self, aviary_options: AviaryValues = None): ------- dymos.Phase """ - phase = super().build_phase(aviary_options) + phase = self.phase = super().build_phase(aviary_options) user_options = self.user_options # Extracting and setting options @@ -48,21 +48,6 @@ def build_phase(self, aviary_options: AviaryValues = None): EAS_constraint_eq = user_options.get_val('EAS_constraint_eq', units='kn') duration_bounds = user_options.get_val('duration_bounds', units='s') duration_ref = user_options.get_val('duration_ref', units='s') - TAS_lower = user_options.get_val('TAS_lower', units='kn') - TAS_upper = user_options.get_val('TAS_upper', units='kn') - TAS_ref = user_options.get_val('TAS_ref', units='kn') - TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') - TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') - mass_lower = user_options.get_val('mass_lower', units='lbm') - mass_upper = user_options.get_val('mass_upper', units='lbm') - mass_ref = user_options.get_val('mass_ref', units='lbm') - mass_ref0 = user_options.get_val('mass_ref0', units='lbm') - mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') - distance_lower = user_options.get_val('distance_lower', units='NM') - distance_upper = user_options.get_val('distance_upper', units='NM') - distance_ref = user_options.get_val('distance_ref', units='NM') - distance_ref0 = user_options.get_val('distance_ref0', units='NM') - distance_defect_ref = user_options.get_val('distance_defect_ref', units='NM') alt = user_options.get_val('alt', units='ft') phase.set_time_options( @@ -73,46 +58,11 @@ def build_phase(self, aviary_options: AviaryValues = None): ) # States - phase.add_state( - "TAS", - fix_initial=fix_initial, - fix_final=False, - lower=TAS_lower, - upper=TAS_upper, - units="kn", - rate_source="TAS_rate", - targets="TAS", - ref=TAS_ref, - ref0=TAS_ref0, - defect_ref=TAS_defect_ref, - ) + self.add_TAS_state(user_options) - phase.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - ref=mass_ref, - ref0=mass_ref0, - defect_ref=mass_defect_ref, - ) + self.add_mass_state(user_options) - phase.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="NM", - rate_source="distance_rate", - ref=distance_ref, - ref0=distance_ref0, - defect_ref=distance_defect_ref, - ) + self.add_distance_state(user_options) # Boundary Constraints phase.add_boundary_constraint( diff --git a/aviary/mission/gasp_based/phases/ascent_phase.py b/aviary/mission/gasp_based/phases/ascent_phase.py index b7df046d5..4b537ef7b 100644 --- a/aviary/mission/gasp_based/phases/ascent_phase.py +++ b/aviary/mission/gasp_based/phases/ascent_phase.py @@ -15,38 +15,14 @@ class AscentPhase(PhaseBuilderBase): _initial_guesses_meta_data_ = {} def build_phase(self, aviary_options: AviaryValues = None): - phase = super().build_phase(aviary_options) + phase = self.phase = super().build_phase(aviary_options) # Retrieve user options values user_options = self.user_options - angle_lower = user_options.get_val('angle_lower', units='rad') - angle_upper = user_options.get_val('angle_upper', units='rad') - angle_ref = user_options.get_val('angle_ref', units='rad') - angle_ref0 = user_options.get_val('angle_ref0', units='rad') - angle_defect_ref = user_options.get_val('angle_defect_ref', units='rad') - alt_lower = user_options.get_val('alt_lower', units='ft') - alt_upper = user_options.get_val('alt_upper', units='ft') - alt_ref = user_options.get_val('alt_ref', units='ft') - alt_ref0 = user_options.get_val('alt_ref0', units='ft') - alt_defect_ref = user_options.get_val('alt_defect_ref', units='ft') + alt_constraint_eq = user_options.get_val('alt_constraint_eq', units='ft') alt_constraint_ref = user_options.get_val('alt_constraint_ref', units='ft') alt_constraint_ref0 = user_options.get_val('alt_constraint_ref0', units='ft') - TAS_lower = user_options.get_val('TAS_lower', units='kn') - TAS_upper = user_options.get_val('TAS_upper', units='kn') - TAS_ref = user_options.get_val('TAS_ref', units='kn') - TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') - TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') - mass_lower = user_options.get_val('mass_lower', units='lbm') - mass_upper = user_options.get_val('mass_upper', units='lbm') - mass_ref = user_options.get_val('mass_ref', units='lbm') - mass_ref0 = user_options.get_val('mass_ref0', units='lbm') - mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') - distance_lower = user_options.get_val('distance_lower', units='ft') - distance_upper = user_options.get_val('distance_upper', units='ft') - distance_ref = user_options.get_val('distance_ref', units='ft') - distance_ref0 = user_options.get_val('distance_ref0', units='ft') - distance_defect_ref = user_options.get_val('distance_defect_ref', units='ft') pitch_constraint_lower = user_options.get_val( 'pitch_constraint_lower', units='deg') pitch_constraint_upper = user_options.get_val( @@ -65,70 +41,11 @@ def build_phase(self, aviary_options: AviaryValues = None): input_duration=True, ) - phase.add_state( - Dynamic.Mission.FLIGHT_PATH_ANGLE, - fix_initial=True, - fix_final=False, - lower=angle_lower, - upper=angle_upper, - units="rad", - rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, - ref=angle_ref, - defect_ref=angle_defect_ref, - ref0=angle_ref0, - ) - - phase.add_state( - Dynamic.Mission.ALTITUDE, - fix_initial=True, - fix_final=False, - lower=alt_lower, - upper=alt_upper, - units="ft", - rate_source=Dynamic.Mission.ALTITUDE_RATE, - ref=alt_ref, - defect_ref=alt_defect_ref, - ref0=alt_ref0, - ) - - phase.add_state( - "TAS", - fix_initial=user_options.get_val('fix_initial'), - fix_final=False, - lower=TAS_lower, - upper=TAS_upper, - units="kn", - rate_source="TAS_rate", - ref=TAS_ref, - defect_ref=TAS_defect_ref, - ref0=TAS_ref0, - ) - - phase.add_state( - Dynamic.Mission.MASS, - fix_initial=user_options.get_val('fix_initial'), - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - ref=mass_ref, - defect_ref=mass_defect_ref, - ref0=mass_ref0, - ) - - phase.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=user_options.get_val('fix_initial'), - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="ft", - rate_source="distance_rate", - ref=distance_ref, - defect_ref=distance_defect_ref, - ref0=distance_ref0, - ) + self.add_flight_path_angle_state(user_options) + self.add_altitude_state(user_options) + self.add_TAS_state(user_options) + self.add_mass_state(user_options) + self.add_distance_state(user_options) phase.add_boundary_constraint( Dynamic.Mission.ALTITUDE, diff --git a/aviary/mission/gasp_based/phases/climb_phase.py b/aviary/mission/gasp_based/phases/climb_phase.py index 13ce427f7..8f8a0a12f 100644 --- a/aviary/mission/gasp_based/phases/climb_phase.py +++ b/aviary/mission/gasp_based/phases/climb_phase.py @@ -42,7 +42,7 @@ def build_phase(self, aviary_options: AviaryValues = None): ------- dymos.Phase """ - phase = super().build_phase(aviary_options) + phase = self.phase = super().build_phase(aviary_options) # Custom configurations for the climb phase user_options = self.user_options @@ -55,21 +55,6 @@ def build_phase(self, aviary_options: AviaryValues = None): 'required_available_climb_rate', units='ft/min') duration_bounds = user_options.get_val('duration_bounds', units='s') duration_ref = user_options.get_val('duration_ref', units='s') - alt_lower = user_options.get_val('alt_lower', units='ft') - alt_upper = user_options.get_val('alt_upper', units='ft') - alt_ref = user_options.get_val('alt_ref', units='ft') - alt_ref0 = user_options.get_val('alt_ref0', units='ft') - alt_defect_ref = user_options.get_val('alt_defect_ref', units='ft') - mass_lower = user_options.get_val('mass_lower', units='lbm') - mass_upper = user_options.get_val('mass_upper', units='lbm') - mass_ref = user_options.get_val('mass_ref', units='lbm') - mass_ref0 = user_options.get_val('mass_ref0', units='lbm') - mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') - distance_lower = user_options.get_val('distance_lower', units='NM') - distance_upper = user_options.get_val('distance_upper', units='NM') - distance_ref = user_options.get_val('distance_ref', units='NM') - distance_ref0 = user_options.get_val('distance_ref0', units='NM') - distance_defect_ref = user_options.get_val('distance_defect_ref', units='NM') phase.set_time_options( fix_initial=fix_initial, @@ -79,46 +64,11 @@ def build_phase(self, aviary_options: AviaryValues = None): ) # States - phase.add_state( - Dynamic.Mission.ALTITUDE, - fix_initial=fix_initial, - fix_final=False, - lower=alt_lower, - upper=alt_upper, - units="ft", - rate_source=Dynamic.Mission.ALTITUDE_RATE, - targets=Dynamic.Mission.ALTITUDE, - ref=alt_ref, - ref0=alt_ref0, - defect_ref=alt_defect_ref, - ) + self.add_altitude_state(user_options) - phase.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - ref=mass_ref, - ref0=mass_ref0, - defect_ref=mass_defect_ref, - ) + self.add_mass_state(user_options) - phase.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="NM", - rate_source="distance_rate", - ref=distance_ref, - ref0=distance_ref0, - defect_ref=distance_defect_ref, - ) + self.add_distance_state(user_options) # Boundary Constraints phase.add_boundary_constraint( diff --git a/aviary/mission/gasp_based/phases/descent_phase.py b/aviary/mission/gasp_based/phases/descent_phase.py index c34ada5f3..9f8980c6e 100644 --- a/aviary/mission/gasp_based/phases/descent_phase.py +++ b/aviary/mission/gasp_based/phases/descent_phase.py @@ -14,7 +14,7 @@ class DescentPhase(PhaseBuilderBase): _initial_guesses_meta_data_ = {} def build_phase(self, aviary_options: AviaryValues = None): - phase = super().build_phase(aviary_options) + phase = self.phase = super().build_phase(aviary_options) # Retrieve user options values user_options = self.user_options @@ -22,23 +22,8 @@ def build_phase(self, aviary_options: AviaryValues = None): fix_initial = user_options.get_val('fix_initial') input_initial = user_options.get_val('input_initial') duration_ref = user_options.get_val('duration_ref', units='s') - alt_lower = user_options.get_val('alt_lower', units='ft') - alt_upper = user_options.get_val('alt_upper', units='ft') - alt_ref = user_options.get_val('alt_ref', units='ft') - alt_ref0 = user_options.get_val('alt_ref0', units='ft') - alt_defect_ref = user_options.get_val('alt_defect_ref', units='ft') final_altitude = user_options.get_val('final_altitude', units='ft') alt_constraint_ref = user_options.get_val('alt_constraint_ref', units='ft') - mass_lower = user_options.get_val('mass_lower', units='lbm') - mass_upper = user_options.get_val('mass_upper', units='lbm') - mass_ref = user_options.get_val('mass_ref', units='lbm') - mass_ref0 = user_options.get_val('mass_ref0', units='lbm') - mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') - distance_lower = user_options.get_val('distance_lower', units='NM') - distance_upper = user_options.get_val('distance_upper', units='NM') - distance_ref = user_options.get_val('distance_ref', units='NM') - distance_ref0 = user_options.get_val('distance_ref0', units='NM') - distance_defect_ref = user_options.get_val('distance_defect_ref', units='NM') input_speed_type = user_options.get_val('input_speed_type') EAS_limit = user_options.get_val('EAS_limit', units='kn') @@ -52,48 +37,11 @@ def build_phase(self, aviary_options: AviaryValues = None): ) # Add states - phase.add_state( - Dynamic.Mission.ALTITUDE, - fix_initial=True, - fix_final=False, - lower=alt_lower, - upper=alt_upper, - units="ft", - rate_source=Dynamic.Mission.ALTITUDE_RATE, - targets=Dynamic.Mission.ALTITUDE, - ref=alt_ref, - ref0=alt_ref0, - defect_ref=alt_defect_ref, - ) + self.add_altitude_state(user_options) - phase.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial, - input_initial=input_initial, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - ref=mass_ref, - ref0=mass_ref0, - defect_ref=mass_defect_ref, - ) + self.add_mass_state(user_options) - phase.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=fix_initial, - input_initial=input_initial, - fix_final=False, - lower=distance_lower, - upper=distance_upper, - units="NM", - rate_source="distance_rate", - ref=distance_ref, - ref0=distance_ref0, - defect_ref=distance_defect_ref, - ) + self.add_distance_state(user_options) # Add boundary constraint phase.add_boundary_constraint( diff --git a/aviary/mission/gasp_based/phases/groundroll_phase.py b/aviary/mission/gasp_based/phases/groundroll_phase.py index 52f78cb9b..7e2ae0ae8 100644 --- a/aviary/mission/gasp_based/phases/groundroll_phase.py +++ b/aviary/mission/gasp_based/phases/groundroll_phase.py @@ -13,7 +13,7 @@ class GroundrollPhase(PhaseBuilderBase): _initial_guesses_meta_data_ = {} def build_phase(self, aviary_options: AviaryValues = None): - phase = super().build_phase(aviary_options) + phase = self.phase = super().build_phase(aviary_options) # Retrieve user options values user_options = self.user_options @@ -23,11 +23,6 @@ def build_phase(self, aviary_options: AviaryValues = None): connect_initial_mass = user_options.get_val('connect_initial_mass') duration_bounds = user_options.get_val('duration_bounds', units='s') duration_ref = user_options.get_val('duration_ref', units='s') - TAS_lower = user_options.get_val('TAS_lower', units='kn') - TAS_upper = user_options.get_val('TAS_upper', units='kn') - TAS_ref = user_options.get_val('TAS_ref', units='kn') - TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') - TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') mass_lower = user_options.get_val('mass_lower', units='lbm') mass_upper = user_options.get_val('mass_upper', units='lbm') mass_ref = user_options.get_val('mass_ref', units='lbm') @@ -50,18 +45,7 @@ def build_phase(self, aviary_options: AviaryValues = None): ) # Add states - phase.add_state( - "TAS", - fix_initial=fix_initial, - fix_final=False, - lower=TAS_lower, - upper=TAS_upper, - units="kn", - rate_source="TAS_rate", - ref=TAS_ref, - defect_ref=TAS_defect_ref, - ref0=TAS_ref0, - ) + self.add_TAS_state(user_options) phase.add_state( Dynamic.Mission.MASS, diff --git a/aviary/mission/gasp_based/phases/rotation_phase.py b/aviary/mission/gasp_based/phases/rotation_phase.py index fa7eaec34..cc183226b 100644 --- a/aviary/mission/gasp_based/phases/rotation_phase.py +++ b/aviary/mission/gasp_based/phases/rotation_phase.py @@ -15,7 +15,7 @@ class RotationPhase(PhaseBuilderBase): _initial_guesses_meta_data_ = {} def build_phase(self, aviary_options: AviaryValues = None): - phase = super().build_phase(aviary_options) + phase = self.phase = super().build_phase(aviary_options) # Retrieve user options values user_options = self.user_options @@ -27,16 +27,6 @@ def build_phase(self, aviary_options: AviaryValues = None): angle_ref = user_options.get_val('angle_ref', units='rad') angle_ref0 = user_options.get_val('angle_ref0', units='rad') angle_defect_ref = user_options.get_val('angle_defect_ref', units='rad') - TAS_lower = user_options.get_val('TAS_lower', units='kn') - TAS_upper = user_options.get_val('TAS_upper', units='kn') - TAS_ref = user_options.get_val('TAS_ref', units='kn') - TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') - TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') - mass_lower = user_options.get_val('mass_lower', units='lbm') - mass_upper = user_options.get_val('mass_upper', units='lbm') - mass_ref = user_options.get_val('mass_ref', units='lbm') - mass_ref0 = user_options.get_val('mass_ref0', units='lbm') - mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') distance_lower = user_options.get_val('distance_lower', units='ft') distance_upper = user_options.get_val('distance_upper', units='ft') distance_ref = user_options.get_val('distance_ref', units='ft') @@ -68,31 +58,9 @@ def build_phase(self, aviary_options: AviaryValues = None): defect_ref=angle_defect_ref, ) - phase.add_state( - "TAS", - fix_initial=fix_initial, - fix_final=False, - lower=TAS_lower, - upper=TAS_upper, - units="kn", - rate_source="TAS_rate", - ref=TAS_ref, - ref0=TAS_ref0, - defect_ref=TAS_defect_ref, - ) + self.add_TAS_state(user_options) - phase.add_state( - Dynamic.Mission.MASS, - fix_initial=fix_initial, - fix_final=False, - lower=mass_lower, - upper=mass_upper, - units="lbm", - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - ref=mass_ref, - ref0=mass_ref0, - defect_ref=mass_defect_ref, - ) + self.add_mass_state(user_options) phase.add_state( Dynamic.Mission.DISTANCE, diff --git a/aviary/mission/phase_builder_base.py b/aviary/mission/phase_builder_base.py index 78c330455..471a3f25a 100644 --- a/aviary/mission/phase_builder_base.py +++ b/aviary/mission/phase_builder_base.py @@ -10,6 +10,7 @@ from collections.abc import Sequence from aviary.mission.initial_guess_builders import InitialGuess +from aviary.variable_info.variables import Dynamic import dymos as dm import numpy as np @@ -420,6 +421,103 @@ def _add_initial_guess_meta_data(cls, initial_guess: InitialGuess, desc=None): meta_data[name] = dict( apply_initial_guess=initial_guess.apply_initial_guess, desc=desc) + def add_TAS_state(self, user_options): + TAS_lower = user_options.get_val('TAS_lower', units='kn') + TAS_upper = user_options.get_val('TAS_upper', units='kn') + TAS_ref = user_options.get_val('TAS_ref', units='kn') + TAS_ref0 = user_options.get_val('TAS_ref0', units='kn') + TAS_defect_ref = user_options.get_val('TAS_defect_ref', units='kn') + self.phase.add_state( + "TAS", + fix_initial=user_options.get_val('fix_initial'), + fix_final=False, + lower=TAS_lower, + upper=TAS_upper, + units="kn", + rate_source="TAS_rate", + targets="TAS", + ref=TAS_ref, + ref0=TAS_ref0, + defect_ref=TAS_defect_ref, + ) + + def add_mass_state(self, user_options): + mass_lower = user_options.get_val('mass_lower', units='lbm') + mass_upper = user_options.get_val('mass_upper', units='lbm') + mass_ref = user_options.get_val('mass_ref', units='lbm') + mass_ref0 = user_options.get_val('mass_ref0', units='lbm') + mass_defect_ref = user_options.get_val('mass_defect_ref', units='lbm') + self.phase.add_state( + Dynamic.Mission.MASS, + fix_initial=user_options.get_val('fix_initial'), + fix_final=False, + lower=mass_lower, + upper=mass_upper, + units="lbm", + rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, + targets=Dynamic.Mission.MASS, + ref=mass_ref, + ref0=mass_ref0, + defect_ref=mass_defect_ref, + ) + + def add_distance_state(self, user_options): + distance_lower = user_options.get_val('distance_lower', units='NM') + distance_upper = user_options.get_val('distance_upper', units='NM') + distance_ref = user_options.get_val('distance_ref', units='NM') + distance_ref0 = user_options.get_val('distance_ref0', units='NM') + distance_defect_ref = user_options.get_val('distance_defect_ref', units='NM') + self.phase.add_state( + Dynamic.Mission.DISTANCE, + fix_initial=user_options.get_val('fix_initial'), + fix_final=False, + lower=distance_lower, + upper=distance_upper, + units="NM", + rate_source=Dynamic.Mission.DISTANCE_RATE, + ref=distance_ref, + ref0=distance_ref0, + defect_ref=distance_defect_ref, + ) + + def add_flight_path_angle_state(self, user_options): + angle_lower = user_options.get_val('angle_lower', units='rad') + angle_upper = user_options.get_val('angle_upper', units='rad') + angle_ref = user_options.get_val('angle_ref', units='rad') + angle_ref0 = user_options.get_val('angle_ref0', units='rad') + angle_defect_ref = user_options.get_val('angle_defect_ref', units='rad') + self.phase.add_state( + Dynamic.Mission.FLIGHT_PATH_ANGLE, + fix_initial=True, + fix_final=False, + lower=angle_lower, + upper=angle_upper, + units="rad", + rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, + ref=angle_ref, + defect_ref=angle_defect_ref, + ref0=angle_ref0, + ) + + def add_altitude_state(self, user_options): + alt_lower = user_options.get_val('alt_lower', units='ft') + alt_upper = user_options.get_val('alt_upper', units='ft') + alt_ref = user_options.get_val('alt_ref', units='ft') + alt_ref0 = user_options.get_val('alt_ref0', units='ft') + alt_defect_ref = user_options.get_val('alt_defect_ref', units='ft') + self.phase.add_state( + Dynamic.Mission.ALTITUDE, + fix_initial=True, + fix_final=False, + lower=alt_lower, + upper=alt_upper, + units="ft", + rate_source=Dynamic.Mission.ALTITUDE_RATE, + ref=alt_ref, + defect_ref=alt_defect_ref, + ref0=alt_ref0, + ) + _registered_phase_builder_types = [] From df79ace1d24fbfee3d0ca9840c1de9dd20e5c568 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 26 Jan 2024 11:20:59 -0600 Subject: [PATCH 178/188] Updated docs links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 230c56f12..e4f930438 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Aviary -- NASA's aircraft design tool -**Check out the Aviary documentation [here](https://openmdao.github.io/om-Aviary/intro.html).** +**Check out the Aviary documentation [here](https://openmdao.github.io/Aviary/intro.html).** ## Description @@ -26,7 +26,7 @@ If you also want to install all packages used for the Aviary tests _and_ externa ## Documentation -The Aviary documentation is located [here](https://openmdao.github.io/om-Aviary/intro.html). +The Aviary documentation is located [here](https://openmdao.github.io/Aviary/intro.html). Otherwise you can build the docs locally: @@ -70,4 +70,4 @@ We have also provided a static version of the `environment.yml` at the top level ## Planned future features Aviary is in active development. -We plan to expand its capabilities and have provided a non-exhaustive [list of future features](https://openmdao.github.io/om-Aviary/misc_resources/planned_future_features.html). \ No newline at end of file +We plan to expand its capabilities and have provided a non-exhaustive [list of future features](https://openmdao.github.io/Aviary/misc_resources/planned_future_features.html). \ No newline at end of file From ce92d5e315b13dfce4b9263fd7f020096272649c Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 26 Jan 2024 11:51:05 -0600 Subject: [PATCH 179/188] Updated doc refs --- aviary/docs/theory_guide/building_metadata_syntax.ipynb | 2 +- aviary/docs/theory_guide/intro.md | 2 +- aviary/docs/theory_guide/merging_syntax.ipynb | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/aviary/docs/theory_guide/building_metadata_syntax.ipynb b/aviary/docs/theory_guide/building_metadata_syntax.ipynb index cfa972381..b99412cbc 100644 --- a/aviary/docs/theory_guide/building_metadata_syntax.ipynb +++ b/aviary/docs/theory_guide/building_metadata_syntax.ipynb @@ -27,7 +27,7 @@ "source": [ "# Building Metadata\n", "\n", - "When working with Aviary models, sometimes it is necessary to extend the Aviary-core variable hierarchy or update existing metadata. The syntax for `add_meta_data` and `update_meta_data` can be found below. For a more detailed explanation of metadata please visit [this link](../user_guide/variable_metadata.md).\n", + "When working with Aviary models, sometimes it is necessary to extend the Aviary-core variable hierarchy or update existing metadata. The syntax for `add_meta_data` and `update_meta_data` can be found below. For a more detailed explanation of metadata please visit [this link](../user_guide/variable_metadata).\n", "\n", "```{eval-rst}\n", ".. autofunction:: aviary.utils.develop_metadata.add_meta_data\n", diff --git a/aviary/docs/theory_guide/intro.md b/aviary/docs/theory_guide/intro.md index 1c894a8db..5bed0564d 100644 --- a/aviary/docs/theory_guide/intro.md +++ b/aviary/docs/theory_guide/intro.md @@ -20,7 +20,7 @@ The [mass](./mass) calculations that Aviary provides are similar to the geometry The [mission analysis](./mission) calculations that Aviary provides are broader in scope than the other disciplines. Aviary provides two different types of equations of motion (2DOF and height energy), and also provides two different ways to integrate these EOMs (collocation and analytic shooting). The intended capability is that either EOM can be used with either integration technique. -The second aspect of Aviary, instead of being computational like the first, is about subsystem integration. In addition to the capability to build purely Aviary-based aircraft models, Aviary provides the ability to build mixed-origin aircraft models, which are aircraft models consisting partially or entirely of external user-provided subsystems. In the case of a mixed-origin model, instead of just selecting existing Aviary subsystems and combining them into an aircraft model, the user also provides the Aviary code with their own subsystems (these could be pre-existing codes such as [pyCycle](https://github.com/OpenMDAO/pyCycle), or they could be new subsystems the user has built themselves). An example of a mixed-origin model is the [OpenAeroStruct example case](../examples/OAS_subsystem.md). In this example, the built-in Aviary subsystem for mass is partially replaced by external subsystems. +The second aspect of Aviary, instead of being computational like the first, is about subsystem integration. In addition to the capability to build purely Aviary-based aircraft models, Aviary provides the ability to build mixed-origin aircraft models, which are aircraft models consisting partially or entirely of external user-provided subsystems. In the case of a mixed-origin model, instead of just selecting existing Aviary subsystems and combining them into an aircraft model, the user also provides the Aviary code with their own subsystems (these could be pre-existing codes such as [pyCycle](https://github.com/OpenMDAO/pyCycle), or they could be new subsystems the user has built themselves). An example of a mixed-origin model is the [OpenAeroStruct example case](../examples/OAS_subsystem). In this example, the built-in Aviary subsystem for mass is partially replaced by external subsystems. ### FLOPS/LEAPS References 1. [Here](https://ntrs.nasa.gov/api/citations/20190000442/downloads/20190000442.pdf) is an overview of the LEAPS code development. diff --git a/aviary/docs/theory_guide/merging_syntax.ipynb b/aviary/docs/theory_guide/merging_syntax.ipynb index 84837c324..2f9bc319f 100644 --- a/aviary/docs/theory_guide/merging_syntax.ipynb +++ b/aviary/docs/theory_guide/merging_syntax.ipynb @@ -26,7 +26,7 @@ "source": [ "# Merging Variable Info\n", "\n", - "When working with multiple external subsystems for Aviary, sometimes it is helpful to merge together variable hierarchies and metadata. The syntax for those merging functions can be found below. For more detailed descriptions of how to merge [metadata](../user_guide/variable_metadata.md) and [hierarchies](../user_guide/variable_hierarchy.md) visit the included links.\n", + "When working with multiple external subsystems for Aviary, sometimes it is helpful to merge together variable hierarchies and metadata. The syntax for those merging functions can be found below. For more detailed descriptions of how to merge [metadata](../user_guide/variable_metadata) and [hierarchies](../user_guide/variable_hierarchy) visit the included links.\n", "\n", "```{eval-rst}\n", " .. autofunction:: aviary.utils.merge_hierarchies.merge_hierarchies\n", @@ -64,4 +64,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} From 8158ee0947c38eb25dd2997bf84247caac4593f6 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 26 Jan 2024 12:17:58 -0600 Subject: [PATCH 180/188] More phase builder simplification --- .../gasp_based/phases/2DOF_phase_builder.py | 264 ------------------ .../mission/gasp_based/phases/accel_phase.py | 10 +- .../mission/gasp_based/phases/climb_phase.py | 12 +- .../gasp_based/phases/groundroll_phase.py | 12 +- .../gasp_based/phases/rotation_phase.py | 11 +- aviary/mission/initial_guess_builders.py | 12 - aviary/mission/phase_builder_base.py | 15 +- 7 files changed, 18 insertions(+), 318 deletions(-) delete mode 100644 aviary/mission/gasp_based/phases/2DOF_phase_builder.py diff --git a/aviary/mission/gasp_based/phases/2DOF_phase_builder.py b/aviary/mission/gasp_based/phases/2DOF_phase_builder.py deleted file mode 100644 index d8f0435c2..000000000 --- a/aviary/mission/gasp_based/phases/2DOF_phase_builder.py +++ /dev/null @@ -1,264 +0,0 @@ -""" -This file is a work in progress and is currently not functional. It is a builder that -will have the ability to build any of the 2DOF phases in Aviary, and should be used in -conjunction with a mission builder. When complete, this file is intended to be the only -phase builder for 2DOF phases. -""" - -import dymos as dm -import openmdao.api as om - -from aviary.variable_info.variables import Dynamic - - -class Phase2DOF: - def __init__( - self, - aviary_options, - initials=None, - bounds=None, - scalers=None, - type=None, - transcription=None, - methods=None, - ): - self.aviary_options = aviary_options - self.initials = initials - self.bounds = bounds - self.scalers = scalers - self.type = type - self.transcription = transcription - self.methods = methods - - def pre_process(self): - if self.type == None: - raise om.AnalysisError( - "You have not provided a type of phase. Providing a type of phase is" - " required." - ) - elif self.type not in ["takeoff", Dynamic.Mission.VELOCITY_RATE, "climb", "cruise", "descent"]: - raise om.AnalysisError( - f'You have provided an invalid phase type to the 2DOF phase builder.' - ' Your phase type is {self.type} which is not on of ["takeoff", Dynamic.Mission.VELOCITY_RATE,' - ' "climb", "cruise", "descent"].' - ) - - if ( - self.initials.get_val("fix_initial_mass")["value"] - and self.initials.get_val("connect_initial_mass")["value"] - ): - raise om.AnalysisError( - "You have both fixed and connected the initial phase mass, which is" - " not allowed." - ) - - if ( - self.initials.get_val("fix_initial_time")["value"] - and self.initials.get_val("connect_initial_time")["value"] - ): - raise om.AnalysisError( - "You have both fixed and connected the initial phase time, which is not" - " allowed." - ) - - def fix_phase_value( - self, variable, units, val - ): # very thin wrapper around dymos to protect user from add parameter function - - self.phase.add_parameter(variable, opt=False, units=units, val=val) - - def build_phase(self): - self.pre_process() - - self.phase = dm.Phase( - ode_class=ODE2DOF, # pass aero and prop methods here - transcription=self.transcription, - ode_init_kwargs=self.aviary_options, - ) - - self.phase.set_time_options( - initial_bounds=self.bounds.get_val("initial_time_bounds")["value"], - duration_bounds=self.bounds.get_val("duration_bounds")["value"], - fix_initial=self.initials.get_val("fix_initial_time")["value"], - input_initial=self.initials.get_val("connect_initial_time")["value"], - units=self.bounds.get_val("initial_time_bounds")["units"], - duration_ref=self.scalers.get_val("duration_ref")["value"], - initial_ref=self.scalers.get_val("initial_time_ref")["value"], - ) - - self.phase.add_state( - Dynamic.Mission.MASS, - fix_initial=self.initials.get_val("fix_initial_mass")["value"], - input_initial=self.initials.get_val("connect_initial_mass")["value"], - fix_final=False, - lower=self.bounds.get_val("mass_bounds")["value"][0], - upper=self.bounds.get_val("mass_bounds")["value"][1], - units=self.bounds.get_val("mass_bounds")["units"], - rate_source=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, - targets=Dynamic.Mission.MASS, - ref=self.scalers.get_val("mass_ref")["value"], - ref0=self.scalers.get_val("mass_ref0")["value"], - defect_ref=self.scalers.get_val("mass_defect_ref")["value"], - ) - self.phase.add_state( - Dynamic.Mission.DISTANCE, - fix_initial=self.initials.get_val("fix_initial_distance")["value"], - input_initial=False, - fix_final=False, # should this be controllable? - lower=self.bounds.get_val("distance_bounds")["value"][0], - upper=self.bounds.get_val("distance_bounds")["value"][1], - units=self.bounds.get_val("distance_bounds")["units"], - rate_source=Dynamic.Mission.DISTANCE_RATE, - targets=Dynamic.Mission.DISTANCE, - ref=self.scalers.get_val("distance_ref")["value"], - ref0=self.scalers.get_val("distance_ref0")["value"], - defect_ref=self.scalers.get_val("distance_defect_ref")["value"], - ) - - if self.type == "takeoff" or self.type == "climb" or self.type == "descent": - self.phase.add_state( - Dynamic.Mission.ALTITUDE, - fix_initial=self.initials.get_val("fix_initial_flight_condition")[ - "value" - ], - input_initial=False, - fix_final=False, - lower=self.bounds.get_val("altitude_bounds")["value"][0], - upper=self.bounds.get_val("altitude_bounds")["value"][1], - units=self.bounds.get_val("altitude_bounds")["units"], - rate_source=Dynamic.Mission.ALTITUDE_RATE, - targets=Dynamic.Mission.ALTITUDE, - ref=self.scalers.get_val("altitude_ref")["value"], - ref0=self.scalers.get_val("altitude_ref0")["value"], - defect_ref=self.scalers.get_val("altitude_defect_ref")["value"], - ) - - if self.type == "takeoff" or self.type == Dynamic.Mission.VELOCITY_RATE: - self.phase.add_state( - "TAS", - fix_initial=self.initials.get_val( - "fix_initial_flight_condition")["value"], - input_initial=False, - fix_final=False, - lower=self.bounds.get_val("TAS_bounds")["value"][0], - upper=self.bounds.get_val("TAS_bounds")["value"][1], - units=self.bounds.get_val("TAS_bounds")["units"], - rate_source="TAS_rate", - targets="TAS", - ref=self.scalers.get_val("TAS_ref")["value"], - ref0=self.scalers.get_val("TAS_ref0")["value"], - defect_ref=self.scalers.get_val("TAS_defect_ref")["value"], - ) - - if self.type == "takeoff": - self.phase.add_state( - "angle_of_attack", # alpha - fix_initial=self.initials.get_val("fix_initial_angles")["value"], - input_initial=False, - fix_final=False, - lower=self.bounds.get_val("angle_of_attack_bounds")["value"][0], - upper=self.bounds.get_val("angle_of_attack_bounds")["value"][1], - units=self.bounds.get_val("angle_of_attack_bounds")["units"], - rate_source="angle_of_attack_rate", - targets="angle_of_attack", - ref=self.scalers.get_val("angle_of_attack_ref")["value"], - ref0=self.scalers.get_val("angle_of_attack_ref0")["value"], - defect_ref=self.scalers.get_val("angle_of_attack_defect_ref")["value"], - ) - self.phase.add_state( - Dynamic.Mission.FLIGHT_PATH_ANGLE, # gamma - fix_initial=self.initials.get_val("fix_initial_angles")["value"], - input_initial=False, - fix_final=False, - lower=self.bounds.get_val("flight_path_angle_bounds")["value"][0], - upper=self.bounds.get_val("flight_path_angle_bounds")["value"][1], - units=self.bounds.get_val("flight_path_angle_bounds")["units"], - rate_source=Dynamic.Mission.FLIGHT_PATH_ANGLE_RATE, - targets=Dynamic.Mission.FLIGHT_PATH_ANGLE, - ref=self.scalers.get_val("angle_of_attack_ref")["value"], - ref0=self.scalers.get_val("angle_of_attack_ref0")["value"], - defect_ref=self.scalers.get_val("angle_of_attack_defect_ref")["value"], - ) - - self.phase.add_timeseries_output( - Dynamic.Mission.MACH, output_name=Dynamic.Mission.MACH, units="unitless") - self.phase.add_timeseries_output("EAS", output_name="EAS", units="unitless") - self.phase.add_timeseries_output( - Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, output_name=Dynamic.Mission.FUEL_FLOW_RATE_NEGATIVE_TOTAL, units="unitless" - ) - self.phase.add_timeseries_output( - "fuselage_pitch", output_name="fuselage_pitch", units="unitless" - ) - self.phase.add_timeseries_output( - "angle_of_attack", output_name="angle_of_attack", units="unitless" - ) - self.phase.add_timeseries_output( - Dynamic.Mission.FLIGHT_PATH_ANGLE, output_name=Dynamic.Mission.FLIGHT_PATH_ANGLE, units="unitless" - ) - self.phase.add_timeseries_output( - "TAS_violation", output_name="TAS_violation", units="unitless" - ) - self.phase.add_timeseries_output("TAS", output_name="TAS", units="unitless") - self.phase.add_timeseries_output("CL", output_name="CL", units="unitless") - self.phase.add_timeseries_output( - Dynamic.Mission.THRUST_TOTAL, output_name=Dynamic.Mission.THRUST_TOTAL, units="unitless") - self.phase.add_timeseries_output("CD", output_name="CD", units="unitless") - self.phase.add_timeseries_output( - Dynamic.Mission.LIFT, output_name=Dynamic.Mission.LIFT, units="unitless") - self.phase.add_timeseries_output( - "normal_force", output_name="normal_force", units="unitless" - ) - - return self.phase - - -def link_trajectory(phases=None, aviary_options=None): - if phases == None: - raise om.AnalysisError("You have not provided any phases to link_trajectory.") - - traj = dm.Trajectory() - phase_names = [] - - for phase in phases: - num_usage = len([phase.type for check in phase_names if phase.type in check]) - new_name = phase.type + str(num_usage + 1) - phase_names.append(new_name) - - traj.add_phase(new_name, phase, **aviary_options) - - if len(phase_names) > 1: - traj.link_phases( - phases=[phase_names[-1], phase_names[-2]], - vars=linked_vars(phase_names[-1], phase_names[-2]), - ) - - return traj - - -def linked_vars(phase1, phase2): # TODO: add other combinations of phases - type1 = "".join((char for char in phase1 if not char.isdigit())) - type2 = "".join((char for char in phase2 if not char.isdigit())) - - linked_vars = [] - - if type1 == "takeoff" and type2 == Dynamic.Mission.VELOCITY_RATE: - linked_vars = [Dynamic.Mission.DISTANCE, "time", Dynamic.Mission.MASS, "TAS"] - elif type1 == Dynamic.Mission.VELOCITY_RATE and type2 == "climb": - linked_vars = ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE] - elif type1 == "climb" and type2 == "climb": - linked_vars = ["time", Dynamic.Mission.ALTITUDE, - Dynamic.Mission.MASS, Dynamic.Mission.DISTANCE] - elif type1 == "climb" and type2 == "cruise": - linked_vars = [] # TODO: update this - elif type1 == "cruise" and type2 == "descent": - linked_vars = [] # TODO: update this - elif type1 == "descent" and type2 == "descent": - linked_vars = ["time", Dynamic.Mission.ALTITUDE, - "mass", Dynamic.Mission.DISTANCE] - else: - raise om.AnalysisError( - "You have provided a phase order which is not yet supported." - ) - - return linked_vars diff --git a/aviary/mission/gasp_based/phases/accel_phase.py b/aviary/mission/gasp_based/phases/accel_phase.py index 3c123cf39..d9a46d4c9 100644 --- a/aviary/mission/gasp_based/phases/accel_phase.py +++ b/aviary/mission/gasp_based/phases/accel_phase.py @@ -44,18 +44,10 @@ def build_phase(self, aviary_options: AviaryValues = None): user_options = self.user_options # Extracting and setting options - fix_initial = user_options.get_val('fix_initial') EAS_constraint_eq = user_options.get_val('EAS_constraint_eq', units='kn') - duration_bounds = user_options.get_val('duration_bounds', units='s') - duration_ref = user_options.get_val('duration_ref', units='s') alt = user_options.get_val('alt', units='ft') - phase.set_time_options( - fix_initial=fix_initial, - duration_bounds=duration_bounds, - units="s", - duration_ref=duration_ref, - ) + self.set_time_options(user_options) # States self.add_TAS_state(user_options) diff --git a/aviary/mission/gasp_based/phases/climb_phase.py b/aviary/mission/gasp_based/phases/climb_phase.py index 8f8a0a12f..1264ce94c 100644 --- a/aviary/mission/gasp_based/phases/climb_phase.py +++ b/aviary/mission/gasp_based/phases/climb_phase.py @@ -47,21 +47,13 @@ def build_phase(self, aviary_options: AviaryValues = None): # Custom configurations for the climb phase user_options = self.user_options - fix_initial = user_options.get_val('fix_initial') mach_cruise = user_options.get_val('mach_cruise') target_mach = user_options.get_val('target_mach') final_altitude = user_options.get_val('final_altitude', units='ft') required_available_climb_rate = user_options.get_val( 'required_available_climb_rate', units='ft/min') - duration_bounds = user_options.get_val('duration_bounds', units='s') - duration_ref = user_options.get_val('duration_ref', units='s') - - phase.set_time_options( - fix_initial=fix_initial, - duration_bounds=duration_bounds, - duration_ref=duration_ref, - units="s", - ) + + self.set_time_options(user_options) # States self.add_altitude_state(user_options) diff --git a/aviary/mission/gasp_based/phases/groundroll_phase.py b/aviary/mission/gasp_based/phases/groundroll_phase.py index 7e2ae0ae8..45c5b5a91 100644 --- a/aviary/mission/gasp_based/phases/groundroll_phase.py +++ b/aviary/mission/gasp_based/phases/groundroll_phase.py @@ -21,8 +21,6 @@ def build_phase(self, aviary_options: AviaryValues = None): fix_initial = user_options.get_val('fix_initial') fix_initial_mass = user_options.get_val('fix_initial_mass') connect_initial_mass = user_options.get_val('connect_initial_mass') - duration_bounds = user_options.get_val('duration_bounds', units='s') - duration_ref = user_options.get_val('duration_ref', units='s') mass_lower = user_options.get_val('mass_lower', units='lbm') mass_upper = user_options.get_val('mass_upper', units='lbm') mass_ref = user_options.get_val('mass_ref', units='lbm') @@ -34,15 +32,7 @@ def build_phase(self, aviary_options: AviaryValues = None): distance_ref0 = user_options.get_val('distance_ref0', units='ft') distance_defect_ref = user_options.get_val('distance_defect_ref', units='ft') - # Set time options - phase.set_time_options( - fix_initial=fix_initial, - fix_duration=False, - units="s", - targets="t_curr", - duration_bounds=duration_bounds, - duration_ref=duration_ref, - ) + self.set_time_options(user_options, targets='t_curr') # Add states self.add_TAS_state(user_options) diff --git a/aviary/mission/gasp_based/phases/rotation_phase.py b/aviary/mission/gasp_based/phases/rotation_phase.py index cc183226b..3ef1e869e 100644 --- a/aviary/mission/gasp_based/phases/rotation_phase.py +++ b/aviary/mission/gasp_based/phases/rotation_phase.py @@ -20,8 +20,6 @@ def build_phase(self, aviary_options: AviaryValues = None): # Retrieve user options values user_options = self.user_options fix_initial = user_options.get_val('fix_initial') - duration_bounds = user_options.get_val('duration_bounds', units='s') - duration_ref = user_options.get_val('duration_ref', units='s') angle_lower = user_options.get_val('angle_lower', units='rad') angle_upper = user_options.get_val('angle_upper', units='rad') angle_ref = user_options.get_val('angle_ref', units='rad') @@ -35,14 +33,7 @@ def build_phase(self, aviary_options: AviaryValues = None): normal_ref = user_options.get_val('normal_ref', units='lbf') normal_ref0 = user_options.get_val('normal_ref0', units='lbf') - phase.set_time_options( - fix_initial=fix_initial, - fix_duration=False, - units="s", - targets="t_curr", - duration_bounds=duration_bounds, - duration_ref=duration_ref, - ) + self.set_time_options(user_options, targets='t_curr') # Add states phase.add_state( diff --git a/aviary/mission/initial_guess_builders.py b/aviary/mission/initial_guess_builders.py index 9b8c3bbb9..4de2e9a02 100644 --- a/aviary/mission/initial_guess_builders.py +++ b/aviary/mission/initial_guess_builders.py @@ -18,24 +18,12 @@ InitialGuessTime : a utility for setting guesses for initial time and duration on a problem ''' -from abc import ABC -from collections import namedtuple from collections.abc import Sequence import dymos as dm import numpy as np import openmdao.api as om -from aviary.mission.flops_based.ode.mission_ODE import MissionODE -from aviary.utils.aviary_values import AviaryValues, get_keys - -_require_new_meta_data_class_attr_ = \ - namedtuple('_require_new_meta_data_class_attr_', ()) - - -_require_new_initial_guesses_meta_data_class_attr_ = \ - namedtuple('_require_new_initial_guesses_meta_data_class_attr_', ()) - class InitialGuess: ''' diff --git a/aviary/mission/phase_builder_base.py b/aviary/mission/phase_builder_base.py index 471a3f25a..458a40497 100644 --- a/aviary/mission/phase_builder_base.py +++ b/aviary/mission/phase_builder_base.py @@ -7,13 +7,11 @@ ''' from abc import ABC from collections import namedtuple -from collections.abc import Sequence from aviary.mission.initial_guess_builders import InitialGuess from aviary.variable_info.variables import Dynamic import dymos as dm -import numpy as np import openmdao.api as om from aviary.mission.flops_based.ode.mission_ODE import MissionODE @@ -421,6 +419,19 @@ def _add_initial_guess_meta_data(cls, initial_guess: InitialGuess, desc=None): meta_data[name] = dict( apply_initial_guess=initial_guess.apply_initial_guess, desc=desc) + def set_time_options(self, user_options, targets=[]): + fix_initial = user_options.get_val('fix_initial') + duration_bounds = user_options.get_val('duration_bounds', units='s') + duration_ref = user_options.get_val('duration_ref', units='s') + + self.phase.set_time_options( + fix_initial=fix_initial, + duration_bounds=duration_bounds, + units="s", + targets=targets, + duration_ref=duration_ref, + ) + def add_TAS_state(self, user_options): TAS_lower = user_options.get_val('TAS_lower', units='kn') TAS_upper = user_options.get_val('TAS_upper', units='kn') From bbfc87564a7c83257130d117e58a47728514b773 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Fri, 26 Jan 2024 12:55:44 -0600 Subject: [PATCH 181/188] Added altitude constraints --- aviary/interface/default_phase_info/two_dof.py | 3 +-- aviary/interface/utils/check_phase_info.py | 3 +-- aviary/mission/gasp_based/phases/ascent_phase.py | 14 ++------------ aviary/mission/gasp_based/phases/descent_phase.py | 9 +-------- aviary/mission/phase_builder_base.py | 11 +++++++++++ 5 files changed, 16 insertions(+), 24 deletions(-) diff --git a/aviary/interface/default_phase_info/two_dof.py b/aviary/interface/default_phase_info/two_dof.py index fc74bc76b..6c1050d51 100644 --- a/aviary/interface/default_phase_info/two_dof.py +++ b/aviary/interface/default_phase_info/two_dof.py @@ -102,9 +102,8 @@ 'alt_upper': (700, 'ft'), 'alt_ref': (1000, 'ft'), 'alt_defect_ref': (1000, 'ft'), - 'alt_constraint_eq': (500, 'ft'), + 'final_altitude': (500, 'ft'), 'alt_constraint_ref': (500, 'ft'), - 'alt_constraint_ref0': (0, 'ft'), 'angle_lower': (-10, 'rad'), 'angle_upper': (20, 'rad'), 'angle_ref': (57.2958, 'deg'), diff --git a/aviary/interface/utils/check_phase_info.py b/aviary/interface/utils/check_phase_info.py index 6d13c5416..0ea5faa96 100644 --- a/aviary/interface/utils/check_phase_info.py +++ b/aviary/interface/utils/check_phase_info.py @@ -103,9 +103,8 @@ def check_phase_info(phase_info, mission_method): **common_mass, **common_distance, **common_alt, - 'alt_constraint_eq': tuple, + 'final_altitude': tuple, 'alt_constraint_ref': tuple, - 'alt_constraint_ref0': tuple, 'alt_defect_ref': tuple, **common_angle, 'pitch_constraint_lower': tuple, diff --git a/aviary/mission/gasp_based/phases/ascent_phase.py b/aviary/mission/gasp_based/phases/ascent_phase.py index 4b537ef7b..7a181aebc 100644 --- a/aviary/mission/gasp_based/phases/ascent_phase.py +++ b/aviary/mission/gasp_based/phases/ascent_phase.py @@ -20,9 +20,6 @@ def build_phase(self, aviary_options: AviaryValues = None): # Retrieve user options values user_options = self.user_options - alt_constraint_eq = user_options.get_val('alt_constraint_eq', units='ft') - alt_constraint_ref = user_options.get_val('alt_constraint_ref', units='ft') - alt_constraint_ref0 = user_options.get_val('alt_constraint_ref0', units='ft') pitch_constraint_lower = user_options.get_val( 'pitch_constraint_lower', units='deg') pitch_constraint_upper = user_options.get_val( @@ -47,14 +44,7 @@ def build_phase(self, aviary_options: AviaryValues = None): self.add_mass_state(user_options) self.add_distance_state(user_options) - phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, - loc="final", - equals=alt_constraint_eq, - units="ft", - ref=alt_constraint_ref, - ref0=alt_constraint_ref0, - ) + self.add_altitude_constraint(user_options) phase.add_path_constraint( "load_factor", @@ -110,7 +100,7 @@ def build_phase(self, aviary_options: AviaryValues = None): AscentPhase._add_meta_data('alt_ref', val=100, units='ft') AscentPhase._add_meta_data('alt_ref0', val=0, units='ft') AscentPhase._add_meta_data('alt_defect_ref', val=100, units='ft') -AscentPhase._add_meta_data('alt_constraint_eq', val=500, units='ft') +AscentPhase._add_meta_data('final_altitude', val=500, units='ft') AscentPhase._add_meta_data('alt_constraint_ref', val=100, units='ft') AscentPhase._add_meta_data('alt_constraint_ref0', val=0, units='ft') AscentPhase._add_meta_data('TAS_lower', val=0, units='kn') diff --git a/aviary/mission/gasp_based/phases/descent_phase.py b/aviary/mission/gasp_based/phases/descent_phase.py index 9f8980c6e..e5a999d91 100644 --- a/aviary/mission/gasp_based/phases/descent_phase.py +++ b/aviary/mission/gasp_based/phases/descent_phase.py @@ -22,8 +22,6 @@ def build_phase(self, aviary_options: AviaryValues = None): fix_initial = user_options.get_val('fix_initial') input_initial = user_options.get_val('input_initial') duration_ref = user_options.get_val('duration_ref', units='s') - final_altitude = user_options.get_val('final_altitude', units='ft') - alt_constraint_ref = user_options.get_val('alt_constraint_ref', units='ft') input_speed_type = user_options.get_val('input_speed_type') EAS_limit = user_options.get_val('EAS_limit', units='kn') @@ -44,12 +42,7 @@ def build_phase(self, aviary_options: AviaryValues = None): self.add_distance_state(user_options) # Add boundary constraint - phase.add_boundary_constraint( - Dynamic.Mission.ALTITUDE, - loc="final", - equals=final_altitude, - units="ft", - ref=alt_constraint_ref) + self.add_altitude_constraint(user_options) # Add parameter if necessary if input_speed_type == SpeedType.EAS: diff --git a/aviary/mission/phase_builder_base.py b/aviary/mission/phase_builder_base.py index 458a40497..ea9007fa4 100644 --- a/aviary/mission/phase_builder_base.py +++ b/aviary/mission/phase_builder_base.py @@ -529,6 +529,17 @@ def add_altitude_state(self, user_options): ref0=alt_ref0, ) + def add_altitude_constraint(self, user_options): + final_altitude = user_options.get_val('final_altitude', units='ft') + alt_constraint_ref = user_options.get_val('alt_constraint_ref', units='ft') + self.phase.add_boundary_constraint( + Dynamic.Mission.ALTITUDE, + loc="final", + equals=final_altitude, + units="ft", + ref=alt_constraint_ref, + ) + _registered_phase_builder_types = [] From 63fecd43dda0b8af1f2ef3ea16ae125b1bed2c7a Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 29 Jan 2024 16:36:46 -0600 Subject: [PATCH 182/188] Updated docs publish path --- .github/workflows/test_workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index b1328c9da..039d756fb 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -262,7 +262,7 @@ jobs: echo "Publishing Docs to github.io" echo "=============================================================" pip install ghp-import - cd $HOME/work/om-Aviary/om-Aviary/aviary + cd $HOME/work/Aviary/Aviary/aviary ghp-import -n -p -f docs/_build/html - name: Scan for security issues From 7e64becd82f7e8f19dbc9a624e7453c1b2948c76 Mon Sep 17 00:00:00 2001 From: johnjasa Date: Mon, 29 Jan 2024 16:37:44 -0600 Subject: [PATCH 183/188] Updated URL paths throughout --- .github/ISSUE_TEMPLATE/config.yml | 2 +- .github/workflows/test_workflow.yml | 2 +- .../contributing_guidelines.md | 4 ++-- aviary/docs/examples/OAS_subsystem.ipynb | 20 +++++++++---------- aviary/docs/examples/intro.md | 2 +- .../getting_started/input_csv_phase_info.md | 2 +- aviary/docs/getting_started/installation.md | 2 +- .../onboarding_ext_subsystem.ipynb | 2 +- .../docs/getting_started/what_aviary_does.md | 4 ++-- aviary/docs/intro.md | 2 +- .../battery_subsystem_example.ipynb | 4 ++-- aviary/docs/user_guide/propulsion.md | 2 +- .../user_guide/step_by_step_external_guide.md | 10 +++++----- 13 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 5b2a47efe..aa6e97d44 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: true contact_links: - name: Discussion Board - url: https://github.com/OpenMDAO/om-Aviary/discussions + url: https://github.com/OpenMDAO/Aviary/discussions about: "If you have questions or need support, please check the discussion board and create a \"New Discussion\" if necessary." diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 039d756fb..b90198918 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -245,7 +245,7 @@ jobs: if: matrix.MAKE_DOCS shell: bash -l {0} run: | - cd $HOME/work/om-Aviary/om-Aviary/aviary/docs + cd $HOME/work/Aviary/Aviary/aviary/docs find _build/html/reports/ -type f -name '*.log' \ -exec echo "#################################################################" \; \ -exec echo {} \; \ diff --git a/aviary/docs/developer_guide/contributing_guidelines.md b/aviary/docs/developer_guide/contributing_guidelines.md index 11ad8b384..523cbc8be 100755 --- a/aviary/docs/developer_guide/contributing_guidelines.md +++ b/aviary/docs/developer_guide/contributing_guidelines.md @@ -15,7 +15,7 @@ Documentation is the backbone of the Aviary team's support for our user communit The Aviary codebase is currently under active development and cleanup, including the addition of docstrings. Thus, not every function and class currently includes a docstring, however, we are slowly adding them. In order to move forwards instead of backwards we require that all added functions and classes include a docstring in the numpy format. ## Benchmark Tests -The Aviary codebase has several benchmark tests which test some of the baseline models included in Aviary. These tests supplement the unit test capability, and are tested frequently by the Aviary team. We encourage you to run these tests using our test runner located [here](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/run_all_benchmarks.py). +The Aviary codebase has several benchmark tests which test some of the baseline models included in Aviary. These tests supplement the unit test capability, and are tested frequently by the Aviary team. We encourage you to run these tests using our test runner located [here](https://github.com/OpenMDAO/Aviary/blob/main/aviary/run_all_benchmarks.py). ## Use of Issue Backlog -The Aviary team would like a chance to interact with and get community engagement in feature changes to the codebase. The primary place that this engagement happens is in the [issue backlog](https://github.com/OpenMDAO/om-Aviary/issues/new/choose) using the "feature or change request" section. In addition, we would like to be able to track bug fixes that come through the code. To support these goals we encourage users to create issues, and we encourage code contributors to link issues to their pull requests. \ No newline at end of file +The Aviary team would like a chance to interact with and get community engagement in feature changes to the codebase. The primary place that this engagement happens is in the [issue backlog](https://github.com/OpenMDAO/Aviary/issues/new/choose) using the "feature or change request" section. In addition, we would like to be able to track bug fixes that come through the code. To support these goals we encourage users to create issues, and we encourage code contributors to link issues to their pull requests. \ No newline at end of file diff --git a/aviary/docs/examples/OAS_subsystem.ipynb b/aviary/docs/examples/OAS_subsystem.ipynb index af46777e2..c36d6ea2e 100644 --- a/aviary/docs/examples/OAS_subsystem.ipynb +++ b/aviary/docs/examples/OAS_subsystem.ipynb @@ -30,11 +30,11 @@ "The subsystem builder uses the Aviary external subsystem builder template to connect the analysis tool to Aviary as either a pre-mission, mission or post-mission subsystem.\n", "\n", "For this case, the analysis tool will compute a wing weight in the pre-mission portion of the Aviary analysis and return its value to Aviary to override the empirical wing weight value.\n", - "Fuel weight is passed in from Aviary as the only input currently, but other inputs may also be passed in through the subsystem builder, [OAS_wing_weight_builder](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_builder.py), by the `promotes_inputs` parameter.\n", + "Fuel weight is passed in from Aviary as the only input currently, but other inputs may also be passed in through the subsystem builder, [OAS_wing_weight_builder](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_builder.py), by the `promotes_inputs` parameter.\n", "Other Aviary variables can also be added as additional inputs based on user needs.\n", "\n", "```{note}\n", - "Some modifications of the [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) code will be necessary to add new inputs not already defined.\n", + "Some modifications of the [OAS_wing_weight_analysis](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) code will be necessary to add new inputs not already defined.\n", "```\n", "\n", "Here is the builder object for the OAS wing weight analysis example:" @@ -95,8 +95,8 @@ "source": [ "## Analysis Model Details\n", "\n", - "This analysis is based on the Aviary benchmark [aircraft_for_bench_FwFm](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv) input data representing a typical large single aisle class transport aircraft.\n", - "The analysis code [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) contains the `OAStructures` class which performs a structural analysis of the wing.\n", + "This analysis is based on the Aviary benchmark [aircraft_for_bench_FwFm](https://github.com/OpenMDAO/Aviary/blob/main/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv) input data representing a typical large single aisle class transport aircraft.\n", + "The analysis code [OAS_wing_weight_analysis](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) contains the `OAStructures` class which performs a structural analysis of the wing.\n", "\n", "We'll now discuss this code in more detail.\n", "\n", @@ -111,7 +111,7 @@ "Results of the structural optimization determine the optimum wing skin thickness, spar cap thickness, wing twist, wing t/c and maneuver angle of attack that satisfies strength constraints while minimizing wing weight.\n", "The 'OAStructures' class returns the optimized wing mass and the fuel mass burned but currently only the wing mass is used to override the Aviary variable 'Aircraft.Wing.MASS'.\n", "\n", - "The [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) code may be executed in Python to test the OpenAeroStruct analysis outside of the Aviary subsystem interface.\n", + "The [OAS_wing_weight_analysis](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) code may be executed in Python to test the OpenAeroStruct analysis outside of the Aviary subsystem interface.\n", "Default values for each of the inputs and options are included at the bottom of the analysis code file.\n", "This can be a useful test to demonstrate that the OpenAeroStruct analysis model has been properly defined and the model returns reasonable results.\n", "\n", @@ -175,29 +175,29 @@ "- wing_weight\n", "- fuel_burn\n", "\n", - "See [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) and the [OpenAeroStruct aerostructural optimization with wingbox](https://mdolab-openaerostruct.readthedocs-hosted.com/en/latest/aerostructural_wingbox_walkthrough.html) documentation for descriptions of these variables.\n", + "See [OAS_wing_weight_analysis](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) and the [OpenAeroStruct aerostructural optimization with wingbox](https://mdolab-openaerostruct.readthedocs-hosted.com/en/latest/aerostructural_wingbox_walkthrough.html) documentation for descriptions of these variables.\n", "\n", "## Test Case\n", "\n", "A simple Aviary mission is defined to test the inclusion of the OpenAeroStruct wing weight subsystem during the pre-mission phase.\n", - "The test mission is defined in [run_simple_OAS_mission](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS/run_simple_OAS_mission.py) and is a mission based on input data read from the benchmark data file [aircraft_for_bench_FwFm](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv).\n", + "The test mission is defined in [run_simple_OAS_mission](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/OAS/run_simple_OAS_mission.py) and is a mission based on input data read from the benchmark data file [aircraft_for_bench_FwFm](https://github.com/OpenMDAO/Aviary/blob/main/aviary/models/test_aircraft/aircraft_for_bench_FwFm.csv).\n", "\n", "The OpenAeroStruct subsystem is used to compute an optimum wing mass which will override the Aviary computed wing mass value.\n", "The value of the Aviary variable `Aircraft.Wing.MASS` is printed at the conclusion of the mission to verify that the wing weight from the subsystem is overriding the Aviary computed wing weight.\n", "\n", - "A variable in the [run_simple_OAS_mission](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS/run_simple_OAS_mission.py) file named `use_OAS` may be set by the user to `True` or `False` to run the simple mission with or without the OpenAeroStruct subsystem included.\n", + "A variable in the [run_simple_OAS_mission](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/OAS/run_simple_OAS_mission.py) file named `use_OAS` may be set by the user to `True` or `False` to run the simple mission with or without the OpenAeroStruct subsystem included.\n", "This will allow the mission to be flown either using the Aviary empirical wing weight estimation (`use_OAS=False`) or with the OpenAeroStruct subsystem (`use_OAS=True`).\n", "\n", "Wing weight optimization of this type usually does not have knowledge of non-optimum wing mass values such as leading and training edge structure, actuators, stiffeners, etc.\n", "The optimum wing mass computed by the `OAStructures` class can be scaled using the option `wing_weight_ratio` to better match either the Aviary empirical wing weight value or a known fly-away weight estimate for your wing model.\n", - "One method to determine the wing_weight_ratio would be to run the mission to calculate the Aviary empirical wing weight and then run [OAS_wing_weight_analysis](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) by itself using its default input values and compare wing weights. The `wing_weight_ratio` value may then be set to calibrate the OpenAeroStruct wing weight to the expected fly-away weight.\n", + "One method to determine the wing_weight_ratio would be to run the mission to calculate the Aviary empirical wing weight and then run [OAS_wing_weight_analysis](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/OAS_weight/OAS_wing_weight_analysis.py) by itself using its default input values and compare wing weights. The `wing_weight_ratio` value may then be set to calibrate the OpenAeroStruct wing weight to the expected fly-away weight.\n", "\n", "This calibration step has already been performed for this model, so the user may run the simple mission with or without the OpenAeroStruct subsystem active and compare the results.\n", "\n", "## Example Run Script\n", "\n", "Here is the full run script used to run the simple mission with the OpenAeroStruct subsystem active.\n", - "This run script is also available in the [run_simple_OAS_mission file.](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/OAS/run_simple_OAS_mission.py)\n", + "This run script is also available in the [run_simple_OAS_mission file.](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/OAS/run_simple_OAS_mission.py)\n", "\n", "\n", "```{note}\n", diff --git a/aviary/docs/examples/intro.md b/aviary/docs/examples/intro.md index 2af40c2d9..abc285ef1 100644 --- a/aviary/docs/examples/intro.md +++ b/aviary/docs/examples/intro.md @@ -4,7 +4,7 @@ Aviary provides a range of built-in examples that serve as both regression tests and demonstrations of the tool's capabilities. These examples showcase various full mission analysis and optimization problems, incorporating different subsystem analyses from FLOPS and GASP. -You can find these examples [here](https://github.com/OpenMDAO/om-Aviary/tree/main/aviary/validation_cases/benchmark_tests), especially the files that start `test_swap`. +You can find these examples [here](https://github.com/OpenMDAO/Aviary/tree/main/aviary/validation_cases/benchmark_tests), especially the files that start `test_swap`. These cases highlight Aviary's ability to replicate GASP and FLOPS capabilities, as well as use both code's methods in a single analysis. In addition to the examples for core Aviary, we also provide some examples for using external subsystems. diff --git a/aviary/docs/getting_started/input_csv_phase_info.md b/aviary/docs/getting_started/input_csv_phase_info.md index 68400e9c2..f0d4c0d8a 100644 --- a/aviary/docs/getting_started/input_csv_phase_info.md +++ b/aviary/docs/getting_started/input_csv_phase_info.md @@ -89,7 +89,7 @@ We will now discuss the meaning of the keys within the `phase_info` objects. - `fix_duration`: default to `False`. ```{note} -Not all the keys apply to all phases. The users should select the right keys for each phase of interest. The required keys for each phase are defined in [check_phase_info](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/interface/utils.py) function. Currently, this function does the check only for `FLOPS` and `GASP` missions. +Not all the keys apply to all phases. The users should select the right keys for each phase of interest. The required keys for each phase are defined in [check_phase_info](https://github.com/OpenMDAO/Aviary/blob/main/aviary/interface/utils.py) function. Currently, this function does the check only for `FLOPS` and `GASP` missions. ``` Users can add their own keys as needed. diff --git a/aviary/docs/getting_started/installation.md b/aviary/docs/getting_started/installation.md index 50e79246b..4691430a9 100644 --- a/aviary/docs/getting_started/installation.md +++ b/aviary/docs/getting_started/installation.md @@ -218,7 +218,7 @@ Successfully installed pyoptsparse-2.10.1 ### Installing Aviary and Running Tests -Now, we are ready to install Aviary. Assuming that you will become a contributor sooner or later, we want to install a copy from the main source. (You will need a GitHub account for this) Let us open `https://github.com/openMDAO/om-aviary/` in a web browser and click [fork](https://github.com/OpenMDAO/om-Aviary/fork) on the top-right corner. You then have created your own copy of Aviary on GitHub website. Now we create a copy on your local drive (supposing `USER_ID` is your GitHub account ID): +Now, we are ready to install Aviary. Assuming that you will become a contributor sooner or later, we want to install a copy from the main source. (You will need a GitHub account for this) Let us open `https://github.com/openMDAO/om-aviary/` in a web browser and click [fork](https://github.com/OpenMDAO/Aviary/fork) on the top-right corner. You then have created your own copy of Aviary on GitHub website. Now we create a copy on your local drive (supposing `USER_ID` is your GitHub account ID): ``` $ cd ~/workspace diff --git a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb index 7d6d6df6e..852c6c9c1 100644 --- a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb +++ b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb @@ -240,7 +240,7 @@ "metadata": {}, "source": [ "\n", - "In the battery subsystem, the type of battery cell we use is `18650`. The option is not set in `input_file`, instead is is controlled by importing the correct battery map [here](https://github.com/OpenMDAO/om-Aviary/blob/1fca1c03cb2e1d6387442162e8d7dabf83eee197/aviary/examples/external_subsystems/battery/model/reg_thevenin_interp_group.py#L5)." + "In the battery subsystem, the type of battery cell we use is `18650`. The option is not set in `input_file`, instead is is controlled by importing the correct battery map [here](https://github.com/OpenMDAO/Aviary/blob/1fca1c03cb2e1d6387442162e8d7dabf83eee197/aviary/examples/external_subsystems/battery/model/reg_thevenin_interp_group.py#L5)." ] }, { diff --git a/aviary/docs/getting_started/what_aviary_does.md b/aviary/docs/getting_started/what_aviary_does.md index 880887397..acf630706 100644 --- a/aviary/docs/getting_started/what_aviary_does.md +++ b/aviary/docs/getting_started/what_aviary_does.md @@ -17,7 +17,7 @@ Let's discuss what Aviary does in more detail. ```{warning} Aviary is under active development! If you're using it, know that we are working to update Aviary to make it more user-friendly and capable. -If you have suggestions or comments please let the Aviary team know by [submitting an issue on GitHub](https://github.com/OpenMDAO/om-Aviary/issues/new/choose). +If you have suggestions or comments please let the Aviary team know by [submitting an issue on GitHub](https://github.com/OpenMDAO/Aviary/issues/new/choose). ``` ## Core functionalities @@ -77,7 +77,7 @@ We've touched on some of these already, but let's discuss them more. ### Benefits -- Open-source: Aviary is open-source and available on [GitHub](https://github.com/OpenMDAO/om-Aviary) +- Open-source: Aviary is open-source and available on [GitHub](https://github.com/OpenMDAO/Aviary) - Flexible: Aviary is intended to be flexible enough to design a variety of aircraft and missions - Customizable: Aviary allows users to add their own subsystems to the problem - Optimization: Aviary is designed to be used effectively with gradient-based optimization diff --git a/aviary/docs/intro.md b/aviary/docs/intro.md index f085b0f58..0904749a4 100644 --- a/aviary/docs/intro.md +++ b/aviary/docs/intro.md @@ -4,7 +4,7 @@ This is the landing page for all of Aviary's documentation, including a user's g ## What Aviary is -[Aviary](https://github.com/OpenMDAO/om-Aviary) is an aircraft analysis, design, and optimization tool built on top of the Python-based optimization framework [OpenMDAO](https://github.com/OpenMDAO/OpenMDAO). +[Aviary](https://github.com/OpenMDAO/Aviary) is an aircraft analysis, design, and optimization tool built on top of the Python-based optimization framework [OpenMDAO](https://github.com/OpenMDAO/OpenMDAO). Aviary provides a flexible and user-friendly optimization platform that allows the beginning aircraft modeler to build a useful model, the intermediate aircraft modeler to build an advanced model, and the advanced aircraft modeler to build any model they can imagine. Features of Aviary include: diff --git a/aviary/docs/user_guide/battery_subsystem_example.ipynb b/aviary/docs/user_guide/battery_subsystem_example.ipynb index 8b4732435..21faef03d 100644 --- a/aviary/docs/user_guide/battery_subsystem_example.ipynb +++ b/aviary/docs/user_guide/battery_subsystem_example.ipynb @@ -13,7 +13,7 @@ "\n", "We'll show you how to define the builder object, how to specify the pre-mission and mission models, and how to implement the interface methods.\n", "In each of these methods, we've removed the initial docstring to increase readability on this page.\n", - "The [`battery_builder.py`](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/examples/external_subsystems/battery/battery_builder.py) file contains the original methods and docstrings.\n", + "The [`battery_builder.py`](https://github.com/OpenMDAO/Aviary/blob/main/aviary/examples/external_subsystems/battery/battery_builder.py) file contains the original methods and docstrings.\n", "Please see that file if you want to examine this example builder in its entirety as one file.\n", "\n", "You can define these methods in any order you want within your subsystem builder and Aviary will use them at the appropriate times during analysis and optimization.\n", @@ -475,7 +475,7 @@ "In the `get_constraints` method, a constraint was added to the dictionary but did not include a `type` key, which is required as stated by the error message.\n", "\n", "If you encounter an error when using your subsystem, but the test here did not find it, please let the Aviary dev team know!\n", - "We'd love to hear from you on the [GitHub issues page](https://github.com/OpenMDAO/om-Aviary/issues) so we can help everyone write great external subsystems." + "We'd love to hear from you on the [GitHub issues page](https://github.com/OpenMDAO/Aviary/issues) so we can help everyone write great external subsystems." ] } ], diff --git a/aviary/docs/user_guide/propulsion.md b/aviary/docs/user_guide/propulsion.md index 74a438c08..a4611cdeb 100644 --- a/aviary/docs/user_guide/propulsion.md +++ b/aviary/docs/user_guide/propulsion.md @@ -13,7 +13,7 @@ Each unique type of engine is referred to as an engine model. Engine decks are a type of engine model - they use the same basic interface, but have additional functionality to handle reading and processing data files. ### Formatting -An engine deck data file requires specific formatting for Aviary to correctly interpret. These files must follow the [Aviary data file format](input_files).An example of a properly-formatted engine deck can be found [here](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/models/engines/turbofan_22k.deck). +An engine deck data file requires specific formatting for Aviary to correctly interpret. These files must follow the [Aviary data file format](input_files).An example of a properly-formatted engine deck can be found [here](https://github.com/OpenMDAO/Aviary/blob/main/aviary/models/engines/turbofan_22k.deck). ### Variables diff --git a/aviary/docs/user_guide/step_by_step_external_guide.md b/aviary/docs/user_guide/step_by_step_external_guide.md index 9ebc812d2..7556873d0 100644 --- a/aviary/docs/user_guide/step_by_step_external_guide.md +++ b/aviary/docs/user_guide/step_by_step_external_guide.md @@ -27,13 +27,13 @@ If your subsystem does not need to tell Aviary about any new variables (i.e. all -1. First, view the [battery_variables.py file](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/battery/battery_variables.py) to see an example of the variable hierarchy we use in Aviary. You can also look at the [core Aviary variables](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/variable_info/variables.py) to see what's available already. You can add any arbitrary system as a subclass within here. Items that define aircraft properties should go within `Aircraft` whereas any variables pertaining to the `Mission` should exist there. +1. First, view the [battery_variables.py file](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/battery/battery_variables.py) to see an example of the variable hierarchy we use in Aviary. You can also look at the [core Aviary variables](https://github.com/OpenMDAO/Aviary/blob/main/aviary/variable_info/variables.py) to see what's available already. You can add any arbitrary system as a subclass within here. Items that define aircraft properties should go within `Aircraft` whereas any variables pertaining to the `Mission` should exist there. These variable names are what's used within the OpenMDAO system that Aviary uses. This sort of hierarchy is a purposeful design choice to make it clear what values live where, which subsystem they belong to, and that they are named the same between different systems. Additionally, we recommend including the legacy name of any variable you add that so that users of your builder will know how the variable names map to existing analyses. -2. Now, with the variable names defined, we need to define variable metadata. Variable metadata helps Aviary understand your system. It also helps humans understand what units, defaults, and other values your variables use. Check out the [battery metadata example](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/battery/battery_variable_meta_data.py) as well as the [core Aviary metadata](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/variable_info/variable_meta_data.py). +2. Now, with the variable names defined, we need to define variable metadata. Variable metadata helps Aviary understand your system. It also helps humans understand what units, defaults, and other values your variables use. Check out the [battery metadata example](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/battery/battery_variable_meta_data.py) as well as the [core Aviary metadata](https://github.com/OpenMDAO/Aviary/blob/main/aviary/variable_info/variable_meta_data.py). When you define your variable metadata, you'll use the same names you just defined. With those names, you'll provide units, a brief description, and default values. You're not locking yourself into specific units here, but by providing units then Aviary can convert the values behind-the-scenes to whatever units are actually used in the code. Users can input variables in any units that can be converted to those units prescribed in the metadata. @@ -67,7 +67,7 @@ The methods you should implement depend on what type of subsystem you're buildin ## Testing your builder and ensuring it's behaving as intended -Okay, now we should test your subsystem builder to make sure it's providing the correct outputs to Aviary. You don't have to put it into Aviary (yet!) to do this. Look at the [`test_battery_builder.py` file](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/battery/test_battery_builder.py) to see how to test your subsystem. This is also detailed in the [battery subsystem example](battery_subsystem_example) doc page. +Okay, now we should test your subsystem builder to make sure it's providing the correct outputs to Aviary. You don't have to put it into Aviary (yet!) to do this. Look at the [`test_battery_builder.py` file](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/battery/test_battery_builder.py) to see how to test your subsystem. This is also detailed in the [battery subsystem example](battery_subsystem_example) doc page. If everything goes well then those tests passed. If they didn't, you should get some info about your builder that you can use to fix any bugs or errors. @@ -75,7 +75,7 @@ This test probably won't catch *everything* that could go wrong when interfacing ## Using your builder within Aviary -Awesome. Let's keep going and start to discuss using these subsystems within Aviary. The overarching idea is that now that you have a subsystem builder, you can pass an instantiation of this builder object to Aviary via the `phase_info` dictionary. Take a look at [`run_cruise.py`](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/battery/run_cruise.py) and [`run_multiphase_mission.py`](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/battery/run_multiphase_mission.py) to see how we do this for the battery model. Specifically, here are the relevant lines of code from the `run_cruise.py` file: +Awesome. Let's keep going and start to discuss using these subsystems within Aviary. The overarching idea is that now that you have a subsystem builder, you can pass an instantiation of this builder object to Aviary via the `phase_info` dictionary. Take a look at [`run_cruise.py`](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/battery/run_cruise.py) and [`run_multiphase_mission.py`](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/battery/run_multiphase_mission.py) to see how we do this for the battery model. Specifically, here are the relevant lines of code from the `run_cruise.py` file: ```python battery_builder = BatteryBuilder() @@ -101,7 +101,7 @@ Those additional `'external_subsystems'` entires are where you add your subsyste 2. **Add any `external_subsystems` to your pre- and post-mission phases too.** If you have pre- or post-mission analyses in your subsystem, make sure to add the `external_subsystems` list to the `pre_mission` and `post_mission` sub-dicts within the `phase_info` dict. This means that Aviary will build and use those systems before or after the mission; otherwise Aviary won't know to put the systems there. -3. **Start with a simple mission in Aviary.** To begin, try adapting the [`run_cruise.py`](https://github.com/OpenMDAO/om-Aviary/blob/main/aviary/external_subsystems/battery/run_cruise.py) script to use your subsystem. Replace the `BatteryBuilder()` instance with your subsystem, for example. You might need other setup or inputs based on the complexity of your model. But in general, it helps to start with the simplest mission you can. In this case, that's probably a steady level cruise flight. +3. **Start with a simple mission in Aviary.** To begin, try adapting the [`run_cruise.py`](https://github.com/OpenMDAO/Aviary/blob/main/aviary/external_subsystems/battery/run_cruise.py) script to use your subsystem. Replace the `BatteryBuilder()` instance with your subsystem, for example. You might need other setup or inputs based on the complexity of your model. But in general, it helps to start with the simplest mission you can. In this case, that's probably a steady level cruise flight. Even though this is a "simple" mission, there's still a lot that can go wrong. It turns out that designing an aircraft is challenging sometimes. I don't expect your mission optimization to converge well your first try; it often takes some debugging and digging to get your subsystem integrated well. It's really challenging to write docs to help you do this without knowing more about your system, what it's trying to do while the aircraft is flying, and what you've already checked. That being said, make sure to reach out if you're encountering problems here. From d01c7137a7af698dc32db14506ab1238208adde8 Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Tue, 30 Jan 2024 11:01:28 -0800 Subject: [PATCH 184/188] Added a CLI for users to download models --- aviary/interface/cmd_entry_points.py | 32 +----- aviary/interface/download_models.py | 100 ++++++++++++++++++ aviary/interface/graphical_input.py | 27 +++++ aviary/interface/test/test_download_models.py | 68 ++++++++++++ 4 files changed, 199 insertions(+), 28 deletions(-) create mode 100644 aviary/interface/download_models.py create mode 100644 aviary/interface/test/test_download_models.py diff --git a/aviary/interface/cmd_entry_points.py b/aviary/interface/cmd_entry_points.py index 56dff8119..117e6dd7f 100644 --- a/aviary/interface/cmd_entry_points.py +++ b/aviary/interface/cmd_entry_points.py @@ -6,34 +6,8 @@ from aviary.interface.methods_for_level1 import _exec_level1, _setup_level1_parser from aviary.utils.Fortran_to_Aviary import _exec_F2A, _setup_F2A_parser from aviary.visualization.dashboard import _dashboard_setup_parser, _dashboard_cmd -from aviary.interface.graphical_input import IntegratedPlottingApp - - -def _setup_flight_profile_parser(parser): - """ - Set up the command line options for the Flight Profile plotting tool. - - Parameters - ---------- - parser : argparse.ArgumentParser - The parser instance. - """ - pass - - -def _exec_flight_profile(options, user_args): - """ - Run the Flight Profile plotting tool. - - Parameters - ---------- - options : argparse.Namespace - Command line options. - user_args : list of str - Args to be passed to the user script. - """ - app = IntegratedPlottingApp() - app.mainloop() +from aviary.interface.graphical_input import _exec_flight_profile, _setup_flight_profile_parser +from aviary.interface.download_models import _exec_hanger, _setup_hanger_parser def _load_and_exec(script_name, user_args): @@ -74,6 +48,8 @@ def _load_and_exec(script_name, user_args): "Allows users to draw a mission profile for use in Aviary."), 'dashboard': (_dashboard_setup_parser, _dashboard_cmd, "Run the Dashboard tool"), + 'hanger': (_setup_hanger_parser, _exec_hanger, + "Allows users that pip installed Aviary to download models from the Aviary Hanger"), } diff --git a/aviary/interface/download_models.py b/aviary/interface/download_models.py new file mode 100644 index 000000000..cdc9594c6 --- /dev/null +++ b/aviary/interface/download_models.py @@ -0,0 +1,100 @@ +import os +from pathlib import Path +import argparse +import pkg_resources +import shutil + + +def aviary_resource(resource_name: str) -> str: + return pkg_resources.resource_filename("aviary", resource_name) + + +def get_model(file_name: str, verbose=False) -> Path: + ''' + This function attempts to find the path to a file or folder in aviary/models + If the path cannot be found in any of the locations, a FileNotFoundError is raised. + + Parameters + ---------- + path : str or Path + The input path, either as a string or a Path object. + + Returns + ------- + aviary_path + The absolute path to the file. + + Raises + ------ + FileNotFoundError + If the path is not found. + ''' + + # Get the path to Aviary's models + path = Path('models', file_name) + aviary_path = Path(aviary_resource(str(path))) + + # If the file name was provided without a path, check in the subfolders + if not aviary_path.exists(): + sub_dirs = [x[0] for x in os.walk(aviary_resource('models'))] + for sub_dir in sub_dirs: + temp_path = Path(sub_dir, file_name) + if temp_path.exists(): + # only return the first matching file + aviary_path = temp_path + continue + + # If the path still doesn't exist, raise an error. + if not aviary_path.exists(): + raise FileNotFoundError( + f"File or Folder not found in Aviary's hanger" + ) + if verbose: + print('found', aviary_path, '\n') + return aviary_path + + +def save_file(aviary_path: Path, outdir: Path, verbose=False) -> Path: + ''' + Saves the file or folder specified into the output directory + ''' + outdir.mkdir(parents=True, exist_ok=True) + if aviary_path.is_dir(): + if verbose: + print(aviary_path, 'is a directory, getting all files') + outdir = outdir.joinpath(aviary_path.stem) + outdir.mkdir(exist_ok=True) + for file in next(os.walk(aviary_path))[-1]: + if verbose: + print('copying', str(aviary_path / file), 'to', str(outdir / file)) + shutil.copy2(aviary_path / file, outdir) + else: + if verbose: + print('copying', str(aviary_path), 'to', str(outdir / aviary_path.name)) + shutil.copy2(aviary_path, outdir) + return outdir + + +def _setup_hanger_parser(parser: argparse.ArgumentParser): + def_outdir = os.path.join(os.getcwd(), "aviary_models") + parser.add_argument( + 'input_decks', metavar='indecks', type=str, nargs='+', help='Name of vehicle input deck file' + ) + parser.add_argument( + "-o", "--outdir", default=def_outdir, help="Directory to write outputs" + ) + parser.add_argument( + "-v", "--verbose", + action="store_true", + help="Enable verbose outputs", + ) + + +def _exec_hanger(args, user_args): + # check if args.input_deck is a list, if so, use the first element + input_decks = [] + for input_deck in args.input_decks: + input_decks.append(get_model(input_deck, args.verbose)) + + for input_deck in input_decks: + save_file(input_deck, Path(args.outdir), args.verbose) diff --git a/aviary/interface/graphical_input.py b/aviary/interface/graphical_input.py index eae7cea41..baeda5cf5 100644 --- a/aviary/interface/graphical_input.py +++ b/aviary/interface/graphical_input.py @@ -559,6 +559,33 @@ def update_plot(self, ax, data, label, color): ax.figure.canvas.draw() +def _setup_flight_profile_parser(parser): + """ + Set up the command line options for the Flight Profile plotting tool. + + Parameters + ---------- + parser : argparse.ArgumentParser + The parser instance. + """ + pass + + +def _exec_flight_profile(options, user_args): + """ + Run the Flight Profile plotting tool. + + Parameters + ---------- + options : argparse.Namespace + Command line options. + user_args : list of str + Args to be passed to the user script. + """ + app = IntegratedPlottingApp() + app.mainloop() + + if __name__ == "__main__": app = IntegratedPlottingApp() app.mainloop() diff --git a/aviary/interface/test/test_download_models.py b/aviary/interface/test/test_download_models.py new file mode 100644 index 000000000..1627243b5 --- /dev/null +++ b/aviary/interface/test/test_download_models.py @@ -0,0 +1,68 @@ +import subprocess +import unittest +from pathlib import Path +import shutil + +import pkg_resources +from openmdao.utils.testing_utils import use_tempdirs +from aviary.interface.download_models import get_model, save_file + + +@use_tempdirs +class CommandEntryPointsTestCases(unittest.TestCase): + + def run_and_test_hanger(self, filenames, out_dir=''): + # this only tests that a given command line tool returns a 0 return code. It doesn't + # check the expected output at all. The underlying functions that implement the + # commands should be tested seperately. + if isinstance(filenames, str): + filenames = [filenames] + cmd = ['aviary', 'hanger'] + filenames + + if out_dir: + cmd += ['-o', out_dir] + out_dir = Path(out_dir) + else: + out_dir = Path.cwd() / 'aviary_models' + + try: + output = subprocess.check_output(cmd) + for filename in filenames: + path = out_dir / filename.split('/')[-1] + self.assertTrue(path.exists()) + except subprocess.CalledProcessError as err: + self.fail(f"Command '{cmd}' failed. Return code: {err.returncode}") + + def test_single_file_without_path(self): + filename = 'turbofan_22k.deck' + self.run_and_test_hanger(filename) + + def test_single_file_with_path(self): + filename = 'engines/turbofan_22k.deck' + self.run_and_test_hanger(filename) + + def test_multiple_files(self): + filenames = ['small_single_aisle_GwGm.dat', 'small_single_aisle_GwGm.csv'] + self.run_and_test_hanger(filenames) + + def test_folder(self): + filename = 'engines' + self.run_and_test_hanger(filename) + + def test_single_file_custom_outdir(self): + filename = 'small_single_aisle_GwGm.csv' + out_dir = '~/test_hanger' + self.run_and_test_hanger(filename, out_dir) + shutil.rmtree(out_dir) + + def test_expected_path(self): + filename = f'test_aircraft/converter_configuration_test_data_GwGm.dat' + aviary_path = get_model('converter_configuration_test_data_GwGm.dat') + + expected_path = pkg_resources.resource_filename('aviary', + 'models/test_aircraft/converter_configuration_test_data_GwGm.dat') + self.assertTrue(str(aviary_path) == expected_path) + + +if __name__ == "__main__": + unittest.main() From 47ad90991bf923f8a0d35d96a006bb280d561d6e Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Tue, 30 Jan 2024 11:15:53 -0800 Subject: [PATCH 185/188] Added docs --- aviary/docs/user_guide/aviary_commands.ipynb | 43 ++++++++++++++++++++ aviary/interface/download_models.py | 4 +- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/aviary/docs/user_guide/aviary_commands.ipynb b/aviary/docs/user_guide/aviary_commands.ipynb index 87d179dd8..ce025100f 100644 --- a/aviary/docs/user_guide/aviary_commands.ipynb +++ b/aviary/docs/user_guide/aviary_commands.ipynb @@ -172,6 +172,49 @@ "source": [ "!aviary fortran_to_aviary -h" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "(aviary-hanger-command)=\n", + "### aviary hanger\n", + "\n", + "The `aviary hanger` command will download files and folders from the Aviary hanger.\n", + "This is useful for users that have pip installed Aviary, but want to experiment with the included examples.\n", + "\n", + "The only required input is the name of an input deck.\n", + "This can be specified as the name of the file, the path from aviary/models, the name of a folder in aviary/models. Multiple files and folders can be downloaded at once.\n", + "Optionally, the output directory can be specified; if it is not, the files will be downloaded into the current working directory in a folder caller aviary_models.\n", + "If specified, the output directory will be created as needed.\n", + "\n", + "Example usage:\n", + "```\n", + "`aviary hanger engines` Download all files in the engines folder\n", + "`aviary hanger turbofan_22k.txt` Download the 22k turbofan deck\n", + "`aviary hanger N3CC/N3CC_data.py` Download the N3CC data\n", + "`aviary hanger small_single_aisle_GwGm.dat small_single_aisle_GwGm.csv` Download the Fortran and Aviary input decks for the small single aisle\n", + "`aviary hanger turbofan_22k.txt ~/example_files` Download the engine model into ~/example_files\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```\n", + "aviary hanger -h\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!aviary hanger -h" + ] } ], "metadata": { diff --git a/aviary/interface/download_models.py b/aviary/interface/download_models.py index cdc9594c6..6debb219e 100644 --- a/aviary/interface/download_models.py +++ b/aviary/interface/download_models.py @@ -56,7 +56,7 @@ def get_model(file_name: str, verbose=False) -> Path: def save_file(aviary_path: Path, outdir: Path, verbose=False) -> Path: ''' - Saves the file or folder specified into the output directory + Saves the file or folder specified into the output directory, creating directories as needed. ''' outdir.mkdir(parents=True, exist_ok=True) if aviary_path.is_dir(): @@ -81,7 +81,7 @@ def _setup_hanger_parser(parser: argparse.ArgumentParser): 'input_decks', metavar='indecks', type=str, nargs='+', help='Name of vehicle input deck file' ) parser.add_argument( - "-o", "--outdir", default=def_outdir, help="Directory to write outputs" + "-o", "--outdir", default=def_outdir, help="Directory to write outputs. Defaults to aviary_models in the current directory." ) parser.add_argument( "-v", "--verbose", From db8639266cd70a382c244442ebc82328cfd5ad3d Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Tue, 30 Jan 2024 13:11:51 -0800 Subject: [PATCH 186/188] Incorporating Feedback --- aviary/docs/user_guide/aviary_commands.ipynb | 22 +++++++++---------- aviary/interface/download_models.py | 8 +++---- aviary/interface/test/test_download_models.py | 20 ++++++++--------- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/aviary/docs/user_guide/aviary_commands.ipynb b/aviary/docs/user_guide/aviary_commands.ipynb index ce025100f..d5adabdb4 100644 --- a/aviary/docs/user_guide/aviary_commands.ipynb +++ b/aviary/docs/user_guide/aviary_commands.ipynb @@ -177,24 +177,24 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "(aviary-hanger-command)=\n", - "### aviary hanger\n", + "(aviary-hangar-command)=\n", + "### aviary hangar\n", "\n", - "The `aviary hanger` command will download files and folders from the Aviary hanger.\n", + "The `aviary hangar` command will download files and folders from the Aviary hangar.\n", "This is useful for users that have pip installed Aviary, but want to experiment with the included examples.\n", "\n", "The only required input is the name of an input deck.\n", - "This can be specified as the name of the file, the path from aviary/models, the name of a folder in aviary/models. Multiple files and folders can be downloaded at once.\n", + "This can be specified as the name of the file, the path from [aviary/models](https://github.com/OpenMDAO/Aviary/tree/main/aviary/models), the name of a folder in aviary/models. Multiple files and folders can be downloaded at once.\n", "Optionally, the output directory can be specified; if it is not, the files will be downloaded into the current working directory in a folder caller aviary_models.\n", "If specified, the output directory will be created as needed.\n", "\n", "Example usage:\n", "```\n", - "`aviary hanger engines` Download all files in the engines folder\n", - "`aviary hanger turbofan_22k.txt` Download the 22k turbofan deck\n", - "`aviary hanger N3CC/N3CC_data.py` Download the N3CC data\n", - "`aviary hanger small_single_aisle_GwGm.dat small_single_aisle_GwGm.csv` Download the Fortran and Aviary input decks for the small single aisle\n", - "`aviary hanger turbofan_22k.txt ~/example_files` Download the engine model into ~/example_files\n", + "`aviary hangar engines` Download all files in the engines folder\n", + "`aviary hangar turbofan_22k.txt` Download the 22k turbofan deck\n", + "`aviary hangar N3CC/N3CC_data.py` Download the N3CC data\n", + "`aviary hangar small_single_aisle_GwGm.dat small_single_aisle_GwGm.csv` Download the Fortran and Aviary input decks for the small single aisle\n", + "`aviary hangar turbofan_22k.txt ~/example_files` Download the engine model into ~/example_files\n", "```\n" ] }, @@ -203,7 +203,7 @@ "metadata": {}, "source": [ "```\n", - "aviary hanger -h\n", + "aviary hangar -h\n", "```" ] }, @@ -213,7 +213,7 @@ "metadata": {}, "outputs": [], "source": [ - "!aviary hanger -h" + "!aviary hangar -h" ] } ], diff --git a/aviary/interface/download_models.py b/aviary/interface/download_models.py index 6debb219e..e58c3dea1 100644 --- a/aviary/interface/download_models.py +++ b/aviary/interface/download_models.py @@ -47,7 +47,7 @@ def get_model(file_name: str, verbose=False) -> Path: # If the path still doesn't exist, raise an error. if not aviary_path.exists(): raise FileNotFoundError( - f"File or Folder not found in Aviary's hanger" + f"File or Folder not found in Aviary's hangar" ) if verbose: print('found', aviary_path, '\n') @@ -75,10 +75,10 @@ def save_file(aviary_path: Path, outdir: Path, verbose=False) -> Path: return outdir -def _setup_hanger_parser(parser: argparse.ArgumentParser): +def _setup_hangar_parser(parser: argparse.ArgumentParser): def_outdir = os.path.join(os.getcwd(), "aviary_models") parser.add_argument( - 'input_decks', metavar='indecks', type=str, nargs='+', help='Name of vehicle input deck file' + 'input_decks', metavar='indecks', type=str, nargs='+', help='Name of file or folder to download from Aviary/models' ) parser.add_argument( "-o", "--outdir", default=def_outdir, help="Directory to write outputs. Defaults to aviary_models in the current directory." @@ -90,7 +90,7 @@ def _setup_hanger_parser(parser: argparse.ArgumentParser): ) -def _exec_hanger(args, user_args): +def _exec_hangar(args, user_args): # check if args.input_deck is a list, if so, use the first element input_decks = [] for input_deck in args.input_decks: diff --git a/aviary/interface/test/test_download_models.py b/aviary/interface/test/test_download_models.py index 1627243b5..c8fa4d036 100644 --- a/aviary/interface/test/test_download_models.py +++ b/aviary/interface/test/test_download_models.py @@ -11,13 +11,11 @@ @use_tempdirs class CommandEntryPointsTestCases(unittest.TestCase): - def run_and_test_hanger(self, filenames, out_dir=''): - # this only tests that a given command line tool returns a 0 return code. It doesn't - # check the expected output at all. The underlying functions that implement the - # commands should be tested seperately. + def run_and_test_hangar(self, filenames, out_dir=''): + # tests that the commands return an exit code of 0 and that the files are generated if isinstance(filenames, str): filenames = [filenames] - cmd = ['aviary', 'hanger'] + filenames + cmd = ['aviary', 'hangar'] + filenames if out_dir: cmd += ['-o', out_dir] @@ -35,24 +33,24 @@ def run_and_test_hanger(self, filenames, out_dir=''): def test_single_file_without_path(self): filename = 'turbofan_22k.deck' - self.run_and_test_hanger(filename) + self.run_and_test_hangar(filename) def test_single_file_with_path(self): filename = 'engines/turbofan_22k.deck' - self.run_and_test_hanger(filename) + self.run_and_test_hangar(filename) def test_multiple_files(self): filenames = ['small_single_aisle_GwGm.dat', 'small_single_aisle_GwGm.csv'] - self.run_and_test_hanger(filenames) + self.run_and_test_hangar(filenames) def test_folder(self): filename = 'engines' - self.run_and_test_hanger(filename) + self.run_and_test_hangar(filename) def test_single_file_custom_outdir(self): filename = 'small_single_aisle_GwGm.csv' - out_dir = '~/test_hanger' - self.run_and_test_hanger(filename, out_dir) + out_dir = '~/test_hangar' + self.run_and_test_hangar(filename, out_dir) shutil.rmtree(out_dir) def test_expected_path(self): From e200219bf2624096815263ac166d27b504a16e0d Mon Sep 17 00:00:00 2001 From: Carl Recine Date: Tue, 30 Jan 2024 13:20:09 -0800 Subject: [PATCH 187/188] fixed typo --- aviary/interface/cmd_entry_points.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aviary/interface/cmd_entry_points.py b/aviary/interface/cmd_entry_points.py index 117e6dd7f..3652a4d60 100644 --- a/aviary/interface/cmd_entry_points.py +++ b/aviary/interface/cmd_entry_points.py @@ -7,7 +7,7 @@ from aviary.utils.Fortran_to_Aviary import _exec_F2A, _setup_F2A_parser from aviary.visualization.dashboard import _dashboard_setup_parser, _dashboard_cmd from aviary.interface.graphical_input import _exec_flight_profile, _setup_flight_profile_parser -from aviary.interface.download_models import _exec_hanger, _setup_hanger_parser +from aviary.interface.download_models import _exec_hangar, _setup_hangar_parser def _load_and_exec(script_name, user_args): @@ -48,8 +48,8 @@ def _load_and_exec(script_name, user_args): "Allows users to draw a mission profile for use in Aviary."), 'dashboard': (_dashboard_setup_parser, _dashboard_cmd, "Run the Dashboard tool"), - 'hanger': (_setup_hanger_parser, _exec_hanger, - "Allows users that pip installed Aviary to download models from the Aviary Hanger"), + 'hangar': (_setup_hangar_parser, _exec_hangar, + "Allows users that pip installed Aviary to download models from the Aviary hangar"), } From b436c864e7796f0612c41945f32ec17b9de5e6c4 Mon Sep 17 00:00:00 2001 From: crecine <51181861+crecine@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:43:48 -0800 Subject: [PATCH 188/188] Update aviary_commands.ipynb --- aviary/docs/user_guide/aviary_commands.ipynb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/aviary/docs/user_guide/aviary_commands.ipynb b/aviary/docs/user_guide/aviary_commands.ipynb index d5adabdb4..e3fe21a4e 100644 --- a/aviary/docs/user_guide/aviary_commands.ipynb +++ b/aviary/docs/user_guide/aviary_commands.ipynb @@ -180,21 +180,21 @@ "(aviary-hangar-command)=\n", "### aviary hangar\n", "\n", - "The `aviary hangar` command will download files and folders from the Aviary hangar.\n", + "The `aviary hangar` command will copy files and folders from the Aviary hangar to an accessible directory.\n", "This is useful for users that have pip installed Aviary, but want to experiment with the included examples.\n", "\n", "The only required input is the name of an input deck.\n", - "This can be specified as the name of the file, the path from [aviary/models](https://github.com/OpenMDAO/Aviary/tree/main/aviary/models), the name of a folder in aviary/models. Multiple files and folders can be downloaded at once.\n", - "Optionally, the output directory can be specified; if it is not, the files will be downloaded into the current working directory in a folder caller aviary_models.\n", + "This can be specified as the name of the file, the path from [aviary/models](https://github.com/OpenMDAO/Aviary/tree/main/aviary/models), the name of a folder in aviary/models. Multiple files and folders can be copied at once.\n", + "Optionally, the output directory can be specified; if it is not, the files will be copied into the current working directory in a folder called aviary_models.\n", "If specified, the output directory will be created as needed.\n", "\n", "Example usage:\n", "```\n", - "`aviary hangar engines` Download all files in the engines folder\n", - "`aviary hangar turbofan_22k.txt` Download the 22k turbofan deck\n", - "`aviary hangar N3CC/N3CC_data.py` Download the N3CC data\n", - "`aviary hangar small_single_aisle_GwGm.dat small_single_aisle_GwGm.csv` Download the Fortran and Aviary input decks for the small single aisle\n", - "`aviary hangar turbofan_22k.txt ~/example_files` Download the engine model into ~/example_files\n", + "`aviary hangar engines` Copy all files in the engines folder\n", + "`aviary hangar turbofan_22k.txt` Copy the 22k turbofan deck\n", + "`aviary hangar N3CC/N3CC_data.py` Copy the N3CC data\n", + "`aviary hangar small_single_aisle_GwGm.dat small_single_aisle_GwGm.csv` Copy the Fortran and Aviary input decks for the small single aisle\n", + "`aviary hangar turbofan_22k.txt ~/example_files` Copy the engine model into ~/example_files\n", "```\n" ] },