diff --git a/aviary/core/aviary_group.py b/aviary/core/aviary_group.py index 9402c37a20..c62c7ebfc4 100644 --- a/aviary/core/aviary_group.py +++ b/aviary/core/aviary_group.py @@ -260,7 +260,7 @@ def load_inputs( if phase_info is None: phase_info = self.configurator.get_default_phase_info(self) - if verbosity is not None and verbosity >= Verbosity.BRIEF: + if verbosity > Verbosity.BRIEF: # VERBOSE, DEBUG print( f'Loaded default phase_info for {self.mission_method.value.lower()} equations ' 'of motion.' diff --git a/aviary/core/aviary_problem.py b/aviary/core/aviary_problem.py index ba7bd3c450..64fa63005f 100644 --- a/aviary/core/aviary_problem.py +++ b/aviary/core/aviary_problem.py @@ -785,12 +785,12 @@ def add_composite_objective(self, *args, ref: float = None): Example inputs can be any of the following: ('fuel') (Mission.FUEL) - (Mission.FUEL, Mission.Summary.CO2) + (Mission.FUEL, Mission.CO2) ('model1', Mission.FUEL) (Mission.FUEL, 1.0) - (Mission.FUEL, 1.0), (Mission.Summary.CO2, 2.0) - ('model1', Mission.FUEL), ('model2', Mission.Summary.CO2) - ('model1', Mission.FUEL, 1.0), ('model2', Mission.Summary.CO2, 2.0) + (Mission.FUEL, 1.0), (Mission.CO2, 2.0) + ('model1', Mission.FUEL), ('model2', Mission.CO2) + ('model1', Mission.FUEL, 1.0), ('model2', Mission.CO2, 2.0) ref : float, optional Reference value for the final objective for scaling. @@ -866,7 +866,7 @@ def add_composite_objective(self, *args, ref: float = None): objectives.append((model, output, weight)) # objectives = [ # ('model1', Mission.FUEL, 1), - # ('model2', Mission.Summary.CO2, 1), + # ('model2', Mission.CO2, 1), # ... # ] diff --git a/aviary/docs/source_docs/phase_info_detailed.ipynb b/aviary/docs/source_docs/phase_info_detailed.ipynb index 92a8a64afc..52b9a74ee8 100644 --- a/aviary/docs/source_docs/phase_info_detailed.ipynb +++ b/aviary/docs/source_docs/phase_info_detailed.ipynb @@ -95,7 +95,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [ + "remove-input" + ] + }, "outputs": [], "source": [ "om.show_options_table(\n", @@ -115,7 +119,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [ + "remove-input" + ] + }, "outputs": [], "source": [ "om.show_options_table('aviary.mission.two_dof.phases.flight_phase.FlightPhaseOptions')" @@ -133,7 +141,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [ + "remove-input" + ] + }, "outputs": [], "source": [ "om.show_options_table('aviary.mission.two_dof.phases.simple_cruise_phase.SimpleCruisePhaseOptions')" @@ -151,7 +163,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [ + "remove-input" + ] + }, "outputs": [], "source": [ "om.show_options_table('aviary.mission.two_dof.phases.takeoff_phase.TakeoffPhaseOptions')" diff --git a/aviary/models/aircraft/blended_wing_body/generic_BWB_GASP.csv b/aviary/models/aircraft/blended_wing_body/generic_BWB_GASP.csv index c031e13e95..834ed1c90e 100644 --- a/aviary/models/aircraft/blended_wing_body/generic_BWB_GASP.csv +++ b/aviary/models/aircraft/blended_wing_body/generic_BWB_GASP.csv @@ -88,7 +88,7 @@ aircraft:hydraulics:gear_mass_coefficient,0.135,unitless aircraft:instruments:mass_coefficient,0.116,unitless aircraft:landing_gear:fixed_gear,False,unitless aircraft:landing_gear:main_gear_location,0,unitless -aircraft:landing_gear:main_gear_mass_coefficient,0.85,unitless +aircraft:landing_gear:main_gear_mass_fraction,0.85,unitless aircraft:landing_gear:mass_coefficient,0.052,unitless aircraft:landing_gear:tail_hook_mass_scaler,1,unitless aircraft:landing_gear:total_mass_scaler,1,unitless diff --git a/aviary/models/aircraft/large_single_aisle_1/V3_bug_fixed_IO.py b/aviary/models/aircraft/large_single_aisle_1/V3_bug_fixed_IO.py index c04065ad7f..f8b25da054 100644 --- a/aviary/models/aircraft/large_single_aisle_1/V3_bug_fixed_IO.py +++ b/aviary/models/aircraft/large_single_aisle_1/V3_bug_fixed_IO.py @@ -112,7 +112,7 @@ V3_bug_fixed_options.set_val(Aircraft.Controls.CONTROL_MASS_INCREMENT, val=0, units='lbm') V3_bug_fixed_options.set_val(Aircraft.LandingGear.MASS_COEFFICIENT, val=0.04, units='unitless') V3_bug_fixed_options.set_val( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, val=0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, val=0.85, units='unitless' ) V3_bug_fixed_options.set_val(Aircraft.Nacelle.CLEARANCE_RATIO, val=0.2, units='unitless') V3_bug_fixed_options.set_val(Aircraft.Engine.MASS_SPECIFIC, val=0.21366, units='lbm/lbf') diff --git a/aviary/models/aircraft/large_single_aisle_1/large_single_aisle_1_GASP.csv b/aviary/models/aircraft/large_single_aisle_1/large_single_aisle_1_GASP.csv index db896b49a6..7a553dda68 100644 --- a/aviary/models/aircraft/large_single_aisle_1/large_single_aisle_1_GASP.csv +++ b/aviary/models/aircraft/large_single_aisle_1/large_single_aisle_1_GASP.csv @@ -73,7 +73,7 @@ aircraft:hydraulics:gear_mass_coefficient,0.14,unitless aircraft:instruments:mass_coefficient,0.0736,unitless aircraft:landing_gear:fixed_gear,False,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_fraction,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 diff --git a/aviary/models/aircraft/large_turboprop_freighter/large_turboprop_freighter_GASP.csv b/aviary/models/aircraft/large_turboprop_freighter/large_turboprop_freighter_GASP.csv index 97d850cfef..289bfb9552 100644 --- a/aviary/models/aircraft/large_turboprop_freighter/large_turboprop_freighter_GASP.csv +++ b/aviary/models/aircraft/large_turboprop_freighter/large_turboprop_freighter_GASP.csv @@ -112,7 +112,7 @@ aircraft:horizontal_tail:volume_coefficient, 0.8614, unitless # Landing Gear aircraft:landing_gear:fixed_gear, False, unitless aircraft:landing_gear:main_gear_location, 0, unitless -aircraft:landing_gear:main_gear_mass_coefficient, 0.916, unitless +aircraft:landing_gear:main_gear_mass_fraction, 0.916, unitless aircraft:landing_gear:mass_coefficient, 0.0337, unitless aircraft:landing_gear:tail_hook_mass_scaler, 1, unitless aircraft:landing_gear:total_mass_scaler, 1, unitless diff --git a/aviary/models/aircraft/small_single_aisle/small_single_aisle_GASP.csv b/aviary/models/aircraft/small_single_aisle/small_single_aisle_GASP.csv index 44bec6363d..33f0e20ae9 100644 --- a/aviary/models/aircraft/small_single_aisle/small_single_aisle_GASP.csv +++ b/aviary/models/aircraft/small_single_aisle/small_single_aisle_GASP.csv @@ -74,7 +74,7 @@ aircraft:hydraulics:gear_mass_coefficient,0.14,unitless aircraft:instruments:mass_coefficient,0.06,unitless aircraft:landing_gear:fixed_gear,False,unitless aircraft:landing_gear:main_gear_location,0.199,unitless -aircraft:landing_gear:main_gear_mass_coefficient,0.85,unitless +aircraft:landing_gear:main_gear_mass_fraction,0.85,unitless aircraft:landing_gear:mass_coefficient,0.036,unitless aircraft:landing_gear:tail_hook_mass_scaler,1,unitless aircraft:landing_gear:total_mass_scaler,1,unitless diff --git a/aviary/models/aircraft/test_aircraft/aircraft_for_bench_FwGm.csv b/aviary/models/aircraft/test_aircraft/aircraft_for_bench_FwGm.csv index d9c6bcde77..2d8f24d440 100644 --- a/aviary/models/aircraft/test_aircraft/aircraft_for_bench_FwGm.csv +++ b/aviary/models/aircraft/test_aircraft/aircraft_for_bench_FwGm.csv @@ -72,7 +72,7 @@ aircraft:horizontal_tail:vertical_tail_mount_location,0.0,unitless aircraft:horizontal_tail:volume_coefficient,1.189,unitless aircraft:landing_gear:fixed_gear,False,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_fraction,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 diff --git a/aviary/models/aircraft/test_aircraft/aircraft_for_bench_GwFm.csv b/aviary/models/aircraft/test_aircraft/aircraft_for_bench_GwFm.csv index fcf2fdb987..c516cdcd64 100644 --- a/aviary/models/aircraft/test_aircraft/aircraft_for_bench_GwFm.csv +++ b/aviary/models/aircraft/test_aircraft/aircraft_for_bench_GwFm.csv @@ -77,7 +77,7 @@ aircraft:hydraulics:gear_mass_coefficient,0.14,unitless aircraft:instruments:mass_coefficient,0.0736,unitless aircraft:landing_gear:fixed_gear,False,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_fraction,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 diff --git a/aviary/models/aircraft/test_aircraft/aircraft_for_bench_GwGm.csv b/aviary/models/aircraft/test_aircraft/aircraft_for_bench_GwGm.csv index 1514e3c9fd..56df356c74 100644 --- a/aviary/models/aircraft/test_aircraft/aircraft_for_bench_GwGm.csv +++ b/aviary/models/aircraft/test_aircraft/aircraft_for_bench_GwGm.csv @@ -77,7 +77,7 @@ aircraft:hydraulics:gear_mass_coefficient,0.14,unitless aircraft:instruments:mass_coefficient,0.0736,unitless aircraft:landing_gear:fixed_gear,False,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_fraction,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 diff --git a/aviary/models/aircraft/test_aircraft/configuration_test_GASP.csv b/aviary/models/aircraft/test_aircraft/configuration_test_GASP.csv index a9694d6724..0066557298 100644 --- a/aviary/models/aircraft/test_aircraft/configuration_test_GASP.csv +++ b/aviary/models/aircraft/test_aircraft/configuration_test_GASP.csv @@ -74,7 +74,7 @@ aircraft:hydraulics:gear_mass_coefficient,0.105,unitless aircraft:instruments:mass_coefficient,0.0736,unitless aircraft:landing_gear:fixed_gear,False,unitless aircraft:landing_gear:main_gear_location,0,unitless -aircraft:landing_gear:main_gear_mass_coefficient,0.85,unitless +aircraft:landing_gear:main_gear_mass_fraction,0.85,unitless aircraft:landing_gear:mass_coefficient,0.0339,unitless aircraft:landing_gear:tail_hook_mass_scaler,1,unitless aircraft:landing_gear:total_mass_scaler,1,unitless diff --git a/aviary/subsystems/mass/flops_based/fuel_capacity.py b/aviary/subsystems/mass/flops_based/fuel_capacity.py index 932588d3b6..a6915a96cf 100644 --- a/aviary/subsystems/mass/flops_based/fuel_capacity.py +++ b/aviary/subsystems/mass/flops_based/fuel_capacity.py @@ -1,8 +1,9 @@ import openmdao.api as om +from openmdao.utils.units import convert_units +from aviary.constants import GRAV_ENGLISH_LBM from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft -from openmdao.utils.units import convert_units class FuelCapacityGroup(om.Group): @@ -117,7 +118,7 @@ class WingFuelCapacity(om.ExplicitComponent): """Compute the maximum fuel that can be carried in the wing's enclosed space.""" def setup(self): - add_aviary_input(self, Aircraft.Fuel.DENSITY, units='lbm/galUS') + add_aviary_input(self, Aircraft.Fuel.DENSITY, units='lbm/ft**3') add_aviary_input(self, Aircraft.Fuel.WING_REF_CAPACITY, units='lbm') add_aviary_input(self, Aircraft.Fuel.WING_REF_CAPACITY_AREA, units='unitless') add_aviary_input(self, Aircraft.Fuel.WING_REF_CAPACITY_TERM_A, units='unitless') @@ -149,7 +150,7 @@ def compute(self, inputs, outputs): ) else: - fuel_density = convert_units(inputs[Aircraft.Fuel.DENSITY], 'lbm/galUS', 'lbm/ft**3') + fuel_density = inputs[Aircraft.Fuel.DENSITY] * GRAV_ENGLISH_LBM volume_fraction = inputs[Aircraft.Fuel.WING_FUEL_FRACTION] span = inputs[Aircraft.Wing.SPAN] taper_ratio = inputs[Aircraft.Wing.TAPER_RATIO] @@ -193,7 +194,7 @@ def compute_partials(self, inputs, partials): ) else: - fuel_density = convert_units(inputs[Aircraft.Fuel.DENSITY], 'lbm/galUS', 'lbm/ft**3') + fuel_density = inputs[Aircraft.Fuel.DENSITY] * GRAV_ENGLISH_LBM volume_fraction = inputs[Aircraft.Fuel.WING_FUEL_FRACTION] span = inputs[Aircraft.Wing.SPAN] taper_ratio = inputs[Aircraft.Wing.TAPER_RATIO] @@ -203,10 +204,9 @@ def compute_partials(self, inputs, partials): tr_fact = 1.0 - taper_ratio / den**2 dfact = -1.0 / den**2 + 2.0 * taper_ratio / den**3 - conversion_factor = convert_units(1.0, 'lbm/galUS', 'lbm/ft**3') partials[Aircraft.Fuel.WING_FUEL_CAPACITY, Aircraft.Fuel.DENSITY] = ( volume_fraction * (2 / 3) * wing_area**2 * thickness_to_chord * tr_fact / span - ) * conversion_factor + ) partials[Aircraft.Fuel.WING_FUEL_CAPACITY, Aircraft.Fuel.WING_FUEL_FRACTION] = ( fuel_density * (2 / 3) * wing_area**2 * thickness_to_chord * tr_fact / span diff --git a/aviary/subsystems/mass/flops_based/mass_premission.py b/aviary/subsystems/mass/flops_based/mass_premission.py index 92f6cb099a..454a6c3d63 100644 --- a/aviary/subsystems/mass/flops_based/mass_premission.py +++ b/aviary/subsystems/mass/flops_based/mass_premission.py @@ -325,3 +325,5 @@ def setup(self): self.add_subsystem( 'mass_summation', MassSummation(), promotes_inputs=['*'], promotes_outputs=['*'] ) + + self.set_input_defaults(Aircraft.Fuel.DENSITY, val=6.7, units='lbm/galUS') diff --git a/aviary/subsystems/mass/flops_based/mass_summation.py b/aviary/subsystems/mass/flops_based/mass_summation.py index 0fd0656a92..49c7c7c01e 100644 --- a/aviary/subsystems/mass/flops_based/mass_summation.py +++ b/aviary/subsystems/mass/flops_based/mass_summation.py @@ -280,6 +280,7 @@ def initialize(self): def setup(self): alt_mass = self.options[Aircraft.Design.USE_ALT_MASS] + # Empty mass margin is calculated here to avoid feedback loop self.add_subsystem( 'empty_mass_margin', EmptyMassMargin(), promotes_inputs=['*'], promotes_outputs=['*'] ) diff --git a/aviary/subsystems/mass/gasp_based/air_conditioning.py b/aviary/subsystems/mass/gasp_based/air_conditioning.py index 10bb6f7a14..3a5c7ca2f4 100644 --- a/aviary/subsystems/mass/gasp_based/air_conditioning.py +++ b/aviary/subsystems/mass/gasp_based/air_conditioning.py @@ -6,9 +6,7 @@ class ACMass(om.ExplicitComponent): - """ - Computation of air conditioning mass. - """ + """Computation of air conditioning mass.""" def setup(self): add_aviary_input(self, Aircraft.AirConditioning.MASS_COEFFICIENT, units='unitless') @@ -97,9 +95,7 @@ def compute_partials(self, inputs, J): class BWBACMass(om.ExplicitComponent): - """ - Computation of air conditioning mass for BWB - """ + """Computation of air conditioning mass for BWB.""" def setup(self): add_aviary_input(self, Aircraft.AirConditioning.MASS_COEFFICIENT, units='unitless') diff --git a/aviary/subsystems/mass/gasp_based/anti_icing.py b/aviary/subsystems/mass/gasp_based/anti_icing.py index f473e8e73d..ebcf8bcc59 100644 --- a/aviary/subsystems/mass/gasp_based/anti_icing.py +++ b/aviary/subsystems/mass/gasp_based/anti_icing.py @@ -1,7 +1,6 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM - from aviary.variable_info.functions import add_aviary_input, add_aviary_option, add_aviary_output from aviary.variable_info.variables import Aircraft diff --git a/aviary/subsystems/mass/gasp_based/apu.py b/aviary/subsystems/mass/gasp_based/apu.py index 55389b8777..415989dc4c 100644 --- a/aviary/subsystems/mass/gasp_based/apu.py +++ b/aviary/subsystems/mass/gasp_based/apu.py @@ -1,10 +1,9 @@ import openmdao.api as om +from aviary.constants import GRAV_ENGLISH_LBM from aviary.variable_info.functions import add_aviary_option, add_aviary_output from aviary.variable_info.variables import Aircraft -from aviary.constants import GRAV_ENGLISH_LBM - class APUMass(om.ExplicitComponent): """ diff --git a/aviary/subsystems/mass/gasp_based/cargo.py b/aviary/subsystems/mass/gasp_based/cargo_containers.py similarity index 90% rename from aviary/subsystems/mass/gasp_based/cargo.py rename to aviary/subsystems/mass/gasp_based/cargo_containers.py index 480bc65276..304a979eec 100644 --- a/aviary/subsystems/mass/gasp_based/cargo.py +++ b/aviary/subsystems/mass/gasp_based/cargo_containers.py @@ -6,14 +6,13 @@ import openmdao.api as om +from aviary.constants import GRAV_ENGLISH_LBM from aviary.variable_info.functions import add_aviary_option, add_aviary_output from aviary.variable_info.variables import Aircraft -from aviary.constants import GRAV_ENGLISH_LBM - -class CargoMass(om.ExplicitComponent): - """Calculate the mass of any passengers, their baggage, and other cargo.""" +class CargoContainerMass(om.ExplicitComponent): + """Calculate the mass of cargo containers.""" def initialize(self): add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_PASSENGERS) diff --git a/aviary/subsystems/mass/gasp_based/crew.py b/aviary/subsystems/mass/gasp_based/crew.py index c52886ee22..cfcf852a13 100644 --- a/aviary/subsystems/mass/gasp_based/crew.py +++ b/aviary/subsystems/mass/gasp_based/crew.py @@ -1,18 +1,18 @@ """ -Define utilities to calculate the estimated mass of the crew (both flight and -non-flight) as well as their baggage. +Define utilities to calculate the estimated mass of the crew (both flight and cabin) as well as +their baggage. """ import openmdao.api as om +from aviary.constants import GRAV_ENGLISH_LBM from aviary.variable_info.enums import GASPEngineType from aviary.variable_info.functions import add_aviary_input, add_aviary_option, add_aviary_output from aviary.variable_info.variables import Aircraft -from aviary.constants import GRAV_ENGLISH_LBM -class NonFlightCrewMass(om.ExplicitComponent): - """Calculate the estimated mass for the non-flight and their baggage.""" +class CabinCrewMass(om.ExplicitComponent): + """Calculate the estimated mass for the cabin crew and their baggage.""" def initialize(self): add_aviary_option(self, Aircraft.Engine.TYPE) diff --git a/aviary/subsystems/mass/gasp_based/design_load.py b/aviary/subsystems/mass/gasp_based/design_load.py index 2c7fa1cf03..311431ee2a 100644 --- a/aviary/subsystems/mass/gasp_based/design_load.py +++ b/aviary/subsystems/mass/gasp_based/design_load.py @@ -2,7 +2,7 @@ import openmdao.api as om from aviary.constants import RHO_SEA_LEVEL_ENGLISH -from aviary.utils.math import sigmoidX, dSigmoidXdx +from aviary.utils.math import dSigmoidXdx, sigmoidX from aviary.variable_info.enums import Verbosity from aviary.variable_info.functions import add_aviary_input, add_aviary_option, add_aviary_output from aviary.variable_info.variables import Aircraft, Mission, Settings @@ -1139,9 +1139,7 @@ def compute_partials(self, inputs, partials): class DesignLoadGroup(om.Group): - """ - Design load group for GASP-based tube and wing type aircraft mass. - """ + """Design load group for GASP-based tube and wing type aircraft mass.""" def setup(self): self.add_subsystem( @@ -2200,9 +2198,7 @@ def compute_partials(self, inputs, partials): class BWBDesignLoadGroup(om.Group): - """ - Design load group for GASP-based BWB type aircraft mass. - """ + """Design load group for GASP-based BWB type aircraft mass.""" def setup(self): self.add_subsystem( diff --git a/aviary/subsystems/mass/gasp_based/emergency_equipment.py b/aviary/subsystems/mass/gasp_based/emergency_equipment.py index 028a33d480..d50faa6071 100644 --- a/aviary/subsystems/mass/gasp_based/emergency_equipment.py +++ b/aviary/subsystems/mass/gasp_based/emergency_equipment.py @@ -4,11 +4,10 @@ import openmdao.api as om +from aviary.constants import GRAV_ENGLISH_LBM from aviary.variable_info.functions import add_aviary_option, add_aviary_output from aviary.variable_info.variables import Aircraft -from aviary.constants import GRAV_ENGLISH_LBM - class EmergencyEquipment(om.ExplicitComponent): """ diff --git a/aviary/subsystems/mass/gasp_based/engine_oil.py b/aviary/subsystems/mass/gasp_based/engine_oil.py index 396fdf2bde..39d36624b5 100644 --- a/aviary/subsystems/mass/gasp_based/engine_oil.py +++ b/aviary/subsystems/mass/gasp_based/engine_oil.py @@ -1,10 +1,9 @@ import openmdao.api as om +from aviary.constants import GRAV_ENGLISH_LBM from aviary.variable_info.enums import GASPEngineType, Verbosity -from aviary.variable_info.variables import Aircraft, Settings from aviary.variable_info.functions import add_aviary_input, add_aviary_option, add_aviary_output - -from aviary.constants import GRAV_ENGLISH_LBM +from aviary.variable_info.variables import Aircraft, Settings class EngineOilMass(om.ExplicitComponent): diff --git a/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py b/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py index eb9dd6b7c3..4c9f40f715 100644 --- a/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py +++ b/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py @@ -1,88 +1,29 @@ import openmdao.api as om -from aviary.constants import GRAV_ENGLISH_LBM -from aviary.variable_info.enums import AircraftTypes -from aviary.variable_info.functions import add_aviary_input, add_aviary_option, add_aviary_output -from aviary.variable_info.variables import Aircraft, Mission from aviary.subsystems.mass.gasp_based.air_conditioning import ACMass, BWBACMass from aviary.subsystems.mass.gasp_based.anti_icing import AntiIcingMass from aviary.subsystems.mass.gasp_based.apu import APUMass from aviary.subsystems.mass.gasp_based.avionics import AvionicsMass -from aviary.subsystems.mass.gasp_based.cargo import CargoMass -from aviary.subsystems.mass.gasp_based.crew import FlightCrewMass -from aviary.subsystems.mass.gasp_based.crew import NonFlightCrewMass +from aviary.subsystems.mass.gasp_based.cargo_containers import CargoContainerMass +from aviary.subsystems.mass.gasp_based.crew import CabinCrewMass, FlightCrewMass from aviary.subsystems.mass.gasp_based.electrical import ElectricalMass from aviary.subsystems.mass.gasp_based.emergency_equipment import EmergencyEquipment from aviary.subsystems.mass.gasp_based.engine_oil import EngineOilMass from aviary.subsystems.mass.gasp_based.fuel_capacity import TrappedFuelCapacity -from aviary.subsystems.mass.gasp_based.furnishings import FurnishingMass, BWBFurnishingMass +from aviary.subsystems.mass.gasp_based.furnishings import BWBFurnishingMass, FurnishingMass from aviary.subsystems.mass.gasp_based.hydraulics import HydraulicsMass from aviary.subsystems.mass.gasp_based.instruments import InstrumentMass from aviary.subsystems.mass.gasp_based.oxygen_system import OxygenSystemMass from aviary.subsystems.mass.gasp_based.passenger_service import PassengerServiceMass - - -class EquipMassSum(om.ExplicitComponent): - def setup(self): - add_aviary_input(self, Aircraft.AirConditioning.MASS, units='lbm') - add_aviary_input(self, Aircraft.APU.MASS, units='lbm') - add_aviary_input(self, Aircraft.Furnishings.MASS, units='lbm') - add_aviary_input(self, Aircraft.Instruments.MASS, units='lbm') - add_aviary_input(self, Aircraft.Hydraulics.MASS, units='lbm') - add_aviary_input(self, Aircraft.Electrical.MASS, units='lbm') - add_aviary_input(self, Aircraft.Avionics.MASS, units='lbm') - add_aviary_input(self, Aircraft.AntiIcing.MASS, units='lbm') - add_aviary_input(self, Aircraft.OxygenSystem.MASS, units='lbm') - add_aviary_input(self, Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS, units='lbm') - - add_aviary_output(self, Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, units='lbm') - - self.declare_partials(Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, '*') - - def compute(self, inputs, outputs): - air_conditioning_mass = inputs[Aircraft.AirConditioning.MASS] - furnishing_mass = inputs[Aircraft.Furnishings.MASS] - APU_wt = inputs[Aircraft.APU.MASS] - instrument_wt = inputs[Aircraft.Instruments.MASS] - hydraulic_wt = inputs[Aircraft.Hydraulics.MASS] - electrical_wt = inputs[Aircraft.Electrical.MASS] - avionics_wt = inputs[Aircraft.Avionics.MASS] - icing_wt = inputs[Aircraft.AntiIcing.MASS] - oxygen_system_wt = inputs[Aircraft.OxygenSystem.MASS] - subsystems_wt = inputs[Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS] - - equip_mass_sum = ( - air_conditioning_mass - + furnishing_mass - + APU_wt - + instrument_wt - + hydraulic_wt - + electrical_wt - + avionics_wt - + icing_wt - + oxygen_system_wt - + subsystems_wt - ) - - outputs[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS] = equip_mass_sum - - def compute_partials(self, inputs, J): - J[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, Aircraft.AirConditioning.MASS] = 1 - J[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, Aircraft.Furnishings.MASS] = 1 - J[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, Aircraft.APU.MASS] = 1 - J[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, Aircraft.Instruments.MASS] = 1 - J[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, Aircraft.Hydraulics.MASS] = 1 - J[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, Aircraft.Electrical.MASS] = 1 - J[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, Aircraft.Avionics.MASS] = 1 - J[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, Aircraft.AntiIcing.MASS] = 1 - J[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, Aircraft.OxygenSystem.MASS] = 1 - J[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS] = 1 +from aviary.variable_info.enums import AircraftTypes +from aviary.variable_info.functions import add_aviary_input, add_aviary_option, add_aviary_output +from aviary.variable_info.variables import Aircraft, Mission class EquipMassGroup(om.Group): def setup(self): self.add_subsystem( - 'ac', + 'aircon', ACMass(), promotes_inputs=['*'], promotes_outputs=['*'], @@ -130,67 +71,18 @@ def setup(self): promotes_outputs=['*'], ) self.add_subsystem( - 'oxygen_system', + 'oxygen', OxygenSystemMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) -class UsefulLoadMass(om.ExplicitComponent): - """ - Computation of fixed equipment mass and useful load for GASP-based mass. - """ - - def setup(self): - add_aviary_input(self, Aircraft.CrewPayload.FLIGHT_CREW_MASS) - add_aviary_input(self, Aircraft.CrewPayload.CABIN_CREW_MASS) - add_aviary_input(self, Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS) - add_aviary_input(self, Aircraft.CrewPayload.PASSENGER_SERVICE_MASS) - add_aviary_input(self, Aircraft.Design.EMERGENCY_EQUIPMENT_MASS) - add_aviary_input(self, Aircraft.Fuel.UNUSABLE_FUEL_MASS) - add_aviary_input(self, Aircraft.CrewPayload.CARGO_CONTAINER_MASS) - - add_aviary_output(self, Mission.USEFUL_LOAD, units='lbm') - - self.declare_partials(Mission.USEFUL_LOAD, '*') - - def compute(self, inputs, outputs): - pilot_wt = inputs[Aircraft.CrewPayload.FLIGHT_CREW_MASS] - flight_attendant_wt = inputs[Aircraft.CrewPayload.CABIN_CREW_MASS] - oil_wt = inputs[Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS] - service_wt = inputs[Aircraft.CrewPayload.PASSENGER_SERVICE_MASS] - emergency_wt = inputs[Aircraft.Design.EMERGENCY_EQUIPMENT_MASS] - trapped_fuel_wt = inputs[Aircraft.Fuel.UNUSABLE_FUEL_MASS] - cargo_handling_wt = inputs[Aircraft.CrewPayload.CARGO_CONTAINER_MASS] - - useful_wt = ( - pilot_wt - + flight_attendant_wt - + oil_wt - + service_wt - + emergency_wt - + trapped_fuel_wt - + cargo_handling_wt - ) - - outputs[Mission.USEFUL_LOAD] = useful_wt / GRAV_ENGLISH_LBM - - def compute_partials(self, inputs, J): - J[Mission.USEFUL_LOAD, Aircraft.CrewPayload.FLIGHT_CREW_MASS] = 1 - J[Mission.USEFUL_LOAD, Aircraft.CrewPayload.CABIN_CREW_MASS] = 1 - J[Mission.USEFUL_LOAD, Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS] = 1 - J[Mission.USEFUL_LOAD, Aircraft.CrewPayload.PASSENGER_SERVICE_MASS] = 1 - J[Mission.USEFUL_LOAD, Aircraft.Design.EMERGENCY_EQUIPMENT_MASS] = 1 - J[Mission.USEFUL_LOAD, Aircraft.Fuel.UNUSABLE_FUEL_MASS] = 1 - J[Mission.USEFUL_LOAD, Aircraft.CrewPayload.CARGO_CONTAINER_MASS] = 1 - - class UsefulLoadMassGroup(om.Group): def setup(self): self.add_subsystem( - 'cargo', - CargoMass(), + 'cargo_containers', + CargoContainerMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -201,8 +93,8 @@ def setup(self): promotes_outputs=['*'], ) self.add_subsystem( - 'non_flight_crew', - NonFlightCrewMass(), + 'cabin_crew', + CabinCrewMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -235,7 +127,7 @@ def setup(self): class BWBEquipMassGroup(om.Group): def setup(self): self.add_subsystem( - 'ac', + 'aircon', BWBACMass(), promotes_inputs=['*'], promotes_outputs=['*'], @@ -283,7 +175,7 @@ def setup(self): promotes_outputs=['*'], ) self.add_subsystem( - 'oxygen_system', + 'oxygen', OxygenSystemMass(), promotes_inputs=['*'], promotes_outputs=['*'], diff --git a/aviary/subsystems/mass/gasp_based/fixed.py b/aviary/subsystems/mass/gasp_based/fixed.py index 17c378ec25..99ad012674 100644 --- a/aviary/subsystems/mass/gasp_based/fixed.py +++ b/aviary/subsystems/mass/gasp_based/fixed.py @@ -545,6 +545,10 @@ class EngineMass(om.ExplicitComponent): additional engine mass. """ + # TODO this component needs to be split into multiple different components so their intermediate + # calculations can be overriden correctly + # TODO no nacelle mass scale factor? + def initialize(self): add_aviary_option(self, Aircraft.Electrical.HAS_HYBRID_SYSTEM) add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) @@ -588,6 +592,8 @@ def setup(self): add_aviary_input(self, Aircraft.LandingGear.MAIN_GEAR_LOCATION, units='unitless') + add_aviary_input(self, Aircraft.Engine.POD_MASS_SCALER) + has_hybrid_system = self.options[Aircraft.Electrical.HAS_HYBRID_SYSTEM] if has_hybrid_system: @@ -597,7 +603,7 @@ def setup(self): units='lbm', desc='WEAUG: mass of electrical augmentation system', ) - + add_aviary_output(self, Aircraft.Engine.MASS, units='lbm') add_aviary_output(self, Aircraft.Propulsion.TOTAL_ENGINE_MASS, units='lbm') add_aviary_output(self, Aircraft.Nacelle.MASS, shape=num_engine_type) self.add_output( @@ -606,6 +612,7 @@ def setup(self): desc='WPYLON: mass of each pylon', val=np.zeros(num_engine_type), ) + # TODO this needs to be renamed (it only contains nacelle & pylon, and nothing inside the pod) add_aviary_output(self, Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, units='lbm', desc='WPES') add_aviary_output(self, Aircraft.Engine.ADDITIONAL_MASS, shape=num_engine_type, units='lbm') self.add_output( @@ -624,7 +631,7 @@ def setup(self): # for multiengine implementation needs this to always be available self.add_input( - 'prop_mass', + Aircraft.Engine.Propeller.MASS, # val=np.full(num_engine_type, 0.000000001), val=np.zeros(num_engine_type), units='lbm', @@ -636,8 +643,8 @@ def setup(self): def setup_partials(self): has_hybrid_system = self.options[Aircraft.Electrical.HAS_HYBRID_SYSTEM] - self.declare_partials('prop_mass_all', ['prop_mass']) - self.declare_partials('wing_mounted_mass', 'prop_mass') + self.declare_partials('prop_mass_all', [Aircraft.Engine.Propeller.MASS]) + self.declare_partials('wing_mounted_mass', Aircraft.Engine.Propeller.MASS) # derivatives w.r.t vectorized engine inputs have known sparsity pattern num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) @@ -678,16 +685,27 @@ def setup_partials(self): Aircraft.Engine.PYLON_FACTOR, Aircraft.Engine.MASS_SPECIFIC, Aircraft.Engine.SCALED_SLS_THRUST, + Aircraft.Engine.POD_MASS_SCALER, ], ) + self.declare_partials( Aircraft.Engine.ADDITIONAL_MASS, - [Aircraft.Engine.MASS_SPECIFIC, Aircraft.Engine.SCALED_SLS_THRUST], + [ + Aircraft.Engine.MASS_SPECIFIC, + Aircraft.Engine.SCALED_SLS_THRUST, + ], rows=shape, cols=shape, val=1.0, ) + self.declare_partials( + Aircraft.Engine.ADDITIONAL_MASS, + Aircraft.Propulsion.MISC_MASS_SCALER, + val=1.0, + ) + self.declare_partials( 'wing_mounted_mass', [ @@ -735,6 +753,7 @@ def compute(self, inputs, outputs): pylon_fac = inputs[Aircraft.Engine.PYLON_FACTOR] CK5 = inputs[Aircraft.Engine.MASS_SCALER] CK7 = inputs[Aircraft.Propulsion.MISC_MASS_SCALER] + CK14 = inputs[Aircraft.Engine.POD_MASS_SCALER] eng_span_frac = inputs[Aircraft.Engine.WING_LOCATIONS] main_gear_wt = inputs[Aircraft.LandingGear.MAIN_GEAR_MASS] * GRAV_ENGLISH_LBM loc_main_gear = inputs[Aircraft.LandingGear.MAIN_GEAR_LOCATION] @@ -752,10 +771,12 @@ def compute(self, inputs, outputs): outputs[Aircraft.Propulsion.TOTAL_ENGINE_MASS] = dry_wt_eng_all / GRAV_ENGLISH_LBM outputs[Aircraft.Nacelle.MASS] = nacelle_wt / GRAV_ENGLISH_LBM outputs['pylon_mass'] = pylon_wt / GRAV_ENGLISH_LBM - outputs[Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS] = ( + # NOTE TOTAL_ENGINE_POD_MASS by definition includes everything *in* the pod too! This component + # should probably use a new/different variable name (same for pod mass scaler) + outputs[Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS] = CK14 * ( sum(pod_wt * num_engines) / GRAV_ENGLISH_LBM ) - outputs[Aircraft.Engine.ADDITIONAL_MASS] = eng_instl_wt / GRAV_ENGLISH_LBM + outputs[Aircraft.Engine.ADDITIONAL_MASS] = CK7 * eng_instl_wt / GRAV_ENGLISH_LBM # In GASP, WPSTAR=CK5*WEP+CK7*WPEI+WPROP+WTGB*ENP, even though the last two terms are 0. outputs['eng_comb_mass'] = ( sum(CK5 * dry_wt_eng * num_engines) + CK7 * eng_instl_wt_all @@ -767,7 +788,7 @@ def compute(self, inputs, outputs): sum(CK5 * dry_wt_eng * num_engines) + CK7 * eng_instl_wt_all + aug_wt ) / GRAV_ENGLISH_LBM - prop_wt = inputs['prop_mass'] * GRAV_ENGLISH_LBM + prop_wt = inputs[Aircraft.Engine.Propeller.MASS] * GRAV_ENGLISH_LBM outputs['prop_mass_all'] = sum(num_engines * prop_wt) / GRAV_ENGLISH_LBM span_frac_factor = eng_span_frac / (eng_span_frac + 0.001) @@ -863,9 +884,12 @@ def compute_partials(self, inputs, J): num_engines * dPW_dSLST / GRAV_ENGLISH_LBM ) - J[Aircraft.Engine.ADDITIONAL_MASS, Aircraft.Engine.MASS_SPECIFIC] = c_instl * Fn_SLS + J[Aircraft.Engine.ADDITIONAL_MASS, Aircraft.Engine.MASS_SPECIFIC] = CK7 * c_instl * Fn_SLS J[Aircraft.Engine.ADDITIONAL_MASS, Aircraft.Engine.SCALED_SLS_THRUST] = ( - c_instl * eng_spec_wt / GRAV_ENGLISH_LBM + CK7 * c_instl * eng_spec_wt / GRAV_ENGLISH_LBM + ) + J[Aircraft.Engine.ADDITIONAL_MASS, Aircraft.Propulsion.MISC_MASS_SCALER] = ( + c_instl * eng_spec_wt * Fn_SLS / GRAV_ENGLISH_LBM ) J['eng_comb_mass', Aircraft.Engine.MASS_SCALER] = ( @@ -887,10 +911,10 @@ def compute_partials(self, inputs, J): pod_wt = nacelle_wt + pylon_wt eng_instl_wt = c_instl * dry_wt_eng - prop_wt = inputs['prop_mass'] * GRAV_ENGLISH_LBM + prop_wt = inputs[Aircraft.Engine.Propeller.MASS] * GRAV_ENGLISH_LBM # prop_wt_all = sum(num_engines * prop_wt) / GRAV_ENGLISH_LBM - J['prop_mass_all', 'prop_mass'] = num_engines + J['prop_mass_all', Aircraft.Engine.Propeller.MASS] = num_engines dPylonWt_dFnSLS = pylon_fac * 0.736 * (dry_wt_eng + nacelle_wt) ** (0.736 - 1) * eng_spec_wt dPylonWt_dEngSpecWt = ( @@ -967,11 +991,15 @@ def compute_partials(self, inputs, J): / (loc_main_gear + 0.001) ** 2 ) - J['wing_mounted_mass', 'prop_mass'] = span_frac_factor_sum * num_engines + J['wing_mounted_mass', Aircraft.Engine.Propeller.MASS] = span_frac_factor_sum * num_engines if self.options[Aircraft.Electrical.HAS_HYBRID_SYSTEM]: J['eng_comb_mass', 'aug_mass'] = 1 + J[Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, Aircraft.Engine.POD_MASS_SCALER] = ( + sum(pod_wt * num_engines) / GRAV_ENGLISH_LBM + ) + class TailMass(om.ExplicitComponent): """Computation of horizontal tail mass and vertical tail mass.""" @@ -1001,6 +1029,8 @@ def setup(self): add_aviary_input(self, Aircraft.VerticalTail.MOMENT_ARM, units='ft') add_aviary_input(self, Aircraft.VerticalTail.THICKNESS_TO_CHORD, units='unitless') add_aviary_input(self, Aircraft.VerticalTail.ROOT_CHORD, units='ft') + add_aviary_input(self, Aircraft.VerticalTail.MASS_SCALER) + add_aviary_input(self, Aircraft.HorizontalTail.MASS_SCALER) self.add_output( 'loc_MAC_vtail', @@ -1035,6 +1065,7 @@ def setup_partials(self): Aircraft.HorizontalTail.MOMENT_ARM, Aircraft.HorizontalTail.THICKNESS_TO_CHORD, Aircraft.HorizontalTail.ROOT_CHORD, + Aircraft.HorizontalTail.MASS_SCALER, ], ) self.declare_partials( @@ -1056,6 +1087,7 @@ def setup_partials(self): Aircraft.VerticalTail.MOMENT_ARM, Aircraft.VerticalTail.THICKNESS_TO_CHORD, Aircraft.VerticalTail.ROOT_CHORD, + Aircraft.VerticalTail.MASS_SCALER, ], ) @@ -1082,6 +1114,8 @@ def compute(self, inputs, outputs): vtail_mom_arm = inputs[Aircraft.VerticalTail.MOMENT_ARM] tc_ratio_root_vtail = inputs[Aircraft.VerticalTail.THICKNESS_TO_CHORD] root_chord_vtail = inputs[Aircraft.VerticalTail.ROOT_CHORD] + CK9 = inputs[Aircraft.HorizontalTail.MASS_SCALER] + CK10 = inputs[Aircraft.VerticalTail.MASS_SCALER] tan_sweep_vtail_LE = (1.0 - taper_ratio_vtail) / ( 1.0 + taper_ratio_vtail @@ -1111,7 +1145,7 @@ def compute(self, inputs, outputs): / 3.0 / (1.0 + taper_ratio_vtail) ) - outputs[Aircraft.HorizontalTail.MASS] = ( + outputs[Aircraft.HorizontalTail.MASS] = CK9 * ( 350.0 / GRAV_ENGLISH_LBM * ( @@ -1122,7 +1156,7 @@ def compute(self, inputs, outputs): ) ** 0.54 ) - outputs[Aircraft.VerticalTail.MASS] = ( + outputs[Aircraft.VerticalTail.MASS] = CK10 * ( 380.0 / GRAV_ENGLISH_LBM * ( @@ -1157,6 +1191,8 @@ def compute_partials(self, inputs, J): vtail_mom_arm = inputs[Aircraft.VerticalTail.MOMENT_ARM] tc_ratio_root_vtail = inputs[Aircraft.VerticalTail.THICKNESS_TO_CHORD] root_chord_vtail = inputs[Aircraft.VerticalTail.ROOT_CHORD] + CK9 = inputs[Aircraft.HorizontalTail.MASS_SCALER] + CK10 = inputs[Aircraft.VerticalTail.MASS_SCALER] tan_sweep_vtail_LE = (1.0 - taper_ratio_vtail) / ( 1.0 + taper_ratio_vtail @@ -1607,6 +1643,29 @@ def compute_partials(self, inputs, J): * (-0.54) * root_chord_vtail ** (-1.54) ) + J[Aircraft.VerticalTail.MASS, Aircraft.VerticalTail.MASS_SCALER] = ( + 380.0 + / GRAV_ENGLISH_LBM + * ( + (FV + htail_loc * FH / 2.0) + * vtail_area + * np.log10(min_dive_vel) + / (100.0 * vtail_mom_arm * tc_ratio_root_vtail * root_chord_vtail) + ) + ** 0.54 + ) + + J[Aircraft.HorizontalTail.MASS, Aircraft.HorizontalTail.MASS_SCALER] = ( + 350.0 + / GRAV_ENGLISH_LBM + * ( + htail_area + * FH + * np.log10(min_dive_vel) + / (100.0 * htail_mom_arm * tc_ratio_root_htail * root_chord_htail) + ) + ** 0.54 + ) class HighLiftMass(om.ExplicitComponent): @@ -2492,6 +2551,8 @@ def setup_partials(self): Aircraft.Wing.ULTIMATE_LOAD_FACTOR, 'min_dive_vel', Aircraft.Design.COCKPIT_CONTROL_MASS_COEFFICIENT, + Aircraft.Controls.COCKPIT_CONTROL_MASS_SCALER, + Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, ], ) @@ -2522,16 +2583,17 @@ def compute(self, inputs, outputs): * ULF**0.525 * dive_param**0.345 ) - cockpit_control_wt = c_mass_trend_cockpit_control * (gross_wt_initial / 1000.0) ** 0.41 - wing_control_wt = intermediate_control_wt - cockpit_control_wt + # TODO these would be nice to output & promote for mass breakdown report + intermediate_cockpit_control_wt = ( + c_mass_trend_cockpit_control * (gross_wt_initial / 1000.0) ** 0.41 + ) + cockpit_control_wt = CK15 * intermediate_cockpit_control_wt + wing_control_wt = CK18 * (intermediate_control_wt - intermediate_cockpit_control_wt) outputs[Aircraft.Wing.SURFACE_CONTROL_MASS] = wing_control_wt / GRAV_ENGLISH_LBM - stab_control_wt = stab_aug_wt + stab_control_wt = CK19 * stab_aug_wt outputs[Aircraft.Controls.MASS] = ( - CK15 * cockpit_control_wt - + CK18 * wing_control_wt - + CK19 * stab_control_wt - + delta_control_wt + cockpit_control_wt + wing_control_wt + stab_control_wt + delta_control_wt ) / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): @@ -2558,11 +2620,22 @@ def compute_partials(self, inputs, J): * ULF**0.525 * dive_param**0.345 ) - cockpit_control_wt = c_mass_trend_cockpit_control * (gross_wt_initial / 1000.0) ** 0.41 - wing_control_wt = intermediate_control_wt - cockpit_control_wt + + intermediate_cockpit_control_wt = ( + c_mass_trend_cockpit_control * (gross_wt_initial / 1000.0) ** 0.41 + ) + + cockpit_control_wt = CK15 * intermediate_cockpit_control_wt + wing_control_wt = CK18 * (intermediate_control_wt - intermediate_cockpit_control_wt) + dSCW_dSWCC = ( - wing_area**0.317 * (gross_wt_initial / 1000.0) ** 0.602 * ULF**0.525 * dive_param**0.345 + CK18 + * wing_area**0.317 + * (gross_wt_initial / 1000.0) ** 0.602 + * ULF**0.525 + * dive_param**0.345 ) + dSCW_dWA = 0.317 * ( c_mass_trend_wing_control * wing_area ** (0.317 - 1) @@ -2570,6 +2643,7 @@ def compute_partials(self, inputs, J): * ULF**0.525 * dive_param**0.345 ) + dSCW_dWG = 0.602 * c_mass_trend_wing_control * wing_area**0.317 * ( gross_wt_initial / 1000.0 ) ** (0.602 - 1) * ( @@ -2577,6 +2651,7 @@ def compute_partials(self, inputs, J): ) * ULF**0.525 * dive_param**0.345 - 0.41 * c_mass_trend_cockpit_control * ( gross_wt_initial / 1000.0 ) ** (0.41 - 1) * (1 / 1000) + dSCW_dULF = ( 0.525 * c_mass_trend_wing_control @@ -2598,7 +2673,7 @@ def compute_partials(self, inputs, J): * 1.15 / 391 ) - dSCW_dCCWC = -((gross_wt_initial / 1000.0) ** 0.41) + dSCW_dCCWC = -CK18 * ((gross_wt_initial / 1000.0) ** 0.41) J[ Aircraft.Wing.SURFACE_CONTROL_MASS, @@ -2606,14 +2681,14 @@ def compute_partials(self, inputs, J): ] = dSCW_dSWCC / GRAV_ENGLISH_LBM J[Aircraft.Controls.MASS, Aircraft.Wing.SURFACE_CONTROL_MASS_COEFFICIENT] = ( - CK18 * dSCW_dSWCC / GRAV_ENGLISH_LBM + dSCW_dSWCC / GRAV_ENGLISH_LBM ) J[Aircraft.Wing.SURFACE_CONTROL_MASS, Aircraft.Wing.AREA] = dSCW_dWA / GRAV_ENGLISH_LBM J[Aircraft.Controls.MASS, Aircraft.Wing.AREA] = CK18 * dSCW_dWA / GRAV_ENGLISH_LBM - J[Aircraft.Wing.SURFACE_CONTROL_MASS, Aircraft.Design.GROSS_MASS] = dSCW_dWG + J[Aircraft.Wing.SURFACE_CONTROL_MASS, Aircraft.Design.GROSS_MASS] = CK18 * dSCW_dWG J[Aircraft.Controls.MASS, Aircraft.Design.GROSS_MASS] = ( 0.41 @@ -2623,12 +2698,17 @@ def compute_partials(self, inputs, J): * (gross_wt_initial / 1000.0) ** (0.41 - 1) * (1 / 1000) ) - + CK18 * dSCW_dWG - ) + + (CK18 * dSCW_dWG) + ) / GRAV_ENGLISH_LBM + J[Aircraft.Wing.SURFACE_CONTROL_MASS, Aircraft.Wing.ULTIMATE_LOAD_FACTOR] = ( dSCW_dULF / GRAV_ENGLISH_LBM ) + J[Aircraft.Wing.SURFACE_CONTROL_MASS, Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER] = ( + intermediate_control_wt - intermediate_cockpit_control_wt + ) / GRAV_ENGLISH_LBM + J[Aircraft.Controls.MASS, Aircraft.Wing.ULTIMATE_LOAD_FACTOR] = ( CK18 * dSCW_dULF / GRAV_ENGLISH_LBM ) @@ -2643,7 +2723,7 @@ def compute_partials(self, inputs, J): J[ Aircraft.Controls.MASS, Aircraft.Design.COCKPIT_CONTROL_MASS_COEFFICIENT, - ] = (CK15 * (gross_wt_initial / 1000.0) ** 0.41 + CK18 * dSCW_dCCWC) / GRAV_ENGLISH_LBM + ] = (CK15 * (gross_wt_initial / 1000.0) ** 0.41 + dSCW_dCCWC) / GRAV_ENGLISH_LBM J[ Aircraft.Controls.MASS, @@ -2651,11 +2731,11 @@ def compute_partials(self, inputs, J): ] = CK19 J[Aircraft.Controls.MASS, Aircraft.Controls.COCKPIT_CONTROL_MASS_SCALER] = ( - cockpit_control_wt / GRAV_ENGLISH_LBM + intermediate_cockpit_control_wt / GRAV_ENGLISH_LBM ) J[Aircraft.Controls.MASS, Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER] = ( - wing_control_wt / GRAV_ENGLISH_LBM + wing_control_wt / CK18 / GRAV_ENGLISH_LBM ) J[ @@ -2665,8 +2745,8 @@ def compute_partials(self, inputs, J): J[Aircraft.Controls.MASS, Aircraft.Controls.CONTROL_MASS_INCREMENT] = 1 -class GearMass(om.ExplicitComponent): - """Computation of total mass of landing gear and mass of main landing gear.""" +class TotalLandingGearMass(om.ExplicitComponent): + """Computation of total mass of landing gear.""" def initialize(self): add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) @@ -2677,7 +2757,6 @@ def setup(self): add_aviary_input(self, Aircraft.Wing.VERTICAL_MOUNT_LOCATION, units='unitless') add_aviary_input(self, Aircraft.LandingGear.MASS_COEFFICIENT, units='unitless') add_aviary_input(self, Aircraft.Design.GROSS_MASS, units='lbm') - add_aviary_input(self, Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, units='unitless') add_aviary_input( self, Aircraft.Nacelle.CLEARANCE_RATIO, @@ -2685,9 +2764,9 @@ def setup(self): units='unitless', ) add_aviary_input(self, Aircraft.Nacelle.AVG_DIAMETER, shape=num_engine_type, units='ft') + add_aviary_input(self, Aircraft.LandingGear.TOTAL_MASS_SCALER) add_aviary_output(self, Aircraft.LandingGear.TOTAL_MASS, units='lbm') - add_aviary_output(self, Aircraft.LandingGear.MAIN_GEAR_MASS, units='lbm') def setup_partials(self): self.declare_partials( @@ -2697,17 +2776,17 @@ def setup_partials(self): Aircraft.Design.GROSS_MASS, Aircraft.Nacelle.CLEARANCE_RATIO, Aircraft.Nacelle.AVG_DIAMETER, + Aircraft.LandingGear.TOTAL_MASS_SCALER, ], ) - self.declare_partials(Aircraft.LandingGear.MAIN_GEAR_MASS, '*') def compute(self, inputs, outputs): wing_loc = inputs[Aircraft.Wing.VERTICAL_MOUNT_LOCATION] c_gear_mass = inputs[Aircraft.LandingGear.MASS_COEFFICIENT] gross_wt_initial = inputs[Aircraft.Design.GROSS_MASS] * GRAV_ENGLISH_LBM - c_main_gear = inputs[Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT] clearance_ratio = inputs[Aircraft.Nacelle.CLEARANCE_RATIO] nacelle_diam = inputs[Aircraft.Nacelle.AVG_DIAMETER] + CK12 = inputs[Aircraft.LandingGear.TOTAL_MASS_SCALER] # When there are multiple engine types, use the largest required clearance # TODO this does not match variable description (e.g. clearance ratio of 1.0 is @@ -2733,15 +2812,11 @@ def compute(self, inputs, outputs): landing_gear_wt = c_gear_mass_modified * gross_wt_initial - outputs[Aircraft.LandingGear.TOTAL_MASS] = landing_gear_wt / GRAV_ENGLISH_LBM - outputs[Aircraft.LandingGear.MAIN_GEAR_MASS] = ( - c_main_gear * landing_gear_wt / GRAV_ENGLISH_LBM - ) + outputs[Aircraft.LandingGear.TOTAL_MASS] = CK12 * landing_gear_wt / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): c_gear_mass = inputs[Aircraft.LandingGear.MASS_COEFFICIENT] gross_wt_initial = inputs[Aircraft.Design.GROSS_MASS] * GRAV_ENGLISH_LBM - c_main_gear = inputs[Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT] wing_loc = inputs[Aircraft.Wing.VERTICAL_MOUNT_LOCATION] clearance_ratio = inputs[Aircraft.Nacelle.CLEARANCE_RATIO] nacelle_diam = inputs[Aircraft.Nacelle.AVG_DIAMETER] @@ -2751,8 +2826,9 @@ def compute_partials(self, inputs, J): dKS, _ = KSfunction.derivatives(val, 50.0) gear_height_temp = gear_height_temp[0] - gear_height = gear_height_temp * sigmoidX(gear_height_temp, 6, 1 / 320.0) - +6 * sigmoidX(gear_height_temp, 6, -1 / 320.0) + gear_height = gear_height_temp * sigmoidX(gear_height_temp, 6, 1 / 320.0) + 6 * sigmoidX( + gear_height_temp, 6, -1 / 320.0 + ) dLGW_dCGW = ( (0.85 * (1.0 + 0.1765 * gear_height / 6.0)) * sigmoidX(wing_loc, 0.005, -0.01 / 320.0) @@ -2800,26 +2876,68 @@ def compute_partials(self, inputs, J): J[Aircraft.LandingGear.TOTAL_MASS, Aircraft.Design.GROSS_MASS] = c_gear_mass_modified - J[Aircraft.LandingGear.MAIN_GEAR_MASS, Aircraft.Nacelle.CLEARANCE_RATIO] = ( - c_main_gear * dLGW_dCR / GRAV_ENGLISH_LBM - ) + J[Aircraft.LandingGear.TOTAL_MASS, Aircraft.LandingGear.TOTAL_MASS_SCALER] = ( + c_gear_mass_modified * gross_wt_initial + ) / GRAV_ENGLISH_LBM + - J[Aircraft.LandingGear.MAIN_GEAR_MASS, Aircraft.Nacelle.AVG_DIAMETER] = ( - c_main_gear * dLGW_dND / GRAV_ENGLISH_LBM +class LandingGearMass(om.ExplicitComponent): + """Computation main and nose landing gear mass.""" + + def setup(self): + add_aviary_input(self, Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, units='unitless') + add_aviary_input(self, Aircraft.LandingGear.TOTAL_MASS, units='lbm') + add_aviary_output(self, Aircraft.LandingGear.MAIN_GEAR_MASS, units='lbm') + add_aviary_output(self, Aircraft.LandingGear.NOSE_GEAR_MASS, units='lbm') + + def setup_partials(self): + self.declare_partials( + Aircraft.LandingGear.MAIN_GEAR_MASS, + [ + Aircraft.LandingGear.TOTAL_MASS, + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, + ], + ) + self.declare_partials( + Aircraft.LandingGear.NOSE_GEAR_MASS, + [ + Aircraft.LandingGear.TOTAL_MASS, + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, + ], ) - J[Aircraft.LandingGear.MAIN_GEAR_MASS, Aircraft.LandingGear.MASS_COEFFICIENT] = ( - c_main_gear * dLGW_dCGW * sigmoidX(wing_loc, 0.005, -0.01 / 320.0) - + c_main_gear * gross_wt_initial * sigmoidX(wing_loc, 0.005, 0.01 / 320.0) - ) / GRAV_ENGLISH_LBM + def compute(self, inputs, outputs): + c_main_gear = inputs[Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION] + landing_gear_mass = inputs[Aircraft.LandingGear.TOTAL_MASS] + + outputs[Aircraft.LandingGear.MAIN_GEAR_MASS] = c_main_gear * landing_gear_mass + outputs[Aircraft.LandingGear.NOSE_GEAR_MASS] = (1 - c_main_gear) * landing_gear_mass + def compute_partials(self, inputs, J): + c_main_gear = inputs[Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION] + landing_gear_mass = inputs[Aircraft.LandingGear.TOTAL_MASS] + + J[Aircraft.LandingGear.MAIN_GEAR_MASS, Aircraft.LandingGear.TOTAL_MASS] = c_main_gear + J[Aircraft.LandingGear.MAIN_GEAR_MASS, Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION] = ( + landing_gear_mass + ) + + J[Aircraft.LandingGear.NOSE_GEAR_MASS, Aircraft.LandingGear.TOTAL_MASS] = 1 - c_main_gear J[ - Aircraft.LandingGear.MAIN_GEAR_MASS, - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, - ] = c_gear_mass_modified * gross_wt_initial / GRAV_ENGLISH_LBM + Aircraft.LandingGear.NOSE_GEAR_MASS, Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION + ] = -landing_gear_mass + - J[Aircraft.LandingGear.MAIN_GEAR_MASS, Aircraft.Design.GROSS_MASS] = ( - c_gear_mass_modified * c_main_gear +class LandingGearMassGroup(om.Group): + def setup(self): + self.add_subsystem( + 'total_landing_gear', + TotalLandingGearMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + self.add_subsystem( + 'landing_gear', LandingGearMass(), promotes_inputs=['*'], promotes_outputs=['*'] ) @@ -2866,7 +2984,7 @@ def setup(self): self.add_subsystem( 'gear', - GearMass(), + LandingGearMassGroup(), promotes_inputs=['*'], promotes_outputs=['*'], ) diff --git a/aviary/subsystems/mass/gasp_based/fuel.py b/aviary/subsystems/mass/gasp_based/fuel.py index b355943942..9bf600dca0 100644 --- a/aviary/subsystems/mass/gasp_based/fuel.py +++ b/aviary/subsystems/mass/gasp_based/fuel.py @@ -1,6 +1,5 @@ import numpy as np import openmdao.api as om -from openmdao.utils.units import convert_units from aviary.constants import GRAV_ENGLISH_LBM from aviary.utils.math import d_smooth_max, dSigmoidXdx, sigmoidX, smooth_max @@ -39,7 +38,7 @@ def setup(self): self.add_input('fuel_mass_required', units='lbm', desc='WFAREQ: no margin') self.add_input('max_wingfuel_mass', val=6, units='lbm', desc='WFWMX: maximum wingfuel mass') add_aviary_input(self, Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, units='ft**3') - add_aviary_input(self, Aircraft.Fuel.DENSITY, units='lbm/galUS') + add_aviary_input(self, Aircraft.Fuel.DENSITY, units='lbm/ft**3') add_aviary_input(self, Aircraft.Design.GROSS_MASS, units='lbm') self.add_input('fuel_mass', units='lbm', desc='WFADES') add_aviary_input(self, Mission.OPERATING_MASS, units='lbm') @@ -119,10 +118,7 @@ def compute(self, inputs, outputs): req_fuel_wt = inputs['fuel_mass_required'] * GRAV_ENGLISH_LBM max_wingfuel_wt = inputs['max_wingfuel_mass'] * GRAV_ENGLISH_LBM geom_fuel_vol = inputs[Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX] - rho_fuel = ( - convert_units(inputs[Aircraft.Fuel.DENSITY], 'lbm/galUS', 'lbm/ft**3') - * GRAV_ENGLISH_LBM - ) + rho_fuel = inputs[Aircraft.Fuel.DENSITY] * GRAV_ENGLISH_LBM gross_wt_initial = inputs[Aircraft.Design.GROSS_MASS] * GRAV_ENGLISH_LBM fuel_wt_des = inputs['fuel_mass'] * GRAV_ENGLISH_LBM OEW = inputs[Mission.OPERATING_MASS] * GRAV_ENGLISH_LBM @@ -210,10 +206,7 @@ def compute_partials(self, inputs, J): req_fuel_wt = inputs['fuel_mass_required'] * GRAV_ENGLISH_LBM max_wingfuel_wt = inputs['max_wingfuel_mass'] * GRAV_ENGLISH_LBM geom_fuel_vol = inputs[Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX] - rho_fuel = ( - convert_units(inputs[Aircraft.Fuel.DENSITY], 'lbm/galUS', 'lbm/ft**3') - * GRAV_ENGLISH_LBM - ) + rho_fuel = inputs[Aircraft.Fuel.DENSITY] * GRAV_ENGLISH_LBM gross_wt_initial = inputs[Aircraft.Design.GROSS_MASS] * GRAV_ENGLISH_LBM fuel_wt_des = inputs['fuel_mass'] * GRAV_ENGLISH_LBM @@ -458,10 +451,8 @@ def compute_partials(self, inputs, J): J['max_extra_fuel_mass', Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX] = ( dmax_extra_fuel_wt_dgeom_fuel_vol / GRAV_ENGLISH_LBM, ) - conversion_factor = convert_units(1.0, 'lbm/galUS', 'lbm/ft**3') - J['max_extra_fuel_mass', Aircraft.Fuel.DENSITY] = ( - dmax_extra_fuel_wt_drho_fuel * conversion_factor - ) + + J['max_extra_fuel_mass', Aircraft.Fuel.DENSITY] = dmax_extra_fuel_wt_drho_fuel J[Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY, 'fuel_mass_required'] = dextra_fuel_wt_dreq_fuel_wt J[Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY, 'max_wingfuel_mass'] = ( @@ -478,9 +469,7 @@ def compute_partials(self, inputs, J): J['wingfuel_mass_min', Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX] = ( dwingfuel_wt_min_dgeom_fuel_vol / GRAV_ENGLISH_LBM ) - J['wingfuel_mass_min', Aircraft.Fuel.DENSITY] = ( - dwingfuel_wt_min_drho_fuel * conversion_factor - ) + J['wingfuel_mass_min', Aircraft.Fuel.DENSITY] = dwingfuel_wt_min_drho_fuel J[Aircraft.Fuel.TOTAL_CAPACITY, 'fuel_mass'] = dmax_fuel_avail_dfuel_wt_des J[Aircraft.Fuel.TOTAL_CAPACITY, 'fuel_mass_required'] = dmax_fuel_avail_dreq_fuel_wt @@ -491,28 +480,23 @@ def compute_partials(self, inputs, J): J[Aircraft.Fuel.TOTAL_CAPACITY, Mission.OPERATING_MASS] = dmax_fuel_avail_dOEW -class FuelAndOEMOutputs(om.ExplicitComponent): +class FuelComponents(om.ExplicitComponent): """ - Computation of various fuel and OEM parameters (such as wing fuel mass when - operating empty, wing tank fuel volume when carrying maximum fuel, wing tank - fuel volume when carrying design fuel plus fuel margin, operating mass empty - of the aircraft, allowable payload mass with maximum fuel, mass of wing fuel - based on volume, maximum wingfuel mass, and wing tank volume based on maximum - wing fuel weight). + Computation of various fuel parameters (wing fuel mass when operating empty, wing tank fuel + volume when carrying maximum fuel, wing tank fuel volume when carrying design fuel plus fuel + margin, operating mass empty of the aircraft, allowable payload mass with maximum fuel, mass of + wing fuel based on volume, maximum wingfuel mass, and wing tank volume based on maximum wing + fuel weight). """ def setup(self): - add_aviary_input(self, Aircraft.Fuel.DENSITY, units='lbm/galUS') + add_aviary_input(self, Aircraft.Fuel.DENSITY, units='lbm/ft**3') add_aviary_input(self, Aircraft.Design.GROSS_MASS, units='lbm') - add_aviary_input(self, Aircraft.Propulsion.MASS, units='lbm') - add_aviary_input(self, Aircraft.Controls.MASS, units='lbm') - add_aviary_input(self, Aircraft.Design.STRUCTURE_MASS, units='lbm') - add_aviary_input(self, Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, units='lbm') - add_aviary_input(self, Mission.USEFUL_LOAD, units='lbm') self.add_input('fuel_mass_required', units='lbm', desc='WFAREQ: no margin') add_aviary_input(self, Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, units='ft**3') add_aviary_input(self, Aircraft.Fuel.VOLUME_MARGIN, units='unitless') add_aviary_input(self, Aircraft.Fuel.TOTAL_CAPACITY, units='lbm') + add_aviary_input(self, Mission.OPERATING_MASS, units='lbm') # GASP total capacity didn't include the unusable mass, but Aviary total capacity does. add_aviary_input(self, Aircraft.Fuel.UNUSABLE_FUEL_MASS, units='lbm') @@ -530,7 +514,6 @@ def setup(self): desc='FVOLW: wing tank fuel volume when carrying maximum fuel', ) add_aviary_output(self, Aircraft.Fuel.WING_VOLUME_DESIGN, units='ft**3') - add_aviary_output(self, Mission.OPERATING_MASS, units='lbm') self.add_output( 'payload_mass_max_fuel', @@ -554,22 +537,14 @@ def setup_partials(self): 'OEM_wingfuel_mass', [ Aircraft.Design.GROSS_MASS, - Aircraft.Propulsion.MASS, - Aircraft.Controls.MASS, - Aircraft.Design.STRUCTURE_MASS, - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, - Mission.USEFUL_LOAD, + Mission.OPERATING_MASS, ], ) self.declare_partials( 'OEM_fuel_vol', [ Aircraft.Design.GROSS_MASS, - Aircraft.Propulsion.MASS, - Aircraft.Controls.MASS, - Aircraft.Design.STRUCTURE_MASS, - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, - Mission.USEFUL_LOAD, + Mission.OPERATING_MASS, Aircraft.Fuel.DENSITY, ], ) @@ -577,27 +552,12 @@ def setup_partials(self): Aircraft.Fuel.WING_VOLUME_DESIGN, ['fuel_mass_required', Aircraft.Fuel.DENSITY, Aircraft.Fuel.VOLUME_MARGIN], ) - self.declare_partials( - Mission.OPERATING_MASS, - [ - Aircraft.Propulsion.MASS, - Aircraft.Controls.MASS, - Aircraft.Design.STRUCTURE_MASS, - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, - Mission.USEFUL_LOAD, - ], - val=1, - ) self.declare_partials('payload_mass_max_fuel', [Aircraft.Design.GROSS_MASS], val=1) self.declare_partials( 'payload_mass_max_fuel', [ Aircraft.Fuel.TOTAL_CAPACITY, - Aircraft.Propulsion.MASS, - Aircraft.Controls.MASS, - Aircraft.Design.STRUCTURE_MASS, - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, - Mission.USEFUL_LOAD, + Mission.OPERATING_MASS, ], val=-1.0, ) @@ -609,11 +569,7 @@ def setup_partials(self): 'max_wingfuel_mass', [ Aircraft.Design.GROSS_MASS, - Aircraft.Propulsion.MASS, - Aircraft.Controls.MASS, - Aircraft.Design.STRUCTURE_MASS, - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, - Mission.USEFUL_LOAD, + Mission.OPERATING_MASS, Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, Aircraft.Fuel.DENSITY, ], @@ -622,44 +578,30 @@ def setup_partials(self): Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, [ Aircraft.Design.GROSS_MASS, - Aircraft.Propulsion.MASS, - Aircraft.Controls.MASS, - Aircraft.Design.STRUCTURE_MASS, - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, - Mission.USEFUL_LOAD, + Mission.OPERATING_MASS, Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, Aircraft.Fuel.DENSITY, ], ) def compute(self, inputs, outputs): - rho_fuel = ( - convert_units(inputs[Aircraft.Fuel.DENSITY], 'lbm/galUS', 'lbm/ft**3') - * GRAV_ENGLISH_LBM - ) + rho_fuel = inputs[Aircraft.Fuel.DENSITY] * GRAV_ENGLISH_LBM + gross_wt_initial = inputs[Aircraft.Design.GROSS_MASS] * GRAV_ENGLISH_LBM - propulsion_wt = inputs[Aircraft.Propulsion.MASS] * GRAV_ENGLISH_LBM - control_wt = inputs[Aircraft.Controls.MASS] * GRAV_ENGLISH_LBM - struct_wt = inputs[Aircraft.Design.STRUCTURE_MASS] * GRAV_ENGLISH_LBM - fixed_equip_wt = inputs[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS] * GRAV_ENGLISH_LBM - useful_wt = inputs[Mission.USEFUL_LOAD] * GRAV_ENGLISH_LBM req_fuel_wt = inputs['fuel_mass_required'] * GRAV_ENGLISH_LBM geometric_fuel_vol = inputs[Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX] fuel_margin = inputs[Aircraft.Fuel.VOLUME_MARGIN] + OEW = inputs[Mission.OPERATING_MASS] * GRAV_ENGLISH_LBM total_fuel = inputs[Aircraft.Fuel.TOTAL_CAPACITY] unusable_fuel = inputs[Aircraft.Fuel.UNUSABLE_FUEL_MASS] max_fuel_avail = (total_fuel - unusable_fuel) * GRAV_ENGLISH_LBM - OEM_wingfuel_wt = ( - gross_wt_initial - propulsion_wt - control_wt - struct_wt - fixed_equip_wt - useful_wt - ) + OEM_wingfuel_wt = gross_wt_initial - OEW OEM_fuel_vol = OEM_wingfuel_wt / rho_fuel design_fuel_vol = (1.0 + fuel_margin / 100.0) * req_fuel_wt / rho_fuel - OEW = propulsion_wt + control_wt + struct_wt + fixed_equip_wt + useful_wt - volume_wingfuel_wt = geometric_fuel_vol * rho_fuel # always smoothing max_wingfuel_wt = OEM_wingfuel_wt * sigmoidX( @@ -671,66 +613,37 @@ def compute(self, inputs, outputs): outputs['OEM_wingfuel_mass'] = OEM_wingfuel_wt / GRAV_ENGLISH_LBM outputs['OEM_fuel_vol'] = OEM_fuel_vol outputs[Aircraft.Fuel.WING_VOLUME_DESIGN] = design_fuel_vol - outputs[Mission.OPERATING_MASS] = OEW / GRAV_ENGLISH_LBM outputs['payload_mass_max_fuel'] = payload_wt_max_fuel / GRAV_ENGLISH_LBM outputs['volume_wingfuel_mass'] = volume_wingfuel_wt / GRAV_ENGLISH_LBM outputs['max_wingfuel_mass'] = max_wingfuel_wt / GRAV_ENGLISH_LBM outputs[Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX] = max_wingfuel_vol def compute_partials(self, inputs, J): - rho_fuel = ( - convert_units(inputs[Aircraft.Fuel.DENSITY], 'lbm/galUS', 'lbm/ft**3') - * GRAV_ENGLISH_LBM - ) + rho_fuel = inputs[Aircraft.Fuel.DENSITY] * GRAV_ENGLISH_LBM gross_wt_initial = inputs[Aircraft.Design.GROSS_MASS] * GRAV_ENGLISH_LBM - propulsion_wt = inputs[Aircraft.Propulsion.MASS] * GRAV_ENGLISH_LBM - control_wt = inputs[Aircraft.Controls.MASS] * GRAV_ENGLISH_LBM - struct_wt = inputs[Aircraft.Design.STRUCTURE_MASS] * GRAV_ENGLISH_LBM - fixed_equip_wt = inputs[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS] * GRAV_ENGLISH_LBM - useful_wt = inputs[Mission.USEFUL_LOAD] * GRAV_ENGLISH_LBM + OEW = inputs[Mission.OPERATING_MASS] * GRAV_ENGLISH_LBM req_fuel_wt = inputs['fuel_mass_required'] * GRAV_ENGLISH_LBM geometric_fuel_vol = inputs[Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX] fuel_margin = inputs[Aircraft.Fuel.VOLUME_MARGIN] - OEM_wingfuel_wt = ( - gross_wt_initial - propulsion_wt - control_wt - struct_wt - fixed_equip_wt - useful_wt - ) + OEM_wingfuel_wt = gross_wt_initial - OEW volume_wingfuel_wt = geometric_fuel_vol * rho_fuel max_wingfuel_wt = OEM_wingfuel_wt * sigmoidX( volume_wingfuel_wt - OEM_wingfuel_wt, 0, 1 / 95.0 ) + volume_wingfuel_wt * sigmoidX(OEM_wingfuel_wt - volume_wingfuel_wt, 0, 1 / 95.0) J['OEM_wingfuel_mass', Aircraft.Design.GROSS_MASS] = dOEMwingfuelWt_dGTOW = 1 - J['OEM_wingfuel_mass', Aircraft.Propulsion.MASS] = dOEMwingfuelWt_dPropWt = -1 - J['OEM_wingfuel_mass', Aircraft.Controls.MASS] = dOEMwingfuelWt_dControlWt = -1 - J['OEM_wingfuel_mass', Aircraft.Design.STRUCTURE_MASS] = dOEMwingfuelWt_dStructWt = -1 - J['OEM_wingfuel_mass', Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS] = ( - dOEMwingfuelWt_dFEqWt - ) = -1 - J['OEM_wingfuel_mass', Mission.USEFUL_LOAD] = dOEMwingfuelWt_dUsefulWt = -1 + J['OEM_wingfuel_mass', Mission.OPERATING_MASS] = dOEMwingfuelWt_dOEW = -1 J['OEM_fuel_vol', Aircraft.Design.GROSS_MASS] = 1 / rho_fuel * GRAV_ENGLISH_LBM - J['OEM_fuel_vol', Aircraft.Propulsion.MASS] = -1 / rho_fuel * GRAV_ENGLISH_LBM - J['OEM_fuel_vol', Aircraft.Controls.MASS] = -1 / rho_fuel * GRAV_ENGLISH_LBM - J['OEM_fuel_vol', Aircraft.Design.STRUCTURE_MASS] = -1 / rho_fuel * GRAV_ENGLISH_LBM - J['OEM_fuel_vol', Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS] = ( - -1 / rho_fuel * GRAV_ENGLISH_LBM - ) - J['OEM_fuel_vol', Mission.USEFUL_LOAD] = -1 / rho_fuel * GRAV_ENGLISH_LBM - conversion_factor = convert_units(1.0, 'lbm/galUS', 'lbm/ft**3') - J['OEM_fuel_vol', Aircraft.Fuel.DENSITY] = ( - -OEM_wingfuel_wt / rho_fuel**2 * conversion_factor * GRAV_ENGLISH_LBM - ) + J['OEM_fuel_vol', Mission.OPERATING_MASS] = -1 / rho_fuel * GRAV_ENGLISH_LBM + J['OEM_fuel_vol', Aircraft.Fuel.DENSITY] = -OEM_wingfuel_wt / rho_fuel**2 * GRAV_ENGLISH_LBM J[Aircraft.Fuel.WING_VOLUME_DESIGN, 'fuel_mass_required'] = ( (1.0 + fuel_margin / 100.0) / rho_fuel * GRAV_ENGLISH_LBM ) J[Aircraft.Fuel.WING_VOLUME_DESIGN, Aircraft.Fuel.DENSITY] = ( - -(1.0 + fuel_margin / 100.0) - * req_fuel_wt - / rho_fuel**2 - * conversion_factor - * GRAV_ENGLISH_LBM + -(1.0 + fuel_margin / 100.0) * req_fuel_wt / rho_fuel**2 * GRAV_ENGLISH_LBM ) J[Aircraft.Fuel.WING_VOLUME_DESIGN, Aircraft.Fuel.VOLUME_MARGIN] = ( 1 / 100.0 * req_fuel_wt / rho_fuel @@ -739,7 +652,7 @@ def compute_partials(self, inputs, J): J['volume_wingfuel_mass', Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX] = ( rho_fuel / GRAV_ENGLISH_LBM ) - J['volume_wingfuel_mass', Aircraft.Fuel.DENSITY] = geometric_fuel_vol * conversion_factor + J['volume_wingfuel_mass', Aircraft.Fuel.DENSITY] = geometric_fuel_vol dMaxWFWt_dGTOW = ( OEM_wingfuel_wt @@ -750,61 +663,14 @@ def compute_partials(self, inputs, J): * dSigmoidXdx(OEM_wingfuel_wt - volume_wingfuel_wt, 0, 1 / 95.0) * dOEMwingfuelWt_dGTOW ) - dMaxWFWt_dPropWt = ( - OEM_wingfuel_wt - * dSigmoidXdx(volume_wingfuel_wt - OEM_wingfuel_wt, 0, 1 / 95.0) - * dOEMwingfuelWt_dPropWt - + dOEMwingfuelWt_dPropWt * sigmoidX(volume_wingfuel_wt - OEM_wingfuel_wt, 0, 1 / 95.0) - + volume_wingfuel_wt - * dSigmoidXdx(OEM_wingfuel_wt - volume_wingfuel_wt, 0, 1 / 95.0) - * dOEMwingfuelWt_dPropWt - ) - dMaxWFWt_dControlWt = ( + dMaxWFWt_dOEW = ( OEM_wingfuel_wt * dSigmoidXdx(volume_wingfuel_wt - OEM_wingfuel_wt, 0, 1 / 95.0) - * dOEMwingfuelWt_dControlWt - + dOEMwingfuelWt_dControlWt - * sigmoidX(volume_wingfuel_wt - OEM_wingfuel_wt, 0, 1 / 95.0) + * dOEMwingfuelWt_dOEW + + dOEMwingfuelWt_dOEW * sigmoidX(volume_wingfuel_wt - OEM_wingfuel_wt, 0, 1 / 95.0) + volume_wingfuel_wt * dSigmoidXdx(OEM_wingfuel_wt - volume_wingfuel_wt, 0, 1 / 95.0) - * dOEMwingfuelWt_dControlWt - ) - dMaxWFWt_dControlWt = ( - OEM_wingfuel_wt - * dSigmoidXdx(volume_wingfuel_wt - OEM_wingfuel_wt, 0, 1 / 95.0) - * dOEMwingfuelWt_dControlWt - + dOEMwingfuelWt_dControlWt - * sigmoidX(volume_wingfuel_wt - OEM_wingfuel_wt, 0, 1 / 95.0) - + volume_wingfuel_wt - * dSigmoidXdx(OEM_wingfuel_wt - volume_wingfuel_wt, 0, 1 / 95.0) - * dOEMwingfuelWt_dControlWt - ) - dMaxWFWt_dStructWt = ( - OEM_wingfuel_wt - * dSigmoidXdx(volume_wingfuel_wt - OEM_wingfuel_wt, 0, 1 / 95.0) - * dOEMwingfuelWt_dStructWt - + dOEMwingfuelWt_dStructWt * sigmoidX(volume_wingfuel_wt - OEM_wingfuel_wt, 0, 1 / 95.0) - + volume_wingfuel_wt - * dSigmoidXdx(OEM_wingfuel_wt - volume_wingfuel_wt, 0, 1 / 95.0) - * dOEMwingfuelWt_dStructWt - ) - dMaxWFWt_dFEqWt = ( - OEM_wingfuel_wt - * dSigmoidXdx(volume_wingfuel_wt - OEM_wingfuel_wt, 0, 1 / 95.0) - * dOEMwingfuelWt_dFEqWt - + dOEMwingfuelWt_dFEqWt * sigmoidX(volume_wingfuel_wt - OEM_wingfuel_wt, 0, 1 / 95.0) - + volume_wingfuel_wt - * dSigmoidXdx(OEM_wingfuel_wt - volume_wingfuel_wt, 0, 1 / 95.0) - * dOEMwingfuelWt_dFEqWt - ) - dMaxWFWt_dUsefulWt = ( - OEM_wingfuel_wt - * dSigmoidXdx(volume_wingfuel_wt - OEM_wingfuel_wt, 0, 1 / 95.0) - * dOEMwingfuelWt_dUsefulWt - + dOEMwingfuelWt_dUsefulWt * sigmoidX(volume_wingfuel_wt - OEM_wingfuel_wt, 0, 1 / 95.0) - + volume_wingfuel_wt - * dSigmoidXdx(OEM_wingfuel_wt - volume_wingfuel_wt, 0, 1 / 95.0) - * dOEMwingfuelWt_dUsefulWt + * dOEMwingfuelWt_dOEW ) dMaxWFWt_dGeomFuelVol = ( OEM_wingfuel_wt @@ -826,40 +692,24 @@ def compute_partials(self, inputs, J): ) J['max_wingfuel_mass', Aircraft.Design.GROSS_MASS] = dMaxWFWt_dGTOW - J['max_wingfuel_mass', Aircraft.Propulsion.MASS] = dMaxWFWt_dPropWt - J['max_wingfuel_mass', Aircraft.Controls.MASS] = dMaxWFWt_dControlWt - J['max_wingfuel_mass', Aircraft.Design.STRUCTURE_MASS] = dMaxWFWt_dStructWt - J['max_wingfuel_mass', Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS] = dMaxWFWt_dFEqWt - J['max_wingfuel_mass', Mission.USEFUL_LOAD] = dMaxWFWt_dUsefulWt + J['max_wingfuel_mass', Mission.OPERATING_MASS] = dMaxWFWt_dOEW J['max_wingfuel_mass', Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX] = ( dMaxWFWt_dGeomFuelVol / GRAV_ENGLISH_LBM ) - J['max_wingfuel_mass', Aircraft.Fuel.DENSITY] = dMaxWFWt_dRhoFuel * conversion_factor + J['max_wingfuel_mass', Aircraft.Fuel.DENSITY] = dMaxWFWt_dRhoFuel J[Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, Aircraft.Design.GROSS_MASS] = dMaxWFWt_dGTOW / ( rho_fuel ) - J[Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, Aircraft.Propulsion.MASS] = dMaxWFWt_dPropWt / ( - rho_fuel - ) - J[Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, Aircraft.Controls.MASS] = ( - dMaxWFWt_dControlWt / (rho_fuel) - ) - J[Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, Aircraft.Design.STRUCTURE_MASS] = ( - dMaxWFWt_dStructWt / (rho_fuel) - ) - J[Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS] = ( - dMaxWFWt_dFEqWt / (rho_fuel) - ) - J[Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, Mission.USEFUL_LOAD] = dMaxWFWt_dUsefulWt / ( + J[Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, Mission.OPERATING_MASS] = dMaxWFWt_dOEW / ( rho_fuel ) J[Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX] = ( dMaxWFWt_dGeomFuelVol / (rho_fuel) ) - J[Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, Aircraft.Fuel.DENSITY] = ( - dMaxWFWt_dRhoFuel / (rho_fuel) - max_wingfuel_wt / (rho_fuel**2) - ) * conversion_factor + J[Aircraft.Fuel.WING_VOLUME_STRUCTURAL_MAX, Aircraft.Fuel.DENSITY] = dMaxWFWt_dRhoFuel / ( + rho_fuel + ) - max_wingfuel_wt / (rho_fuel**2) class FuelSysAndFullFuselageMass(om.ExplicitComponent): @@ -979,9 +829,7 @@ def compute_partials(self, inputs, J): class FuselageMass(om.ExplicitComponent): - """ - Computation of the fuselage structure mass. - """ + """Computation of the fuselage structure mass.""" def setup(self): self.add_input( @@ -990,6 +838,7 @@ def setup(self): units='lbm', desc='WX: mass of fuselage and contents, including empennage', ) + add_aviary_input(self, Aircraft.Fuselage.MASS_SCALER, units='unitless') add_aviary_input(self, Aircraft.Fuselage.MASS_COEFFICIENT, units='unitless') add_aviary_input(self, Aircraft.Fuselage.WETTED_AREA, units='ft**2') add_aviary_input(self, Aircraft.Fuselage.AVG_DIAMETER, units='ft') @@ -1015,6 +864,7 @@ def setup_partials(self): self.declare_partials( Aircraft.Fuselage.MASS, [ + Aircraft.Fuselage.MASS_SCALER, Aircraft.Fuselage.MASS_COEFFICIENT, 'fus_mass_full', Aircraft.Fuselage.WETTED_AREA, @@ -1029,6 +879,7 @@ def setup_partials(self): ) def compute(self, inputs, outputs): + CK11 = inputs[Aircraft.Fuselage.MASS_SCALER] fus_wt_full = inputs['fus_mass_full'] * GRAV_ENGLISH_LBM c_fuselage = inputs[Aircraft.Fuselage.MASS_COEFFICIENT] fus_SA = inputs[Aircraft.Fuselage.WETTED_AREA] @@ -1040,7 +891,7 @@ def compute(self, inputs, outputs): ULF = inputs[Aircraft.Wing.ULTIMATE_LOAD_FACTOR] WAT = inputs['MAT'] * GRAV_ENGLISH_LBM - fus_wt = ( + fus_wt = CK11 * ( c_fuselage * ( (fus_wt_full / 10000.0) ** 0.7 @@ -1058,6 +909,7 @@ def compute(self, inputs, outputs): outputs[Aircraft.Fuselage.MASS] = fus_wt / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): + CK11 = inputs[Aircraft.Fuselage.MASS_SCALER] fus_wt_full = inputs['fus_mass_full'] * GRAV_ENGLISH_LBM c_fuselage = inputs[Aircraft.Fuselage.MASS_COEFFICIENT] fus_SA = inputs[Aircraft.Fuselage.WETTED_AREA] @@ -1067,25 +919,50 @@ def compute_partials(self, inputs, J): min_dive_vel = inputs['min_dive_vel'] p_diff_fus = inputs[Aircraft.Fuselage.PRESSURE_DIFFERENTIAL] ULF = inputs[Aircraft.Wing.ULTIMATE_LOAD_FACTOR] + WAT = inputs['MAT'] * GRAV_ENGLISH_LBM - x = 0.508 * ( - (fus_wt_full / 10000.0) ** 0.7 - * (fus_SA / 1000.0) - * cabin_width - * (cabin_len_tailboom + pylon_len) ** 0.5 - * np.log10(min_dive_vel) - * (p_diff_fus + 1.0) ** 0.2 - * ULF**0.3 - ) ** (0.508 - 1) + fus_wt = CK11 * ( + c_fuselage + * ( + (fus_wt_full / 10000.0) ** 0.7 + * (fus_SA / 1000.0) + * cabin_width + * (cabin_len_tailboom + pylon_len) ** 0.5 + * np.log10(min_dive_vel) + * (p_diff_fus + 1.0) ** 0.2 + * ULF**0.3 + ) + ** 0.508 + + WAT + ) + + x = ( + CK11 + * 0.508 + * ( + (fus_wt_full / 10000.0) ** 0.7 + * (fus_SA / 1000.0) + * cabin_width + * (cabin_len_tailboom + pylon_len) ** 0.5 + * np.log10(min_dive_vel) + * (p_diff_fus + 1.0) ** 0.2 + * ULF**0.3 + ) + ** (0.508 - 1) + ) dFusWt_dCFus = ( - (fus_wt_full / 10000.0) ** 0.7 - * (fus_SA / 1000.0) - * cabin_width - * (cabin_len_tailboom + pylon_len) ** 0.5 - * np.log10(min_dive_vel) - * (p_diff_fus + 1.0) ** 0.2 - * ULF**0.3 - ) ** 0.508 + CK11 + * ( + (fus_wt_full / 10000.0) ** 0.7 + * (fus_SA / 1000.0) + * cabin_width + * (cabin_len_tailboom + pylon_len) ** 0.5 + * np.log10(min_dive_vel) + * (p_diff_fus + 1.0) ** 0.2 + * ULF**0.3 + ) + ** 0.508 + ) dFusWt_dFusWtFull = ( c_fuselage * x @@ -1180,7 +1057,7 @@ def compute_partials(self, inputs, J): * 0.3 * ULF ** (0.3 - 1) ) - + J[Aircraft.Fuselage.MASS, Aircraft.Fuselage.MASS_SCALER] = fus_wt / CK11 / GRAV_ENGLISH_LBM J[Aircraft.Fuselage.MASS, Aircraft.Fuselage.MASS_COEFFICIENT] = ( dFusWt_dCFus / GRAV_ENGLISH_LBM ) @@ -1216,6 +1093,7 @@ def setup(self): ) add_aviary_input(self, Aircraft.Fuselage.AFTBODY_MASS_PER_UNIT_AREA, units='lbm/ft**2') add_aviary_input(self, Aircraft.Fuselage.WETTED_AREA, units='ft**2') + add_aviary_input(self, Aircraft.Fuselage.MASS_SCALER) add_aviary_output(self, Aircraft.Fuselage.MASS, units='lbm') @@ -1229,6 +1107,7 @@ def setup_partials(self): Aircraft.Design.GROSS_MASS, Aircraft.Fuselage.WETTED_AREA_RATIO_AFTBODY_TO_TOTAL, Aircraft.Fuselage.AFTBODY_MASS_PER_UNIT_AREA, + Aircraft.Fuselage.MASS_SCALER, ], ) @@ -1239,12 +1118,13 @@ def compute(self, inputs, outputs): area_aft_to_total = inputs[Aircraft.Fuselage.WETTED_AREA_RATIO_AFTBODY_TO_TOTAL] uwt_aft = inputs[Aircraft.Fuselage.AFTBODY_MASS_PER_UNIT_AREA] * GRAV_ENGLISH_LBM fus_SA = inputs[Aircraft.Fuselage.WETTED_AREA] + CK11 = inputs[Aircraft.Fuselage.MASS_SCALER] fus_wt_fb = c_fuselage * 1.8 * (gross_wt_initial**0.167) * (area_cabin**1.06) fus_wt_ab = c_fuselage * fus_SA * area_aft_to_total * uwt_aft - fus_mass = (fus_wt_fb + fus_wt_ab) / GRAV_ENGLISH_LBM + fus_wt = fus_wt_fb + fus_wt_ab - outputs[Aircraft.Fuselage.MASS] = fus_mass + outputs[Aircraft.Fuselage.MASS] = CK11 * fus_wt / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): c_fuselage = inputs[Aircraft.Fuselage.MASS_COEFFICIENT] @@ -1276,103 +1156,11 @@ def compute_partials(self, inputs, J): ) J[Aircraft.Fuselage.MASS, Aircraft.Fuselage.AFTBODY_MASS_PER_UNIT_AREA] = dFusWt_duwt_aft J[Aircraft.Fuselage.MASS, Aircraft.Fuselage.WETTED_AREA] = dFusWt_dfus_SA - - -class StructMass(om.ExplicitComponent): - """ - Computation of total structural group mass. - """ - - def initialize(self): - add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) - - def setup(self): - num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) - - add_aviary_input(self, Aircraft.Fuselage.MASS, units='lbm') - add_aviary_input(self, Aircraft.Wing.MASS_SCALER, units='unitless') - add_aviary_input(self, Aircraft.Wing.MASS, units='lbm') - add_aviary_input(self, Aircraft.HorizontalTail.MASS_SCALER, units='unitless') - add_aviary_input(self, Aircraft.HorizontalTail.MASS, units='lbm') - add_aviary_input(self, Aircraft.VerticalTail.MASS_SCALER, units='unitless') - add_aviary_input(self, Aircraft.VerticalTail.MASS, units='lbm') - add_aviary_input(self, Aircraft.Fuselage.MASS_SCALER, units='unitless') - add_aviary_input(self, Aircraft.LandingGear.TOTAL_MASS_SCALER, units='unitless') - add_aviary_input(self, Aircraft.LandingGear.TOTAL_MASS, units='lbm') - add_aviary_input( - self, Aircraft.Engine.POD_MASS_SCALER, shape=num_engine_type, units='unitless' - ) - add_aviary_input(self, Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, units='lbm') - add_aviary_input(self, Aircraft.Design.STRUCTURAL_MASS_INCREMENT, units='lbm') - - add_aviary_output(self, Aircraft.Design.STRUCTURE_MASS, units='lbm', desc='WST') - - self.declare_partials(Aircraft.Design.STRUCTURE_MASS, '*') - - def compute(self, inputs, outputs): - fus_wt = inputs[Aircraft.Fuselage.MASS] * GRAV_ENGLISH_LBM - CK8 = inputs[Aircraft.Wing.MASS_SCALER] - total_wing_wt = inputs[Aircraft.Wing.MASS] * GRAV_ENGLISH_LBM - CK9 = inputs[Aircraft.HorizontalTail.MASS_SCALER] - htail_wt = inputs[Aircraft.HorizontalTail.MASS] * GRAV_ENGLISH_LBM - CK10 = inputs[Aircraft.VerticalTail.MASS_SCALER] - vtail_wt = inputs[Aircraft.VerticalTail.MASS] * GRAV_ENGLISH_LBM - CK11 = inputs[Aircraft.Fuselage.MASS_SCALER] - CK12 = inputs[Aircraft.LandingGear.TOTAL_MASS_SCALER] - landing_gear_wt = inputs[Aircraft.LandingGear.TOTAL_MASS] * GRAV_ENGLISH_LBM - CK14 = inputs[Aircraft.Engine.POD_MASS_SCALER] - sec_wt = inputs[Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS] * GRAV_ENGLISH_LBM - delta_struct_wt = inputs[Aircraft.Design.STRUCTURAL_MASS_INCREMENT] * GRAV_ENGLISH_LBM - - outputs[Aircraft.Design.STRUCTURE_MASS] = ( - CK8 * total_wing_wt - + CK9 * htail_wt - + CK10 * vtail_wt - + CK11 * fus_wt - + CK12 * landing_gear_wt - + CK14 * sec_wt - + delta_struct_wt + J[Aircraft.Fuselage.MASS, Aircraft.Fuselage.MASS_SCALER] = ( + c_fuselage * 1.8 * (gross_wt_initial**0.167) * (area_cabin**1.06) + + c_fuselage * fus_SA * area_aft_to_total * uwt_aft ) / GRAV_ENGLISH_LBM - def compute_partials(self, inputs, J): - fus_wt = inputs[Aircraft.Fuselage.MASS] * GRAV_ENGLISH_LBM - CK8 = inputs[Aircraft.Wing.MASS_SCALER] - total_wing_wt = inputs[Aircraft.Wing.MASS] * GRAV_ENGLISH_LBM - CK9 = inputs[Aircraft.HorizontalTail.MASS_SCALER] - htail_wt = inputs[Aircraft.HorizontalTail.MASS] * GRAV_ENGLISH_LBM - CK10 = inputs[Aircraft.VerticalTail.MASS_SCALER] - vtail_wt = inputs[Aircraft.VerticalTail.MASS] * GRAV_ENGLISH_LBM - CK11 = inputs[Aircraft.Fuselage.MASS_SCALER] - CK12 = inputs[Aircraft.LandingGear.TOTAL_MASS_SCALER] - landing_gear_wt = inputs[Aircraft.LandingGear.TOTAL_MASS] * GRAV_ENGLISH_LBM - CK14 = inputs[Aircraft.Engine.POD_MASS_SCALER] - sec_wt = inputs[Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS] * GRAV_ENGLISH_LBM - delta_struct_wt = inputs[Aircraft.Design.STRUCTURAL_MASS_INCREMENT] * GRAV_ENGLISH_LBM - - J[Aircraft.Design.STRUCTURE_MASS, Aircraft.Wing.MASS_SCALER] = ( - total_wing_wt / GRAV_ENGLISH_LBM - ) - J[Aircraft.Design.STRUCTURE_MASS, Aircraft.Wing.MASS] = CK8 - J[Aircraft.Design.STRUCTURE_MASS, Aircraft.HorizontalTail.MASS_SCALER] = ( - htail_wt / GRAV_ENGLISH_LBM - ) - J[Aircraft.Design.STRUCTURE_MASS, Aircraft.HorizontalTail.MASS] = CK9 - J[Aircraft.Design.STRUCTURE_MASS, Aircraft.VerticalTail.MASS_SCALER] = ( - vtail_wt / GRAV_ENGLISH_LBM - ) - J[Aircraft.Design.STRUCTURE_MASS, Aircraft.VerticalTail.MASS] = CK10 - J[Aircraft.Design.STRUCTURE_MASS, Aircraft.Fuselage.MASS_SCALER] = fus_wt / GRAV_ENGLISH_LBM - J[Aircraft.Design.STRUCTURE_MASS, Aircraft.Fuselage.MASS] = CK11 - J[Aircraft.Design.STRUCTURE_MASS, Aircraft.LandingGear.TOTAL_MASS_SCALER] = ( - landing_gear_wt / GRAV_ENGLISH_LBM - ) - J[Aircraft.Design.STRUCTURE_MASS, Aircraft.LandingGear.TOTAL_MASS] = CK12 - J[Aircraft.Design.STRUCTURE_MASS, Aircraft.Engine.POD_MASS_SCALER] = ( - sec_wt / GRAV_ENGLISH_LBM - ) - J[Aircraft.Design.STRUCTURE_MASS, Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS] = CK14 - J[Aircraft.Design.STRUCTURE_MASS, Aircraft.Design.STRUCTURAL_MASS_INCREMENT] = 1 - class FuelMass(om.ExplicitComponent): """ @@ -1381,18 +1169,9 @@ class FuelMass(om.ExplicitComponent): """ def setup(self): - add_aviary_input(self, Aircraft.Design.STRUCTURE_MASS, units='lbm') add_aviary_input(self, Aircraft.Fuel.FUEL_SYSTEM_MASS, units='lbm') add_aviary_input(self, Aircraft.Design.GROSS_MASS, units='lbm') - self.add_input( - 'eng_comb_mass', - val=14371.0, - units='lbm', - desc='WPSTAR: mass of dry engine and engine installation. Includes mass of electrical augmentation system.', - ) - add_aviary_input(self, Aircraft.Controls.MASS, units='lbm') - add_aviary_input(self, Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, units='lbm') - add_aviary_input(self, Mission.USEFUL_LOAD, units='lbm') + add_aviary_input(self, Mission.OPERATING_MASS, units='lbm') self.add_input('payload_mass_des', val=36000, units='lbm', desc='WPLDES: design payload') add_aviary_input(self, Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, units='unitless') add_aviary_input(self, Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, units='unitless') @@ -1408,7 +1187,6 @@ def setup(self): add_aviary_input(self, Aircraft.Fuel.VOLUME_MARGIN, units='unitless') self.add_output('fuel_mass', units='lbm', desc='WFADES') - add_aviary_output(self, Aircraft.Propulsion.MASS, units='lbm', desc='WP') self.add_output('fuel_mass_required', units='lbm', desc='WFAREQ') self.add_output( 'fuel_mass_min', @@ -1422,31 +1200,20 @@ def setup_partials(self): 'fuel_mass', [ Aircraft.Design.GROSS_MASS, - 'eng_comb_mass', - Aircraft.Design.STRUCTURE_MASS, - Aircraft.Controls.MASS, - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, - Mission.USEFUL_LOAD, + Mission.OPERATING_MASS, 'payload_mass_des', Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, Aircraft.Fuel.DENSITY, Aircraft.Fuel.VOLUME_MARGIN, + Aircraft.Fuel.FUEL_SYSTEM_MASS, ], ) - self.declare_partials( - Aircraft.Propulsion.MASS, ['eng_comb_mass', Aircraft.Fuel.FUEL_SYSTEM_MASS], val=1 - ) self.declare_partials('fuel_mass_required', [Aircraft.Design.GROSS_MASS], val=1) self.declare_partials( 'fuel_mass_required', [ - 'eng_comb_mass', - Aircraft.Design.STRUCTURE_MASS, - Aircraft.Controls.MASS, - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, - Mission.USEFUL_LOAD, - Aircraft.Fuel.FUEL_SYSTEM_MASS, + Mission.OPERATING_MASS, 'payload_mass_des', ], val=-1, @@ -1455,25 +1222,16 @@ def setup_partials(self): self.declare_partials( 'fuel_mass_min', [ - 'eng_comb_mass', - Aircraft.Design.STRUCTURE_MASS, - Aircraft.Controls.MASS, - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, - Mission.USEFUL_LOAD, + Mission.OPERATING_MASS, 'payload_mass_max', - Aircraft.Fuel.FUEL_SYSTEM_MASS, ], val=-1, ) def compute(self, inputs, outputs): - struct_wt = inputs[Aircraft.Design.STRUCTURE_MASS] * GRAV_ENGLISH_LBM fuel_sys_wt = inputs[Aircraft.Fuel.FUEL_SYSTEM_MASS] * GRAV_ENGLISH_LBM gross_wt_initial = inputs[Aircraft.Design.GROSS_MASS] * GRAV_ENGLISH_LBM - eng_comb_wt = inputs['eng_comb_mass'] * GRAV_ENGLISH_LBM - control_wt = inputs[Aircraft.Controls.MASS] * GRAV_ENGLISH_LBM - fixed_equip_wt = inputs[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS] * GRAV_ENGLISH_LBM - useful_wt = inputs[Mission.USEFUL_LOAD] * GRAV_ENGLISH_LBM + OEW = inputs[Mission.OPERATING_MASS] * GRAV_ENGLISH_LBM payload_wt_des = inputs['payload_mass_des'] * GRAV_ENGLISH_LBM CK21 = inputs[Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER] c_mass_trend_fuel_sys = inputs[Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT] @@ -1483,47 +1241,17 @@ def compute(self, inputs, outputs): # GASP code is updated later than the following formula. outputs['fuel_mass'] = ( - ( - gross_wt_initial - - eng_comb_wt - - struct_wt - - control_wt - - fixed_equip_wt - - useful_wt - - payload_wt_des - ) + (gross_wt_initial - OEW + fuel_sys_wt - payload_wt_des) / (1.0 + CK21 * c_mass_trend_fuel_sys * (1 + fuel_margin / 100) * 6.687 / rho_fuel) / GRAV_ENGLISH_LBM ) - outputs[Aircraft.Propulsion.MASS] = (eng_comb_wt + fuel_sys_wt) / GRAV_ENGLISH_LBM - outputs['fuel_mass_required'] = ( - gross_wt_initial - - eng_comb_wt - - struct_wt - - control_wt - - fixed_equip_wt - - useful_wt - - payload_wt_des - - fuel_sys_wt - ) / GRAV_ENGLISH_LBM - outputs['fuel_mass_min'] = ( - gross_wt_initial - - eng_comb_wt - - struct_wt - - control_wt - - fixed_equip_wt - - useful_wt - - payload_wt_max - - fuel_sys_wt - ) / GRAV_ENGLISH_LBM + outputs['fuel_mass_required'] = (gross_wt_initial - OEW - payload_wt_des) / GRAV_ENGLISH_LBM + outputs['fuel_mass_min'] = (gross_wt_initial - OEW - payload_wt_max) / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): - struct_wt = inputs[Aircraft.Design.STRUCTURE_MASS] * GRAV_ENGLISH_LBM + fuel_sys_wt = inputs[Aircraft.Fuel.FUEL_SYSTEM_MASS] * GRAV_ENGLISH_LBM gross_wt_initial = inputs[Aircraft.Design.GROSS_MASS] * GRAV_ENGLISH_LBM - eng_comb_wt = inputs['eng_comb_mass'] * GRAV_ENGLISH_LBM - control_wt = inputs[Aircraft.Controls.MASS] * GRAV_ENGLISH_LBM - fixed_equip_wt = inputs[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS] * GRAV_ENGLISH_LBM - useful_wt = inputs[Mission.USEFUL_LOAD] * GRAV_ENGLISH_LBM + OEW = inputs[Mission.OPERATING_MASS] * GRAV_ENGLISH_LBM payload_wt_des = inputs['payload_mass_des'] * GRAV_ENGLISH_LBM CK21 = inputs[Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER] c_mass_trend_fuel_sys = inputs[Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT] @@ -1533,34 +1261,17 @@ def compute_partials(self, inputs, J): J['fuel_mass', Aircraft.Design.GROSS_MASS] = 1 / ( 1.0 + CK21 * c_mass_trend_fuel_sys * (1 + fuel_margin / 100) * 6.687 / rho_fuel ) - J['fuel_mass', 'eng_comb_mass'] = -1 / ( + J['fuel_mass', Mission.OPERATING_MASS] = -1 / ( 1.0 + CK21 * c_mass_trend_fuel_sys * (1 + fuel_margin / 100) * 6.687 / rho_fuel ) - J['fuel_mass', Aircraft.Design.STRUCTURE_MASS] = -1 / ( - 1.0 + CK21 * c_mass_trend_fuel_sys * (1 + fuel_margin / 100) * 6.687 / rho_fuel - ) - J['fuel_mass', Aircraft.Controls.MASS] = -1 / ( - 1.0 + CK21 * c_mass_trend_fuel_sys * (1 + fuel_margin / 100) * 6.687 / rho_fuel - ) - J['fuel_mass', Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS] = -1 / ( - 1.0 + CK21 * c_mass_trend_fuel_sys * (1 + fuel_margin / 100) * 6.687 / rho_fuel - ) - J['fuel_mass', Mission.USEFUL_LOAD] = -1 / ( + J['fuel_mass', 'payload_mass_des'] = -1 / ( 1.0 + CK21 * c_mass_trend_fuel_sys * (1 + fuel_margin / 100) * 6.687 / rho_fuel ) - J['fuel_mass', 'payload_mass_des'] = -1 / ( + J['fuel_mass', Aircraft.Fuel.FUEL_SYSTEM_MASS] = 1 / ( 1.0 + CK21 * c_mass_trend_fuel_sys * (1 + fuel_margin / 100) * 6.687 / rho_fuel ) J['fuel_mass', Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER] = ( - -( - gross_wt_initial - - eng_comb_wt - - struct_wt - - control_wt - - fixed_equip_wt - - useful_wt - - payload_wt_des - ) + -(gross_wt_initial - OEW + fuel_sys_wt - payload_wt_des) / (1.0 + CK21 * c_mass_trend_fuel_sys * (1 + fuel_margin / 100) * 6.687 / rho_fuel) ** 2 * c_mass_trend_fuel_sys * (1 + fuel_margin / 100) @@ -1569,15 +1280,7 @@ def compute_partials(self, inputs, J): / GRAV_ENGLISH_LBM ) J['fuel_mass', Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT] = ( - -( - gross_wt_initial - - eng_comb_wt - - struct_wt - - control_wt - - fixed_equip_wt - - useful_wt - - payload_wt_des - ) + -(gross_wt_initial - OEW + fuel_sys_wt - payload_wt_des) / (1.0 + CK21 * c_mass_trend_fuel_sys * (1 + fuel_margin / 100) * 6.687 / rho_fuel) ** 2 * CK21 * (1 + fuel_margin / 100) @@ -1586,28 +1289,12 @@ def compute_partials(self, inputs, J): / GRAV_ENGLISH_LBM ) J['fuel_mass', Aircraft.Fuel.DENSITY] = ( - -( - gross_wt_initial - - eng_comb_wt - - struct_wt - - control_wt - - fixed_equip_wt - - useful_wt - - payload_wt_des - ) + -(gross_wt_initial - OEW + fuel_sys_wt - payload_wt_des) / (1.0 + CK21 * c_mass_trend_fuel_sys * (1 + fuel_margin / 100) * 6.687 / rho_fuel) ** 2 * (-CK21 * c_mass_trend_fuel_sys * (1 + fuel_margin / 100) * 6.687 / rho_fuel**2) ) J['fuel_mass', Aircraft.Fuel.VOLUME_MARGIN] = ( - -( - gross_wt_initial - - eng_comb_wt - - struct_wt - - control_wt - - fixed_equip_wt - - useful_wt - - payload_wt_des - ) + -(gross_wt_initial - OEW + fuel_sys_wt - payload_wt_des) / (1.0 + CK21 * c_mass_trend_fuel_sys * (1 + fuel_margin / 100) * 6.687 / rho_fuel) ** 2 * CK21 * c_mass_trend_fuel_sys @@ -1616,83 +1303,3 @@ def compute_partials(self, inputs, J): / rho_fuel / GRAV_ENGLISH_LBM ) - - -class FuelMassGroup(om.Group): - """ - Group of fuel related components including FuelSysAndFullFuselageMass, - FuselageMass, StructMass, FuelMass, FuelAndOEMOutputs, and BodyTankCalculations. - In case of BWB, FuselageMass is replaced by BWBFuselageMass. - """ - - def initialize(self): - add_aviary_option(self, Aircraft.Design.TYPE) - - def setup(self): - design_type = self.options[Aircraft.Design.TYPE] - - self.add_subsystem( - 'sys_and_full_fus', - FuelSysAndFullFuselageMass(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) - - if design_type is AircraftTypes.BLENDED_WING_BODY: - self.add_subsystem( - 'fuselage', - BWBFuselageMass(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) - elif design_type is AircraftTypes.TRANSPORT: - self.add_subsystem( - 'fuselage', - FuselageMass(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) - - self.add_subsystem( - 'struct', - StructMass(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) - - self.add_subsystem( - 'fuel', - FuelMass(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) - - self.add_subsystem( - 'fuel_and_oem', - FuelAndOEMOutputs(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) - - self.add_subsystem( - 'body_tank', - BodyTankCalculations(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) - - newton = self.nonlinear_solver = om.NewtonSolver() - newton.options['atol'] = 1e-9 - newton.options['rtol'] = 1e-9 - newton.options['iprint'] = 2 - newton.options['maxiter'] = 10 - newton.options['solve_subsystems'] = True - newton.options['max_sub_solves'] = 10 - newton.options['err_on_non_converge'] = True - newton.options['reraise_child_analysiserror'] = False - newton.linesearch = om.BoundsEnforceLS() - newton.linesearch.options['bound_enforcement'] = 'scalar' - newton.linesearch.options['iprint'] = -1 - newton.options['err_on_non_converge'] = False - - self.linear_solver = om.DirectSolver(assemble_jac=True) diff --git a/aviary/subsystems/mass/gasp_based/fuel_capacity.py b/aviary/subsystems/mass/gasp_based/fuel_capacity.py index 1fcf71e83c..8db2cc3851 100644 --- a/aviary/subsystems/mass/gasp_based/fuel_capacity.py +++ b/aviary/subsystems/mass/gasp_based/fuel_capacity.py @@ -1,10 +1,9 @@ import openmdao.api as om +from aviary.constants import GRAV_ENGLISH_LBM from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft -from aviary.constants import GRAV_ENGLISH_LBM - class TrappedFuelCapacity(om.ExplicitComponent): """Compute the maximum fuel that can be carried in the fuselage.""" diff --git a/aviary/subsystems/mass/gasp_based/furnishings.py b/aviary/subsystems/mass/gasp_based/furnishings.py index 4a1b5039e3..a079f0819f 100644 --- a/aviary/subsystems/mass/gasp_based/furnishings.py +++ b/aviary/subsystems/mass/gasp_based/furnishings.py @@ -2,10 +2,10 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.math import sigmoidX, dSigmoidXdx, smooth_max, d_smooth_max +from aviary.utils.math import d_smooth_max, dSigmoidXdx, sigmoidX, smooth_max +from aviary.variable_info.enums import GASPEngineType from aviary.variable_info.functions import add_aviary_input, add_aviary_option from aviary.variable_info.variables import Aircraft, Mission -from aviary.variable_info.enums import GASPEngineType def get_num_of_flight_attendent(num_pax): diff --git a/aviary/subsystems/mass/gasp_based/mass_premission.py b/aviary/subsystems/mass/gasp_based/mass_premission.py index 14455be3fa..22d7e7527c 100644 --- a/aviary/subsystems/mass/gasp_based/mass_premission.py +++ b/aviary/subsystems/mass/gasp_based/mass_premission.py @@ -1,14 +1,18 @@ import openmdao.api as om -from aviary.subsystems.mass.gasp_based.design_load import DesignLoadGroup, BWBDesignLoadGroup -from aviary.subsystems.mass.gasp_based.equipment_and_useful_load import ( - EquipAndUsefulLoadMassGroup, - EquipMassSum, - UsefulLoadMass, -) +from aviary.subsystems.mass.gasp_based.design_load import BWBDesignLoadGroup, DesignLoadGroup +from aviary.subsystems.mass.gasp_based.equipment_and_useful_load import EquipAndUsefulLoadMassGroup from aviary.subsystems.mass.gasp_based.fixed import FixedMassGroup -from aviary.subsystems.mass.gasp_based.fuel import FuelMassGroup -from aviary.subsystems.mass.gasp_based.wing import WingMassGroup, BWBWingMassGroup +from aviary.subsystems.mass.gasp_based.fuel import ( + BodyTankCalculations, + BWBFuselageMass, + FuelComponents, + FuelMass, + FuelSysAndFullFuselageMass, + FuselageMass, +) +from aviary.subsystems.mass.gasp_based.mass_summation import MassSummation +from aviary.subsystems.mass.gasp_based.wing import BWBWingMassGroup, WingMassGroup from aviary.variable_info.enums import AircraftTypes from aviary.variable_info.functions import add_aviary_option from aviary.variable_info.variables import Aircraft @@ -23,41 +27,40 @@ def initialize(self): def setup(self): design_type = self.options[Aircraft.Design.TYPE] - # output values from design_load that are connected to fixed_mass via promotion - fixed_mass_design_load_values = ['max_mach', 'min_dive_vel'] + # # output values from design_load that are connected to fixed_mass via promotion + # fixed_mass_design_load_values = ['max_mach', 'min_dive_vel'] - # output values from fixed_mass that are connected to wing_mass via promotion - wing_mass_fixed_mass_values = [ - 'c_strut_braced', - 'c_gear_loc', - 'half_sweep', - ] + # # output values from fixed_mass that are connected to wing_mass via promotion + # wing_mass_fixed_mass_values = [ + # 'c_strut_braced', + # 'c_gear_loc', + # 'half_sweep', + # ] - # output values from design_load that are connected to fuel_mass via promotion - fuel_mass_design_load_values = ['min_dive_vel'] + # # output values from design_load that are connected to fuel_mass via promotion + # fuel_mass_design_load_values = ['min_dive_vel'] - # output values from fixed_mass that are connected to fuel_mass via promotion - fuel_mass_fixed_mass_values = [ - 'payload_mass_des', - 'payload_mass_max', - 'wing_mounted_mass', - 'eng_comb_mass', - ] + # # output values from fixed_mass that are connected to fuel_mass via promotion + # fuel_mass_fixed_mass_values = [ + # 'payload_mass_des', + # 'payload_mass_max', + # 'wing_mounted_mass', + # 'eng_comb_mass', + # ] - # combine all necessary inputs and outputs for each group + # # combine all necessary inputs and outputs for each group - fixed_mass_inputs = fixed_mass_design_load_values + ['density'] - fixed_mass_outputs = wing_mass_fixed_mass_values + fuel_mass_fixed_mass_values + # fixed_mass_inputs = fixed_mass_design_load_values + ['density'] + # fixed_mass_outputs = wing_mass_fixed_mass_values + fuel_mass_fixed_mass_values - wing_mass_inputs = wing_mass_fixed_mass_values + # wing_mass_inputs = wing_mass_fixed_mass_values - if design_type is AircraftTypes.BLENDED_WING_BODY: - fuel_mass_inputs = fuel_mass_fixed_mass_values - elif design_type is AircraftTypes.TRANSPORT: - fuel_mass_inputs = fuel_mass_design_load_values + fuel_mass_fixed_mass_values + # if design_type is AircraftTypes.BLENDED_WING_BODY: + # fuel_mass_inputs = fuel_mass_fixed_mass_values + # elif design_type is AircraftTypes.TRANSPORT: + # fuel_mass_inputs = fuel_mass_design_load_values + fuel_mass_fixed_mass_values # create the instances of the groups - if design_type is AircraftTypes.BLENDED_WING_BODY: self.add_subsystem( 'design_load', @@ -87,14 +90,6 @@ def setup(self): promotes_outputs=['*'], ) - self.add_subsystem( - 'equip_mass', EquipMassSum(), promotes_inputs=['*'], promotes_outputs=['*'] - ) - - self.add_subsystem( - 'useful_load', UsefulLoadMass(), promotes_inputs=['*'], promotes_outputs=['*'] - ) - if design_type is AircraftTypes.BLENDED_WING_BODY: self.add_subsystem( 'wing_mass', @@ -111,8 +106,67 @@ def setup(self): ) self.add_subsystem( - 'fuel_mass', - FuelMassGroup(), + 'sys_and_full_fus', + FuelSysAndFullFuselageMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) + + if design_type is AircraftTypes.BLENDED_WING_BODY: + self.add_subsystem( + 'fuselage', + BWBFuselageMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + elif design_type is AircraftTypes.TRANSPORT: + self.add_subsystem( + 'fuselage', + FuselageMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + self.add_subsystem( + 'fuel', + FuelMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + self.add_subsystem( + 'fuel_components', + FuelComponents(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + self.add_subsystem( + 'body_tank', + BodyTankCalculations(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + self.add_subsystem( + 'mass_summation', + MassSummation(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + newton = self.nonlinear_solver = om.NewtonSolver() + newton.options['atol'] = 1e-9 + newton.options['rtol'] = 1e-9 + newton.options['iprint'] = 2 + newton.options['maxiter'] = 10 + newton.options['solve_subsystems'] = True + newton.options['max_sub_solves'] = 10 + newton.options['err_on_non_converge'] = True + newton.options['reraise_child_analysiserror'] = False + newton.linesearch = om.BoundsEnforceLS() + newton.linesearch.options['bound_enforcement'] = 'scalar' + newton.linesearch.options['iprint'] = -1 + newton.options['err_on_non_converge'] = False + + self.linear_solver = om.DirectSolver(assemble_jac=True) diff --git a/aviary/subsystems/mass/gasp_based/mass_summation.py b/aviary/subsystems/mass/gasp_based/mass_summation.py new file mode 100644 index 0000000000..3b76909b3d --- /dev/null +++ b/aviary/subsystems/mass/gasp_based/mass_summation.py @@ -0,0 +1,263 @@ +import numpy as np +import openmdao.api as om + +from aviary.variable_info.functions import add_aviary_input, add_aviary_option, add_aviary_output +from aviary.variable_info.variables import Aircraft, Mission + + +class MassSummation(om.Group): + """ + Group to compute top-level mass groups for GASP mass estimation. No new masses are computed + here, just grouping and summing already calculated masses. + """ + + def setup(self): + self.add_subsystem( + 'empennage_mass', EmpennageMass(), promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem( + 'structure_mass', StructureMass(), promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem( + 'propulsion_mass', PropulsionMass(), promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem( + 'systems_and_equipment_mass', + SystemsEquipmentMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + self.add_subsystem( + 'empty_mass_group', EmptyMass(), promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem( + 'useful_load_mass', UsefulLoadMass(), promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem( + 'operating_mass', OperatingMass(), promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem( + 'zero_fuel_mass', ZeroFuelMass(), promotes_inputs=['*'], promotes_outputs=['*'] + ) + + +class EmpennageMass(om.ExplicitComponent): + def setup(self): + add_aviary_input(self, Aircraft.HorizontalTail.MASS, units='lbm') + add_aviary_input(self, Aircraft.VerticalTail.MASS, units='lbm') + + add_aviary_output(self, Aircraft.Design.EMPENNAGE_MASS, units='lbm') + + def setup_partials(self): + self.declare_partials(Aircraft.Design.EMPENNAGE_MASS, '*', val=1) + + def compute(self, inputs, outputs): + htail_mass = inputs[Aircraft.HorizontalTail.MASS] + vtail_mass = inputs[Aircraft.VerticalTail.MASS] + + outputs[Aircraft.Design.EMPENNAGE_MASS] = htail_mass + vtail_mass + + +class StructureMass(om.ExplicitComponent): + def setup(self): + add_aviary_input(self, Aircraft.Design.EMPENNAGE_MASS, units='lbm') + add_aviary_input(self, Aircraft.Fuselage.MASS, units='lbm') + add_aviary_input(self, Aircraft.LandingGear.TOTAL_MASS, units='lbm') + add_aviary_input(self, Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, units='lbm') + add_aviary_input(self, Aircraft.Wing.MASS, units='lbm') + add_aviary_input(self, Aircraft.Design.STRUCTURAL_MASS_INCREMENT, units='lbm') + + add_aviary_output(self, Aircraft.Design.STRUCTURE_MASS, units='lbm') + + def setup_partials(self): + self.declare_partials(Aircraft.Design.STRUCTURE_MASS, '*', val=1) + + def compute(self, inputs, outputs): + empennage_mass = inputs[Aircraft.Design.EMPENNAGE_MASS] + fuselage_mass = inputs[Aircraft.Fuselage.MASS] + landing_gear_mass = inputs[Aircraft.LandingGear.TOTAL_MASS] + pod_mass = inputs[Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS] + wing_mass = inputs[Aircraft.Wing.MASS] + delta_struct_wt = inputs[Aircraft.Design.STRUCTURAL_MASS_INCREMENT] + + outputs[Aircraft.Design.STRUCTURE_MASS] = ( + wing_mass + + empennage_mass + + fuselage_mass + + landing_gear_mass + + pod_mass + + delta_struct_wt + ) + + +class PropulsionMass(om.ExplicitComponent): + def setup(self): + add_aviary_input(self, Aircraft.Fuel.FUEL_SYSTEM_MASS, units='lbm') + # TODO These variables need cleanup, proper names, etc. + # They should probably be removed and we pass the couple individual masses that make it + # up here instead + self.add_input('eng_comb_mass', units='lbm') + self.add_input('prop_mass_all', units='lbm') + add_aviary_input(self, Aircraft.Battery.MASS, units='lbm') + + add_aviary_output(self, Aircraft.Propulsion.MASS, units='lbm') + + def setup_partials(self): + self.declare_partials(Aircraft.Propulsion.MASS, ['*'], val=1) + + def compute(self, inputs, outputs): + fuel_sys_mass = inputs[Aircraft.Fuel.FUEL_SYSTEM_MASS] + eng_comb_mass = inputs['eng_comb_mass'] + prop_mass_all = inputs['prop_mass_all'] + battery_mass = inputs[Aircraft.Battery.MASS] + + outputs[Aircraft.Propulsion.MASS] = ( + fuel_sys_mass + eng_comb_mass + prop_mass_all + battery_mass + ) + + +class SystemsEquipmentMass(om.ExplicitComponent): + def setup(self): + add_aviary_input(self, Aircraft.AirConditioning.MASS, units='lbm') + add_aviary_input(self, Aircraft.AntiIcing.MASS, units='lbm') + add_aviary_input(self, Aircraft.APU.MASS, units='lbm') + add_aviary_input(self, Aircraft.Avionics.MASS, units='lbm') + add_aviary_input(self, Aircraft.Electrical.MASS, units='lbm') + add_aviary_input(self, Aircraft.Furnishings.MASS, units='lbm') + add_aviary_input(self, Aircraft.Hydraulics.MASS, units='lbm') + add_aviary_input(self, Aircraft.Instruments.MASS, units='lbm') + add_aviary_input(self, Aircraft.Controls.MASS, units='lbm') + add_aviary_input(self, Aircraft.OxygenSystem.MASS, units='lbm') + + add_aviary_output(self, Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, units='lbm') + + def setup_partials(self): + self.declare_partials(Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, '*', val=1) + + def compute(self, inputs, outputs): + AC_mass = inputs[Aircraft.AirConditioning.MASS] + anti_icing_mass = inputs[Aircraft.AntiIcing.MASS] + APU_mass = inputs[Aircraft.APU.MASS] + avionics_mass = inputs[Aircraft.Avionics.MASS] + elec_mass = inputs[Aircraft.Electrical.MASS] + furnish_mass = inputs[Aircraft.Furnishings.MASS] + hydraulics_mass = inputs[Aircraft.Hydraulics.MASS] + instrument_mass = inputs[Aircraft.Instruments.MASS] + controls_mass = inputs[Aircraft.Controls.MASS] + oxygen_mass = inputs[Aircraft.OxygenSystem.MASS] + + outputs[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS] = ( + APU_mass + + instrument_mass + + hydraulics_mass + + elec_mass + + avionics_mass + + furnish_mass + + AC_mass + + anti_icing_mass + + controls_mass + + oxygen_mass + ) + + +class EmptyMass(om.ExplicitComponent): + def setup(self): + add_aviary_input(self, Aircraft.Design.STRUCTURE_MASS, units='lbm') + add_aviary_input(self, Aircraft.Propulsion.MASS, units='lbm') + add_aviary_input(self, Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, units='lbm') + add_aviary_input(self, Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS, units='lbm') + + add_aviary_output(self, Aircraft.Design.EMPTY_MASS, units='lbm') + + def setup_partials(self): + self.declare_partials(Aircraft.Design.EMPTY_MASS, '*', val=1) + + def compute(self, inputs, outputs): + structure_mass = inputs[Aircraft.Design.STRUCTURE_MASS] + prop_mass = inputs[Aircraft.Propulsion.MASS] + sys_equip_mass = inputs[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS] + subsystems_mass = inputs[Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS] + + outputs[Aircraft.Design.EMPTY_MASS] = ( + structure_mass + prop_mass + sys_equip_mass + subsystems_mass + ) + + +class UsefulLoadMass(om.ExplicitComponent): + def setup(self): + add_aviary_input(self, Aircraft.CrewPayload.CARGO_CONTAINER_MASS, units='lbm') + add_aviary_input(self, Aircraft.CrewPayload.CABIN_CREW_MASS, units='lbm') + add_aviary_input(self, Aircraft.CrewPayload.FLIGHT_CREW_MASS, units='lbm') + add_aviary_input(self, Aircraft.CrewPayload.PASSENGER_SERVICE_MASS, units='lbm') + add_aviary_input(self, Aircraft.Fuel.UNUSABLE_FUEL_MASS, units='lbm') + add_aviary_input(self, Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS, units='lbm') + add_aviary_input(self, Aircraft.Design.EMERGENCY_EQUIPMENT_MASS) + + add_aviary_output(self, Mission.USEFUL_LOAD, units='lbm') + + def setup_partials(self): + self.declare_partials(Mission.USEFUL_LOAD, '*', val=1) + + def compute(self, inputs, outputs): + cargo_container_mass = inputs[Aircraft.CrewPayload.CARGO_CONTAINER_MASS] + cabin_crew_mass = inputs[Aircraft.CrewPayload.CABIN_CREW_MASS] + flight_crew_mass = inputs[Aircraft.CrewPayload.FLIGHT_CREW_MASS] + oil_mass = inputs[Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS] + pass_service_mass = inputs[Aircraft.CrewPayload.PASSENGER_SERVICE_MASS] + unusable_fuel_mass = inputs[Aircraft.Fuel.UNUSABLE_FUEL_MASS] + emergency_equip_mass = inputs[Aircraft.Design.EMERGENCY_EQUIPMENT_MASS] + + outputs[Mission.USEFUL_LOAD] = ( + cabin_crew_mass + + flight_crew_mass + + unusable_fuel_mass + + oil_mass + + pass_service_mass + + cargo_container_mass + + emergency_equip_mass + ) + + +class OperatingMass(om.ExplicitComponent): + def setup(self): + add_aviary_input(self, Aircraft.Design.EMPTY_MASS, units='lbm') + add_aviary_input(self, Mission.USEFUL_LOAD, units='lbm') + + add_aviary_output(self, Mission.OPERATING_MASS, units='lbm') + + def setup_partials(self): + self.declare_partials(Mission.OPERATING_MASS, '*', val=1) + + def compute(self, inputs, outputs): + useful_load = inputs[Mission.USEFUL_LOAD] + empty_mass = inputs[Aircraft.Design.EMPTY_MASS] + + outputs[Mission.OPERATING_MASS] = empty_mass + useful_load + + +class ZeroFuelMass(om.ExplicitComponent): + def setup(self): + add_aviary_input(self, Aircraft.CrewPayload.PASSENGER_MASS_TOTAL, units='lbm') + add_aviary_input(self, Aircraft.CrewPayload.BAGGAGE_MASS, units='lbm') + add_aviary_input(self, Aircraft.CrewPayload.CARGO_MASS, units='lbm') + add_aviary_input(self, Mission.OPERATING_MASS, units='lbm') + + add_aviary_output(self, Mission.ZERO_FUEL_MASS, units='lbm') + + def setup_partials(self): + self.declare_partials(Mission.ZERO_FUEL_MASS, '*', val=1) + + def compute(self, inputs, outputs): + pass_mass = inputs[Aircraft.CrewPayload.PASSENGER_MASS_TOTAL] + bag_mass = inputs[Aircraft.CrewPayload.BAGGAGE_MASS] + cargo_mass = inputs[Aircraft.CrewPayload.CARGO_MASS] + operating_mass = inputs[Mission.OPERATING_MASS] + + outputs[Mission.ZERO_FUEL_MASS] = operating_mass + pass_mass + bag_mass + cargo_mass diff --git a/aviary/subsystems/mass/gasp_based/oxygen_system.py b/aviary/subsystems/mass/gasp_based/oxygen_system.py index 5d0b980445..b3891520eb 100644 --- a/aviary/subsystems/mass/gasp_based/oxygen_system.py +++ b/aviary/subsystems/mass/gasp_based/oxygen_system.py @@ -1,7 +1,7 @@ import openmdao.api as om from aviary.constants import GRAV_ENGLISH_LBM -from aviary.utils.math import sigmoidX, dSigmoidXdx +from aviary.utils.math import dSigmoidXdx, sigmoidX from aviary.variable_info.functions import add_aviary_input, add_aviary_option, add_aviary_output from aviary.variable_info.variables import Aircraft, Mission diff --git a/aviary/subsystems/mass/gasp_based/test/test_air_conditioning.py b/aviary/subsystems/mass/gasp_based/test/test_air_conditioning.py index 10b1dccf36..69af215710 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_air_conditioning.py +++ b/aviary/subsystems/mass/gasp_based/test/test_air_conditioning.py @@ -4,7 +4,6 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.mass.gasp_based.air_conditioning import ACMass, BWBACMass - from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission diff --git a/aviary/subsystems/mass/gasp_based/test/test_anti_icing.py b/aviary/subsystems/mass/gasp_based/test/test_anti_icing.py index cd0cf03cbf..b261ad7046 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_anti_icing.py +++ b/aviary/subsystems/mass/gasp_based/test/test_anti_icing.py @@ -4,7 +4,6 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.mass.gasp_based.anti_icing import AntiIcingMass - from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft diff --git a/aviary/subsystems/mass/gasp_based/test/test_apu.py b/aviary/subsystems/mass/gasp_based/test/test_apu.py index 9f9695f597..55658cad33 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_apu.py +++ b/aviary/subsystems/mass/gasp_based/test/test_apu.py @@ -4,7 +4,6 @@ from openmdao.utils.assert_utils import assert_near_equal from aviary.subsystems.mass.gasp_based.apu import APUMass - from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft diff --git a/aviary/subsystems/mass/gasp_based/test/test_avionics.py b/aviary/subsystems/mass/gasp_based/test/test_avionics.py index 40d4b4d077..6dcc6b03da 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_avionics.py +++ b/aviary/subsystems/mass/gasp_based/test/test_avionics.py @@ -4,7 +4,6 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.mass.gasp_based.avionics import AvionicsMass - from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission diff --git a/aviary/subsystems/mass/gasp_based/test/test_cargo.py b/aviary/subsystems/mass/gasp_based/test/test_cargo_containers.py similarity index 84% rename from aviary/subsystems/mass/gasp_based/test/test_cargo.py rename to aviary/subsystems/mass/gasp_based/test/test_cargo_containers.py index 4627cf90b3..367006d7db 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_cargo.py +++ b/aviary/subsystems/mass/gasp_based/test/test_cargo_containers.py @@ -3,15 +3,14 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal -from aviary.subsystems.mass.gasp_based.cargo import CargoMass - +from aviary.subsystems.mass.gasp_based.cargo_containers import CargoContainerMass from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft class CargoTestCase1(unittest.TestCase): - """this is the large single aisle 1 V3 test case""" + """this is the large single aisle 1 V3 test case.""" def setUp(self): options = get_option_defaults() @@ -25,7 +24,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( 'cargo', - CargoMass(), + CargoContainerMass(), promotes=['*'], ) @@ -44,7 +43,7 @@ def test_case1(self): class CargoTestCase2(unittest.TestCase): - """this is the large single aisle 1 V3 test case""" + """this is the large single aisle 1 V3 test case.""" def setUp(self): options = get_option_defaults() @@ -58,22 +57,22 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( 'cargo', - CargoMass(), + CargoContainerMass(), promotes=['*'], ) - import aviary.subsystems.mass.gasp_based.cargo as cargo + import aviary.subsystems.mass.gasp_based.cargo_containers as cargo_containers - cargo.GRAV_ENGLISH_LBM = 1.1 + cargo_containers.GRAV_ENGLISH_LBM = 1.1 setup_model_options(self.prob, options) self.prob.setup(check=False, force_alloc_complex=True) def tearDown(self): - import aviary.subsystems.mass.gasp_based.cargo as cargo + import aviary.subsystems.mass.gasp_based.cargo_containers as cargo_containers - cargo.GRAV_ENGLISH_LBM = 1.0 + cargo_containers.GRAV_ENGLISH_LBM = 1.0 def test_case1(self): self.prob.run_model() @@ -86,7 +85,7 @@ def test_case1(self): class CargoTestCase3(unittest.TestCase): - """BWB Parameters""" + """BWB Parameters.""" def setUp(self): options = get_option_defaults() @@ -100,7 +99,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( 'cargo', - CargoMass(), + CargoContainerMass(), promotes=['*'], ) diff --git a/aviary/subsystems/mass/gasp_based/test/test_crew.py b/aviary/subsystems/mass/gasp_based/test/test_crew.py index 2468bd24c1..e0dd6e17d1 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_crew.py +++ b/aviary/subsystems/mass/gasp_based/test/test_crew.py @@ -3,8 +3,7 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal -from aviary.subsystems.mass.gasp_based.crew import FlightCrewMass, NonFlightCrewMass - +from aviary.subsystems.mass.gasp_based.crew import CabinCrewMass, FlightCrewMass from aviary.variable_info.enums import GASPEngineType from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults @@ -12,7 +11,7 @@ class CrewTestCase1(unittest.TestCase): - """this is the large single aisle 1 V3 test case""" + """this is the large single aisle 1 V3 test case.""" def setUp(self): options = get_option_defaults() @@ -26,7 +25,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( 'non_flight_crew', - NonFlightCrewMass(), + CabinCrewMass(), promotes=['*'], ) @@ -56,7 +55,7 @@ def test_case1(self): class CrewTestCase2(unittest.TestCase): - """Gravity Modification Test""" + """Gravity Modification Test.""" def setUp(self): options = get_option_defaults() @@ -70,7 +69,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( 'non_flight_crew', - NonFlightCrewMass(), + CabinCrewMass(), promotes=['*'], ) @@ -109,7 +108,7 @@ def test_case1(self): class CrewTestCase3(unittest.TestCase): - """BWB Parameters""" + """BWB Parameters.""" def setUp(self): options = get_option_defaults() @@ -123,7 +122,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( 'non_flight_crew', - NonFlightCrewMass(), + CabinCrewMass(), promotes=['*'], ) 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 9d4d93c7d0..990c72cb1f 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_design_load.py +++ b/aviary/subsystems/mass/gasp_based/test/test_design_load.py @@ -5,17 +5,15 @@ from openmdao.utils.testing_utils import use_tempdirs from aviary.subsystems.mass.gasp_based.design_load import ( + BWBDesignLoadGroup, + BWBLoadFactors, + BWBLoadSpeeds, DesignLoadGroup, LiftCurveSlopeAtCruise, LoadFactors, LoadParameters, LoadSpeeds, ) -from aviary.subsystems.mass.gasp_based.design_load import ( - BWBDesignLoadGroup, - BWBLoadFactors, - BWBLoadSpeeds, -) from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission diff --git a/aviary/subsystems/mass/gasp_based/test/test_electrical.py b/aviary/subsystems/mass/gasp_based/test/test_electrical.py index 6940c60c44..a5f2700c8b 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_electrical.py +++ b/aviary/subsystems/mass/gasp_based/test/test_electrical.py @@ -4,7 +4,6 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.mass.gasp_based.electrical import ElectricalMass - from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission diff --git a/aviary/subsystems/mass/gasp_based/test/test_emergency_equipment.py b/aviary/subsystems/mass/gasp_based/test/test_emergency_equipment.py index 93e1868d47..70e0a0a494 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_emergency_equipment.py +++ b/aviary/subsystems/mass/gasp_based/test/test_emergency_equipment.py @@ -4,7 +4,6 @@ from openmdao.utils.assert_utils import assert_near_equal from aviary.subsystems.mass.gasp_based.emergency_equipment import EmergencyEquipment - from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft diff --git a/aviary/subsystems/mass/gasp_based/test/test_engine_oil.py b/aviary/subsystems/mass/gasp_based/test/test_engine_oil.py index 8f5c42bf95..3f00df5c93 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_engine_oil.py +++ b/aviary/subsystems/mass/gasp_based/test/test_engine_oil.py @@ -4,7 +4,6 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.mass.gasp_based.engine_oil import EngineOilMass - from aviary.variable_info.enums import GASPEngineType, Verbosity from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults 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 a8103686f6..753f287439 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 @@ -6,20 +6,18 @@ from aviary.subsystems.mass.gasp_based.equipment_and_useful_load import ( BWBEquipMassGroup, - EquipMassSum, + EquipAndUsefulLoadMassGroup, EquipMassGroup, - UsefulLoadMass, UsefulLoadMassGroup, - EquipAndUsefulLoadMassGroup, ) - +from aviary.subsystems.mass.gasp_based.mass_summation import SystemsEquipmentMass, UsefulLoadMass from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission, Settings -class FixedEquipMassTestCase1(unittest.TestCase): - """this is the large single aisle 1 V3 test case""" +class EquipmentMassSummationTest(unittest.TestCase): + """this is the large single aisle 1 V3 test case.""" def setUp(self): options = get_option_defaults() @@ -29,7 +27,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( 'equip', - EquipMassSum(), + SystemsEquipmentMass(), promotes=['*'], ) @@ -44,9 +42,6 @@ def setUp(self): self.prob.model.set_input_defaults(Aircraft.Hydraulics.MASS, val=1487.78, units='lbm') self.prob.model.set_input_defaults(Aircraft.Electrical.MASS, val=2231.0, units='lbm') self.prob.model.set_input_defaults(Aircraft.OxygenSystem.MASS, val=50, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.Design.EXTERNAL_SUBSYSTEMS_MASS, val=0.0, units='lbm' - ) setup_model_options(self.prob, options) @@ -62,8 +57,8 @@ def test_case1(self): assert_check_partials(partial_data, atol=8e-12, rtol=1e-12) -class FixedEquipMassGroupTest(unittest.TestCase): - """this is the large single aisle 1 V3 test case""" +class EquipMassGroupTest(unittest.TestCase): + """this is the large single aisle 1 V3 test case.""" def setUp(self): options = get_option_defaults() @@ -129,8 +124,8 @@ def test_case1(self): assert_check_partials(partial_data, atol=8e-12, rtol=1e-12) -class UsefulMassTestCase1(unittest.TestCase): - """this is the large single aisle 1 V3 test case""" +class UsefulMassSumTest(unittest.TestCase): + """this is the large single aisle 1 V3 test case.""" def setUp(self): options = get_option_defaults() @@ -181,7 +176,7 @@ def test_case1(self): class UsefulMassGroupTest(unittest.TestCase): - """this is the large single aisle 1 V3 test case""" + """this is the large single aisle 1 V3 test case.""" def setUp(self): options = get_option_defaults() @@ -236,7 +231,7 @@ def test_case1(self): class FixedEquipAndUsefulMassGroupTest(unittest.TestCase): - """this is the large single aisle 1 V3 test case""" + """this is the large single aisle 1 V3 test case.""" def setUp(self): options = get_option_defaults() @@ -330,7 +325,7 @@ def test_case1(self): @use_tempdirs class BWBFixedEquipMassGroupTest(unittest.TestCase): - """Created based on GASP BWB model""" + """Created based on GASP BWB model.""" def setUp(self): options = get_option_defaults() @@ -393,10 +388,8 @@ def test_case1(self): assert_check_partials(partial_data, atol=8e-12, rtol=1e-12) -class BWBUsefulMassTestCase1(unittest.TestCase): - """ - Created based on GASP BWB modele - """ +class BWBUsefulMassSumTest(unittest.TestCase): + """Created based on GASP BWB model.""" def setUp(self): options = get_option_defaults() @@ -446,7 +439,7 @@ def test_case1(self): @use_tempdirs class BWBFixedEquipAndUsefulMassGroupTest(unittest.TestCase): - """this is the large single aisle 1 V3 test case""" + """this is the large single aisle 1 V3 test case.""" def setUp(self): options = get_option_defaults() diff --git a/aviary/subsystems/mass/gasp_based/test/test_fixed.py b/aviary/subsystems/mass/gasp_based/test/test_fixed.py index d997da103c..65c3b9e9ed 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_fixed.py +++ b/aviary/subsystems/mass/gasp_based/test/test_fixed.py @@ -12,8 +12,8 @@ ElectricAugmentationMass, EngineMass, FixedMassGroup, - GearMass, HighLiftMass, + LandingGearMassGroup, MassParameters, PayloadGroup, TailMass, @@ -446,7 +446,7 @@ def test_case1(self): expected_values = { Aircraft.Propulsion.TOTAL_ENGINE_MASS: 12606.0, - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS: 3785.0, + # Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS: 3785.0, Aircraft.Engine.ADDITIONAL_MASS: 1765.0 / 2, 'eng_comb_mass': 14370.8, 'wing_mounted_mass': 24446.343040697346, @@ -497,7 +497,7 @@ def setUp(self): Aircraft.Propulsion.MISC_MASS_SCALER, val=1, units='unitless' ) # bug fixed value and original value self.prob.model.set_input_defaults( - 'prop_mass', val=0, units='lbm' + Aircraft.Engine.Propeller.MASS, val=0, units='lbm' ) # bug fixed value and original value self.prob.model.set_input_defaults( 'aug_mass', val=0, units='lbm' @@ -521,7 +521,7 @@ def test_case1(self): expected_values = { Aircraft.Propulsion.TOTAL_ENGINE_MASS: 12606.0, - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS: 3785.0, + # Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS: 3785.0, Aircraft.Engine.ADDITIONAL_MASS: 1765.0 / 2, 'eng_comb_mass': 14370.8, 'prop_mass_all': 0, @@ -595,7 +595,7 @@ def test_case_1(self): tol = 5e-4 expected_values = { Aircraft.Propulsion.TOTAL_ENGINE_MASS: 23405.94, - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS: 8074.09809932, + # Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS: 8074.09809932, Aircraft.Engine.ADDITIONAL_MASS: [882.4158, 513.0], 'eng_comb_mass': 26142.7716, 'wing_mounted_mass': 41417.49593562, @@ -824,7 +824,7 @@ def test_case1(self): class GearTestCase1(unittest.TestCase): # this is the large single aisle 1 V3 test case def setUp(self): self.prob = om.Problem() - self.prob.model.add_subsystem('gear_mass', GearMass(), promotes=['*']) + self.prob.model.add_subsystem('gear_mass', LandingGearMassGroup(), promotes=['*']) self.prob.model.set_input_defaults( Aircraft.LandingGear.MASS_COEFFICIENT, val=0.04, units='unitless' @@ -833,7 +833,7 @@ def setUp(self): Aircraft.Design.GROSS_MASS, val=175400, units='lbm' ) # bug fixed value and original value self.prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, val=0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, val=0.85, units='unitless' ) # bug fixed value and original value self.prob.model.set_input_defaults( Aircraft.Nacelle.CLEARANCE_RATIO, val=0.2, units='unitless' @@ -873,7 +873,7 @@ class GearTestCase2(unittest.TestCase): def setUp(self): options = get_option_defaults() self.prob = om.Problem() - self.prob.model.add_subsystem('gear_mass', GearMass(), promotes=['*']) + self.prob.model.add_subsystem('gear_mass', LandingGearMassGroup(), promotes=['*']) self.prob.model.set_input_defaults( Aircraft.LandingGear.MASS_COEFFICIENT, val=0.04, units='unitless' @@ -882,7 +882,7 @@ def setUp(self): Aircraft.Design.GROSS_MASS, val=175400, units='lbm' ) # bug fixed value and original value self.prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, val=0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, val=0.85, units='unitless' ) # bug fixed value and original value self.prob.model.set_input_defaults( Aircraft.Wing.VERTICAL_MOUNT_LOCATION, val=0.1, units='unitless' @@ -919,7 +919,7 @@ def test_case1(self): self.prob = om.Problem() self.prob.model.add_subsystem( 'gear_mass', - GearMass(), + LandingGearMassGroup(), promotes=['*'], ) @@ -930,9 +930,7 @@ def test_case1(self): Aircraft.Nacelle.AVG_DIAMETER, val=[7.5, 8.22], units='ft' ) self.prob.model.set_input_defaults(Aircraft.LandingGear.MASS_COEFFICIENT, val=0.04) - self.prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, val=0.85 - ) + self.prob.model.set_input_defaults(Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, val=0.85) self.prob.model.set_input_defaults(Aircraft.Design.GROSS_MASS, val=152000) self.prob.model_options['*'] = extract_options(options) @@ -1099,7 +1097,7 @@ def setUp(self): Aircraft.LandingGear.MASS_COEFFICIENT, val=0.04, units='unitless' ) # bug fixed value and original value self.prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, val=0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, val=0.85, units='unitless' ) # bug fixed value and original value self.prob.model.set_input_defaults( Aircraft.Nacelle.CLEARANCE_RATIO, val=0.2, units='unitless' @@ -1164,7 +1162,7 @@ def test_case1(self): Aircraft.Controls.MASS: 3945, Aircraft.LandingGear.TOTAL_MASS: 7511, Aircraft.Propulsion.TOTAL_ENGINE_MASS: 12606, - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS: 3785, + # Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS: 3785, Aircraft.Engine.ADDITIONAL_MASS: 1765 / 2, 'eng_comb_mass': 14370.8, 'wing_mounted_mass': 24446.343040697346, @@ -1330,7 +1328,7 @@ def setUp(self): Aircraft.LandingGear.MASS_COEFFICIENT, val=0.04, units='unitless' ) # bug fixed value and original value self.prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, val=0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, val=0.85, units='unitless' ) # bug fixed value and original value self.prob.model.set_input_defaults( @@ -1410,7 +1408,7 @@ def setUp(self): Aircraft.LandingGear.MAIN_GEAR_LOCATION, val=0.15, units='unitless' ) # bug fixed value and original value self.prob.model.set_input_defaults( - 'prop_mass', val=0, units='lbm' + Aircraft.Engine.Propeller.MASS, val=0, units='lbm' ) # bug fixed value and original value self.prob.model.set_input_defaults(Aircraft.Fuselage.AVG_DIAMETER, val=13.1) self.prob.model.set_input_defaults(Aircraft.Wing.SLAT_CHORD_RATIO, val=0.15) @@ -1445,7 +1443,7 @@ def test_case1(self): Aircraft.Controls.MASS: 3895, Aircraft.LandingGear.TOTAL_MASS: 7016, Aircraft.Propulsion.TOTAL_ENGINE_MASS: 12606, - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS: 3785, + # Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS: 3785, Aircraft.Engine.ADDITIONAL_MASS: 1765 / 2, 'eng_comb_mass': 14599.28196478, 'wing_mounted_mass': 24027.6, @@ -1557,7 +1555,7 @@ def test_case1(self): Aircraft.Engine.MASS_SCALER: (np.array([1.05]), 'unitless'), Aircraft.Propulsion.MISC_MASS_SCALER: (1.06, 'unitless'), Aircraft.Engine.WING_LOCATIONS: (np.array([0.35]), 'unitless'), - 'prop_mass': (0.5, 'lbm'), + Aircraft.Engine.Propeller.MASS: (0.5, 'lbm'), Aircraft.VerticalTail.TAPER_RATIO: (0.26, 'unitless'), Aircraft.VerticalTail.ASPECT_RATIO: (5.0, 'unitless'), Aircraft.VerticalTail.SWEEP: (25.0, 'deg'), @@ -1603,7 +1601,7 @@ def test_case1(self): ), Aircraft.Controls.CONTROL_MASS_INCREMENT: (25.0, 'lbm'), Aircraft.LandingGear.MASS_COEFFICIENT: (1.15, 'unitless'), - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT: (1.16, 'unitless'), + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION: (1.16, 'unitless'), Aircraft.Nacelle.CLEARANCE_RATIO: (0.2, 'unitless'), Aircraft.Nacelle.AVG_DIAMETER: (7.5, 'ft'), } @@ -1751,7 +1749,7 @@ def test_case1(self): Aircraft.Propulsion.TOTAL_ENGINE_MASS: 7005.15475443, Aircraft.Nacelle.MASS: 487.39296691, 'pylon_mass': 558.757916785, - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS: 2092.30176475, + # Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS: 2092.30176475, Aircraft.Engine.ADDITIONAL_MASS: 153.16770871, 'eng_comb_mass': 7311.49017184, 'wing_mounted_mass': 0, @@ -1938,14 +1936,14 @@ class BWBGearTestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() - self.prob.model.add_subsystem('gear_mass', GearMass(), promotes=['*']) + self.prob.model.add_subsystem('gear_mass', LandingGearMassGroup(), promotes=['*']) self.prob.model.set_input_defaults( Aircraft.LandingGear.MASS_COEFFICIENT, 0.0520, units='unitless' ) self.prob.model.set_input_defaults(Aircraft.Design.GROSS_MASS, 150000, units='lbm') self.prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, 0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, 0.85, units='unitless' ) self.prob.model.set_input_defaults(Aircraft.Nacelle.CLEARANCE_RATIO, 0.2, units='unitless') self.prob.model.set_input_defaults(Aircraft.Nacelle.AVG_DIAMETER, 7.35163168, units='ft') @@ -2070,7 +2068,7 @@ def setUp(self): Aircraft.LandingGear.MASS_COEFFICIENT, 0.0520, units='unitless' ) prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, 0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, 0.85, units='unitless' ) prob.model.set_input_defaults(Aircraft.Nacelle.CLEARANCE_RATIO, 0.2, units='unitless') prob.model.set_input_defaults(Aircraft.Nacelle.AVG_DIAMETER, 7.35163168, units='ft') diff --git a/aviary/subsystems/mass/gasp_based/test/test_fuel.py b/aviary/subsystems/mass/gasp_based/test/test_fuel.py index 33ca704420..c3bdc9b52d 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_fuel.py +++ b/aviary/subsystems/mass/gasp_based/test/test_fuel.py @@ -6,13 +6,11 @@ from aviary.subsystems.mass.gasp_based.fuel import ( BodyTankCalculations, - FuelAndOEMOutputs, + BWBFuselageMass, + FuelComponents, FuelMass, - FuelMassGroup, FuelSysAndFullFuselageMass, FuselageMass, - StructMass, - BWBFuselageMass, ) from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.enums import Verbosity @@ -301,9 +299,7 @@ def test_case1(self): class BodyCalculationTestCase7smooth(unittest.TestCase): - """ - It tests the case Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES = True. - """ + """It tests the case Aircraft.Design.SMOOTH_MASS_DISCONTINUITIES = True.""" def setUp(self): self.prob = om.Problem() @@ -346,20 +342,14 @@ def test_case1(self): # this is the large single aisle 1 V3 test case -class FuelAndOEMTestCase(unittest.TestCase): +class FuelComponentsTestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() - self.prob.model.add_subsystem('wing_calcs', FuelAndOEMOutputs(), promotes=['*']) + self.prob.model.add_subsystem('wing_calcs', FuelComponents(), promotes=['*']) self.prob.model.set_input_defaults(Aircraft.Fuel.DENSITY, val=6.687, units='lbm/galUS') self.prob.model.set_input_defaults(Aircraft.Design.GROSS_MASS, val=175400, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Propulsion.MASS, val=16129, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Controls.MASS, val=3895.0, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Design.STRUCTURE_MASS, val=50461.0, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, val=21089.0, units='lbm' - ) - self.prob.model.set_input_defaults(Mission.USEFUL_LOAD, val=4932.0, units='lbm') + self.prob.model.set_input_defaults(Mission.OPERATING_MASS, val=96506, units='lbm') self.prob.model.set_input_defaults('fuel_mass_required', val=42892.0, units='lbm') self.prob.model.set_input_defaults( Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, 1114, units='ft**3' @@ -405,16 +395,10 @@ def tearDown(self): def test_case1(self): prob = om.Problem() - prob.model.add_subsystem('wing_calcs', FuelAndOEMOutputs(), promotes=['*']) + prob.model.add_subsystem('wing_calcs', FuelComponents(), promotes=['*']) prob.model.set_input_defaults(Aircraft.Fuel.DENSITY, val=6.687, units='lbm/galUS') prob.model.set_input_defaults(Aircraft.Design.GROSS_MASS, val=175400, units='lbm') - prob.model.set_input_defaults(Aircraft.Propulsion.MASS, val=16129, units='lbm') - prob.model.set_input_defaults(Aircraft.Controls.MASS, val=3895.0, units='lbm') - prob.model.set_input_defaults(Aircraft.Design.STRUCTURE_MASS, val=50461.0, units='lbm') - prob.model.set_input_defaults( - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, val=21089.0, units='lbm' - ) - prob.model.set_input_defaults(Mission.USEFUL_LOAD, val=4932.0, units='lbm') + prob.model.set_input_defaults(Mission.OPERATING_MASS, val=96506, units='lbm') prob.model.set_input_defaults('fuel_mass_required', val=42892.0, units='lbm') prob.model.set_input_defaults(Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, 1114, units='ft**3') prob.model.set_input_defaults(Aircraft.Fuel.VOLUME_MARGIN, val=0, units='unitless') @@ -542,9 +526,7 @@ def test_case1(self): class FuselageMassTestCase2(unittest.TestCase): - """ - Test mass-weight conversion - """ + """Test mass-weight conversion.""" def setUp(self): import aviary.subsystems.mass.gasp_based.fuel as fuel @@ -583,119 +565,14 @@ def test_case1(self): assert_check_partials(partial_data, atol=1e-11, rtol=1e-12) -# this is the large single aisle 1 V3 test case -class StructMassTestCase1(unittest.TestCase): - def setUp(self): - self.prob = om.Problem() - self.prob.model.add_subsystem('struct', StructMass(), promotes=['*']) - - self.prob.model.set_input_defaults(Aircraft.Fuselage.MASS, val=18763, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Wing.MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults(Aircraft.Wing.MASS, val=15830, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.HorizontalTail.MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.HorizontalTail.MASS, val=2275, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.VerticalTail.MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.VerticalTail.MASS, val=2297, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Fuselage.MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.LandingGear.TOTAL_MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS, val=7511, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Engine.POD_MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, val=3785, units='lbm' - ) - self.prob.model.set_input_defaults( - Aircraft.Design.STRUCTURAL_MASS_INCREMENT, val=0, units='lbm' - ) - - setup_model_options( - self.prob, AviaryValues({Aircraft.Engine.NUM_ENGINES: ([2], 'unitless')}) - ) - - self.prob.setup(check=False, force_alloc_complex=True) - - def test_case1(self): - self.prob.run_model() - - tol = 1e-4 - assert_near_equal(self.prob[Aircraft.Design.STRUCTURE_MASS], 50461.0, tol) - - partial_data = self.prob.check_partials(out_stream=None, method='cs') - assert_check_partials(partial_data, atol=4e-12, rtol=1e-12) - - -class StructMassTestCase2(unittest.TestCase): - """ - Test mass-weight conversion - """ - - def setUp(self): - import aviary.subsystems.mass.gasp_based.fuel as fuel - - fuel.GRAV_ENGLISH_LBM = 1.1 - - def tearDown(self): - import aviary.subsystems.mass.gasp_based.fuel as fuel - - fuel.GRAV_ENGLISH_LBM = 1.0 - - def test_case1(self): - self.prob = om.Problem() - self.prob.model.add_subsystem('struct', StructMass(), promotes=['*']) - - self.prob.model.set_input_defaults(Aircraft.Fuselage.MASS, val=18763, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Wing.MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults(Aircraft.Wing.MASS, val=15830, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.HorizontalTail.MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.HorizontalTail.MASS, val=2275, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.VerticalTail.MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.VerticalTail.MASS, val=2297, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Fuselage.MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.LandingGear.TOTAL_MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS, val=7511, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Engine.POD_MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, val=3785, units='lbm' - ) - self.prob.model.set_input_defaults( - Aircraft.Design.STRUCTURAL_MASS_INCREMENT, val=0, units='lbm' - ) - - setup_model_options( - self.prob, AviaryValues({Aircraft.Engine.NUM_ENGINES: ([2], 'unitless')}) - ) - - self.prob.setup(check=False, force_alloc_complex=True) - - partial_data = self.prob.check_partials(out_stream=None, method='cs') - assert_check_partials(partial_data, atol=1e-11, rtol=1e-12) - - class FuelMassTestCase(unittest.TestCase): # this is the large single aisle 1 V3 test case def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem('fuel', FuelMass(), promotes=['*']) - self.prob.model.set_input_defaults(Aircraft.Design.STRUCTURE_MASS, val=50461.0, units='lbm') self.prob.model.set_input_defaults(Aircraft.Fuel.FUEL_SYSTEM_MASS, val=1759, units='lbm') self.prob.model.set_input_defaults(Aircraft.Design.GROSS_MASS, val=175400, units='lbm') - self.prob.model.set_input_defaults('eng_comb_mass', val=14370.8, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Controls.MASS, val=3895.0, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, val=21089.0, units='lbm' - ) - self.prob.model.set_input_defaults(Mission.USEFUL_LOAD, val=4932.0, units='lbm') + self.prob.model.set_input_defaults(Mission.OPERATING_MASS, val=96506.8, units='lbm') self.prob.model.set_input_defaults('payload_mass_des', val=36000, units='lbm') self.prob.model.set_input_defaults( Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, val=1, units='unitless' @@ -718,7 +595,6 @@ def test_case1(self): tol = 1e-4 assert_near_equal(self.prob['fuel_mass'], 42893, tol) - assert_near_equal(self.prob[Aircraft.Propulsion.MASS], 16129, tol) assert_near_equal(self.prob['fuel_mass_required'], 42892.0, tol) assert_near_equal(self.prob['fuel_mass_min'], 32853, tol) @@ -742,15 +618,9 @@ def tearDown(self): def test_case1(self): prob = om.Problem() prob.model.add_subsystem('fuel', FuelMass(), promotes=['*']) - prob.model.set_input_defaults(Aircraft.Design.STRUCTURE_MASS, val=50461.0, units='lbm') prob.model.set_input_defaults(Aircraft.Fuel.FUEL_SYSTEM_MASS, val=1759, units='lbm') prob.model.set_input_defaults(Aircraft.Design.GROSS_MASS, val=175400, units='lbm') - prob.model.set_input_defaults('eng_comb_mass', val=14370.8, units='lbm') - prob.model.set_input_defaults(Aircraft.Controls.MASS, val=3895.0, units='lbm') - prob.model.set_input_defaults( - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, val=21089.0, units='lbm' - ) - prob.model.set_input_defaults(Mission.USEFUL_LOAD, val=4932.0, units='lbm') + prob.model.set_input_defaults(Mission.OPERATING_MASS, val=94505.8, units='lbm') prob.model.set_input_defaults('payload_mass_des', val=36000, units='lbm') prob.model.set_input_defaults( Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, val=1, units='unitless' @@ -770,431 +640,8 @@ def test_case1(self): assert_check_partials(partial_data, atol=1e-11, rtol=1e-12) -# this is the large single aisle 1 V3 test case -class FuelMassGroupTestCase1(unittest.TestCase): - def setUp(self): - self.prob = om.Problem() - self.prob.model.add_subsystem('group', FuelMassGroup(), promotes=['*']) - - # top level - self.prob.model.set_input_defaults(Aircraft.Design.GROSS_MASS, val=175400, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Wing.MASS, val=15830, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults( - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, val=0.041, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.Fuel.DENSITY, val=6.687, units='lbm/galUS') - self.prob.model.set_input_defaults(Aircraft.Controls.MASS, val=3895, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, val=21089.0, units='lbm' - ) - self.prob.model.set_input_defaults(Mission.USEFUL_LOAD, val=4932, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, 1114.0, units='ft**3' - ) - - # sys and fus - self.prob.model.set_input_defaults('wing_mounted_mass', val=24446.343040697346, units='lbm') - - # fus and struct - self.prob.model.set_input_defaults( - Aircraft.Fuselage.MASS_COEFFICIENT, val=128, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.Fuselage.WETTED_AREA, val=4000, units='ft**2') - self.prob.model.set_input_defaults(Aircraft.Fuselage.AVG_DIAMETER, val=13.1, units='ft') - self.prob.model.set_input_defaults(Aircraft.TailBoom.LENGTH, val=129.4, units='ft') - self.prob.model.set_input_defaults('pylon_len', val=0, units='ft') - self.prob.model.set_input_defaults('min_dive_vel', val=420, units='kn') - self.prob.model.set_input_defaults( - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, val=7.5, units='psi' - ) - self.prob.model.set_input_defaults( - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, val=3.893, units='unitless' - ) - self.prob.model.set_input_defaults('MAT', val=0, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Wing.MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.HorizontalTail.MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.HorizontalTail.MASS, val=2275, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.VerticalTail.MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.VerticalTail.MASS, val=2297, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Fuselage.MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.LandingGear.TOTAL_MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS, val=7511, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Engine.POD_MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, val=3785, units='lbm' - ) - self.prob.model.set_input_defaults(Aircraft.Fuselage.AVG_DIAMETER, val=13.1, units='ft') - self.prob.model.set_input_defaults(Aircraft.TailBoom.LENGTH, val=129.4, units='ft') - self.prob.model.set_input_defaults('pylon_len', val=0, units='ft') - self.prob.model.set_input_defaults('min_dive_vel', val=420, units='kn') - self.prob.model.set_input_defaults( - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, val=7.5, units='psi' - ) - self.prob.model.set_input_defaults( - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, val=3.893, units='unitless' - ) - self.prob.model.set_input_defaults('MAT', val=0, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Wing.MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.HorizontalTail.MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.HorizontalTail.MASS, val=2275, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.VerticalTail.MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.VerticalTail.MASS, val=2297, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Fuselage.MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.LandingGear.TOTAL_MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS, val=7511, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Engine.POD_MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, val=3785, units='lbm' - ) - self.prob.model.set_input_defaults( - Aircraft.Design.STRUCTURAL_MASS_INCREMENT, val=0, units='lbm' - ) - - # fuel - self.prob.model.set_input_defaults('eng_comb_mass', val=14370.8, units='lbm') - self.prob.model.set_input_defaults('payload_mass_des', val=36000, units='lbm') - self.prob.model.set_input_defaults('payload_mass_max', val=46040, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Fuel.VOLUME_MARGIN, val=0, units='unitless') - - setup_model_options( - self.prob, AviaryValues({Aircraft.Engine.NUM_ENGINES: ([2], 'unitless')}) - ) - - self.prob.setup(check=False, force_alloc_complex=True) - - def test_case1(self): - self.prob.run_model() - - tol = 5e-4 - - # wingfuel - assert_near_equal(self.prob['OEM_wingfuel_mass'], 78894, tol) - assert_near_equal(self.prob['OEM_fuel_vol'], 1577.160566039489, tol) - assert_near_equal(self.prob[Mission.OPERATING_MASS], 96508.0, tol) - assert_near_equal( - self.prob['payload_mass_max_fuel'], 36000, tol - ) # note: this is calculated differently in V3, so this is the V3.6 value - assert_near_equal(self.prob['volume_wingfuel_mass'], 55725.1, tol) - assert_near_equal(self.prob['max_wingfuel_mass'], 55725.1, tol) - - # sys and fus - assert_near_equal(self.prob['fus_mass_full'], 102270, tol) - assert_near_equal(self.prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 1759, tol) - - # fus and struct - assert_near_equal(self.prob[Aircraft.Design.STRUCTURE_MASS], 50461.0, tol) - assert_near_equal(self.prob[Aircraft.Fuselage.MASS], 18763, tol) - - # fuel - assert_near_equal(self.prob['fuel_mass'], 42893, tol) - assert_near_equal(self.prob[Aircraft.Propulsion.MASS], 16129, tol) - assert_near_equal(self.prob['fuel_mass_required'], 42892.0, tol) - assert_near_equal(self.prob['fuel_mass_min'], 32853, tol) - - # body tank - assert_near_equal( - self.prob[Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY], 0, tol - ) # note: not in version 3 output, calculated by hand - assert_near_equal( - self.prob['extra_fuel_volume'], 0.69314718, tol - ) # note: not in version 3 output, calculated by hand - assert_near_equal( - self.prob['max_extra_fuel_mass'], 34.67277748, tol - ) # note: not in version 3 output, calculated by hand - # note: Aircraft.Fuel.TOTAL_CAPACITY is calculated differently in V3, so it is not included here - - partial_data = self.prob.check_partials(out_stream=None, method='cs') - assert_check_partials(partial_data, atol=2e-11, rtol=1e-12) - - -class FuelMassGroupTestCase2( - unittest.TestCase -): # this is v 3.6 large single aisle 1 test case with wing loading of 150 psf and fuel margin of 10% - def setUp(self): - self.prob = om.Problem() - self.prob.model.add_subsystem('group', FuelMassGroup(), promotes=['*']) - - # top level - self.prob.model.set_input_defaults(Aircraft.Design.GROSS_MASS, val=175400, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Wing.MASS, val=13833, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults( - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, val=0.041, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.Fuel.DENSITY, val=6.687, units='lbm/galUS') - self.prob.model.set_input_defaults(Aircraft.Controls.MASS, val=3632, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, val=21031.0, units='lbm' - ) - self.prob.model.set_input_defaults(Mission.USEFUL_LOAD, val=4885.18, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, 876.7, units='ft**3' - ) - - # sys and fus - self.prob.model.set_input_defaults( - 'wing_mounted_mass', val=24446.343040697346, units='lbm' - ) # note: calculated by hand - - # fus and struct - self.prob.model.set_input_defaults( - Aircraft.Fuselage.MASS_COEFFICIENT, val=128, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.Fuselage.WETTED_AREA, val=4000, units='ft**2') - self.prob.model.set_input_defaults(Aircraft.Fuselage.AVG_DIAMETER, val=13.1, units='ft') - self.prob.model.set_input_defaults( - Aircraft.TailBoom.LENGTH, val=129.5, units='ft' - ) # note: calculated by hand - self.prob.model.set_input_defaults( - 'pylon_len', val=0, units='ft' - ) # note: calculated by hand - self.prob.model.set_input_defaults('min_dive_vel', val=420, units='kn') - self.prob.model.set_input_defaults( - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, val=7.5, units='psi' - ) - self.prob.model.set_input_defaults( - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, val=3.75, units='unitless' - ) - self.prob.model.set_input_defaults('MAT', val=0, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.HorizontalTail.MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.HorizontalTail.MASS, val=2181, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.VerticalTail.MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.VerticalTail.MASS, val=2158, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Fuselage.MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.LandingGear.TOTAL_MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS, val=7511, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Engine.POD_MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, val=3785, units='lbm' - ) - self.prob.model.set_input_defaults( - Aircraft.Design.STRUCTURAL_MASS_INCREMENT, val=0, units='lbm' - ) - - # fuel - self.prob.model.set_input_defaults('eng_comb_mass', val=14370.8, units='lbm') - self.prob.model.set_input_defaults('payload_mass_des', val=36000, units='lbm') - self.prob.model.set_input_defaults('payload_mass_max', val=46040, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Fuel.VOLUME_MARGIN, val=10, units='unitless') - - setup_model_options( - self.prob, AviaryValues({Aircraft.Engine.NUM_ENGINES: ([2], 'unitless')}) - ) - - self.prob.setup(check=False, force_alloc_complex=True) - - def test_case1(self): - self.prob.run_model() - - tol = 5e-4 - - # wingfuel - assert_near_equal(self.prob['OEM_wingfuel_mass'], 80982.7, tol) - assert_near_equal(self.prob['OEM_fuel_vol'], 1618.9, tol) - assert_near_equal(self.prob[Mission.OPERATING_MASS], 94417.0, tol) - assert_near_equal(self.prob['payload_mass_max_fuel'], 34879.2, tol) - assert_near_equal(self.prob['volume_wingfuel_mass'], 43852.1, tol) - assert_near_equal(self.prob['max_wingfuel_mass'], 43852.1, tol) - - # sys and fus - assert_near_equal( - self.prob['fus_mass_full'], 107806.75695930266, tol - ) # note: calculated by hand - assert_near_equal(self.prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 2029, tol) - - # fus and struct - assert_near_equal(self.prob[Aircraft.Design.STRUCTURE_MASS], 48470.0, tol) - assert_near_equal( - self.prob[Aircraft.Fuselage.MASS], 19002.0, 0.00054 - ) # tol is slightly higher because GASP iteration is less rigorous. - - # fuel - assert_near_equal(self.prob['fuel_mass'], 44982.7, tol) - assert_near_equal(self.prob[Aircraft.Propulsion.MASS], 16399.0, tol) - assert_near_equal(self.prob['fuel_mass_required'], 44982.7, tol) - assert_near_equal(self.prob['fuel_mass_min'], 34942.7, tol) - - # body tank - assert_near_equal( - self.prob[Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY], 1130.6, 0.0112 - ) # tol is slightly higher because GASP iteration is less rigorous, and also because of numerical issues with inputs. - assert_near_equal( - self.prob['extra_fuel_volume'], 112.5, 0.0022 - ) # tol is slightly higher because GASP iteration is less rigorous. - assert_near_equal( - self.prob['max_extra_fuel_mass'], 5628.9, 0.0025 - ) # tol is slightly higher because GASP iteration is less rigorous. - - partial_data = self.prob.check_partials(out_stream=None, method='cs') - assert_check_partials(partial_data, atol=2e-11, rtol=1e-12) - - -class FuelMassGroupTestCase3(unittest.TestCase): # this is v 3.6 advanced tube and wing case - def setUp(self): - self.prob = om.Problem() - self.prob.model.add_subsystem('group', FuelMassGroup(), promotes=['*']) - - # top level - self.prob.model.set_input_defaults(Aircraft.Design.GROSS_MASS, val=145388.0, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Wing.MASS, val=15098.0, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults( - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, val=0.041, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.Fuel.DENSITY, val=6.687, units='lbm/galUS') - self.prob.model.set_input_defaults(Aircraft.Controls.MASS, val=3765, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, val=17201.0, units='lbm' - ) - self.prob.model.set_input_defaults(Mission.USEFUL_LOAD, val=4701, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, 677.6, units='ft**3' - ) - - # sys and fus - self.prob.model.set_input_defaults( - 'wing_mounted_mass', val=17272.898624554255, units='lbm' - ) # note: calculated by hand - - # fus and struct - self.prob.model.set_input_defaults( - Aircraft.Fuselage.MASS_COEFFICIENT, val=128, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.Fuselage.WETTED_AREA, val=4209, units='ft**2') - self.prob.model.set_input_defaults(Aircraft.Fuselage.AVG_DIAMETER, val=13.1, units='ft') - self.prob.model.set_input_defaults(Aircraft.TailBoom.LENGTH, val=119.03, units='ft') - self.prob.model.set_input_defaults('pylon_len', val=0, units='ft') - self.prob.model.set_input_defaults('min_dive_vel', val=420, units='kn') - self.prob.model.set_input_defaults( - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, val=7.5, units='psi' - ) - self.prob.model.set_input_defaults( - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, val=4.484, units='unitless' - ) - self.prob.model.set_input_defaults('MAT', val=0, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Wing.MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.HorizontalTail.MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.HorizontalTail.MASS, val=2018, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.VerticalTail.MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.VerticalTail.MASS, val=1500, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Fuselage.MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.LandingGear.TOTAL_MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS, val=6140, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Engine.POD_MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, val=2795, units='lbm' - ) - self.prob.model.set_input_defaults(Aircraft.Fuselage.AVG_DIAMETER, val=13.1, units='ft') - self.prob.model.set_input_defaults(Aircraft.TailBoom.LENGTH, val=119.03, units='ft') - self.prob.model.set_input_defaults('pylon_len', val=0, units='ft') - self.prob.model.set_input_defaults('min_dive_vel', val=420, units='kn') - self.prob.model.set_input_defaults( - Aircraft.Fuselage.PRESSURE_DIFFERENTIAL, val=7.5, units='psi' - ) - self.prob.model.set_input_defaults( - Aircraft.Wing.ULTIMATE_LOAD_FACTOR, val=4.484, units='unitless' - ) - self.prob.model.set_input_defaults('MAT', val=0, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Wing.MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.HorizontalTail.MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.HorizontalTail.MASS, val=2018, units='lbm') - self.prob.model.set_input_defaults( - Aircraft.VerticalTail.MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.VerticalTail.MASS, val=1500, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Fuselage.MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.LandingGear.TOTAL_MASS_SCALER, val=1, units='unitless' - ) - self.prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS, val=6140, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Engine.POD_MASS_SCALER, val=1, units='unitless') - self.prob.model.set_input_defaults( - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, val=2795, units='lbm' - ) - self.prob.model.set_input_defaults( - Aircraft.Design.STRUCTURAL_MASS_INCREMENT, val=0, units='lbm' - ) - - # fuel - self.prob.model.set_input_defaults('eng_comb_mass', val=9328.2, units='lbm') - self.prob.model.set_input_defaults('payload_mass_des', val=30800, units='lbm') - self.prob.model.set_input_defaults('payload_mass_max', val=46770.0, units='lbm') - self.prob.model.set_input_defaults(Aircraft.Fuel.VOLUME_MARGIN, val=10, units='unitless') - - setup_model_options( - self.prob, AviaryValues({Aircraft.Engine.NUM_ENGINES: ([2], 'unitless')}) - ) - - self.prob.setup(check=False, force_alloc_complex=True) - - def test_case1(self): - self.prob.run_model() - - tol = 5e-4 - - # wingfuel - assert_near_equal(self.prob['OEM_wingfuel_mass'], 62427.2, tol) - assert_near_equal(self.prob['OEM_fuel_vol'], 1248.0, tol) - assert_near_equal(self.prob[Mission.OPERATING_MASS], 82961.0, tol) - assert_near_equal(self.prob['volume_wingfuel_mass'], 33892.8, tol) - assert_near_equal(self.prob['max_wingfuel_mass'], 33892.8, tol) - - # sys and fus - assert_near_equal(self.prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 1426, tol) - - # fus and struct - assert_near_equal(self.prob[Aircraft.Design.STRUCTURE_MASS], 46539.0, tol) - assert_near_equal(self.prob[Aircraft.Fuselage.MASS], 18988, tol) - - # fuel - assert_near_equal(self.prob['fuel_mass'], 31627.2, tol) - assert_near_equal(self.prob[Aircraft.Propulsion.MASS], 10755.0, tol) - assert_near_equal(self.prob['fuel_mass_required'], 31627, tol) - assert_near_equal(self.prob['fuel_mass_min'], 15657.2, tol) - - # body tank - assert_near_equal(self.prob[Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY], 0, tol) - assert_near_equal(self.prob['extra_fuel_volume'], 17.9, tol) - - partial_data = self.prob.check_partials(out_stream=None, method='cs') - assert_check_partials(partial_data, atol=3e-9, rtol=6e-11) - - class BWBFuelSysAndFullFusMassTestCase(unittest.TestCase): - """Using BWB data""" + """Using BWB data.""" def setUp(self): prob = self.prob = om.Problem() @@ -1228,7 +675,7 @@ def test_case1(self): class BWBFuselageMassTestCase(unittest.TestCase): - """GASP data""" + """GASP data.""" def setUp(self): prob = self.prob = om.Problem() @@ -1257,59 +704,16 @@ def test_case1(self): assert_check_partials(partial_data, atol=4e-11, rtol=1e-12) -class BWBStructMassTestCase(unittest.TestCase): - """Using BWB data""" - - def setUp(self): - prob = self.prob = om.Problem() - prob.model.add_subsystem('struct', StructMass(), promotes=['*']) - - prob.model.set_input_defaults(Aircraft.Fuselage.MASS, 27159.69841266, units='lbm') - prob.model.set_input_defaults(Aircraft.Wing.MASS_SCALER, 1.0, units='unitless') - prob.model.set_input_defaults(Aircraft.Wing.MASS, 7055.90333649, units='lbm') - prob.model.set_input_defaults(Aircraft.HorizontalTail.MASS_SCALER, 1.0, units='unitless') - prob.model.set_input_defaults(Aircraft.HorizontalTail.MASS, 1.02401953, units='lbm') - prob.model.set_input_defaults(Aircraft.VerticalTail.MASS_SCALER, 1.0, units='unitless') - prob.model.set_input_defaults(Aircraft.VerticalTail.MASS, 864.17404177, units='lbm') - prob.model.set_input_defaults(Aircraft.Fuselage.MASS_SCALER, 1.0, units='unitless') - prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS_SCALER, 1.0, units='unitless') - prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS, 7800.0, units='lbm') - prob.model.set_input_defaults(Aircraft.Engine.POD_MASS_SCALER, 1.0, units='unitless') - prob.model.set_input_defaults( - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, 2230.13208284, units='lbm' - ) - prob.model.set_input_defaults(Aircraft.Design.STRUCTURAL_MASS_INCREMENT, 0.0, units='lbm') - - setup_model_options(prob, AviaryValues({Aircraft.Engine.NUM_ENGINES: ([2], 'unitless')})) - - prob.setup(check=False, force_alloc_complex=True) - - def test_case1(self): - self.prob.run_model() - - tol = 1e-7 - assert_near_equal(self.prob[Aircraft.Design.STRUCTURE_MASS], 45110.93189329, tol) - - partial_data = self.prob.check_partials(out_stream=None, method='cs') - assert_check_partials(partial_data, atol=4e-12, rtol=1e-12) - - class BWBFuelMassTestCase(unittest.TestCase): - """Using BWB data""" + """Using BWB data.""" def setUp(self): prob = self.prob = om.Problem() prob.model.add_subsystem('fuel', FuelMass(), promotes=['*']) - prob.model.set_input_defaults(Aircraft.Design.STRUCTURE_MASS, 45110.93189329, units='lbm') prob.model.set_input_defaults(Aircraft.Fuel.FUEL_SYSTEM_MASS, 932.82805, units='lbm') prob.model.set_input_defaults(Aircraft.Design.GROSS_MASS, 150000.0, units='lbm') - prob.model.set_input_defaults('eng_comb_mass', 6934.7, units='lbm') - prob.model.set_input_defaults(Aircraft.Controls.MASS, 2115.19946, units='lbm') - prob.model.set_input_defaults( - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, 20876.477, units='lbm' - ) - prob.model.set_input_defaults(Mission.USEFUL_LOAD, 4156.795, units='lbm') + prob.model.set_input_defaults(Mission.OPERATING_MASS, 80126.93140329, units='lbm') prob.model.set_input_defaults('payload_mass_des', 33750.0, units='lbm') prob.model.set_input_defaults(Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, 1.0, units='unitless') prob.model.set_input_defaults( @@ -1328,7 +732,6 @@ def test_case1(self): tol = 1e-7 assert_near_equal(self.prob['fuel_mass'], 35682.13446963, tol) - assert_near_equal(self.prob[Aircraft.Propulsion.MASS], 7867.52805, tol) assert_near_equal(self.prob['fuel_mass_required'], 36123.06859671, tol) assert_near_equal(self.prob['fuel_mass_min'], 21123.06859671, tol) @@ -1337,21 +740,22 @@ def test_case1(self): class BWBFuelAndOEMTestCase(unittest.TestCase): - """Using BWB data""" + """Using BWB data.""" def setUp(self): prob = self.prob = om.Problem() - prob.model.add_subsystem('wing_calcs', FuelAndOEMOutputs(), promotes=['*']) + prob.model.add_subsystem('wing_calcs', FuelComponents(), promotes=['*']) prob.model.set_input_defaults(Aircraft.Fuel.DENSITY, 6.687, units='lbm/galUS') prob.model.set_input_defaults(Aircraft.Design.GROSS_MASS, 150000.0, units='lbm') - prob.model.set_input_defaults(Aircraft.Propulsion.MASS, 16161.21, units='lbm') - prob.model.set_input_defaults(Aircraft.Controls.MASS, 1942.3, units='lbm') - prob.model.set_input_defaults(Aircraft.Design.STRUCTURE_MASS, 43566.079, units='lbm') - prob.model.set_input_defaults( - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, 20876.477, units='lbm' - ) - prob.model.set_input_defaults(Mission.USEFUL_LOAD, 5736.3, units='lbm') + # prob.model.set_input_defaults(Aircraft.Propulsion.MASS, 16161.21, units='lbm') + # prob.model.set_input_defaults(Aircraft.Controls.MASS, 1942.3, units='lbm') + # prob.model.set_input_defaults(Aircraft.Design.STRUCTURE_MASS, 43566.079, units='lbm') + # prob.model.set_input_defaults( + # Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, 20876.477, units='lbm' + # ) + # prob.model.set_input_defaults(Mission.USEFUL_LOAD, 5736.3, units='lbm') + prob.model.set_input_defaults(Mission.OPERATING_MASS, 88282.366, units='lbm') prob.model.set_input_defaults('fuel_mass_required', 26652.3, units='lbm') prob.model.set_input_defaults( Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, 605.90781747, units='ft**3' @@ -1382,7 +786,7 @@ def test_case1(self): @use_tempdirs class BWBBodyCalculationTest(unittest.TestCase): - """Using BWB data""" + """Using BWB data.""" def setUp(self): prob = self.prob = om.Problem() @@ -1419,139 +823,5 @@ def test_case1(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) -@use_tempdirs -class BWBFuelMassGroupTest(unittest.TestCase): - """Using BWB data""" - - def setUp(self): - options = get_option_defaults() - options.set_val(Aircraft.Engine.NUM_ENGINES, val=[2], units='unitless') - options.set_val(Aircraft.Design.TYPE, val='BWB', units='unitless') - - prob = self.prob = om.Problem() - prob.model.add_subsystem('group', FuelMassGroup(), promotes=['*']) - - # FuelSysAndFullFuselageMass - prob.model.set_input_defaults(Aircraft.Design.GROSS_MASS, 150000, units='lbm') - prob.model.set_input_defaults(Aircraft.Wing.MASS, 6962.4, units='lbm') - prob.model.set_input_defaults('wing_mounted_mass', 0.0, units='lbm') - prob.model.set_input_defaults(Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, 1.0, units='unitless') - prob.model.set_input_defaults( - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, 0.035, units='unitless' - ) - prob.model.set_input_defaults(Aircraft.Fuel.DENSITY, 6.687, units='lbm/galUS') - prob.model.set_input_defaults('fuel_mass', 33268.2, units='lbm') - # prob.model.set_input_defaults('wingfuel_mass_min', 0.0, units='lbm') - prob.model.set_input_defaults(Aircraft.Fuel.VOLUME_MARGIN, 10.0, units='unitless') - - # BWBFuselageMass - prob.model.set_input_defaults(Aircraft.Fuselage.MASS_COEFFICIENT, 0.889, units='unitless') - prob.model.set_input_defaults(Aircraft.Fuselage.WETTED_AREA, 4573.8833, units='ft**2') - prob.model.set_input_defaults( - Aircraft.Fuselage.WETTED_AREA_RATIO_AFTBODY_TO_TOTAL, 0.2, units='unitless' - ) - prob.model.set_input_defaults( - Aircraft.Fuselage.AFTBODY_MASS_PER_UNIT_AREA, 5.0, units='lbm/ft**2' - ) - prob.model.set_input_defaults(Aircraft.Fuselage.CABIN_AREA, 1283.5249, units='ft**2') - - # StructMass - # prob.model.set_input_defaults(Aircraft.Fuselage.MASS, 27159.7, units='lbm') - prob.model.set_input_defaults(Aircraft.Wing.MASS_SCALER, 1.0, units='unitless') - prob.model.set_input_defaults(Aircraft.HorizontalTail.MASS_SCALER, 1.0, units='unitless') - prob.model.set_input_defaults(Aircraft.HorizontalTail.MASS, 1.0, units='lbm') - prob.model.set_input_defaults(Aircraft.VerticalTail.MASS_SCALER, 1.0, units='unitless') - prob.model.set_input_defaults(Aircraft.VerticalTail.MASS, 790.1, units='lbm') - prob.model.set_input_defaults(Aircraft.Fuselage.MASS_SCALER, 1.0, units='unitless') - prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS_SCALER, 1.0, units='unitless') - prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS, 7800.0, units='lbm') - prob.model.set_input_defaults(Aircraft.Engine.POD_MASS_SCALER, 1.0, units='unitless') - prob.model.set_input_defaults( - Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, 2153.0, units='lbm' - ) - prob.model.set_input_defaults(Aircraft.Design.STRUCTURAL_MASS_INCREMENT, 0.0, units='lbm') - - # FuelMass - prob.model.set_input_defaults('eng_comb_mass', 7311.5, units='lbm') - prob.model.set_input_defaults(Aircraft.Controls.MASS, 2115, units='lbm') - prob.model.set_input_defaults( - Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, 20876, units='lbm' - ) - prob.model.set_input_defaults(Mission.USEFUL_LOAD, 5775, units='lbm') - prob.model.set_input_defaults('payload_mass_des', 33750.0, units='lbm') - prob.model.set_input_defaults(Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, 1.0, units='unitless') - prob.model.set_input_defaults( - Aircraft.Fuel.FUEL_SYSTEM_MASS_COEFFICIENT, 0.035, units='unitless' - ) - prob.model.set_input_defaults('payload_mass_max', 48750.0, units='lbm') - prob.model.set_input_defaults(Aircraft.Fuel.VOLUME_MARGIN, 10.0, units='unitless') - - # FuelAndOEMOutputs - prob.model.set_input_defaults(Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX, 783.6, units='ft**3') - - setup_model_options(prob, options) - - prob.setup(check=False, force_alloc_complex=True) - - def test_case1(self): - """ - Testing GASP data case: - Aircraft.Fuel.FUEL_SYSTEM_MASS -- WFSS = 1281 - fus_mass_full -- 124040.19837521 -- WX = 121864 - Mission.OPERATING_MASS -- OWE = 82982. - fuel_and_oem.OEM_wingfuel_mass -- WFWOWE(WFW_MAX) = 67018.2 - fuel_and_oem.OEM_fuel_vol -- FVOLW_MAX = 1339.8 - fuel_and_oem.payload_mass_max_fuel -- WPLMXF = 30423.2 - max_wingfuel_mass -- WFWMX = 30309.0 - Aircraft.Design.STRUCTURE_MASS -- WST = 45623. - Aircraft.Fuselage.MASS -- WB = 27160. - 'fuel_mass' -- WFADES = 33268.2 - Aircraft.Propulsion.MASS -- WP = 8592. - 'fuel_mass_required' -- WFAREQ = 36595.0 - fuel_mass_min -- WFAMIN = 18268.2 - Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY -- 0.0 - Aircraft.Fuel.TOTAL_CAPACITY -- WFAMAX = 33268.2 - body_tank.extra_fuel_volume -- FVOLAUX = 0.2 - body_tank.max_extra_fuel_mass -- 0.0 - wingfuel_mass_min -- WFWMIN = 11982.2 - Note: can not match Aircraft.Fuel.FUEL_SYSTEM_MASS to GASP. Guess it is WFSS - """ - self.prob.run_model() - - tol = 1e-7 - - # sys and fus - assert_near_equal(self.prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 1308.89996255, tol) - assert_near_equal(self.prob['fus_mass_full'], 124040.19837521, tol) - - # wingfuel - assert_near_equal(self.prob[Mission.OPERATING_MASS], 82252.59837521, tol) - assert_near_equal(self.prob['OEM_wingfuel_mass'], 67747.40162479, tol) - assert_near_equal(self.prob['OEM_fuel_vol'], 1354.34550784, tol) - assert_near_equal(self.prob['payload_mass_max_fuel'], 33750.0, tol) - # assert_near_equal(self.prob['volume_wingfuel_mass'], 26646.849, tol) - assert_near_equal(self.prob['max_wingfuel_mass'], 39197.43049744, tol) - - # fus and struct - assert_near_equal(self.prob[Aircraft.Design.STRUCTURE_MASS], 44866.19841266, tol) - assert_near_equal(self.prob[Aircraft.Fuselage.MASS], 27159.69841266, tol) - - # fuel - assert_near_equal(self.prob['fuel_mass'], 33997.40162479, tol) - assert_near_equal(self.prob[Aircraft.Propulsion.MASS], 8620.39996255, tol) - assert_near_equal(self.prob['fuel_mass_required'], 33997.40162479, tol) - assert_near_equal(self.prob['fuel_mass_min'], 18997.40162479, tol) - - # body tank - assert_near_equal(self.prob[Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY], 0.0, tol) - assert_near_equal(self.prob[Aircraft.Fuel.TOTAL_CAPACITY], 33997.40162479, tol) - assert_near_equal(self.prob['extra_fuel_volume'], 0.0, tol) - assert_near_equal(self.prob['max_extra_fuel_mass'], 0.0, tol) - assert_near_equal(self.prob['wingfuel_mass_min'], 18997.40162479, tol) - - partial_data = self.prob.check_partials(out_stream=None, method='cs') - assert_check_partials(partial_data, atol=2e-11, rtol=1e-12) - - if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/gasp_based/test/test_fuel_capacity.py b/aviary/subsystems/mass/gasp_based/test/test_fuel_capacity.py index 43b82b53d3..126b3b20d6 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_fuel_capacity.py +++ b/aviary/subsystems/mass/gasp_based/test/test_fuel_capacity.py @@ -4,7 +4,6 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.mass.gasp_based.fuel_capacity import TrappedFuelCapacity - from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft diff --git a/aviary/subsystems/mass/gasp_based/test/test_furnishings.py b/aviary/subsystems/mass/gasp_based/test/test_furnishings.py index 29c433b8f3..35941c206f 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_furnishings.py +++ b/aviary/subsystems/mass/gasp_based/test/test_furnishings.py @@ -3,8 +3,7 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal -from aviary.subsystems.mass.gasp_based.furnishings import FurnishingMass, BWBFurnishingMass - +from aviary.subsystems.mass.gasp_based.furnishings import BWBFurnishingMass, FurnishingMass from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission diff --git a/aviary/subsystems/mass/gasp_based/test/test_hydraulics.py b/aviary/subsystems/mass/gasp_based/test/test_hydraulics.py index 7d451e4066..b7f6434f1f 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_hydraulics.py +++ b/aviary/subsystems/mass/gasp_based/test/test_hydraulics.py @@ -4,7 +4,6 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.mass.gasp_based.hydraulics import HydraulicsMass - from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft diff --git a/aviary/subsystems/mass/gasp_based/test/test_instruments.py b/aviary/subsystems/mass/gasp_based/test/test_instruments.py index 609b71dfef..f256640d6b 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_instruments.py +++ b/aviary/subsystems/mass/gasp_based/test/test_instruments.py @@ -4,7 +4,6 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.mass.gasp_based.instruments import InstrumentMass - from aviary.variable_info.enums import GASPEngineType from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults diff --git a/aviary/subsystems/mass/gasp_based/test/test_mass_summation.py b/aviary/subsystems/mass/gasp_based/test/test_mass_premission.py similarity index 96% rename from aviary/subsystems/mass/gasp_based/test/test_mass_summation.py rename to aviary/subsystems/mass/gasp_based/test/test_mass_premission.py index c1ccfdb8b6..ca6bd5a242 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_mass_summation.py +++ b/aviary/subsystems/mass/gasp_based/test/test_mass_premission.py @@ -10,13 +10,14 @@ ) from aviary.subsystems.geometry.gasp_based.size_group import SizeGroup from aviary.subsystems.mass.gasp_based.mass_premission import MassPremission -from aviary.utils.aviary_values import get_items +from aviary.subsystems.mass.gasp_based.mass_summation import StructureMass +from aviary.utils.aviary_values import AviaryValues, get_items from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults, is_option from aviary.variable_info.variables import Aircraft, Mission -class MassSummationTestCase1(unittest.TestCase): +class MassPremissionTestCase1(unittest.TestCase): """ This is the large single aisle 1 V3 bug fixed test case. All values are from V3 bug fixed output (or hand calculated from output) unless @@ -116,7 +117,7 @@ def test_case1(self): assert_check_partials(partial_data, atol=3e-10, rtol=1e-12) -class MassSummationTestCase2(unittest.TestCase): +class MassPremissionTestCase2(unittest.TestCase): """ This is the large single aisle 1 V3.5 test case. All values are from V3.5 output (or hand calculated from the output, and these cases @@ -281,7 +282,7 @@ def setUp(self): Aircraft.LandingGear.MASS_COEFFICIENT, val=0.04, units='unitless' ) self.prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, val=0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, val=0.85, units='unitless' ) self.prob.model.set_input_defaults( Aircraft.Nacelle.CLEARANCE_RATIO, val=0.2, units='unitless' @@ -462,10 +463,11 @@ def test_case1(self): assert_check_partials(partial_data, atol=2e-10, rtol=1e-12) -class MassSummationTestCase3(unittest.TestCase): +class MassPremissionTestCase3(unittest.TestCase): """ - This is thelarge single aisle 1V3.6 test case with a fuel margin of 0%, a wing loading of 128 psf, and a SLS thrust of 29500 lbf - All values are from V3.6 output (or hand calculated from the output, and these cases are specified). + This is the large single aisle 1V3.6 test case with a fuel margin of 0%, a wing loading of 128 + psf, and a SLS thrust of 29500 lbf. All values are from V3.6 output (or hand calculated from the + output, and these cases are specified). """ def setUp(self): @@ -627,7 +629,7 @@ def setUp(self): Aircraft.LandingGear.MASS_COEFFICIENT, val=0.04, units='unitless' ) self.prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, val=0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, val=0.85, units='unitless' ) self.prob.model.set_input_defaults( Aircraft.Nacelle.CLEARANCE_RATIO, val=0.2, units='unitless' @@ -804,7 +806,7 @@ def test_case1(self): assert_check_partials(partial_data, atol=2e-10, rtol=1e-12) -class MassSummationTestCase4(unittest.TestCase): +class MassPremissionTestCase4(unittest.TestCase): """ This is the large single aisle 1V3.6 test case with a fuel margin of 10%, a wing loading of 128 psf, and a SLS thrust of 29500 lbf All values are from V3.6 output (or hand calculated from the output, and these cases are specified). @@ -969,7 +971,7 @@ def setUp(self): Aircraft.LandingGear.MASS_COEFFICIENT, val=0.04, units='unitless' ) self.prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, val=0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, val=0.85, units='unitless' ) self.prob.model.set_input_defaults( Aircraft.Nacelle.CLEARANCE_RATIO, val=0.2, units='unitless' @@ -1319,7 +1321,7 @@ def setUp(self): Aircraft.LandingGear.MASS_COEFFICIENT, val=0.04, units='unitless' ) self.prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, val=0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, val=0.85, units='unitless' ) self.prob.model.set_input_defaults( Aircraft.Nacelle.CLEARANCE_RATIO, val=0.2, units='unitless' @@ -1664,7 +1666,7 @@ def setUp(self): Aircraft.LandingGear.MASS_COEFFICIENT, val=0.04, units='unitless' ) self.prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, val=0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, val=0.85, units='unitless' ) self.prob.model.set_input_defaults( Aircraft.Nacelle.CLEARANCE_RATIO, val=0.2, units='unitless' @@ -2013,7 +2015,7 @@ def setUp(self): Aircraft.LandingGear.MASS_COEFFICIENT, val=0.04, units='unitless' ) self.prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, val=0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, val=0.85, units='unitless' ) self.prob.model.set_input_defaults( Aircraft.Nacelle.CLEARANCE_RATIO, val=0.2, units='unitless' @@ -2424,7 +2426,7 @@ def setUp(self): Aircraft.LandingGear.MASS_COEFFICIENT, val=0.03390, units='unitless' ) self.prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, val=0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, val=0.85, units='unitless' ) self.prob.model.set_input_defaults(Aircraft.Fuel.DENSITY, val=6.687, units='lbm/galUS') self.prob.model.set_input_defaults(Aircraft.Fuel.VOLUME_MARGIN, val=10.0, units='unitless') @@ -2793,7 +2795,7 @@ def setUp(self): Aircraft.LandingGear.MASS_COEFFICIENT, val=0.03390, units='unitless' ) self.prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, val=0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, val=0.85, units='unitless' ) self.prob.model.set_input_defaults(Aircraft.Fuel.DENSITY, val=6.687, units='lbm/galUS') self.prob.model.set_input_defaults(Aircraft.Fuel.VOLUME_MARGIN, val=0.0, units='unitless') @@ -2974,9 +2976,7 @@ def test_case1(self): @use_tempdirs class BWBMassSummationTestCase(unittest.TestCase): - """ - GASP BWB model - """ + """GASP BWB model.""" def setUp(self): options = get_option_defaults() @@ -3162,7 +3162,7 @@ def setUp(self): Aircraft.LandingGear.MASS_COEFFICIENT, 0.0520, units='unitless' ) prob.model.set_input_defaults( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, 0.85, units='unitless' + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, 0.85, units='unitless' ) prob.model.set_input_defaults(Aircraft.Fuel.DENSITY, 6.687, units='lbm/galUS') @@ -3176,7 +3176,7 @@ def setUp(self): prob.model.set_input_defaults(Aircraft.VerticalTail.MASS_SCALER, 1, units='unitless') prob.model.set_input_defaults(Aircraft.Fuselage.MASS_SCALER, 1, units='unitless') prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS_SCALER, 1, units='unitless') - prob.model.set_input_defaults(Aircraft.Engine.POD_MASS_SCALER, 1, units='unitless') + # prob.model.set_input_defaults(Aircraft.Engine.POD_MASS_SCALER, 1, units='unitless') prob.model.set_input_defaults(Aircraft.Design.STRUCTURAL_MASS_INCREMENT, 0, units='lbm') prob.model.set_input_defaults(Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, 1, units='unitless') prob.model.set_input_defaults(Aircraft.Wing.MASS_COEFFICIENT, 75.78, units='unitless') @@ -3283,7 +3283,7 @@ def test_case1(self): FUEL_MASS_REQUIRED -- WFAREQ = 36595.0 fuel_mass_min -- WFAMIN = 18268.2 fuel_mass.wingfuel_mass_min -- WFWMIN = 11982.2 - Aircraft.Fuel.TOTAL_CAPACITY -- WFAMAX = 33268.2 + Aircraft.Fuel.TOTAL_CAPACITY -- WFAMAX = 33268.2. """ prob = self.prob prob.run_model() @@ -3341,7 +3341,7 @@ def test_case1(self): assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS], 1686.626, tol) assert_near_equal(prob[Aircraft.Engine.ADDITIONAL_MASS], 153.16770871, tol) assert_near_equal(prob[Aircraft.Engine.POSITION_FACTOR], 1.05, tol) - assert_near_equal(prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 19770.39927907, tol) + assert_near_equal(prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 21885.38086961, tol) assert_near_equal(prob[Mission.USEFUL_LOAD], 5961.79463002, tol) assert_near_equal(prob[Aircraft.Wing.SURFACE_CONTROL_MASS], 1986.25111783, tol) @@ -3382,5 +3382,107 @@ def test_case1(self): assert_near_equal(prob['wingfuel_mass_min'], 11782.58105019, tol) +# this is the large single aisle 1 V3 test case +class StructMassTestCase1(unittest.TestCase): + def setUp(self): + self.prob = om.Problem() + self.prob.model.add_subsystem('struct', StructureMass(), promotes=['*']) + + self.prob.model.set_input_defaults(Aircraft.Fuselage.MASS, val=18763, units='lbm') + self.prob.model.set_input_defaults(Aircraft.Wing.MASS, val=15830, units='lbm') + self.prob.model.set_input_defaults(Aircraft.Design.EMPENNAGE_MASS, val=4572, units='lbm') + self.prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS, val=7511, units='lbm') + self.prob.model.set_input_defaults( + Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, val=3785, units='lbm' + ) + self.prob.model.set_input_defaults( + Aircraft.Design.STRUCTURAL_MASS_INCREMENT, val=0, units='lbm' + ) + + setup_model_options( + self.prob, AviaryValues({Aircraft.Engine.NUM_ENGINES: ([2], 'unitless')}) + ) + + self.prob.setup(check=False, force_alloc_complex=True) + + def test_case1(self): + self.prob.run_model() + + tol = 1e-4 + assert_near_equal(self.prob[Aircraft.Design.STRUCTURE_MASS], 50461.0, tol) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data, atol=4e-12, rtol=1e-12) + + +class StructMassTestCase2(unittest.TestCase): + """Test mass-weight conversion.""" + + def setUp(self): + import aviary.subsystems.mass.gasp_based.fuel as fuel + + fuel.GRAV_ENGLISH_LBM = 1.1 + + def tearDown(self): + import aviary.subsystems.mass.gasp_based.fuel as fuel + + fuel.GRAV_ENGLISH_LBM = 1.0 + + def test_case1(self): + self.prob = om.Problem() + self.prob.model.add_subsystem('struct', StructureMass(), promotes=['*']) + + self.prob.model.set_input_defaults(Aircraft.Fuselage.MASS, val=18763, units='lbm') + self.prob.model.set_input_defaults(Aircraft.Wing.MASS, val=15830, units='lbm') + self.prob.model.set_input_defaults(Aircraft.Design.EMPENNAGE_MASS, val=4572, units='lbm') + + self.prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS, val=7511, units='lbm') + self.prob.model.set_input_defaults( + Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, val=3785, units='lbm' + ) + self.prob.model.set_input_defaults( + Aircraft.Design.STRUCTURAL_MASS_INCREMENT, val=0, units='lbm' + ) + + setup_model_options( + self.prob, AviaryValues({Aircraft.Engine.NUM_ENGINES: ([2], 'unitless')}) + ) + + self.prob.setup(check=False, force_alloc_complex=True) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data, atol=1e-11, rtol=1e-12) + + +class BWBStructMassTestCase(unittest.TestCase): + """Using BWB data.""" + + def setUp(self): + prob = self.prob = om.Problem() + prob.model.add_subsystem('struct', StructureMass(), promotes=['*']) + + prob.model.set_input_defaults(Aircraft.Fuselage.MASS, 27159.69841266, units='lbm') + prob.model.set_input_defaults(Aircraft.Wing.MASS, 7055.90333649, units='lbm') + prob.model.set_input_defaults(Aircraft.Design.EMPENNAGE_MASS, 865.1980613, units='lbm') + prob.model.set_input_defaults(Aircraft.LandingGear.TOTAL_MASS, 7800.0, units='lbm') + prob.model.set_input_defaults( + Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS, 2230.13208284, units='lbm' + ) + prob.model.set_input_defaults(Aircraft.Design.STRUCTURAL_MASS_INCREMENT, 0.0, units='lbm') + + setup_model_options(prob, AviaryValues({Aircraft.Engine.NUM_ENGINES: ([2], 'unitless')})) + + prob.setup(check=False, force_alloc_complex=True) + + def test_case1(self): + self.prob.run_model() + + tol = 1e-7 + assert_near_equal(self.prob[Aircraft.Design.STRUCTURE_MASS], 45110.93189329, tol) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data, atol=4e-12, rtol=1e-12) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/gasp_based/test/test_oxygen_system.py b/aviary/subsystems/mass/gasp_based/test/test_oxygen_system.py index 4c868436bf..5e7c1a3a24 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_oxygen_system.py +++ b/aviary/subsystems/mass/gasp_based/test/test_oxygen_system.py @@ -4,7 +4,6 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.mass.gasp_based.oxygen_system import OxygenSystemMass - from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission diff --git a/aviary/subsystems/mass/gasp_based/test/test_passenger_service.py b/aviary/subsystems/mass/gasp_based/test/test_passenger_service.py index d8ed6412bf..727b177a67 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_passenger_service.py +++ b/aviary/subsystems/mass/gasp_based/test/test_passenger_service.py @@ -4,7 +4,6 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.mass.gasp_based.passenger_service import PassengerServiceMass - from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft diff --git a/aviary/subsystems/mass/gasp_based/test/test_wing.py b/aviary/subsystems/mass/gasp_based/test/test_wing.py index 3d90ced52a..326d498327 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_wing.py +++ b/aviary/subsystems/mass/gasp_based/test/test_wing.py @@ -4,12 +4,17 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from openmdao.utils.testing_utils import use_tempdirs -from aviary.subsystems.mass.gasp_based.wing import WingMassGroup, WingMassSolve, WingMassTotal -from aviary.subsystems.mass.gasp_based.wing import BWBWingMassSolve, BWBWingMassGroup +from aviary.subsystems.mass.gasp_based.wing import ( + BWBWingMassGroup, + BWBWingMassSolve, + WingMassGroup, + WingMassSolve, + WingMassTotal, +) +from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.functions import setup_model_options from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission -from aviary.utils.aviary_values import AviaryValues class WingMassSolveTestCase(unittest.TestCase): diff --git a/aviary/subsystems/mass/gasp_based/wing.py b/aviary/subsystems/mass/gasp_based/wing.py index 0a0f2c77c9..82963f1340 100644 --- a/aviary/subsystems/mass/gasp_based/wing.py +++ b/aviary/subsystems/mass/gasp_based/wing.py @@ -266,6 +266,8 @@ def initialize(self): add_aviary_option(self, Aircraft.Wing.HAS_STRUT) def setup(self): + add_aviary_input(self, Aircraft.Wing.MASS_SCALER) + self.add_input( 'isolated_wing_mass', val=1500, @@ -286,6 +288,7 @@ def setup(self): add_aviary_output(self, Aircraft.Wing.FOLD_MASS, units='lbm') self.declare_partials(Aircraft.Wing.MASS, '*') + if self.options[Aircraft.Wing.HAS_STRUT]: self.declare_partials( Aircraft.Strut.MASS, [Aircraft.Strut.MASS_COEFFICIENT, 'isolated_wing_mass'] @@ -302,16 +305,17 @@ def setup(self): ) def compute(self, inputs, outputs): + CK8 = inputs[Aircraft.Wing.MASS_SCALER] isolated_wing_wt = inputs['isolated_wing_mass'] * GRAV_ENGLISH_LBM + strut_wt = 0 + fold_wt = 0 + + # TODO output the wing mass subcomponents? if self.options[Aircraft.Wing.HAS_STRUT]: c_strut_mass = inputs[Aircraft.Strut.MASS_COEFFICIENT] strut_wt = c_strut_mass * isolated_wing_wt - outputs[Aircraft.Strut.MASS] = strut_wt / GRAV_ENGLISH_LBM - - else: - outputs[Aircraft.Strut.MASS] = strut_wt = 0 if self.options[Aircraft.Wing.HAS_FOLD]: wing_area = inputs[Aircraft.Wing.AREA] @@ -321,16 +325,18 @@ def compute(self, inputs, outputs): wt_per_area = isolated_wing_wt / wing_area temp_fold_wt = folding_area * wt_per_area fold_wt = c_wing_fold * temp_fold_wt - outputs[Aircraft.Wing.FOLD_MASS] = fold_wt / GRAV_ENGLISH_LBM - else: - outputs[Aircraft.Wing.FOLD_MASS] = fold_wt = 0 + outputs[Aircraft.Strut.MASS] = strut_wt / GRAV_ENGLISH_LBM + outputs[Aircraft.Wing.FOLD_MASS] = fold_wt / GRAV_ENGLISH_LBM total_wing_wt = isolated_wing_wt + strut_wt + fold_wt - outputs[Aircraft.Wing.MASS] = total_wing_wt / GRAV_ENGLISH_LBM + outputs[Aircraft.Wing.MASS] = CK8 * total_wing_wt / GRAV_ENGLISH_LBM def compute_partials(self, inputs, J): + CK8 = inputs[Aircraft.Wing.MASS_SCALER] isolated_wing_wt = inputs['isolated_wing_mass'] * GRAV_ENGLISH_LBM + strut_wt = 0 + fold_wt = 0 if self.options[Aircraft.Wing.HAS_STRUT]: c_strut_mass = inputs[Aircraft.Strut.MASS_COEFFICIENT] @@ -340,6 +346,7 @@ def compute_partials(self, inputs, J): ] = isolated_wing_wt / GRAV_ENGLISH_LBM J[Aircraft.Wing.MASS, 'isolated_wing_mass'] = 1 + c_strut_mass J[Aircraft.Strut.MASS, 'isolated_wing_mass'] = c_strut_mass + strut_wt = c_strut_mass * isolated_wing_wt if self.options[Aircraft.Wing.HAS_FOLD]: wing_area = inputs[Aircraft.Wing.AREA] @@ -362,9 +369,10 @@ def compute_partials(self, inputs, J): J[Aircraft.Wing.FOLD_MASS, 'isolated_wing_mass'] = ( c_wing_fold * folding_area / wing_area ) + fold_wt = c_wing_fold * temp_fold_wt if self.options[Aircraft.Wing.HAS_FOLD] and self.options[Aircraft.Wing.HAS_STRUT]: - J[Aircraft.Wing.MASS, 'isolated_wing_mass'] = ( + J[Aircraft.Wing.MASS, 'isolated_wing_mass'] = CK8 * ( 1 + c_wing_fold * folding_area / wing_area + c_strut_mass ) @@ -374,6 +382,10 @@ def compute_partials(self, inputs, J): ): J[Aircraft.Wing.MASS, 'isolated_wing_mass'] = 1 + J[Aircraft.Wing.MASS, Aircraft.Wing.MASS_SCALER] = ( + isolated_wing_wt + strut_wt + fold_wt + ) / GRAV_ENGLISH_LBM + class BWBWingMassSolve(om.ImplicitComponent): """ @@ -461,7 +473,6 @@ def apply_nonlinear(self, inputs, outputs, residuals): def linearize(self, inputs, outputs, J): gross_wt_initial = inputs[Aircraft.Design.GROSS_MASS] * GRAV_ENGLISH_LBM - high_lift_wt = inputs[Aircraft.Wing.HIGH_LIFT_MASS] * GRAV_ENGLISH_LBM c_strut_braced = inputs['c_strut_braced'] ULF = inputs[Aircraft.Wing.ULTIMATE_LOAD_FACTOR] c_wing_mass = inputs[Aircraft.Wing.MASS_COEFFICIENT] @@ -481,15 +492,6 @@ def linearize(self, inputs, outputs, J): foo_denom = 1.0 + CLBqCLW foo = (foo_numer / foo_denom) ** 0.757 wingspan_mod = wingspan - cabin_width # modification for BWB - wing_wt_guess = ( - c_wing_mass - * c_material - * c_eng_pos - * c_gear_loc - * foo - * wingspan_mod**1.049 - * (1.0 + taper_ratio) ** 0.4 - ) / (100000.0 * tc_ratio_root**0.4 * np.cos(half_sweep) ** 1.535) + high_lift_wt J['isolated_wing_mass', Aircraft.Design.GROSS_MASS] = ( -( @@ -709,6 +711,7 @@ def setup(self): 'isolated_wing_mass', ] connected_inputs_total = [ + Aircraft.Wing.MASS_SCALER, 'isolated_wing_mass', ] @@ -745,9 +748,7 @@ def setup(self): class BWBWingMassGroup(om.Group): - """ - Group to compute wing mass for GASP-based mass. - """ + """Group to compute wing mass for GASP-based mass.""" def initialize(self): add_aviary_option(self, Aircraft.Wing.HAS_FOLD) diff --git a/aviary/subsystems/mass/test/test_gasp_mass_builder.py b/aviary/subsystems/mass/test/test_gasp_mass_builder.py index 4198ac5dec..c2075d7ddb 100644 --- a/aviary/subsystems/mass/test/test_gasp_mass_builder.py +++ b/aviary/subsystems/mass/test/test_gasp_mass_builder.py @@ -1,8 +1,13 @@ import unittest +import openmdao.api as om +from openmdao.core.system import System + import aviary.api as av from aviary.subsystems.mass.mass_builder import CoreMassBuilder +from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.enums import LegacyCode +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData from aviary.variable_info.variables import Aircraft @@ -11,9 +16,8 @@ class TestGASPMassBuilderHybrid(av.TestSubsystemBuilder): """ - That class inherits from TestSubsystemBuilder. So all the test functions are - within that inherited class. The setUp() method prepares the class and is run - before the test methods; then the test methods are run. + TestSubsystemBuilder for the CoreMassBuilder using GASP methods. SetUp used to provide required + variables. Some methods are overriden so set_input_defaults can be called on the problem. """ def setUp(self): @@ -29,12 +33,77 @@ def setUp(self): self.aviary_values.set_val(Aircraft.Engine.NUM_ENGINES, [1], units='unitless') self.aviary_values.set_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, 1) + def test_check_pre_mission(self): + if not hasattr(self, 'aviary_values'): + self.aviary_values = AviaryValues() + + pre_mission_sys = self.subsystem_builder.build_pre_mission( + aviary_inputs=self.aviary_values, subsystem_options={} + ) + + if pre_mission_sys is None: + return + + group = om.Group() + group.add_subsystem('pre_mission_sys', pre_mission_sys) + prob = om.Problem(group) + + setup_model_options(prob, self.aviary_values) + prob.model.set_input_defaults( + f'pre_mission_sys.{Aircraft.Fuel.DENSITY}', val=6.687, units='lbm/galUS' + ) + + prob.setup() + prob.final_setup() + + self.assertIsInstance( + pre_mission_sys, System, 'The method should return an OpenMDAO System object.' + ) + + mass_names = self.subsystem_builder.get_mass_names() + outputs = pre_mission_sys.list_outputs(out_stream=None, prom_name=True) + + for name in mass_names: + mass_var_exists = any(name == output_[1]['prom_name'] for output_ in outputs) + self.assertTrue( + mass_var_exists, f"Mass variable '{name}' not found in the pre-mission model." + ) + + def test_check_design_variables(self): + if not hasattr(self, 'aviary_values'): + self.aviary_values = AviaryValues() + + design_vars = self.subsystem_builder.get_design_vars() + + pre_mission_sys = self.subsystem_builder.build_pre_mission( + aviary_inputs=self.aviary_values, subsystem_options={} + ) + + if pre_mission_sys is None: + return + + group = om.Group() + group.add_subsystem('pre_mission', pre_mission_sys, promotes=['*']) + prob = om.Problem(group) + + setup_model_options(prob, self.aviary_values) + prob.model.set_input_defaults(f'{Aircraft.Fuel.DENSITY}', val=6.687, units='lbm/galUS') + + prob.setup() + prob.final_setup() + + inputs = prob.model.list_inputs(out_stream=None, prom_name=True) + + for key, value in design_vars.items(): + # Check design variable existence + design_var_exists = any(key == input_[1]['prom_name'] for input_ in inputs) + self.assertTrue(design_var_exists, f"Design variable '{key}' not found in the model.") + class TestGASPMassBuilder(av.TestSubsystemBuilder): """ - That class inherits from TestSubsystemBuilder. So all the test functions are - within that inherited class. The setUp() method prepares the class and is run - before the test methods; then the test methods are run. + TestSubsystemBuilder for the CoreMassBuilder using GASP methods. SetUp used to provide required + variables. Some methods are overriden so set_input_defaults can be called on the problem. """ def setUp(self): @@ -50,6 +119,72 @@ def setUp(self): self.aviary_values.set_val(Aircraft.Engine.NUM_ENGINES, [1], units='unitless') self.aviary_values.set_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, 1) + def test_check_pre_mission(self): + if not hasattr(self, 'aviary_values'): + self.aviary_values = AviaryValues() + + pre_mission_sys = self.subsystem_builder.build_pre_mission( + aviary_inputs=self.aviary_values, subsystem_options={} + ) + + if pre_mission_sys is None: + return + + group = om.Group() + group.add_subsystem('pre_mission_sys', pre_mission_sys) + prob = om.Problem(group) + + setup_model_options(prob, self.aviary_values) + prob.model.set_input_defaults( + f'pre_mission_sys.{Aircraft.Fuel.DENSITY}', val=6.687, units='lbm/galUS' + ) + + prob.setup() + prob.final_setup() + + self.assertIsInstance( + pre_mission_sys, System, 'The method should return an OpenMDAO System object.' + ) + + mass_names = self.subsystem_builder.get_mass_names() + outputs = pre_mission_sys.list_outputs(out_stream=None, prom_name=True) + + for name in mass_names: + mass_var_exists = any(name == output_[1]['prom_name'] for output_ in outputs) + self.assertTrue( + mass_var_exists, f"Mass variable '{name}' not found in the pre-mission model." + ) + + def test_check_design_variables(self): + if not hasattr(self, 'aviary_values'): + self.aviary_values = AviaryValues() + + design_vars = self.subsystem_builder.get_design_vars() + + pre_mission_sys = self.subsystem_builder.build_pre_mission( + aviary_inputs=self.aviary_values, subsystem_options={} + ) + + if pre_mission_sys is None: + return + + group = om.Group() + group.add_subsystem('pre_mission', pre_mission_sys, promotes=['*']) + prob = om.Problem(group) + + setup_model_options(prob, self.aviary_values) + prob.model.set_input_defaults(f'{Aircraft.Fuel.DENSITY}', val=6.687, units='lbm/galUS') + + prob.setup() + prob.final_setup() + + inputs = prob.model.list_inputs(out_stream=None, prom_name=True) + + for key, value in design_vars.items(): + # Check design variable existence + design_var_exists = any(key == input_[1]['prom_name'] for input_ in inputs) + self.assertTrue(design_var_exists, f"Design variable '{key}' not found in the model.") + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/test/test_gasp_based_premission.py b/aviary/subsystems/test/test_gasp_based_premission.py index e437831a4c..b3887b29fc 100644 --- a/aviary/subsystems/test/test_gasp_based_premission.py +++ b/aviary/subsystems/test/test_gasp_based_premission.py @@ -55,62 +55,66 @@ def test_case1(self): prob.run_model() tol = 1e-5 - # propulsion subsystem - # geometry subsystem - assert_near_equal(prob[Aircraft.Fuselage.AVG_DIAMETER], 157.2, tol) - assert_near_equal(prob[Aircraft.Fuselage.LENGTH], 129.497, tol) - assert_near_equal(prob[Aircraft.Fuselage.WETTED_AREA], 4000.0, tol) - assert_near_equal(prob[Aircraft.Wing.AREA], 1370.3125, tol) - assert_near_equal(prob[Aircraft.Wing.SPAN], 117.81878299, tol) - assert_near_equal(prob[Aircraft.Wing.CENTER_CHORD], 17.48974356, tol) - assert_near_equal(prob[Aircraft.Wing.AVERAGE_CHORD], 12.61453233, tol) - assert_near_equal(prob[Aircraft.Wing.ROOT_CHORD], 16.40711451, tol) - assert_near_equal(prob[Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED], 0.139656, tol) - assert_near_equal(prob[Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX], 1114.0056, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.AREA], 375.8798, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.SPAN], 42.2543, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.ROOT_CHORD], 13.1592, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.AVERAGE_CHORD], 9.5768, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.MOMENT_ARM], 54.6793, tol) - assert_near_equal(prob[Aircraft.VerticalTail.AREA], 469.3183, tol) - assert_near_equal(prob[Aircraft.VerticalTail.SPAN], 27.9957, tol) - assert_near_equal(prob[Aircraft.VerticalTail.ROOT_CHORD], 18.6162, tol) - assert_near_equal(prob[Aircraft.VerticalTail.AVERAGE_CHORD], 16.8321, tol) - assert_near_equal(prob[Aircraft.VerticalTail.MOMENT_ARM], 49.8809, tol) - assert_near_equal(prob[Aircraft.Nacelle.AVG_DIAMETER], 7.25, tol) - assert_near_equal(prob[Aircraft.Nacelle.AVG_LENGTH], 14.5, tol) - assert_near_equal(prob[Aircraft.Nacelle.SURFACE_AREA], 330.2599, tol) - # mass subsystem - assert_near_equal(self.prob[Aircraft.Design.LIFT_CURVE_SLOPE], 6.39471, tol) - assert_near_equal(self.prob[Aircraft.Wing.ULTIMATE_LOAD_FACTOR], 3.75, tol) - assert_near_equal(self.prob[Aircraft.Wing.MATERIAL_FACTOR], 1.22129, tol) - assert_near_equal(self.prob[Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS], 36000.0, tol) - assert_near_equal(self.prob[Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS], 36000.0, tol) - assert_near_equal(self.prob[Aircraft.Propulsion.TOTAL_ENGINE_MASS], 12605.94, tol) - assert_near_equal(self.prob[Aircraft.Nacelle.MASS], 990.7798, tol) - assert_near_equal(self.prob[Aircraft.HorizontalTail.MASS], 2276.1316, tol) - assert_near_equal(self.prob[Aircraft.VerticalTail.MASS], 2297.9697, tol) - assert_near_equal(self.prob[Aircraft.Wing.HIGH_LIFT_MASS], 4740.1241, tol) - assert_near_equal(self.prob[Aircraft.Controls.MASS], 3819.3564, tol) - assert_near_equal(self.prob[Aircraft.Wing.SURFACE_CONTROL_MASS], 3682.099, tol) - assert_near_equal(prob[Aircraft.LandingGear.TOTAL_MASS], 7489.8343, tol) - assert_near_equal(prob[Aircraft.LandingGear.MAIN_GEAR_MASS], 6366.3591, tol) - assert_near_equal(self.prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 21078.3911, tol) - assert_near_equal(self.prob[Mission.USEFUL_LOAD], 5341.4317956, tol) - - assert_near_equal(prob[Aircraft.Engine.ADDITIONAL_MASS], 850.90095, tol) - assert_near_equal(prob[Aircraft.Wing.MASS], 16206.8122, tol) - assert_near_equal(prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 1740.2606, tol) - assert_near_equal(prob[Aircraft.Design.STRUCTURE_MASS], 50667.4376, tol) - assert_near_equal(prob[Aircraft.Fuselage.MASS], 18673.0352, tol) - assert_near_equal(prob[Aircraft.Propulsion.MASS], 16048.0025, tol) - assert_near_equal(prob[Aircraft.Fuel.WING_VOLUME_DESIGN], 848.5301, tol) - assert_near_equal(prob[Mission.OPERATING_MASS], 96954.6194, tol) - assert_near_equal(prob[Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY], 0, tol) + expected_values = { + # geometry subsystem + Aircraft.Fuselage.AVG_DIAMETER: 157.2, + Aircraft.Fuselage.LENGTH: 129.497, + Aircraft.Fuselage.WETTED_AREA: 4000.0, + Aircraft.Wing.AREA: 1370.3125, + Aircraft.Wing.SPAN: 117.81878299, + Aircraft.Wing.CENTER_CHORD: 17.48974356, + Aircraft.Wing.AVERAGE_CHORD: 12.61453233, + Aircraft.Wing.ROOT_CHORD: 16.40711451, + Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED: 0.139656, + Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX: 1114.0056, + Aircraft.HorizontalTail.AREA: 375.8798, + Aircraft.HorizontalTail.SPAN: 42.2543, + Aircraft.HorizontalTail.ROOT_CHORD: 13.1592, + Aircraft.HorizontalTail.AVERAGE_CHORD: 9.5768, + Aircraft.HorizontalTail.MOMENT_ARM: 54.6793, + Aircraft.VerticalTail.AREA: 469.3183, + Aircraft.VerticalTail.SPAN: 27.9957, + Aircraft.VerticalTail.ROOT_CHORD: 18.6162, + Aircraft.VerticalTail.AVERAGE_CHORD: 16.8321, + Aircraft.VerticalTail.MOMENT_ARM: 49.8809, + Aircraft.Nacelle.AVG_DIAMETER: 7.25, + Aircraft.Nacelle.AVG_LENGTH: 14.5, + Aircraft.Nacelle.SURFACE_AREA: 330.2599, + # mass subsystem + Aircraft.Design.LIFT_CURVE_SLOPE: 6.39471, + Aircraft.Wing.ULTIMATE_LOAD_FACTOR: 3.75, + Aircraft.Wing.MATERIAL_FACTOR: 1.22129, + Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS: 36000.0, + Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS: 36000.0, + Aircraft.Propulsion.TOTAL_ENGINE_MASS: 12605.94, + Aircraft.Nacelle.MASS: 990.7798, + Aircraft.HorizontalTail.MASS: 2276.1316, + Aircraft.VerticalTail.MASS: 2297.9697, + Aircraft.Wing.HIGH_LIFT_MASS: 4740.1241, + Aircraft.Controls.MASS: 3819.3564, + Aircraft.Wing.SURFACE_CONTROL_MASS: 3682.099, + Aircraft.LandingGear.TOTAL_MASS: 7489.8343, + Aircraft.LandingGear.MAIN_GEAR_MASS: 6366.3591, + # GASP original 21078.3911, added controls mass + Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS: 24_897.7475, + Mission.USEFUL_LOAD: 5341.4317956, + Aircraft.Engine.ADDITIONAL_MASS: 850.90095, + Aircraft.Wing.MASS: 16206.8122, + Aircraft.Fuel.FUEL_SYSTEM_MASS: 1740.2606, + Aircraft.Design.STRUCTURE_MASS: 50667.4376, + Aircraft.Fuselage.MASS: 18673.0352, + Aircraft.Propulsion.MASS: 16048.0025, + Aircraft.Fuel.WING_VOLUME_DESIGN: 848.5301, + Mission.OPERATING_MASS: 96954.6194, + Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY: 0, + } + + for var_name, expected in expected_values.items(): + with self.subTest(var=var_name): + assert_near_equal(prob[var_name], expected, tol) def test_case2(self): - """premission: propulsion + geometry + aerodynamics + mass""" - + """premission: propulsion + geometry + aerodynamics + mass.""" prob = self.prob engines = [build_engine_deck(self.gasp_inputs)] preprocess_options(self.gasp_inputs, engine_models=engines) @@ -134,60 +138,67 @@ def test_case2(self): prob.run_model() tol = 1e-5 - # propulsion subsystem - assert_near_equal(prob[Aircraft.Engine.SCALED_SLS_THRUST], 28690.0, tol) - # geometry subsystem - assert_near_equal(prob[Aircraft.Fuselage.AVG_DIAMETER], 157.2, tol) - assert_near_equal(prob[Aircraft.Fuselage.LENGTH], 129.497, tol) - assert_near_equal(prob[Aircraft.Fuselage.WETTED_AREA], 4000.0, tol) - assert_near_equal(prob[Aircraft.Wing.AREA], 1370.3125, tol) - assert_near_equal(prob[Aircraft.Wing.SPAN], 117.81878299, tol) - assert_near_equal(prob[Aircraft.Wing.CENTER_CHORD], 17.48974356, tol) - assert_near_equal(prob[Aircraft.Wing.AVERAGE_CHORD], 12.61453233, tol) - assert_near_equal(prob[Aircraft.Wing.ROOT_CHORD], 16.40711451, tol) - assert_near_equal(prob[Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED], 0.139656, tol) - assert_near_equal(prob[Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX], 1114.0056, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.AREA], 375.8798, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.SPAN], 42.2543, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.ROOT_CHORD], 13.1592, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.AVERAGE_CHORD], 9.5768, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.MOMENT_ARM], 54.6793, tol) - assert_near_equal(prob[Aircraft.VerticalTail.AREA], 469.3183, tol) - assert_near_equal(prob[Aircraft.VerticalTail.SPAN], 27.9957, tol) - assert_near_equal(prob[Aircraft.VerticalTail.ROOT_CHORD], 18.6162, tol) - assert_near_equal(prob[Aircraft.VerticalTail.AVERAGE_CHORD], 16.8321, tol) - assert_near_equal(prob[Aircraft.VerticalTail.MOMENT_ARM], 49.8809, tol) - assert_near_equal(prob[Aircraft.Nacelle.AVG_DIAMETER], 7.25, tol) - assert_near_equal(prob[Aircraft.Nacelle.AVG_LENGTH], 14.5, tol) - assert_near_equal(prob[Aircraft.Nacelle.SURFACE_AREA], 330.2599, tol) - # aerodynamics subsystem - assert_near_equal(prob[Mission.Landing.LIFT_COEFFICIENT_MAX], 2.8179491, tol) - # mass subsystem - assert_near_equal(self.prob[Aircraft.Design.LIFT_CURVE_SLOPE], 6.39471, tol) - assert_near_equal(self.prob[Aircraft.Wing.ULTIMATE_LOAD_FACTOR], 3.75, tol) - assert_near_equal(self.prob[Aircraft.Wing.MATERIAL_FACTOR], 1.22129, tol) - assert_near_equal(self.prob[Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS], 36000.0, tol) - assert_near_equal(self.prob[Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS], 36000.0, tol) - assert_near_equal(self.prob[Aircraft.Propulsion.TOTAL_ENGINE_MASS], 12259.8108, tol) - assert_near_equal(self.prob[Aircraft.Nacelle.MASS], 990.7798, tol) - assert_near_equal(self.prob[Aircraft.HorizontalTail.MASS], 2276.1316, tol) - assert_near_equal(self.prob[Aircraft.VerticalTail.MASS], 2297.9697, tol) - assert_near_equal(self.prob[Aircraft.Wing.HIGH_LIFT_MASS], 4161.22777613, tol) - assert_near_equal(self.prob[Aircraft.Controls.MASS], 3819.3564, tol) - assert_near_equal(self.prob[Aircraft.Wing.SURFACE_CONTROL_MASS], 3682.099, tol) - assert_near_equal(prob[Aircraft.LandingGear.TOTAL_MASS], 7489.8343, tol) - assert_near_equal(prob[Aircraft.LandingGear.MAIN_GEAR_MASS], 6366.3591, tol) - assert_near_equal(self.prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 21078.3911, tol) - assert_near_equal(self.prob[Mission.USEFUL_LOAD], 5332.684, tol) - assert_near_equal(prob[Aircraft.Engine.ADDITIONAL_MASS], 827.5372, tol) - assert_near_equal(prob[Aircraft.Wing.MASS], 15651.64198957, tol) - assert_near_equal(prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 1779.06667944, tol) - assert_near_equal(prob[Aircraft.Design.STRUCTURE_MASS], 50083.74652256, tol) - assert_near_equal(prob[Aircraft.Fuselage.MASS], 18675.0408, tol) - assert_near_equal(prob[Aircraft.Propulsion.MASS], 15694.0515, tol) - assert_near_equal(prob[Aircraft.Fuel.WING_VOLUME_DESIGN], 867.4514906, tol) - assert_near_equal(prob[Mission.OPERATING_MASS], 96008.12976964, tol) - assert_near_equal(prob[Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY], 0, tol) + expected_values = { + # propulsion subsystem + Aircraft.Engine.SCALED_SLS_THRUST: 28690.0, + # geometry subsystem + Aircraft.Fuselage.AVG_DIAMETER: 157.2, + Aircraft.Fuselage.LENGTH: 129.497, + Aircraft.Fuselage.WETTED_AREA: 4000.0, + Aircraft.Wing.AREA: 1370.3125, + Aircraft.Wing.SPAN: 117.81878299, + Aircraft.Wing.CENTER_CHORD: 17.48974356, + Aircraft.Wing.AVERAGE_CHORD: 12.61453233, + Aircraft.Wing.ROOT_CHORD: 16.40711451, + Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED: 0.139656, + Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX: 1114.0056, + Aircraft.HorizontalTail.AREA: 375.8798, + Aircraft.HorizontalTail.SPAN: 42.2543, + Aircraft.HorizontalTail.ROOT_CHORD: 13.1592, + Aircraft.HorizontalTail.AVERAGE_CHORD: 9.5768, + Aircraft.HorizontalTail.MOMENT_ARM: 54.6793, + Aircraft.VerticalTail.AREA: 469.3183, + Aircraft.VerticalTail.SPAN: 27.9957, + Aircraft.VerticalTail.ROOT_CHORD: 18.6162, + Aircraft.VerticalTail.AVERAGE_CHORD: 16.8321, + Aircraft.VerticalTail.MOMENT_ARM: 49.8809, + Aircraft.Nacelle.AVG_DIAMETER: 7.25, + Aircraft.Nacelle.AVG_LENGTH: 14.5, + Aircraft.Nacelle.SURFACE_AREA: 330.2599, + # aerodynamics subsystem + Mission.Landing.LIFT_COEFFICIENT_MAX: 2.8179491, + # mass subsystem + Aircraft.Design.LIFT_CURVE_SLOPE: 6.39471, + Aircraft.Wing.ULTIMATE_LOAD_FACTOR: 3.75, + Aircraft.Wing.MATERIAL_FACTOR: 1.22129, + Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS: 36000.0, + Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS: 36000.0, + Aircraft.Propulsion.TOTAL_ENGINE_MASS: 12259.8108, + Aircraft.Nacelle.MASS: 990.7798, + Aircraft.HorizontalTail.MASS: 2276.1316, + Aircraft.VerticalTail.MASS: 2297.9697, + Aircraft.Wing.HIGH_LIFT_MASS: 4161.22777613, + Aircraft.Controls.MASS: 3819.3564, + Aircraft.Wing.SURFACE_CONTROL_MASS: 3682.099, + Aircraft.LandingGear.TOTAL_MASS: 7489.8343, + Aircraft.LandingGear.MAIN_GEAR_MASS: 6366.3591, + # GASP original 21078.3911, added controls mass + Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS: 24_897.7475, + Mission.USEFUL_LOAD: 5332.684, + Aircraft.Engine.ADDITIONAL_MASS: 827.5372, + Aircraft.Wing.MASS: 15651.64198957, + Aircraft.Fuel.FUEL_SYSTEM_MASS: 1779.06667944, + Aircraft.Design.STRUCTURE_MASS: 50083.74652256, + Aircraft.Fuselage.MASS: 18675.0408, + Aircraft.Propulsion.MASS: 15694.0515, + Aircraft.Fuel.WING_VOLUME_DESIGN: 867.4514906, + Mission.OPERATING_MASS: 96008.12976964, + Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY: 0, + } + + for var_name, expected in expected_values.items(): + with self.subTest(var=var_name): + assert_near_equal(prob[var_name], expected, tol) @use_tempdirs @@ -239,7 +250,7 @@ def test_case1(self): FUEL_MASS -- WFADES = 33268.2 Aircraft.Fuel.WING_VOLUME_DESIGN -- FVOLREQ = 731.6 Mission.OPERATING_MASS tol -- OWE = 82982. - Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY -- not in GASP + Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY -- not in GASP. """ prob = self.prob @@ -265,66 +276,71 @@ def test_case1(self): prob.run_model() tol = 1e-5 - # geometry subsystem - assert_near_equal(prob[Aircraft.Fuselage.AVG_DIAMETER], 38, tol) - assert_near_equal(prob[Aircraft.Fuselage.LENGTH], 71.52455, tol) - assert_near_equal(prob[Aircraft.Fuselage.WETTED_AREA], 4573.882, tol) - assert_near_equal(prob[Aircraft.Wing.AREA], 2142.857, tol) - assert_near_equal(prob[Aircraft.Wing.SPAN], 146.385, tol) - assert_near_equal(prob[Aircraft.Wing.CENTER_CHORD], 22.97244, tol) - assert_near_equal(prob[Aircraft.Wing.AVERAGE_CHORD], 16.22, tol) - assert_near_equal(prob[Aircraft.Wing.ROOT_CHORD], 20.3337, tol) - assert_near_equal(prob[Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED], 0.135966, tol) - assert_near_equal(prob[Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX], 605.9078, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.AREA], 0.00117064, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.SPAN], 0.04467601, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.ROOT_CHORD], 0.0383645, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.AVERAGE_CHORD], 0.0280845, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.MOMENT_ARM], 29.6907, tol) - assert_near_equal(prob[Aircraft.VerticalTail.AREA], 169.1196, tol) - assert_near_equal(prob[Aircraft.VerticalTail.SPAN], 16.98084, tol) - assert_near_equal(prob[Aircraft.VerticalTail.ROOT_CHORD], 14.5819, tol) - assert_near_equal(prob[Aircraft.VerticalTail.AVERAGE_CHORD], 10.6746, tol) - assert_near_equal(prob[Aircraft.VerticalTail.MOMENT_ARM], 27.8219, tol) - assert_near_equal(prob[Aircraft.Nacelle.AVG_DIAMETER], 5.33382, tol) - assert_near_equal(prob[Aircraft.Nacelle.AVG_LENGTH], 7.2476, tol) - assert_near_equal(prob[Aircraft.Nacelle.SURFACE_AREA], 121.4458, tol) - # mass subsystem - assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS], 1686.6256, tol) - assert_near_equal(prob[Aircraft.Design.LIFT_CURVE_SLOPE], 5.948, tol) - assert_near_equal(prob[Aircraft.Wing.ULTIMATE_LOAD_FACTOR], 3.77336, tol) - assert_near_equal(prob[Aircraft.Wing.MATERIAL_FACTOR], 1.194612, tol) - assert_near_equal(prob[Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS], 33750.0, tol) - assert_near_equal(prob[Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS], 33750.0, tol) - assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_MASS], 7005.15475, tol) - assert_near_equal(prob[Aircraft.Nacelle.MASS], 303.6144, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.MASS], 1.02402, tol) - assert_near_equal(prob[Aircraft.VerticalTail.MASS], 864.174, tol) - assert_near_equal(prob[Aircraft.Wing.HIGH_LIFT_MASS], 974.436, tol) - assert_near_equal(prob[Aircraft.Controls.MASS], 2114.982, tol) - assert_near_equal(prob[Aircraft.Wing.SURFACE_CONTROL_MASS], 1986.251, tol) - assert_near_equal(prob[Aircraft.LandingGear.TOTAL_MASS], 7800.0, tol) - assert_near_equal(prob[Aircraft.LandingGear.MAIN_GEAR_MASS], 6630.0, tol) - assert_near_equal(prob[Aircraft.Avionics.MASS], 3225.0, tol) - assert_near_equal(prob[Aircraft.AirConditioning.MASS], 1301.573, tol) - assert_near_equal(prob[Aircraft.Furnishings.MASS], 11269.876, tol) - assert_near_equal(prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 20876.453, tol) - assert_near_equal(prob[Mission.USEFUL_LOAD], 5971.7946, tol) - assert_near_equal(prob[Aircraft.Engine.ADDITIONAL_MASS], 153.1677, tol) - assert_near_equal(prob[Aircraft.Wing.FOLD_MASS], 107.8736151, tol) - assert_near_equal(prob[Aircraft.Wing.MASS], 6962.31442344, tol) - assert_near_equal(prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 1316.13400269, tol) - assert_near_equal(prob[Aircraft.Design.STRUCTURE_MASS], 44473.41356849, tol) - assert_near_equal(prob[Aircraft.Fuselage.MASS], 27159.693, tol) - assert_near_equal(prob[Aircraft.Propulsion.MASS], 8627.6738, tol) - assert_near_equal(prob[Aircraft.Fuel.WING_VOLUME_DESIGN], 751.74213602, tol) - assert_near_equal(prob[Mission.OPERATING_MASS], 82064.29761786, tol) - assert_near_equal(prob[Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY], 3876.43000743, tol) + expected_values = { + # geometry subsystem + Aircraft.Fuselage.AVG_DIAMETER: 38, + Aircraft.Fuselage.LENGTH: 71.52455, + Aircraft.Fuselage.WETTED_AREA: 4573.882, + Aircraft.Wing.AREA: 2142.857, + Aircraft.Wing.SPAN: 146.385, + Aircraft.Wing.CENTER_CHORD: 22.97244, + Aircraft.Wing.AVERAGE_CHORD: 16.22, + Aircraft.Wing.ROOT_CHORD: 20.3337, + Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED: 0.135966, + Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX: 605.9078, + Aircraft.HorizontalTail.AREA: 0.00117064, + Aircraft.HorizontalTail.SPAN: 0.04467601, + Aircraft.HorizontalTail.ROOT_CHORD: 0.0383645, + Aircraft.HorizontalTail.AVERAGE_CHORD: 0.0280845, + Aircraft.HorizontalTail.MOMENT_ARM: 29.6907, + Aircraft.VerticalTail.AREA: 169.1196, + Aircraft.VerticalTail.SPAN: 16.98084, + Aircraft.VerticalTail.ROOT_CHORD: 14.5819, + Aircraft.VerticalTail.AVERAGE_CHORD: 10.6746, + Aircraft.VerticalTail.MOMENT_ARM: 27.8219, + Aircraft.Nacelle.AVG_DIAMETER: 5.33382, + Aircraft.Nacelle.AVG_LENGTH: 7.2476, + Aircraft.Nacelle.SURFACE_AREA: 121.4458, + # mass subsystem + Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS: 1686.6256, + Aircraft.Design.LIFT_CURVE_SLOPE: 5.948, + Aircraft.Wing.ULTIMATE_LOAD_FACTOR: 3.77336, + Aircraft.Wing.MATERIAL_FACTOR: 1.194612, + Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS: 33750.0, + Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS: 33750.0, + Aircraft.Propulsion.TOTAL_ENGINE_MASS: 7005.15475, + Aircraft.Nacelle.MASS: 303.6144, + Aircraft.HorizontalTail.MASS: 1.02402, + Aircraft.VerticalTail.MASS: 864.174, + Aircraft.Wing.HIGH_LIFT_MASS: 974.436, + Aircraft.Controls.MASS: 2114.982, + Aircraft.Wing.SURFACE_CONTROL_MASS: 1986.251, + Aircraft.LandingGear.TOTAL_MASS: 7800.0, + Aircraft.LandingGear.MAIN_GEAR_MASS: 6630.0, + Aircraft.Avionics.MASS: 3225.0, + Aircraft.AirConditioning.MASS: 1301.573, + Aircraft.Furnishings.MASS: 11269.876, + # GASP original 20876.453, added controls mass + Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS: 22_991.435, + Mission.USEFUL_LOAD: 5971.7946, + Aircraft.Engine.ADDITIONAL_MASS: 153.1677, + Aircraft.Wing.FOLD_MASS: 107.8736151, + Aircraft.Wing.MASS: 6962.31442344, + Aircraft.Fuel.FUEL_SYSTEM_MASS: 1316.13400269, + Aircraft.Design.STRUCTURE_MASS: 44473.41356849, + Aircraft.Fuselage.MASS: 27159.693, + Aircraft.Propulsion.MASS: 8627.6738, + Aircraft.Fuel.WING_VOLUME_DESIGN: 751.74213602, + Mission.OPERATING_MASS: 82064.29761786, + Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY: 3876.43000743, + } + + for var_name, expected in expected_values.items(): + with self.subTest(var=var_name): + assert_near_equal(prob[var_name], expected, tol) def test_case_geom(self): - """ - premission: geometry - """ + """premission: geometry.""" prob = self.prob preprocess_options(self.gasp_inputs) @@ -348,35 +364,39 @@ def test_case_geom(self): prob.run_model() tol = 1e-5 - # geometry subsystem - assert_near_equal(prob[Aircraft.Fuselage.AVG_DIAMETER], 38, tol) - assert_near_equal(prob[Aircraft.Fuselage.LENGTH], 71.52455, tol) - assert_near_equal(prob[Aircraft.Fuselage.WETTED_AREA], 4573.882, tol) - assert_near_equal(prob[Aircraft.Wing.AREA], 2142.857, tol) - assert_near_equal(prob[Aircraft.Wing.SPAN], 146.385, tol) - assert_near_equal(prob[Aircraft.Wing.CENTER_CHORD], 22.97244, tol) - assert_near_equal(prob[Aircraft.Wing.AVERAGE_CHORD], 16.22, tol) - assert_near_equal(prob[Aircraft.Wing.ROOT_CHORD], 20.3337, tol) - assert_near_equal(prob[Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED], 0.135966, tol) - assert_near_equal(prob[Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX], 605.9078, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.AREA], 0.00117064, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.SPAN], 0.04467601, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.ROOT_CHORD], 0.0383645, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.AVERAGE_CHORD], 0.0280845, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.MOMENT_ARM], 29.6907, tol) - assert_near_equal(prob[Aircraft.VerticalTail.AREA], 169.1196, tol) - assert_near_equal(prob[Aircraft.VerticalTail.SPAN], 16.98084, tol) - assert_near_equal(prob[Aircraft.VerticalTail.ROOT_CHORD], 14.5819, tol) - assert_near_equal(prob[Aircraft.VerticalTail.AVERAGE_CHORD], 10.6746, tol) - assert_near_equal(prob[Aircraft.VerticalTail.MOMENT_ARM], 27.8219, tol) - assert_near_equal(prob[Aircraft.Nacelle.AVG_DIAMETER], 5.33382, tol) - assert_near_equal(prob[Aircraft.Nacelle.AVG_LENGTH], 7.2476, tol) - assert_near_equal(prob[Aircraft.Nacelle.SURFACE_AREA], 121.4458, tol) + expected_values = { + # geometry subsystem + Aircraft.Fuselage.AVG_DIAMETER: 38, + Aircraft.Fuselage.LENGTH: 71.52455, + Aircraft.Fuselage.WETTED_AREA: 4573.882, + Aircraft.Wing.AREA: 2142.857, + Aircraft.Wing.SPAN: 146.385, + Aircraft.Wing.CENTER_CHORD: 22.97244, + Aircraft.Wing.AVERAGE_CHORD: 16.22, + Aircraft.Wing.ROOT_CHORD: 20.3337, + Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED: 0.135966, + Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX: 605.9078, + Aircraft.HorizontalTail.AREA: 0.00117064, + Aircraft.HorizontalTail.SPAN: 0.04467601, + Aircraft.HorizontalTail.ROOT_CHORD: 0.0383645, + Aircraft.HorizontalTail.AVERAGE_CHORD: 0.0280845, + Aircraft.HorizontalTail.MOMENT_ARM: 29.6907, + Aircraft.VerticalTail.AREA: 169.1196, + Aircraft.VerticalTail.SPAN: 16.98084, + Aircraft.VerticalTail.ROOT_CHORD: 14.5819, + Aircraft.VerticalTail.AVERAGE_CHORD: 10.6746, + Aircraft.VerticalTail.MOMENT_ARM: 27.8219, + Aircraft.Nacelle.AVG_DIAMETER: 5.33382, + Aircraft.Nacelle.AVG_LENGTH: 7.2476, + Aircraft.Nacelle.SURFACE_AREA: 121.4458, + } + + for var_name, expected in expected_values.items(): + with self.subTest(var=var_name): + assert_near_equal(prob[var_name], expected, tol) def test_case_geom_mass(self): - """ - premission: geometry + mass - """ + """premission: geometry + mass.""" prob = self.prob preprocess_options(self.gasp_inputs) @@ -410,61 +430,68 @@ def test_case_geom_mass(self): prob.run_model() tol = 1e-5 - # geometry subsystem - assert_near_equal(prob[Aircraft.Fuselage.AVG_DIAMETER], 38, tol) - assert_near_equal(prob[Aircraft.Fuselage.LENGTH], 71.52455, tol) - assert_near_equal(prob[Aircraft.Fuselage.WETTED_AREA], 4573.882, tol) - assert_near_equal(prob[Aircraft.Wing.AREA], 2142.857, tol) - assert_near_equal(prob[Aircraft.Wing.SPAN], 146.385, tol) - assert_near_equal(prob[Aircraft.Wing.CENTER_CHORD], 22.97244, tol) - assert_near_equal(prob[Aircraft.Wing.AVERAGE_CHORD], 16.22, tol) - assert_near_equal(prob[Aircraft.Wing.ROOT_CHORD], 20.3337, tol) - assert_near_equal(prob[Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED], 0.135966, tol) - assert_near_equal(prob[Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX], 605.9078, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.AREA], 0.00117064, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.SPAN], 0.04467601, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.ROOT_CHORD], 0.0383645, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.AVERAGE_CHORD], 0.0280845, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.MOMENT_ARM], 29.6907, tol) - assert_near_equal(prob[Aircraft.VerticalTail.AREA], 169.1196, tol) - assert_near_equal(prob[Aircraft.VerticalTail.SPAN], 16.98084, tol) - assert_near_equal(prob[Aircraft.VerticalTail.ROOT_CHORD], 14.5819, tol) - assert_near_equal(prob[Aircraft.VerticalTail.AVERAGE_CHORD], 10.6746, tol) - assert_near_equal(prob[Aircraft.VerticalTail.MOMENT_ARM], 27.8219, tol) - assert_near_equal(prob[Aircraft.Nacelle.AVG_DIAMETER], 5.33382, tol) - assert_near_equal(prob[Aircraft.Nacelle.AVG_LENGTH], 7.2476, tol) - assert_near_equal(prob[Aircraft.Nacelle.SURFACE_AREA], 121.4458, tol) - # mass subsystem - assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS], 1686.6256, tol) - assert_near_equal(prob[Aircraft.Design.LIFT_CURVE_SLOPE], 5.948, tol) - assert_near_equal(prob[Aircraft.Wing.ULTIMATE_LOAD_FACTOR], 3.77336, tol) - assert_near_equal(prob[Aircraft.Wing.MATERIAL_FACTOR], 1.194612, tol) - assert_near_equal(prob[Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS], 33750.0, tol) - assert_near_equal(prob[Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS], 33750.0, tol) - assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_MASS], 7005.155, tol) - assert_near_equal(prob[Aircraft.Nacelle.MASS], 303.6144, tol) - assert_near_equal(prob[Aircraft.HorizontalTail.MASS], 1.02402, tol) - assert_near_equal(prob[Aircraft.VerticalTail.MASS], 864.174, tol) - assert_near_equal(prob[Aircraft.Wing.HIGH_LIFT_MASS], 971.8248, tol) - assert_near_equal(prob[Aircraft.Controls.MASS], 2114.982, tol) - assert_near_equal(prob[Aircraft.Wing.SURFACE_CONTROL_MASS], 1986.251, tol) - assert_near_equal(prob[Aircraft.LandingGear.TOTAL_MASS], 7800.0, tol) - assert_near_equal(prob[Aircraft.LandingGear.MAIN_GEAR_MASS], 6630.0, tol) - assert_near_equal(prob[Aircraft.Avionics.MASS], 3225.0, tol) - assert_near_equal(prob[Aircraft.AirConditioning.MASS], 1301.573, tol) - assert_near_equal(prob[Aircraft.Furnishings.MASS], 11269.876, tol) - assert_near_equal(prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 20876.453, tol) - assert_near_equal(prob[Mission.USEFUL_LOAD], 5971.7946, tol) - assert_near_equal(prob[Aircraft.Engine.ADDITIONAL_MASS], 153.1677, tol) - assert_near_equal(prob[Aircraft.Wing.FOLD_MASS], 107.8335, tol) - assert_near_equal(prob[Aircraft.Wing.MASS], 6959.7262, tol) - assert_near_equal(prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 1316.2306, tol) - assert_near_equal(prob[Aircraft.Design.STRUCTURE_MASS], 44471.243, tol) - assert_near_equal(prob[Aircraft.Fuselage.MASS], 27159.693, tol) - assert_near_equal(prob[Aircraft.Propulsion.MASS], 8627.72, tol) - assert_near_equal(prob[Aircraft.Fuel.WING_VOLUME_DESIGN], 751.7973, tol) - assert_near_equal(prob[Mission.OPERATING_MASS], 82062.193, tol) - assert_near_equal(prob[Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY], 3878.938, tol) + expected_values = { + # geometry subsystem + Aircraft.Fuselage.AVG_DIAMETER: 38, + Aircraft.Fuselage.LENGTH: 71.52455, + Aircraft.Fuselage.WETTED_AREA: 4573.882, + Aircraft.Wing.AREA: 2142.857, + Aircraft.Wing.SPAN: 146.385, + Aircraft.Wing.CENTER_CHORD: 22.97244, + Aircraft.Wing.AVERAGE_CHORD: 16.22, + Aircraft.Wing.ROOT_CHORD: 20.3337, + Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED: 0.135966, + Aircraft.Fuel.WING_VOLUME_GEOMETRIC_MAX: 605.9078, + Aircraft.HorizontalTail.AREA: 0.00117064, + Aircraft.HorizontalTail.SPAN: 0.04467601, + Aircraft.HorizontalTail.ROOT_CHORD: 0.0383645, + Aircraft.HorizontalTail.AVERAGE_CHORD: 0.0280845, + Aircraft.HorizontalTail.MOMENT_ARM: 29.6907, + Aircraft.VerticalTail.AREA: 169.1196, + Aircraft.VerticalTail.SPAN: 16.98084, + Aircraft.VerticalTail.ROOT_CHORD: 14.5819, + Aircraft.VerticalTail.AVERAGE_CHORD: 10.6746, + Aircraft.VerticalTail.MOMENT_ARM: 27.8219, + Aircraft.Nacelle.AVG_DIAMETER: 5.33382, + Aircraft.Nacelle.AVG_LENGTH: 7.2476, + Aircraft.Nacelle.SURFACE_AREA: 121.4458, + # mass subsystem + Aircraft.Propulsion.TOTAL_ENGINE_POD_MASS: 1686.6256, + Aircraft.Design.LIFT_CURVE_SLOPE: 5.948, + Aircraft.Wing.ULTIMATE_LOAD_FACTOR: 3.77336, + Aircraft.Wing.MATERIAL_FACTOR: 1.194612, + Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS: 33750.0, + Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS: 33750.0, + Aircraft.Propulsion.TOTAL_ENGINE_MASS: 7005.155, + Aircraft.Nacelle.MASS: 303.6144, + Aircraft.HorizontalTail.MASS: 1.02402, + Aircraft.VerticalTail.MASS: 864.174, + Aircraft.Wing.HIGH_LIFT_MASS: 971.8248, + Aircraft.Controls.MASS: 2114.982, + Aircraft.Wing.SURFACE_CONTROL_MASS: 1986.251, + Aircraft.LandingGear.TOTAL_MASS: 7800.0, + Aircraft.LandingGear.MAIN_GEAR_MASS: 6630.0, + Aircraft.Avionics.MASS: 3225.0, + Aircraft.AirConditioning.MASS: 1301.573, + Aircraft.Furnishings.MASS: 11269.876, + # GASP original 20876.453, added controls mass + Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS: 22_991.435, + Mission.USEFUL_LOAD: 5971.7946, + Aircraft.Engine.ADDITIONAL_MASS: 153.1677, + Aircraft.Wing.FOLD_MASS: 107.8335, + Aircraft.Wing.MASS: 6959.7262, + Aircraft.Fuel.FUEL_SYSTEM_MASS: 1316.2306, + Aircraft.Design.STRUCTURE_MASS: 44471.243, + Aircraft.Fuselage.MASS: 27159.693, + Aircraft.Propulsion.MASS: 8627.72, + Aircraft.Fuel.WING_VOLUME_DESIGN: 751.7973, + Mission.OPERATING_MASS: 82062.193, + Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY: 3878.938, + } + + for var_name, expected in expected_values.items(): + with self.subTest(var=var_name): + assert_near_equal(prob[var_name], expected, tol) if __name__ == '__main__': diff --git a/aviary/utils/preprocessors.py b/aviary/utils/preprocessors.py index d3fd791b7f..024f71e78c 100644 --- a/aviary/utils/preprocessors.py +++ b/aviary/utils/preprocessors.py @@ -756,14 +756,14 @@ def preprocess_propulsion( if total_engines_calc == 0: if num_engines > 1: num_wing_engines_all[i] = num_engines - if verbosity >= Verbosity.BRIEF: # BRIEF, VERBOSE, DEBUG + if verbosity >= Verbosity.VERBOSE: # VERBOSE, DEBUG warnings.warn( f'Mount location for engines of type <{eng_name}> not ' 'specified. Wing-mounted engines are assumed.' ) else: num_fuse_engines_all[i] = num_engines - if verbosity >= Verbosity.BRIEF: # BRIEF, VERBOSE, DEBUG + if verbosity >= Verbosity.VERBOSE: # VERBOSE, DEBUG warnings.warn( f'Mount location for single engine of type <{eng_name}> not ' 'specified. Assuming it is fuselage-mounted.' @@ -786,14 +786,14 @@ def preprocess_propulsion( num_unspecified_engines = num_engines - num_fuse_engines - num_wing_engines if num_unspecified_engines > 1: num_wing_engines_all[i] = num_wing_engines + num_unspecified_engines - if verbosity >= Verbosity.BRIEF: # BRIEF, VERBOSE, DEBUG + if verbosity >= Verbosity.VERBOSE: # VERBOSE, DEBUG warnings.warn( 'Mount location was not defined for all engines of EngineModel ' f'<{eng_name}> - unspecified engines are assumed wing-mounted.' ) elif num_unspecified_engines == 1 and num_wing_engines != 0: num_fuse_engines_all[i] = num_fuse_engines + num_unspecified_engines - if verbosity >= Verbosity.BRIEF: # BRIEF, VERBOSE, DEBUG + if verbosity >= Verbosity.VERBOSE: # VERBOSE, DEBUG warnings.warn( 'Mount location was not defined for all engine of EngineModel ' f'<{eng_name}> - unspecified engine is assumed fuselage-mounted.' diff --git a/aviary/utils/test/data/converter_test_BWB_GASP.csv b/aviary/utils/test/data/converter_test_BWB_GASP.csv index 6bd086b919..28df44cc50 100644 --- a/aviary/utils/test/data/converter_test_BWB_GASP.csv +++ b/aviary/utils/test/data/converter_test_BWB_GASP.csv @@ -88,7 +88,7 @@ aircraft:hydraulics:gear_mass_coefficient,0.135,unitless aircraft:instruments:mass_coefficient,0.116,unitless aircraft:landing_gear:fixed_gear,False,unitless aircraft:landing_gear:main_gear_location,0.0,unitless -aircraft:landing_gear:main_gear_mass_coefficient,0.85,unitless +aircraft:landing_gear:main_gear_mass_fraction,0.85,unitless aircraft:landing_gear:mass_coefficient,0.052,unitless aircraft:landing_gear:tail_hook_mass_scaler,1.0,unitless aircraft:landing_gear:total_mass_scaler,1.0,unitless diff --git a/aviary/utils/test/data/converter_test_configuration_GASP.csv b/aviary/utils/test/data/converter_test_configuration_GASP.csv index 4701d87b6d..26e9c7d3e0 100644 --- a/aviary/utils/test/data/converter_test_configuration_GASP.csv +++ b/aviary/utils/test/data/converter_test_configuration_GASP.csv @@ -81,7 +81,7 @@ aircraft:hydraulics:gear_mass_coefficient,0.105,unitless aircraft:instruments:mass_coefficient,0.0736,unitless aircraft:landing_gear:fixed_gear,False,unitless aircraft:landing_gear:main_gear_location,0.0,unitless -aircraft:landing_gear:main_gear_mass_coefficient,0.85,unitless +aircraft:landing_gear:main_gear_mass_fraction,0.85,unitless aircraft:landing_gear:mass_coefficient,0.0339,unitless aircraft:landing_gear:tail_hook_mass_scaler,1.0,unitless aircraft:landing_gear:total_mass_scaler,1.0,unitless 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 c1432b7ab3..6c730373db 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 @@ -81,7 +81,7 @@ aircraft:hydraulics:gear_mass_coefficient,0.14,unitless aircraft:instruments:mass_coefficient,0.0736,unitless aircraft:landing_gear:fixed_gear,False,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_fraction,0.85,unitless aircraft:landing_gear:mass_coefficient,0.04,unitless aircraft:landing_gear:tail_hook_mass_scaler,1.0,unitless aircraft:landing_gear:total_mass_scaler,1.0,unitless 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 f81e55c7d9..ba5b906dd2 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 @@ -81,7 +81,7 @@ aircraft:hydraulics:gear_mass_coefficient,0.14,unitless aircraft:instruments:mass_coefficient,0.06,unitless aircraft:landing_gear:fixed_gear,False,unitless aircraft:landing_gear:main_gear_location,0.199,unitless -aircraft:landing_gear:main_gear_mass_coefficient,0.85,unitless +aircraft:landing_gear:main_gear_mass_fraction,0.85,unitless aircraft:landing_gear:mass_coefficient,0.036,unitless aircraft:landing_gear:tail_hook_mass_scaler,1.0,unitless aircraft:landing_gear:total_mass_scaler,1.0,unitless diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index d7b64916f1..35c2ffbfe8 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -2040,8 +2040,8 @@ meta_data=_MetaData, historical_name={'GASP': None, 'FLOPS': None, 'LEAPS1': None}, units='lbm', - desc='additional propulsion system mass added to engine control and starter mass, or ' - 'engine installation mass', + desc='additional engine mass not counted by existing categories (such as engine control and ' + 'starter mass in FLOPS). In GASP, this is engine installation mass.', default_value=0.0, multivalue=True, ) @@ -2056,9 +2056,8 @@ }, units='unitless', option=True, - desc='fraction of (scaled) engine mass used to calculate additional propulsion ' - 'system mass added to engine control and starter mass, or used to calculate engine ' - 'installation mass', + desc='fraction of (scaled) engine mass used to calculate additional engine mass (see ' + 'Aircraft.Engine.ADDITIONAL_MASS)', types=(float, int, np.ndarray), multivalue=True, default_value=0.0, @@ -2828,6 +2827,19 @@ multivalue=True, ) +add_meta_data( + Aircraft.Engine.Propeller.MASS, + meta_data=_MetaData, + # TODO Check if GASP has a variable for this + historical_name={'GASP': None, 'FLOPS': None, 'LEAPS1': None}, + units='lbm', + desc='mass of propellers on engine (sum of all blades)', + option=False, + types=float, + multivalue=True, + default_value=0, +) + add_meta_data( Aircraft.Engine.Propeller.NUM_BLADES, meta_data=_MetaData, @@ -3318,6 +3330,9 @@ default_value=0.0, ) +# TODO the GASP use of this variable is misleading (optional coefficient for additional +# furnishing mass, which is activated by Aircraft.Furnishings.USE_EMPERICAL_EQUATION). Create +# new variable (Aircraft.Furnishings.MASS_COEFFICIENT?) for GASP side add_meta_data( Aircraft.Furnishings.MASS_SCALER, meta_data=_MetaData, @@ -3333,6 +3348,9 @@ default_value=1.0, ) +# Misnamed. This sets if Aircraft.Furnishings.MASS_SCALER is used as a coefficient for additional +# furnishings weight and the alternative (False) is to use the emperical equation. The variable toggle +# based on gross mass and num_pax is bad Aviary behavior and should occur in fortran_to_aviary instead add_meta_data( Aircraft.Furnishings.USE_EMPIRICAL_EQUATION, meta_data=_MetaData, @@ -4376,11 +4394,11 @@ ) add_meta_data( - Aircraft.LandingGear.MAIN_GEAR_MASS_COEFFICIENT, + Aircraft.LandingGear.MAIN_GEAR_MASS_FRACTION, meta_data=_MetaData, historical_name={'GASP': 'INGASP.SKMG', 'FLOPS': None, 'LEAPS1': None}, units='unitless', - desc='mass trend coefficient of main gear, fraction of total landing gear', + desc='fraction of total landing gear mass that is main gear mass', default_value=0.0, ) @@ -4855,6 +4873,8 @@ ) # TODO clash with per-engine scaling, need to resolve w/ heterogeneous engine +# TODO in GASP this applies to ADDITIONAL_MASS (installation weight), confusing because that also +# uses ADDITIONAL_MASS_FRACTION - also applies globally to all engines there, which is wrong add_meta_data( Aircraft.Propulsion.MISC_MASS_SCALER, meta_data=_MetaData, @@ -4865,8 +4885,8 @@ 'LEAPS1': ['aircraft.inputs.L0_overrides.misc_propulsion_weight'], }, units='unitless', - desc='scaler applied to miscellaneous engine mass (sum of engine control, starter, ' - 'and additional mass)', + desc='scaler applied to miscellaneous engine mass (in FLOPS, sum of engine control, starter, ' + 'and additional mass. In GASP, applied to ADDITIONAL_MASS, which is engine installation mass)', default_value=1.0, ) diff --git a/aviary/variable_info/variables.py b/aviary/variable_info/variables.py index 7c7bcb6f95..373658a063 100644 --- a/aviary/variable_info/variables.py +++ b/aviary/variable_info/variables.py @@ -243,6 +243,7 @@ class Propeller: DATA_FILE = 'aircraft:engine:propeller:data_file' DIAMETER = 'aircraft:engine:propeller:diameter' INTEGRATED_LIFT_COEFFICIENT = 'aircraft:engine:propeller:integrated_lift_coefficient' + MASS = 'aircraft:engine:propeller:mass' NUM_BLADES = 'aircraft:engine:propeller:num_blades' TIP_MACH_MAX = 'aircraft:engine:propeller:tip_mach_max' TIP_SPEED_MAX = 'aircraft:engine:propeller:tip_speed_max' @@ -375,7 +376,7 @@ class LandingGear: FIXED_GEAR = 'aircraft:landing_gear:fixed_gear' MAIN_GEAR_LOCATION = 'aircraft:landing_gear:main_gear_location' MAIN_GEAR_MASS = 'aircraft:landing_gear:main_gear_mass' - MAIN_GEAR_MASS_COEFFICIENT = 'aircraft:landing_gear:main_gear_mass_coefficient' + MAIN_GEAR_MASS_FRACTION = 'aircraft:landing_gear:main_gear_mass_fraction' MAIN_GEAR_MASS_SCALER = 'aircraft:landing_gear:main_gear_mass_scaler' MAIN_GEAR_OLEO_LENGTH = 'aircraft:landing_gear:main_gear_oleo_length' MASS_COEFFICIENT = 'aircraft:landing_gear:mass_coefficient'