diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 4120d42b5..848ed615b 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -1384,10 +1384,7 @@ def add_post_mission_systems(self, include_landing=True): initial_mass={'units': 'lbm'}, mass_resid={'units': 'lbm'}) - if self.mass_method is GASP: - payload_mass_src = Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS - else: - payload_mass_src = Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS + payload_mass_src = Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS self.post_mission.add_subsystem( 'mass_constraint', ecomp, @@ -2563,7 +2560,8 @@ def run_aviary_problem(self, record_filename="problem_history.db", def alternate_mission(self, run_mission=True, json_filename='sizing_problem.json', - payload_mass=None, mission_range=None, + num_first=None, num_business=None, num_tourist=None, num_pax=None, + wing_cargo=None, misc_cargo=None, cargo_mass=None, mission_range=None, phase_info=None, verbosity=Verbosity.BRIEF): """ This function runs an alternate mission based on a sizing mission output. @@ -2584,26 +2582,43 @@ def alternate_mission(self, run_mission=True, If Verbosity.DEBUG, debug print options ['desvars','ln_cons','nl_cons','objs'] will be set. If a list is provided, it will be used as the debug print options. """ + mass_method = self.aviary_inputs.get_val(Settings.MASS_METHOD) + if mass_method == LegacyCode.FLOPS: + if num_first is None or num_business is None or num_tourist is None: + print('Incomplete PAX numbers for FLOPS fallout - assume same as design') + num_first = self.aviary_inputs.get_val( + Aircraft.CrewPayload.Design.NUM_FIRST_CLASS) + num_business = self.aviary_inputs.get_val( + Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS) + num_tourist = self.aviary_inputs.get_val( + Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS) + if wing_cargo is None or misc_cargo is None: + print('Incomplete Cargo masses for FLOPS fallout - assume same as design') + wing_cargo = self.aviary_inputs.get_val( + Aircraft.CrewPayload.WING_CARGO, 'lbm') + misc_cargo = self.aviary_inputs.get_val( + Aircraft.CrewPayload.MISC_CARGO, 'lbm') + num_pax = cargo_mass = 0 + elif mass_method == LegacyCode.GASP: + if num_pax is None: + print('Unspecifed PAX number for GASP fallout - assume same as design') + num_pax = self.aviary_inputs.get_val( + Aircraft.CrewPayload.Design.NUM_PASSENGERS) + if cargo_mass is None: + print('Unspecifed Cargo mass for GASP fallout - assume same as design') + cargo_mass = self.get_val(Aircraft.CrewPayload.CARGO_MASS, 'lbm') + num_first = num_business = num_tourist = wing_cargo = misc_cargo = 0 + if phase_info is None: phase_info = self.phase_info if mission_range is None: - design_range = self.get_val(Mission.Design.RANGE) - if payload_mass is None: - if self.mission_method is HEIGHT_ENERGY: - payload_mass = self.get_val(Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS) - elif self.mission_method is TWO_DEGREES_OF_FREEDOM: - payload_mass = self.get_val(Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS) + mission_range = self.get_val(Mission.Design.RANGE) mission_mass = self.get_val(Mission.Design.GROSS_MASS) optimizer = self.driver.options["optimizer"] - prob_alternate = _load_off_design( - json_filename, - ProblemType.ALTERNATE, - phase_info, - payload_mass, - design_range, - mission_mass) + prob_alternate = _load_off_design(json_filename, ProblemType.ALTERNATE, mass_method, phase_info, num_first, + num_business, num_tourist, num_pax, wing_cargo, misc_cargo, cargo_mass, mission_range, mission_mass) prob_alternate.check_and_preprocess_inputs() prob_alternate.add_pre_mission_systems() @@ -2622,7 +2637,8 @@ def alternate_mission(self, run_mission=True, def fallout_mission(self, run_mission=True, json_filename='sizing_problem.json', - mission_mass=None, payload_mass=None, + num_first=None, num_business=None, num_tourist=None, num_pax=None, + wing_cargo=None, misc_cargo=None, cargo_mass=None, mission_mass=None, phase_info=None, verbosity=Verbosity.BRIEF): """ This function runs a fallout mission based on a sizing mission output. @@ -2643,21 +2659,42 @@ def fallout_mission(self, run_mission=True, If Verbosity.DEBUG, debug print options ['desvars','ln_cons','nl_cons','objs'] will be set. If a list is provided, it will be used as the debug print options. """ + mass_method = self.aviary_inputs.get_val(Settings.MASS_METHOD) + if mass_method == LegacyCode.FLOPS: + if num_first is None or num_business is None or num_tourist is None: + print('Incomplete PAX numbers for FLOPS fallout - assume same as design') + num_first = self.aviary_inputs.get_val( + Aircraft.CrewPayload.Design.NUM_FIRST_CLASS) + num_business = self.aviary_inputs.get_val( + Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS) + num_tourist = self.aviary_inputs.get_val( + Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS) + if wing_cargo is None or misc_cargo is None: + print('Incomplete Cargo masses for FLOPS fallout - assume same as design') + wing_cargo = self.aviary_inputs.get_val( + Aircraft.CrewPayload.WING_CARGO, 'lbm') + misc_cargo = self.aviary_inputs.get_val( + Aircraft.CrewPayload.MISC_CARGO, 'lbm') + num_pax = cargo_mass = 0 + elif mass_method == LegacyCode.GASP: + if num_pax is None: + print('Unspecifed PAX number for GASP fallout - assume same as design') + num_pax = self.aviary_inputs.get_val( + Aircraft.CrewPayload.Design.NUM_PASSENGERS) + if cargo_mass is None: + print('Unspecifed Cargo mass for GASP fallout - assume same as design') + cargo_mass = self.get_val(Aircraft.CrewPayload.CARGO_MASS, 'lbm') + num_first = num_business = num_tourist = wing_cargo = misc_cargo = 0 + if phase_info is None: phase_info = self.phase_info if mission_mass is None: mission_mass = self.get_val(Mission.Design.GROSS_MASS) - if payload_mass is None: - if self.mission_method is HEIGHT_ENERGY: - payload_mass = self.get_val(Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS) - elif self.mission_method is TWO_DEGREES_OF_FREEDOM: - payload_mass = self.get_val(Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS) - design_range = self.get_val(Mission.Design.RANGE) optimizer = self.driver.options["optimizer"] - prob_fallout = _load_off_design(json_filename, ProblemType.FALLOUT, phase_info, - payload_mass, design_range, mission_mass) + prob_fallout = _load_off_design(json_filename, ProblemType.FALLOUT, mass_method, phase_info, num_first, + num_business, num_tourist, num_pax, wing_cargo, misc_cargo, cargo_mass, None, mission_mass) prob_fallout.check_and_preprocess_inputs() prob_fallout.add_pre_mission_systems() @@ -3090,8 +3127,8 @@ def _read_sizing_json(aviary_problem, json_filename): return aviary_problem -def _load_off_design(json_filename, ProblemType, phase_info, - payload, mission_range, mission_gross_mass): +def _load_off_design(json_filename, ProblemType, Mass_Method, phase_info, num_first, num_business, num_tourist, + num_pax, wing_cargo, misc_cargo, cargo_mass, mission_range=None, mission_gross_mass=None): """ This function loads a sized aircraft, and sets up an aviary problem for a specified off design mission. @@ -3101,11 +3138,19 @@ def _load_off_design(json_filename, ProblemType, phase_info, json_filename: string User specified name and relative path of json file containing the sized aircraft data ProblemType: enum - Alternate or Fallout. Alternate requires mission_range input and - Fallout requires mission_fuel input + Alternate or Fallout. Alternate requires mission_range input and fallout requires mission_fuel input + MassMethod: enum + FLOPS or GASP. FLOPS requires num_first, num_business, num_tourist, wing_cargo and misc cargo inputs. GASP requires num_pax and cargo_mass inputs phase_info: phase_info dictionary for off design mission - payload: float - Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS + num_first: integer (FLOPS only) + num_business: integer (FLOPS only) + num_tourist: integer (FLOPS only) + num_pax: integer + Aircraft.CrewPayload.NUM_PASSENGERS (GASP only) + wing_cargo: float (FLOPS only) + misc_cargo: float (FLOPS only) + cargo_mass: float + Aircraft.CrewPayload.CARGO_MASS (GASP only) mission_range float Mission.Summary.RANGE 'NM' mission_gross_mass float @@ -3126,18 +3171,45 @@ def _load_off_design(json_filename, ProblemType, phase_info, prob.problem_type = ProblemType prob.aviary_inputs.set_val('settings:problem_type', ProblemType, units='unitless') - # Set Payload + # Setup Payload + if Mass_Method == LegacyCode.FLOPS: + prob.aviary_inputs.set_val( + Aircraft.CrewPayload.NUM_FIRST_CLASS, num_first, units='unitless') + prob.aviary_inputs.set_val( + Aircraft.CrewPayload.NUM_BUSINESS_CLASS, num_business, units='unitless') + prob.aviary_inputs.set_val( + Aircraft.CrewPayload.NUM_TOURIST_CLASS, num_tourist, units='unitless') + num_pax = num_first + num_business + num_tourist + prob.aviary_inputs.set_val(Aircraft.CrewPayload.MISC_CARGO, misc_cargo, 'lbm') + prob.aviary_inputs.set_val(Aircraft.CrewPayload.WING_CARGO, wing_cargo, 'lbm') + cargo_mass = misc_cargo + wing_cargo + prob.aviary_inputs.set_val( - Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, payload, units='lbm') + Aircraft.CrewPayload.NUM_PASSENGERS, num_pax, units='unitless') + prob.aviary_inputs.set_val(Aircraft.CrewPayload.CARGO_MASS, cargo_mass, 'lbm') if ProblemType == ProblemType.ALTERNATE: # Set mission range, aviary will calculate required fuel - prob.aviary_inputs.set_val(Mission.Design.RANGE, mission_range, units='NM') + if mission_range is None: + print( + 'ERROR in _load_off_design - Alternate problem type requested with no specified Range') + else: + prob.aviary_inputs.set_val(Mission.Design.RANGE, mission_range, units='NM') + prob.aviary_inputs.set_val(Mission.Summary.RANGE, mission_range, units='NM') + try: + target_range = phase_info['post_mission']['target_range'] + phase_info['post_mission']['target_range'] = (mission_range, 'nmi') + except KeyError: + print('no target range to update') elif ProblemType == ProblemType.FALLOUT: # Set mission fuel and calculate gross weight, aviary will calculate range - prob.aviary_inputs.set_val(Mission.Summary.GROSS_MASS, - mission_gross_mass, units='lbm') + if mission_gross_mass is None: + print( + 'Error in _load_off_design - Fallout problem type requested with no specified Gross Mass') + else: + prob.aviary_inputs.set_val( + Mission.Summary.GROSS_MASS, mission_gross_mass, units='lbm') # Load inputs prob.load_inputs(prob.aviary_inputs, phase_info) diff --git a/aviary/models/N3CC/N3CC_data.py b/aviary/models/N3CC/N3CC_data.py index 35c8a6f28..35bca7c4e 100644 --- a/aviary/models/N3CC/N3CC_data.py +++ b/aviary/models/N3CC/N3CC_data.py @@ -22,7 +22,7 @@ from aviary.utils.test_utils.default_subsystems import get_default_premission_subsystems, get_default_mission_subsystems from aviary.utils.functions import get_path from aviary.variable_info.variables import Aircraft, Dynamic, Mission, Settings -from aviary.variable_info.enums import EquationsOfMotion, LegacyCode +from aviary.variable_info.enums import EquationsOfMotion, LegacyCode, ProblemType # from aviary.utils.preprocessors import preprocess_options N3CC = {} @@ -305,6 +305,7 @@ inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.HEIGHT_ENERGY) inputs.set_val(Settings.MASS_METHOD, LegacyCode.FLOPS) inputs.set_val(Settings.VERBOSITY, 0) +inputs.set_val(Settings.PROBLEM_TYPE, ProblemType.SIZING) # --------------------------- # OUTPUTS 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 229a932d0..66400955f 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 @@ -144,7 +144,10 @@ Aircraft.CrewPayload.PASSENGER_MASS_WITH_BAGS, val=200, units="lbm" ) V3_bug_fixed_options.set_val( - Aircraft.CrewPayload.CARGO_MASS, val=10040, units="lbm" + Aircraft.CrewPayload.CARGO_MASS, val=0, units="lbm" +) +V3_bug_fixed_options.set_val( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, val=10040, units="lbm" ) V3_bug_fixed_options.set_val( Aircraft.VerticalTail.SWEEP, val=0, units='deg' diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_GASP.csv b/aviary/models/large_single_aisle_1/large_single_aisle_1_GASP.csv index 09894b55c..77617d041 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_GASP.csv +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_GASP.csv @@ -7,7 +7,6 @@ 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:crew_and_payload:catering_items_mass_per_passenger,7.6,lbm aircraft:crew_and_payload:design:num_passengers,180,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm diff --git a/aviary/models/small_single_aisle/small_single_aisle_GASP.csv b/aviary/models/small_single_aisle/small_single_aisle_GASP.csv index 0d7afc190..5b462bfc3 100644 --- a/aviary/models/small_single_aisle/small_single_aisle_GASP.csv +++ b/aviary/models/small_single_aisle/small_single_aisle_GASP.csv @@ -7,7 +7,6 @@ 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,8598,lbm aircraft:crew_and_payload:catering_items_mass_per_passenger,6,lbm aircraft:crew_and_payload:design:num_passengers,96,unitless aircraft:crew_and_payload:passenger_mass_with_bags,210,lbm diff --git a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv index 3a052eca2..f5c2913a7 100644 --- a/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv +++ b/aviary/models/test_aircraft/aircraft_for_bench_GwGm.csv @@ -7,6 +7,8 @@ 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:design:cargo_mass,0,lbm +#aircraft:crew_and_payload:design:max_cargo_mass,0,lbm aircraft:crew_and_payload:catering_items_mass_per_passenger,7.6,lbm aircraft:crew_and_payload:design:num_passengers,180,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm diff --git a/aviary/subsystems/mass/gasp_based/fixed.py b/aviary/subsystems/mass/gasp_based/fixed.py index 5c46b3680..559e1b12b 100644 --- a/aviary/subsystems/mass/gasp_based/fixed.py +++ b/aviary/subsystems/mass/gasp_based/fixed.py @@ -253,11 +253,15 @@ def initialize(self): add_aviary_option(self, Aircraft.CrewPayload.NUM_PASSENGERS) add_aviary_option(self, Aircraft.CrewPayload.PASSENGER_MASS_WITH_BAGS, units='lbm') + add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_PASSENGERS) def setup(self): add_aviary_input(self, Aircraft.CrewPayload.CARGO_MASS, val=10040) + add_aviary_input(self, Aircraft.CrewPayload.Design.CARGO_MASS, val=0) + add_aviary_input(self, Aircraft.CrewPayload.Design.MAX_CARGO_MASS) add_aviary_output(self, Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, val=0) + add_aviary_output(self, Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS, val=0) self.add_output( "payload_mass_des", val=0, units="lbm", desc="WPLDES: design payload" @@ -269,21 +273,26 @@ def setup(self): desc="WPLMAX: maximum payload that the aircraft is being asked to carry" " (design payload + cargo)", ) - - self.declare_partials( - "payload_mass_max", [ - Aircraft.CrewPayload.CARGO_MASS], - val=1.0) + self.declare_partials(Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS, [ + Aircraft.CrewPayload.CARGO_MASS], val=1.0) + self.declare_partials("payload_mass_des", [ + Aircraft.CrewPayload.Design.CARGO_MASS], val=1.0) + self.declare_partials("payload_mass_max", [ + Aircraft.CrewPayload.Design.MAX_CARGO_MASS], val=1.0) def compute(self, inputs, outputs): pax_mass, _ = self.options[Aircraft.CrewPayload.PASSENGER_MASS_WITH_BAGS] - PAX = self.options[Aircraft.CrewPayload.NUM_PASSENGERS] + pax = self.options[Aircraft.CrewPayload.NUM_PASSENGERS] + pax_des = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] cargo_mass = inputs[Aircraft.CrewPayload.CARGO_MASS] + cargo_mass_des = inputs[Aircraft.CrewPayload.Design.CARGO_MASS] + cargo_mass_max = inputs[Aircraft.CrewPayload.Design.MAX_CARGO_MASS] outputs[Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS] = \ - payload_mass = pax_mass * PAX - outputs["payload_mass_des"] = payload_mass - outputs["payload_mass_max"] = pax_mass * PAX + cargo_mass + payload_mass = pax_mass * pax + outputs["payload_mass_des"] = pax_mass * pax_des + cargo_mass_des + outputs["payload_mass_max"] = pax_mass * pax_des + cargo_mass_max + outputs[Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS] = pax_mass * pax + cargo_mass class ElectricAugmentationMass(om.ExplicitComponent): diff --git a/aviary/subsystems/mass/gasp_based/fuel.py b/aviary/subsystems/mass/gasp_based/fuel.py index 4092e3bb3..7c58a048d 100644 --- a/aviary/subsystems/mass/gasp_based/fuel.py +++ b/aviary/subsystems/mass/gasp_based/fuel.py @@ -1256,8 +1256,8 @@ def setup(self): Aircraft.Controls.TOTAL_MASS, Aircraft.Design.FIXED_EQUIPMENT_MASS, Aircraft.Design.FIXED_USEFUL_LOAD, - Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, Aircraft.Fuel.FUEL_SYSTEM_MASS, + "payload_mass_des", ], val=-1, ) @@ -1317,7 +1317,7 @@ def compute(self, inputs, outputs): - control_wt - fixed_equip_wt - useful_wt - - payload_wt + - payload_wt_des - fuel_sys_wt ) / GRAV_ENGLISH_LBM outputs["fuel_mass_min"] = ( diff --git a/aviary/subsystems/mass/gasp_based/test/test_fixed.py b/aviary/subsystems/mass/gasp_based/test/test_fixed.py index 1af3573d5..1155c9260 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_fixed.py +++ b/aviary/subsystems/mass/gasp_based/test/test_fixed.py @@ -306,14 +306,19 @@ def setUp(self): options = get_option_defaults() options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.CrewPayload.PASSENGER_MASS_WITH_BAGS, val=200, units="lbm") # bug fixed value and original value self.prob = om.Problem() self.prob.model.add_subsystem("payload", PayloadMass(), promotes=["*"]) self.prob.model.set_input_defaults( - Aircraft.CrewPayload.CARGO_MASS, val=10040, units="lbm" - ) # bug fixed value and original value + Aircraft.CrewPayload.CARGO_MASS, val=0, units="lbm" + ) + self.prob.model.set_input_defaults( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, val=10040, units="lbm" + ) setup_model_options(self.prob, options) @@ -992,6 +997,8 @@ def setUp(self): options.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False, units='unitless') options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.CrewPayload.PASSENGER_MASS_WITH_BAGS, val=200, units="lbm") # bug fixed value and original value @@ -1028,9 +1035,11 @@ def setUp(self): "max_mach", val=0.9, units="unitless" ) # bug fixed value and original value self.prob.model.set_input_defaults( - Aircraft.CrewPayload.CARGO_MASS, val=10040, units="lbm" + Aircraft.CrewPayload.CARGO_MASS, val=0, units="lbm" ) # bug fixed value and original value - + self.prob.model.set_input_defaults( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, val=10040, units="lbm" + ) self.prob.model.set_input_defaults( Aircraft.VerticalTail.TAPER_RATIO, val=0.801, units="unitless" ) # bug fixed value and original value @@ -1242,6 +1251,8 @@ def setUp(self): options = get_option_defaults() options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, val=180, units='unitless') + options.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, + val=180, units='unitless') options.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, val=2, units='unitless') options.set_val(Aircraft.Engine.HAS_PROPELLERS, val=[True], units='unitless') options.set_val(Aircraft.Wing.HAS_STRUT, val=True, units='unitless') @@ -1287,8 +1298,11 @@ def setUp(self): Aircraft.Strut.ATTACHMENT_LOCATION_DIMENSIONLESS, val=10/117.8, units='unitless' ) # bug fixed value and original value self.prob.model.set_input_defaults( - Aircraft.CrewPayload.CARGO_MASS, val=10040, units="lbm" + Aircraft.CrewPayload.CARGO_MASS, val=0, units="lbm" ) # bug fixed value and original value + self.prob.model.set_input_defaults( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, val=10040, units="lbm" + ) self.prob.model.set_input_defaults( Aircraft.VerticalTail.TAPER_RATIO, val=0.801, units="unitless" ) # bug fixed value and original value @@ -1596,6 +1610,7 @@ def test_case1(self): Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES: (False, 'unitless'), Aircraft.Engine.NUM_FUSELAGE_ENGINES: (0, 'unitless'), Aircraft.CrewPayload.NUM_PASSENGERS: (150, 'unitless'), + Aircraft.CrewPayload.Design.NUM_PASSENGERS: (150, 'unitless'), Aircraft.Electrical.HAS_HYBRID_SYSTEM: (False, 'unitless'), Aircraft.Engine.HAS_PROPELLERS: ([False], 'unitless'), Aircraft.Wing.FLAP_TYPE: ('plain', 'unitless'), @@ -1608,7 +1623,8 @@ def test_case1(self): Aircraft.Strut.ATTACHMENT_LOCATION: (10.0, 'ft'), Aircraft.LandingGear.MAIN_GEAR_LOCATION: (0.2, 'unitless'), Aircraft.CrewPayload.PASSENGER_MASS_WITH_BAGS: (200.0, 'lbm'), - Aircraft.CrewPayload.CARGO_MASS: (10040.0, 'lbm'), + Aircraft.CrewPayload.CARGO_MASS: (0.0, 'lbm'), + Aircraft.CrewPayload.Design.MAX_CARGO_MASS: (10040.0, 'lbm'), 'wire_area': (0.0015, 'ft**2'), 'rho_wire': (1.1, 'lbm/ft**3'), 'battery_energy': (0.0, 'MJ'), 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 94a671914..baf5b6681 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_mass_summation.py +++ b/aviary/subsystems/mass/gasp_based/test/test_mass_summation.py @@ -294,10 +294,10 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Design.MAX_STRUCTURAL_SPEED, val=402.5, units="mi/h" ) - self.prob.model.set_input_defaults( - Aircraft.CrewPayload.CARGO_MASS, val=10040, units="lbm" - ) + Aircraft.CrewPayload.CARGO_MASS, val=0, units="lbm") + self.prob.model.set_input_defaults( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, val=10040, units="lbm") self.prob.model.set_input_defaults( Aircraft.VerticalTail.SWEEP, val=0, units='deg' ) @@ -686,8 +686,9 @@ def setUp(self): ) self.prob.model.set_input_defaults( - Aircraft.CrewPayload.CARGO_MASS, val=10040, units="lbm" - ) + Aircraft.CrewPayload.CARGO_MASS, val=0, units="lbm") + self.prob.model.set_input_defaults( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, val=10040, units="lbm") self.prob.model.set_input_defaults( Aircraft.VerticalTail.SWEEP, val=0, units='deg' ) @@ -1066,8 +1067,9 @@ def setUp(self): ) self.prob.model.set_input_defaults( - Aircraft.CrewPayload.CARGO_MASS, val=10040, units="lbm" - ) + Aircraft.CrewPayload.CARGO_MASS, val=0, units="lbm") + self.prob.model.set_input_defaults( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, val=10040, units="lbm") self.prob.model.set_input_defaults( Aircraft.VerticalTail.SWEEP, val=0, units='deg' ) @@ -1447,8 +1449,9 @@ def setUp(self): ) self.prob.model.set_input_defaults( - Aircraft.CrewPayload.CARGO_MASS, val=10040, units="lbm" - ) + Aircraft.CrewPayload.CARGO_MASS, val=0, units="lbm") + self.prob.model.set_input_defaults( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, val=10040, units="lbm") self.prob.model.set_input_defaults( Aircraft.VerticalTail.SWEEP, val=0, units='deg' ) @@ -1827,8 +1830,9 @@ def setUp(self): ) self.prob.model.set_input_defaults( - Aircraft.CrewPayload.CARGO_MASS, val=10040, units="lbm" - ) + Aircraft.CrewPayload.CARGO_MASS, val=0, units="lbm") + self.prob.model.set_input_defaults( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, val=10040, units="lbm") self.prob.model.set_input_defaults( Aircraft.VerticalTail.SWEEP, val=0, units='deg' ) @@ -2207,10 +2211,10 @@ def setUp(self): self.prob.model.set_input_defaults( Aircraft.Design.MAX_STRUCTURAL_SPEED, val=402.5, units="mi/h" ) - self.prob.model.set_input_defaults( - Aircraft.CrewPayload.CARGO_MASS, val=15970.0, units="lbm" - ) + Aircraft.CrewPayload.CARGO_MASS, val=0, units="lbm") + self.prob.model.set_input_defaults( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, val=15970.0, units="lbm") self.prob.model.set_input_defaults( Aircraft.VerticalTail.SWEEP, val=0, units='deg' ) @@ -2609,8 +2613,9 @@ def setUp(self): Aircraft.Strut.ATTACHMENT_LOCATION, val=118, units="ft" ) self.prob.model.set_input_defaults( - Aircraft.CrewPayload.CARGO_MASS, val=15970.0, units="lbm" - ) + Aircraft.CrewPayload.CARGO_MASS, val=0, units="lbm") + self.prob.model.set_input_defaults( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, val=15970.0, units="lbm") self.prob.model.set_input_defaults( Aircraft.Engine.MASS_SPECIFIC, val=0.2470, units="lbm/lbf" ) @@ -3003,8 +3008,9 @@ def setUp(self): Aircraft.Strut.ATTACHMENT_LOCATION, val=118.0, units="ft" ) self.prob.model.set_input_defaults( - Aircraft.CrewPayload.CARGO_MASS, val=15970.0, units="lbm" - ) + Aircraft.CrewPayload.CARGO_MASS, val=0, units="lbm") + self.prob.model.set_input_defaults( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, val=15970.0, units="lbm") self.prob.model.set_input_defaults( Aircraft.Engine.MASS_SPECIFIC, val=0.2744, units="lbm/lbf" ) diff --git a/aviary/utils/preprocessors.py b/aviary/utils/preprocessors.py index d428c93b5..e9dd66e9a 100644 --- a/aviary/utils/preprocessors.py +++ b/aviary/utils/preprocessors.py @@ -7,6 +7,7 @@ from aviary.utils.named_values import get_keys from aviary.variable_info.variable_meta_data import _MetaData from aviary.variable_info.variables import Aircraft, Mission, Settings +from aviary.variable_info.enums import ProblemType, LegacyCode from aviary.utils.test_utils.variable_test import get_names_from_hierarchy @@ -162,6 +163,130 @@ def preprocess_crewpayload(aviary_options: AviaryValues): raise om.AnalysisError( f"ERROR: In preprocesssors.py: NUM_PASSENGERS ({aviary_options.get_val(Aircraft.CrewPayload.NUM_PASSENGERS)}) is larger than the number of seats set by Design.NUM_PASSENGERS ({aviary_options.get_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS)}) .") + # Check and process cargo variables - confirm mass method + if Settings.MASS_METHOD in aviary_options: + mass_method = aviary_options.get_val(Settings.MASS_METHOD) + else: + raise om.AnalysisError( + f'ERROR: In preprocessors.py: MASS_METHOD not specified. Cannot preprocess cargo inputs.') + + # Process GASP based cargo variables + if mass_method == LegacyCode.GASP: + try: + cargo = aviary_options.get_val(Aircraft.CrewPayload.CARGO_MASS, 'lbm') + except KeyError: + cargo = None + try: + max_cargo = aviary_options.get_val( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, 'lbm') + except KeyError: + max_cargo = None + try: + des_cargo = aviary_options.get_val( + Aircraft.CrewPayload.Design.CARGO_MASS, 'lbm') + except KeyError: + des_cargo = None + + if Settings.PROBLEM_TYPE in aviary_options: + problem_type = aviary_options.get_val(Settings.PROBLEM_TYPE) + else: + problem_type = ProblemType.SIZING + + if cargo is not None: + if max_cargo is not None: + if des_cargo is not None: + if problem_type == ProblemType.SIZING and cargo != des_cargo: + # user has set all three check if self consistent + cargo = des_cargo + if verbosity >= 1: + print(f"WARNING: Aircraft.CrewPayload.CARGO_MASS ({cargo}) != Aircraft.CrewPayload.Design.CARGO_MASS \ + ({des_cargo}) for SIZING mission. Setting as-flown CARGO_MASS = Design.CARGO_MASS ({des_cargo})") + else: + # user has set cargo & max: assume des = max + des_cargo = max_cargo + if verbosity >= 1: + print(f"Aircraft.CrewPayload.Design.CARGO_MASS missing, \ + assume Design.CARGO_MASS = Design.MAX_CARGO_MASS ({max_cargo})") + elif des_cargo is not None: + # user has set cargo & des: assume max = des + max_cargo = des_cargo + if verbosity >= 1: + print(f"Aircraft.CrewPayload.Design.MAX_CARGO_MASS missing, \ + assume Design.MAX_CARGO_MASS = Design.CARGO_MASS ({des_cargo})") + else: + # user has set cargo only: assume intention to set max only for backwards compatability. + max_cargo = cargo + cargo = des_cargo = 0 + if verbosity >= 1: + print(f"WARNING: User has only set Aircraft.CrewPayload.CARGO_MASS {cargo}. \ + For backwards compatiability, Aviary is assuming user intended to set Design.MAX_CARGO_MASS = ({cargo}). \ + Setting Aircraft.CrewPayload.CARGO_MASS and Aircraft.CrewPayload.Design.CARGO_MASS = 0") + + elif max_cargo is not None: + if des_cargo is not None: + # user has set max & des: assume flown = 0 + cargo = 0 + if verbosity >= 1: + print(f"Aircraft.CrewPayload.CARGO_MASS missing, assume CARGO_MASS = 0") + else: + # user has set max only: assume flown = des = 0 + cargo = des_cargo = 0 + if verbosity >= 1: + print(f"Aircraft.CrewPayload.CARGO_MASS and Aircraft.CrewPayload.Design.CARGO_MASS missing, assume CARGO_MASS and Design.CARGO_MASS = 0. No Cargo is flown on any mission") + + elif des_cargo is not None: + # user has only input des: assume max = des and flown = 0 + max_cargo = des_cargo + cargo = 0 + if verbosity >= 1: + print(f"Aircraft.CrewPayload.CARGO_MASS and Aircraft.CrewPayload.Design.MAX_CARGO_MASS missing, \ + assume CARGO_MASS = 0 and Design.MAX_CARGO_MASS = Design.CARGO_MASS ({des_cargo})") + + else: + # user has input no cargo information + cargo = max_cargo = des_cargo = 0 + if verbosity >= 1: + print( + f"No CARGO variables detected, assume CARGO_MASS = Design.MAX_CARGO_MASS = Design.CARGO_MASS = 0") + + # check for potential cargo errors: + if cargo > des_cargo: + if verbosity >= 1: + print(f"WARNING! as flown cargo ({cargo}) > design cargo ({des_cargo})") + + if cargo > max_cargo or des_cargo > max_cargo: + raise om.AnalysisError( + f"ERROR: In preprocesssors.py: Aircraft.CrewPayload.CARGO_MASS ({cargo}) and/or Aircraft.CrewPayload.Design.CARGO_MASS ({des_cargo}) > Aircraft.CrewPayload.Design.MAX_CARGO_MASS ({max_cargo})") + + # calculate passenger mass with bags based on user inputs. + try: + pax_mass_with_bag = aviary_options.get_val( + Aircraft.CrewPayload.PASSENGER_MASS_WITH_BAGS, 'lbm') + except KeyError: + pax_mass = aviary_options.get_val( + Aircraft.CrewPayload.MASS_PER_PASSENGER, 'lbm') + bag_mass = aviary_options.get_val( + Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER, 'lbm') + pax_mass_with_bag = pax_mass + bag_mass + aviary_options.set_val( + Aircraft.CrewPayload.PASSENGER_MASS_WITH_BAGS, pax_mass_with_bag, 'lbm') + + # calculate and check total payload NOTE this is only used for error messaging the calculations for analysis are subsystems/mass/gasp_based: + design_passenger_payload_mass = design_num_pax * pax_mass_with_bag + des_payload = design_passenger_payload_mass + des_cargo + num_pax = aviary_options.get_val(Aircraft.CrewPayload.NUM_PASSENGERS) + as_flown_passenger_payload_mass = num_pax * pax_mass_with_bag + as_flown_payload = as_flown_passenger_payload_mass + cargo + if as_flown_payload > des_payload and verbosity >= 1: + print(f"WARNING: as flown payload ({as_flown_payload}) > design payload \ + ({des_payload}) . Consider potential need to re-design the aircraft!") + + # set assumed cargo mass variables: + aviary_options.set_val(Aircraft.CrewPayload.CARGO_MASS, cargo, 'lbm') + aviary_options.set_val( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, max_cargo, 'lbm') + aviary_options.set_val(Aircraft.CrewPayload.Design.CARGO_MASS, des_cargo, 'lbm') + if Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS not in aviary_options: flight_attendants_count = 0 # assume no passengers diff --git a/aviary/utils/test/data/converter_test_configuration_GASP.csv b/aviary/utils/test/data/converter_test_configuration_GASP.csv index 5e33e153f..ec6b61e2e 100644 --- a/aviary/utils/test/data/converter_test_configuration_GASP.csv +++ b/aviary/utils/test/data/converter_test_configuration_GASP.csv @@ -9,8 +9,8 @@ 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,15970,lbm aircraft:crew_and_payload:catering_items_mass_per_passenger,10,lbm +aircraft:crew_and_payload:design:max_cargo_mass,15970,lbm aircraft:crew_and_payload:design:num_passengers,154,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:crew_and_payload:passenger_service_mass_per_passenger,5,lbm diff --git a/aviary/utils/test/data/converter_test_large_single_aisle_1_GASP.csv b/aviary/utils/test/data/converter_test_large_single_aisle_1_GASP.csv index 79a79d9cc..240d9ef8c 100644 --- a/aviary/utils/test/data/converter_test_large_single_aisle_1_GASP.csv +++ b/aviary/utils/test/data/converter_test_large_single_aisle_1_GASP.csv @@ -9,8 +9,8 @@ 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:crew_and_payload:catering_items_mass_per_passenger,7.6,lbm +aircraft:crew_and_payload:design:max_cargo_mass,10040,lbm aircraft:crew_and_payload:design:num_passengers,180,unitless aircraft:crew_and_payload:passenger_mass_with_bags,200,lbm aircraft:crew_and_payload:passenger_service_mass_per_passenger,5,lbm diff --git a/aviary/utils/test/data/converter_test_small_single_aisle_GASP.csv b/aviary/utils/test/data/converter_test_small_single_aisle_GASP.csv index 1465fbf34..69aa608ef 100644 --- a/aviary/utils/test/data/converter_test_small_single_aisle_GASP.csv +++ b/aviary/utils/test/data/converter_test_small_single_aisle_GASP.csv @@ -9,8 +9,8 @@ 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,8598,lbm aircraft:crew_and_payload:catering_items_mass_per_passenger,6,lbm +aircraft:crew_and_payload:design:max_cargo_mass,8598,lbm aircraft:crew_and_payload:design:num_passengers,96,unitless aircraft:crew_and_payload:passenger_mass_with_bags,210,lbm aircraft:crew_and_payload:passenger_service_mass_per_passenger,7.6,lbm diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index 0d766e685..fdb822a6d 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -700,18 +700,12 @@ add_meta_data( Aircraft.CrewPayload.CARGO_MASS, meta_data=_MetaData, - historical_name={ - "GASP": 'INGASP.WCARGO', - # ['WTS.WSP(36,2)', '~WEIGHT.WCARGO', '~WTSTAT.WSP(36,2)', '~INERT.WCARGO',], - "FLOPS": None, - "LEAPS1": [ - '(WeightABC)self._cargo_weight', - 'aircraft.outputs.L0_weights_summary.cargo_weight', - ], - }, + historical_name={"GASP": None, + "FLOPS": None, + "LEAPS1": None + }, units='lbm', - desc='total mass of cargo', - default_value=0.0, + desc='total mass of as-flown cargo' ) add_meta_data( @@ -729,6 +723,34 @@ # |___/ \___| /__/ |_| \__, | |_||_| # ====================== |___/ ====== +add_meta_data( + Aircraft.CrewPayload.Design.CARGO_MASS, + meta_data=_MetaData, + historical_name={"GASP": None, + "FLOPS": None, + "LEAPS1": None + }, + units='lbm', + desc='total mass of cargo flown on design mission' +) + +add_meta_data( + Aircraft.CrewPayload.Design.MAX_CARGO_MASS, + meta_data=_MetaData, + historical_name={ + "GASP": 'INGASP.WCARGO', + # ['WTS.WSP(36,2)', '~WEIGHT.WCARGO', '~WTSTAT.WSP(36,2)', '~INERT.WCARGO',], + "FLOPS": None, + "LEAPS1": [ + '(WeightABC)self._cargo_weight', + 'aircraft.outputs.L0_weights_summary.cargo_weight', + ], + }, + units='lbm', + desc='maximum mass of cargo', + default_value=0.0, +) + add_meta_data( Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS, meta_data=_MetaData, diff --git a/aviary/variable_info/variables.py b/aviary/variable_info/variables.py index 3baaeae74..19d7a42d5 100644 --- a/aviary/variable_info/variables.py +++ b/aviary/variable_info/variables.py @@ -131,6 +131,8 @@ class CrewPayload: WING_CARGO = 'aircraft:crew_and_payload:wing_cargo' class Design: + CARGO_MASS = 'aircraft:crew_and_payload:design:cargo_mass' + MAX_CARGO_MASS = 'aircraft:crew_and_payload:design:max_cargo_mass' NUM_BUSINESS_CLASS = 'aircraft:crew_and_payload:design:num_business_class' NUM_FIRST_CLASS = 'aircraft:crew_and_payload:design:num_first_class' NUM_TOURIST_CLASS = 'aircraft:crew_and_payload:design:num_tourist_class'