diff --git a/aviary/docs/examples/modified_aircraft.csv b/aviary/docs/examples/modified_aircraft.csv index b89269289..a50be4fd1 100644 --- a/aviary/docs/examples/modified_aircraft.csv +++ b/aviary/docs/examples/modified_aircraft.csv @@ -115,7 +115,7 @@ aircraft:wing:airfoil_technology,1.92669766647637,unitless aircraft:wing:area,1370.0,ft**2 aircraft:wing:aspect_ratio,11.02091,unitless aircraft:wing:bending_material_mass_scaler,1.0,unitless -aircraft:wing:chord_per_semispan,0.31,0.23,0.084,unitless +aircraft:wing:chord_per_semispan_dist,0.31,0.23,0.084,unitless aircraft:wing:composite_fraction,0.2,unitless aircraft:wing:control_surface_area,137,ft**2 aircraft:wing:control_surface_area_ratio,0.1,unitless diff --git a/aviary/interface/test/sizing_problem_for_test.json b/aviary/interface/test/sizing_problem_for_test.json index af4e386d3..106d1f9e3 100644 --- a/aviary/interface/test/sizing_problem_for_test.json +++ b/aviary/interface/test/sizing_problem_for_test.json @@ -1050,7 +1050,7 @@ "" ], [ - "aircraft:wing:chord_per_semispan", + "aircraft:wing:chord_per_semispan_dist", [ 0.31, 0.23, diff --git a/aviary/models/aircraft/advanced_single_aisle/advanced_single_aisle_FLOPS.csv b/aviary/models/aircraft/advanced_single_aisle/advanced_single_aisle_FLOPS.csv index a411a73d6..87bf273e3 100644 --- a/aviary/models/aircraft/advanced_single_aisle/advanced_single_aisle_FLOPS.csv +++ b/aviary/models/aircraft/advanced_single_aisle/advanced_single_aisle_FLOPS.csv @@ -131,7 +131,7 @@ aircraft:wing:aspect_ratio,11.5587605382765,unitless aircraft:wing:aspect_ratio_reference,11.5587605382765,unitless aircraft:wing:bending_material_mass_scaler,1,unitless aircraft:wing:bwb_aft_body_mass_scaler,1,unitless -aircraft:wing:chord_per_semispan,0.273522534166506,0.204274849507037,0.0888152947868224,0.0725353313595661,unitless +aircraft:wing:chord_per_semispan_dist,0.273522534166506,0.204274849507037,0.0888152947868224,0.0725353313595661,unitless aircraft:wing:composite_fraction,0.33333,unitless aircraft:wing:control_surface_area_ratio,0.333,unitless aircraft:wing:dihedral,6,deg diff --git a/aviary/models/aircraft/blended_wing_body/bwb_1a_FLOPS_data.py b/aviary/models/aircraft/blended_wing_body/bwb_1a_FLOPS_data.py new file mode 100644 index 000000000..db7b19b75 --- /dev/null +++ b/aviary/models/aircraft/blended_wing_body/bwb_1a_FLOPS_data.py @@ -0,0 +1,569 @@ +import numpy as np + +from aviary.utils.aviary_values import AviaryValues +from aviary.utils.functions import get_path +from aviary.variable_info.enums import AircraftTypes, EquationsOfMotion, LegacyCode +from aviary.variable_info.variables import Aircraft, Mission, Settings + +BWB1aFLOPS = {} +inputs = BWB1aFLOPS['inputs'] = AviaryValues() +outputs = BWB1aFLOPS['outputs'] = AviaryValues() + +# Overall Aircraft +# --------------------------- +inputs.set_val( + Aircraft.Design.BASE_AREA, 0.0, 'ft**2' +) # SBASE not in bwb.in, set to 0.0 as all others +inputs.set_val( + Aircraft.Design.EMPTY_MASS_MARGIN_SCALER, 0.0 +) # EWMARG not in bwb.in, set to default +inputs.set_val( + Aircraft.Design.TOUCHDOWN_MASS, 699279.2, 'lbm' +) # WLDG not in bwb.in, WLDG = GW*WRATIO +inputs.set_val(Mission.Design.GROSS_MASS, 874099.0, 'lbm') # DGW in bwb.in +inputs.set_val(Aircraft.Design.USE_ALT_MASS, False) +inputs.set_val(Aircraft.Design.LIFT_DEPENDENT_DRAG_COEFF_FACTOR, 1.0) # FCDI in bwb.in +inputs.set_val( + Aircraft.Design.SUBSONIC_DRAG_COEFF_FACTOR, 1.0 +) # FCDSUB not in bwb.in, set to default +inputs.set_val( + Aircraft.Design.SUPERSONIC_DRAG_COEFF_FACTOR, 1.0 +) # FCDSUP not in bwb.in, set to default +inputs.set_val(Aircraft.Design.ZERO_LIFT_DRAG_COEFF_FACTOR, 1.0) # FCDO in bwb.in +inputs.set_val(Aircraft.Design.TYPE, AircraftTypes.BLENDED_WING_BODY) + +# Air Conditioning +# --------------------------- +inputs.set_val(Aircraft.AirConditioning.MASS_SCALER, 1.0) # WAC not in bwb.in + +# Anti-Icing +# --------------------------- +inputs.set_val(Aircraft.AntiIcing.MASS_SCALER, 1.0) # WAI not in bwb.in + +# APU +# --------------------------- +inputs.set_val(Aircraft.APU.MASS_SCALER, 1.0) # WAPU not in bwb.in, set to Aviary default + +# Avionics +# --------------------------- +inputs.set_val(Aircraft.Avionics.MASS_SCALER, 1.0) # WAVONC in bwb.in + +# Canard +# --------------------------- +inputs.set_val(Aircraft.Canard.AREA, 0.0, 'ft**2') # SCAN not in bwb.in, set to default +inputs.set_val(Aircraft.Canard.ASPECT_RATIO, 0.0) # ARCAN not in bwb.in, set to default +inputs.set_val(Aircraft.Canard.THICKNESS_TO_CHORD, 0.0) # TCCAN not in bwb.in, default to TCHT + +# Crew and Payload +# --------------------------- +inputs.set_val(Aircraft.CrewPayload.Design.NUM_BUSINESS_CLASS, 100) # NPB in bwb.in +inputs.set_val(Aircraft.CrewPayload.Design.NUM_FIRST_CLASS, 28) # NPF in bwb.in +inputs.set_val(Aircraft.CrewPayload.Design.NUM_PASSENGERS, 468, units='unitless') # NPB+NPF+NPT +inputs.set_val(Aircraft.CrewPayload.Design.NUM_TOURIST_CLASS, 340) # NPT in bwb.in +inputs.set_val(Aircraft.CrewPayload.NUM_BUSINESS_CLASS, 100) # NPB in bwb.in +inputs.set_val(Aircraft.CrewPayload.NUM_FIRST_CLASS, 28) # NPF in bwb.in +inputs.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, 468, units='unitless') +inputs.set_val(Aircraft.CrewPayload.NUM_TOURIST_CLASS, 340) # NPT in bwb.in +inputs.set_val(Aircraft.CrewPayload.Design.NUM_SEATS_ABREAST_BUSINESS, 4) # NBABR in bwb.in +inputs.set_val(Aircraft.CrewPayload.Design.NUM_SEATS_ABREAST_FIRST, 4) # NFABR in bwb.in +inputs.set_val(Aircraft.CrewPayload.Design.NUM_SEATS_ABREAST_TOURIST, 6) # NTABR in bwb.in +inputs.set_val(Aircraft.CrewPayload.Design.SEAT_PITCH_BUSINESS, 39, 'inch') # BPITCH in bwb.in +inputs.set_val(Aircraft.CrewPayload.Design.SEAT_PITCH_FIRST, 61, 'inch') # FPITCH in bwb.in +inputs.set_val(Aircraft.CrewPayload.Design.SEAT_PITCH_TOURIST, 32, 'inch') # TPITCH in bwb.in + +inputs.set_val( + Aircraft.CrewPayload.CARGO_CONTAINER_MASS_SCALER, 1.0 +) # WCON not in bwb.in, set to Aviary default +inputs.set_val(Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS, 22) # NSTU in bwb.in +inputs.set_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW, 2) # NFLCR in bwb.in +inputs.set_val( + Aircraft.CrewPayload.FLIGHT_CREW_MASS_SCALER, 1.0 +) # WFLCRB not in bwb.in, set to Aviary default +inputs.set_val( + Aircraft.CrewPayload.NUM_GALLEY_CREW, 0 +) # NGALC not in bwb.in, set to Aviary default +inputs.set_val( + Aircraft.CrewPayload.MISC_CARGO, 0.0, 'lbm' +) # CARGOF not in bwb.in, set to Aviary default +inputs.set_val( + Aircraft.CrewPayload.NON_FLIGHT_CREW_MASS_SCALER, 1.0 +) # WSTUAB not in bwb.in, set to Aviary default +inputs.set_val( + Aircraft.CrewPayload.PASSENGER_SERVICE_MASS_SCALER, 1.0 +) # WSRV not in bwb.in, set to Aviary default +inputs.set_val( + Aircraft.CrewPayload.MASS_PER_PASSENGER, 165.0, 'lbm' +) # WPPASS not in bwb.in, set to default +inputs.set_val( + Aircraft.CrewPayload.WING_CARGO, 0.0, 'lbm' +) # CARGOW not in bwb.in, set to Aviary default +inputs.set_val( + Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER, 44.0, 'lbm' +) # BPP not in bwb.in, set to default + +# Electrical +# --------------------------- +inputs.set_val(Aircraft.Electrical.MASS_SCALER, 1.0) # WELEC not in bwb.in, set to Aviary default + +# Fins +# --------------------------- +inputs.set_val(Aircraft.Fins.AREA, 184.89, 'ft**2') # SFIN in bwb.in +inputs.set_val(Aircraft.Fins.NUM_FINS, 2) # NFIN in bwb.in +inputs.set_val(Aircraft.Fins.TAPER_RATIO, 0.464) # TRFIN in bwb.in +inputs.set_val(Aircraft.Fins.MASS, 0.0, 'lbm') # WFIN not in bwb.in, set to Aviary default +inputs.set_val(Aircraft.Fins.MASS_SCALER, 1.0) # FRFIN not in bwb.in, set to Aviary default + +# Fuel +# --------------------------- +inputs.set_val( + Aircraft.Fuel.AUXILIARY_FUEL_CAPACITY, 0.0, 'lbm' +) # FULAUX not in bwb.in, set to Aviary default +inputs.set_val( + Aircraft.Fuel.DENSITY, 6.7, 'lbm/galUS' +) # FULDEN not in bwb.in, set to Aviary default +inputs.set_val( + Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, 1.0 +) # WFSYS not in bwb.in, set to Aviary default +inputs.set_val( + Aircraft.Fuel.FUSELAGE_FUEL_CAPACITY, 0.0, 'lbm' +) # FULFMX not in bwb.in, set to Aviary default +inputs.set_val(Aircraft.Fuel.NUM_TANKS, 7) # NTANK not in bwb.in, set to default +inputs.set_val( + Aircraft.Fuel.UNUSABLE_FUEL_MASS_SCALER, 1.0 +) # WUF not in bwb.in, set to Aviary default +inputs.set_val( + Aircraft.Fuel.IGNORE_FUEL_CAPACITY_CONSTRAINT, False +) # IFUFU not in bwb.in, set to default + +# Furnishings +# --------------------------- +inputs.set_val(Aircraft.Furnishings.MASS_SCALER, 1.0) # WFURN in bwb.in + +# Fuselage +# --------------------------- +inputs.set_val(Aircraft.Fuselage.NUM_FUSELAGES, 1) # NFUSE in bwb.in +inputs.set_val(Aircraft.Fuselage.LENGTH, 137.5, 'ft') # XL in bwb.in +inputs.set_val(Aircraft.Fuselage.MILITARY_CARGO_FLOOR, False) # CARGF in bwb.in +inputs.set_val(Aircraft.Fuselage.MASS_SCALER, 1.0) # FRFU in bwb.in +inputs.set_val(Aircraft.Fuselage.MAX_WIDTH, 64.58, 'ft') # WF in bwb.in +# inputs.set_val(Aircraft.Fuselage.MAX_HEIGHT, 15.125, 'ft') # DF in bwb.in, but should not be here +# inputs.set_val(Aircraft.Fuselage.CABIN_AREA, 0, 'ft**2') # ACABIN in bwb.in, but should not be here +# inputs.set_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH, 0, 'ft') # XLP in bwb.in, but should not be here + + +# inputs.set_val(Aircraft.Fuselage.WETTED_AREA, 0.0, 'ft**2') # For BWB, see _BWBFuselage() +inputs.set_val( + Aircraft.Fuselage.WETTED_AREA_SCALER, 1.0 +) # SWETF not in bwb.in, set to Aviary default + +# Horizontal Tail +# --------------------------- +inputs.set_val(Aircraft.HorizontalTail.AREA, 0.0, 'ft**2') # SHT in bwb.in +inputs.set_val(Aircraft.HorizontalTail.ASPECT_RATIO, 0.0) # SHT in bwb.in +inputs.set_val(Aircraft.HorizontalTail.TAPER_RATIO, 0.0) # TRHT in bwb.in +inputs.set_val(Aircraft.HorizontalTail.THICKNESS_TO_CHORD, 0.0) # TCHT in bwb.in +# inputs.set_val(Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, 0.0) # HHT not in bwb.in, +inputs.set_val(Aircraft.HorizontalTail.MASS_SCALER, 1.0) # SHT in bwb.in +# inputs.set_val(Aircraft.HorizontalTail.WETTED_AREA, 592.65, 'ft**2') # SWTHT not in bwb.in +inputs.set_val( + Aircraft.HorizontalTail.WETTED_AREA_SCALER, 1.0 +) # SWETH not in bwb.in, set to Aviary default +# inputs.set_val(Aircraft.HorizontalTail.SWEEP, 0) # SWPHT in bwb.in, but should not be here + +# Hydraulics +# --------------------------- +# inputs.set_val(Aircraft.Hydraulics.SYSTEM_PRESSURE, 3000.0, 'psi') # HYDPR not in bwb.in +inputs.set_val(Aircraft.Hydraulics.MASS_SCALER, 1.0) # WHYD in bwb.in + +# Instruments +# --------------------------- +inputs.set_val(Aircraft.Instruments.MASS_SCALER, 1.0) # WIN not in bwb.in, set to Aviary default + +# Landing Gear +# --------------------------- +inputs.set_val(Aircraft.LandingGear.MAIN_GEAR_OLEO_LENGTH, 85.0, 'inch') # XMLG in bwb.in +inputs.set_val( + Aircraft.LandingGear.MAIN_GEAR_MASS_SCALER, 1.0 +) # FRLGM not in bwb.in, set to Aviary default +inputs.set_val(Aircraft.LandingGear.NOSE_GEAR_OLEO_LENGTH, 87.0, 'inch') # XNLG in bwb.in +inputs.set_val( + Aircraft.LandingGear.NOSE_GEAR_MASS_SCALER, 1.0 +) # FRLGN not in bwb.in, set to Aviary default + +# Nacelle +# --------------------------- +inputs.set_val(Aircraft.Nacelle.AVG_DIAMETER, 12.608, 'ft') # DNAC in bwb.in +inputs.set_val(Aircraft.Nacelle.AVG_LENGTH, 17.433, 'ft') # XNAC in bwb.in +inputs.set_val(Aircraft.Nacelle.MASS_SCALER, 0.0) # FRNA in bwb.in +inputs.set_val( + Aircraft.Nacelle.WETTED_AREA_SCALER, 1.0 +) # SWETN not in bwb.in, set to Aviary default + +# Paint +# --------------------------- +# inputs.set_val(Aircraft.Paint.MASS_PER_UNIT_AREA, 0.037, 'lbm/ft**2') # WPAINT not in bwb.in, + +# Propulsion and Engine +# --------------------------- +inputs.set_val( + Aircraft.Propulsion.ENGINE_OIL_MASS_SCALER, 1.0 +) # WOIL not in bwb.in, set to Aviary default +inputs.set_val(Aircraft.Propulsion.MISC_MASS_SCALER, 0.0) # WPMSC in bwb.in + +filename = get_path('models/engines/PAX300_baseline_ENGDEK.csv') + +inputs.set_val(Aircraft.Engine.DATA_FILE, filename) +# inputs.set_val(Aircraft.Engine.MASS, 7400, 'lbm') # not in bwb.in, not a FLOPS variable +inputs.set_val(Aircraft.Engine.REFERENCE_MASS, 22017, 'lbm') # WENG in bwb.in +inputs.set_val( + Aircraft.Engine.SCALED_SLS_THRUST, 70000, 'lbf' +) # THRUST in bwb.in [70000, 1, 0, 0, 0, 0] +inputs.set_val(Aircraft.Engine.REFERENCE_SLS_THRUST, 86459.2, 'lbf') # THRSO in bwb.in +inputs.set_val( + Aircraft.Engine.NUM_ENGINES, [3] +) # not in bwb.in, not a FLOPS variable, set to NEW+NEF +inputs.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, 3) # NEF in bwb.in +inputs.set_val(Aircraft.Engine.NUM_WING_ENGINES, 0) # NEW in bwb.in +inputs.set_val(Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER, 0.0) # WTHR in bwb.in +inputs.set_val(Aircraft.Engine.WING_LOCATIONS, 0) # ETAE not in bwb.in, not a FLOPS variable +inputs.set_val( + Aircraft.Engine.SCALE_FACTOR, 0.8096304384 +) # not in bwb.in, not a FLOPS variable, set to THRUST/THRSO +inputs.set_val( + Aircraft.Engine.SCALE_MASS, True +) # not in bwb.in, not a FLOPS variable, set to Aviary default +inputs.set_val(Aircraft.Engine.MASS_SCALER, 1.0) # EEXP in bwb.in +inputs.set_val( + Aircraft.Engine.SCALE_PERFORMANCE, True +) # not in bwb.in, not a FLOPS variable, set to Aviary default +inputs.set_val( + Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER, 1.0 +) # FFFSUB not in bwb.in, set to default +inputs.set_val( + Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER, 1.0 +) # FFFSUP not in bwb.in, set to default +inputs.set_val( + Aircraft.Engine.FUEL_FLOW_SCALER_CONSTANT_TERM, 0.0 +) # DFFAC not in bwb.in, set to default +inputs.set_val( + Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM, 0.0 +) # FFFAC not in bwb.in, set to default +inputs.set_val( + Aircraft.Engine.CONSTANT_FUEL_CONSUMPTION, 0.0, units='lbm/h' +) # FLEAK not in bwb.in, set to Aviary default +inputs.set_val( + Aircraft.Engine.ADDITIONAL_MASS_FRACTION, 0.0 +) # WPMISC not in bwb.in, set to Aviary default +inputs.set_val(Aircraft.Engine.GENERATE_FLIGHT_IDLE, True) # IDLE in bwb.in +inputs.set_val( + Aircraft.Engine.IGNORE_NEGATIVE_THRUST, False +) # NONEG not in bwb.in, set to Aviary default +inputs.set_val( + Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION, 0.0 +) # not in bwb.in, not a FLOPS variable, set to Aviary default +inputs.set_val( + Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION, 1.0 +) # FIDMAX not in bwb.in, set to default +inputs.set_val( + Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION, 0.08 +) # FIDMIN not in bwb.in, set to default +inputs.set_val(Aircraft.Engine.GEOPOTENTIAL_ALT, False) # IGEO not in bwb.in, set to default +inputs.set_val( + Aircraft.Engine.INTERPOLATION_METHOD, 'slinear' +) # not in bwb.in, not a FLOPS variable, set to Aviary default + +# Vertical Tail +# --------------------------- +inputs.set_val(Aircraft.VerticalTail.NUM_TAILS, 0) # NVERT in bwb.in +# inputs.set_val(Aircraft.VerticalTail.AREA, 284.0, 'ft**2') # SVT not in bwb.in, +inputs.set_val( + Aircraft.VerticalTail.ASPECT_RATIO, 0.0 +) # ARVT not in bwb.in, set to default ARHT/2 = 0/2 +inputs.set_val( + Aircraft.VerticalTail.TAPER_RATIO, 0.0 +) # TRVT not in bwb.in, set to default TRHT = 0 +inputs.set_val( + Aircraft.VerticalTail.THICKNESS_TO_CHORD, 0.0 +) # TCVT not in bwb.in, set to default TCHT = 0 +inputs.set_val(Aircraft.VerticalTail.MASS_SCALER, 1.0) # FRVT in bwb.in +# inputs.set_val(Aircraft.VerticalTail.WETTED_AREA, 581.13, 'ft**2') # not in bwb.in, not a FLOPS variable +inputs.set_val( + Aircraft.VerticalTail.WETTED_AREA_SCALER, 1.0 +) # SWETV not in bwb.in, set to Aviary default + +# Wing +# --------------------------- +inputs.set_val(Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, 0.0) # FAERT in bwb.in +inputs.set_val(Aircraft.Wing.AIRFOIL_TECHNOLOGY, 2.0) # AITEK in bwb.in +inputs.set_val(Aircraft.Wing.AREA, 7621.66, 'ft**2') # SW in bwb.in +inputs.set_val(Aircraft.Wing.ASPECT_RATIO, 7.557) # AR in bwb.in +inputs.set_val( + Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER, 1.0 +) # FRWI1 not in bwb.in, set to Aviary default +# inputs.set_val(Aircraft.Wing.CHORD_PER_SEMISPAN_DIST, np.array([0.31, 0.23, 0.084])) # CHD not in bwb.in, +inputs.set_val(Aircraft.Wing.COMPOSITE_FRACTION, 1.0) # FCOMP in bwb.in +# inputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA, 137, 'ft**2') # not in bwb.in, not a FLOPS variable +inputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA_RATIO, 0.333) # FLAPR in bwb.in +inputs.set_val(Aircraft.Wing.DETAILED_WING, True) # for BWB, always true +inputs.set_val(Aircraft.Wing.GLOVE_AND_BAT, 121.05, 'ft**2') # GLOV in bwb.in +# inputs.set_val(Aircraft.Wing.INPUT_STATION_DIST, np.array([0.0, 0.2759, 0.9367])) +inputs.set_val(Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL, 2.0) # PDIST not in bwb.in, set to default +inputs.set_val(Aircraft.Wing.LOAD_FRACTION, 1.0) # PCTL not in bwb.in, set to default +# inputs.set_val(Aircraft.Wing.LOAD_PATH_SWEEP_DIST, np.array([0.0, 22.0]), 'deg') # SWL not in bwb.in +inputs.set_val(Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN, 2.0) # CAM in bwb.in +inputs.set_val(Aircraft.Wing.MISC_MASS_SCALER, 1.0) # FRWI3 not in bwb.in, set to Aviary default +# inputs.set_val(Aircraft.Wing.NUM_INTEGRATION_STATIONS, 50) # NSTD not in bwb.in +inputs.set_val( + Aircraft.Wing.SHEAR_CONTROL_MASS_SCALER, 1.0 +) # FRWI2 not in bwb.in, set to Aviary default +inputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA_RATIO, 0.333) # FLAPR in bwb.in +inputs.set_val(Aircraft.Wing.SPAN, 238.08, 'ft') # SPAN not in bwb.in, SPAN = WF+OSSPAN*2 +inputs.set_val(Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, False) # MIKE not in bwb.in, set to default +inputs.set_val(Aircraft.Wing.STRUT_BRACING_FACTOR, 0.0) # FSTRT in bwb.in +inputs.set_val( + Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, 1.0 +) # FRSC not in bwb.in, set to Aviary default +inputs.set_val(Aircraft.Wing.SWEEP, 35.7, 'deg') # SWEEP in bwb.ins +inputs.set_val(Aircraft.Wing.TAPER_RATIO, 0.311) # TR in bwb.in +inputs.set_val(Aircraft.Wing.THICKNESS_TO_CHORD, 0.11) # TCA in bwb.in +# inputs.set_val(Aircraft.Wing.THICKNESS_TO_CHORD_DIST, np.array([0.145, 0.115, 0.104])) # TOC +inputs.set_val(Aircraft.Wing.ULTIMATE_LOAD_FACTOR, 3.75) # ULF not in bwb.in, set to default +inputs.set_val(Aircraft.Wing.VAR_SWEEP_MASS_PENALTY, 0.0) # VARSWP in bwb.in +inputs.set_val(Aircraft.Wing.MASS_SCALER, 1.0) # FRWI in bwb.in +# inputs.set_val(Aircraft.Wing.WETTED_AREA, 2396.56, 'ft**2') # SWETW not in bwb.in, +inputs.set_val(Aircraft.Wing.WETTED_AREA_SCALER, 1.0) # SWETW not in bwb.in, set to Aviary default +inputs.set_val(Aircraft.Wing.DIHEDRAL, 3.0, 'deg') # DIH in bwb.in +inputs.set_val(Aircraft.Wing.SPAN_EFFICIENCY_FACTOR, 0.0) # E in bwb.in + +# Mission +# --------------------------- +inputs.set_val(Mission.Summary.CRUISE_MACH, 0.85) # VCMN in bwb.in +inputs.set_val(Mission.Summary.FUEL_FLOW_SCALER, 1.0) # FACT not in bwb.in, set to default +inputs.set_val(Mission.Design.RANGE, 7750, 'NM') # DESRNG in bwb.in +inputs.set_val(Mission.Constraints.MAX_MACH, 0.85) # VMMO in bwb.in +# TODO investigate the origin of these values (taken from benchmark tests) +# TODO: where should this get connected from? +# inputs.set_val(Mission.Takeoff.FUEL_SIMPLE, 577, 'lbm') # FTKOFL not in bwb.in + +# region TODO: should this come from aero? +inputs.set_val(Mission.Landing.LIFT_COEFFICIENT_MAX, 3) # CLLDM not in bwb.in +inputs.set_val(Mission.Takeoff.LIFT_COEFFICIENT_MAX, 2) # CLTOM not in bwb.in +# inputs.set_val(Mission.Takeoff.LIFT_OVER_DRAG, 17.354) # not in bwb.in, not a FLOPS variable +# endregion TODO: should this come from aero? +inputs.set_val(Aircraft.Design.LANDING_TO_TAKEOFF_MASS_RATIO, 0.8) # WRATIO in bwb.in +inputs.set_val(Mission.Landing.INITIAL_VELOCITY, 140, 'ft/s') # VAPPR in bwb.in + +# TODO: should this be a user input or should it be hard coded somewhere assuming it will +# # never change? +inputs.set_val( + Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT, 0.025 +) # ROLLMU not in bwb.in, set to default +# lbf TODO: where should this get connected from? +inputs.set_val( + Mission.Design.THRUST_TAKEOFF_PER_ENG, 0.25, 'lbf' +) # THROFF in bwb.in, output is 52724.3 + +# Settings +# --------------------------- +inputs.set_val(Settings.EQUATIONS_OF_MOTION, EquationsOfMotion.HEIGHT_ENERGY) +inputs.set_val(Settings.MASS_METHOD, LegacyCode.FLOPS) + +# --------------------------- +# OUTPUTS +# --------------------------- + +outputs.set_val(Aircraft.Design.EMPTY_MASS, 92023.0, 'lbm') +outputs.set_val(Aircraft.Design.EMPTY_MASS_MARGIN, 0.0, 'lbm') +outputs.set_val(Aircraft.Design.OPERATING_MASS, 97992.0, 'lbm') +outputs.set_val(Aircraft.Propulsion.MASS, 16118.0, 'lbm') +outputs.set_val(Aircraft.Design.STRUCTURE_MASS, 50736.0, 'lbm') +outputs.set_val(Aircraft.Design.SYSTEMS_EQUIP_MASS, 25169.0, 'lbm') +outputs.set_val(Aircraft.Design.TOTAL_WETTED_AREA, 8275.86, 'ft**2') +outputs.set_val(Aircraft.Design.ZERO_FUEL_MASS, 135848.0, 'lbm') +outputs.set_val(Mission.Design.FUEL_MASS, 45352.0, 'lbm') + +outputs.set_val(Aircraft.AirConditioning.MASS, 4383.96064972, 'lbm') + +outputs.set_val(Aircraft.AntiIcing.MASS, 533.77301314, 'lbm') + +outputs.set_val(Aircraft.APU.MASS, 2148.13002234, 'lbm') + +outputs.set_val(Aircraft.Avionics.MASS, 2896.223816950469, 'lbm') + +outputs.set_val(Aircraft.Canard.CHARACTERISTIC_LENGTH, 0.0, 'ft') +outputs.set_val(Aircraft.Canard.FINENESS, 0.0) +outputs.set_val(Aircraft.Canard.WETTED_AREA, 0.0, 'ft**2') +outputs.set_val(Aircraft.Canard.MASS, 0.0, 'lbm') + +outputs.set_val(Aircraft.CrewPayload.BAGGAGE_MASS, 7436.0, 'lbm') +outputs.set_val(Aircraft.CrewPayload.CARGO_MASS, 0.0, 'lbm') +outputs.set_val(Aircraft.CrewPayload.CARGO_CONTAINER_MASS, 1400.0, 'lbm') +outputs.set_val(Aircraft.CrewPayload.FLIGHT_CREW_MASS, 450.0, 'lbm') +outputs.set_val(Aircraft.CrewPayload.NON_FLIGHT_CREW_MASS, 3410.0, 'lbm') +outputs.set_val(Aircraft.CrewPayload.PASSENGER_SERVICE_MASS, 3022.74805809, 'lbm') +outputs.set_val(Aircraft.CrewPayload.PASSENGER_MASS, 30420.0, 'lbm') +outputs.set_val(Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS, 37856.0, 'lbm') + +outputs.set_val(Aircraft.Electrical.MASS, 4514.28869169, 'lbm') + +outputs.set_val(Aircraft.Fuel.FUEL_SYSTEM_MASS, 669.58, 'lbm') +outputs.set_val(Aircraft.Fuel.UNUSABLE_FUEL_MASS, 501.3, 'lbm') + +outputs.set_val(Aircraft.Fins.MASS, 0.0, 'lbm') + +outputs.set_val(Aircraft.Furnishings.MASS, 15517.0, 'lbm') + +avg_diameter = 12.75 +avg_diameter_units = 'ft' +outputs.set_val(Aircraft.Fuselage.AVG_DIAMETER, avg_diameter, avg_diameter_units) +outputs.set_val(Aircraft.Fuselage.CHARACTERISTIC_LENGTH, 128.0, 'ft') +outputs.set_val( + Aircraft.Fuselage.CROSS_SECTION, np.pi * (avg_diameter / 2.0) ** 2.0, f'{avg_diameter_units}**2' +) +outputs.set_val(Aircraft.Fuselage.DIAMETER_TO_WING_SPAN, 0.108207) +outputs.set_val(Aircraft.Fuselage.FINENESS, 10.0392) +outputs.set_val(Aircraft.Fuselage.LENGTH_TO_DIAMETER, 10.039216) +outputs.set_val(Aircraft.Fuselage.MASS, 18357.0, 'lbm') +outputs.set_val(Aircraft.Fuselage.MAX_HEIGHT, 15.125, 'ft') # DF in bwb.in, but should not be here +outputs.set_val(Aircraft.Fuselage.PLANFORM_AREA, 7390.267432149546, 'ft**2') # FPAREA + +outputs.set_val(Aircraft.HorizontalTail.CHARACTERISTIC_LENGTH, 7.69, 'ft') +outputs.set_val(Aircraft.HorizontalTail.FINENESS, 0.1250) +outputs.set_val(Aircraft.HorizontalTail.MASS, 1831.0, 'lbm') + +outputs.set_val(Aircraft.Hydraulics.MASS, 1086.7, 'lbm') + +outputs.set_val(Aircraft.Instruments.MASS, 601, 'lbm') + +outputs.set_val(Aircraft.LandingGear.MAIN_GEAR_MASS, 7910.32, 'lbm') +outputs.set_val(Aircraft.LandingGear.NOSE_GEAR_MASS, 870.59, 'lbm') + +outputs.set_val(Aircraft.Nacelle.CHARACTERISTIC_LENGTH, np.array([12.30]), 'ft') +outputs.set_val(Aircraft.Nacelle.FINENESS, np.array([1.5491])) +outputs.set_val(Aircraft.Nacelle.MASS, 1971.4, 'lbm') + +nacelle_wetted_area = np.array([273.45]) +nacelle_wetted_area_units = 'ft**2' +outputs.set_val(Aircraft.Nacelle.WETTED_AREA, nacelle_wetted_area, nacelle_wetted_area_units) + +outputs.set_val( + Aircraft.Nacelle.TOTAL_WETTED_AREA, 3 * nacelle_wetted_area, nacelle_wetted_area_units +) + +outputs.set_val(Aircraft.Paint.MASS, 306.2, 'lbm') + +outputs.set_val( + Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, 70000.0 * 3, 'lbf' +) # output from propulsion, + +outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 3) + +engine_ctrls_mass = 206.36860226 +engine_ctrls_mass_units = 'lbm' +outputs.set_val(Aircraft.Engine.CONTROLS_MASS, engine_ctrls_mass, engine_ctrls_mass_units) +outputs.set_val( + Aircraft.Propulsion.TOTAL_ENGINE_CONTROLS_MASS, engine_ctrls_mass, engine_ctrls_mass_units +) + +outputs.set_val(Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS, 346.93557352, 'lbm') +outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, 2) + +outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES, 0) + +outputs.set_val(Aircraft.Engine.MASS, 17825.63336233, 'lbm') +outputs.set_val(Aircraft.Engine.POD_MASS, 9000, 'lbm') +outputs.set_val(Aircraft.Engine.ADDITIONAL_MASS, 0.0, 'lbm') +outputs.set_val(Aircraft.Propulsion.TOTAL_MISC_MASS, 648.83, 'lbm') +outputs.set_val(Aircraft.Propulsion.TOTAL_STARTER_MASS, 560.39, 'lbm') +outputs.set_val(Aircraft.Propulsion.TOTAL_THRUST_REVERSERS_MASS, 0, 'lbm') +outputs.set_val(Aircraft.Engine.THRUST_REVERSERS_MASS, 0, 'lbm') +outputs.set_val(Aircraft.Engine.SCALED_SLS_THRUST, 28928.1, 'lbf') + +outputs.set_val(Aircraft.Propulsion.TOTAL_ENGINE_MASS, 53476.90008698, 'lbm') + +outputs.set_val(Aircraft.VerticalTail.CHARACTERISTIC_LENGTH, 12.74, 'ft') +outputs.set_val(Aircraft.VerticalTail.FINENESS, 0.1195) +outputs.set_val(Aircraft.VerticalTail.MASS, 1221.8, 'lbm') + +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR, 11.5918) +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS, 8184.8, 'lbm') +outputs.set_val(Aircraft.Wing.CHARACTERISTIC_LENGTH, 10.49, 'ft') +# Not in FLOPS output; calculated from inputs. +outputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA, 137, 'ft**2') +outputs.set_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR, 0.967333) +outputs.set_val(Aircraft.Wing.FINENESS, 0.1300) +outputs.set_val(Aircraft.Wing.MISC_MASS, 1668.3, 'lbm') +outputs.set_val(Aircraft.Wing.SHEAR_CONTROL_MASS, 4998.8, 'lbm') +outputs.set_val(Aircraft.Wing.SURFACE_CONTROL_MASS, 894, 'lbm') + +outputs.set_val(Aircraft.Wing.MASS, 18268, 'lbm') + +outputs.set_val(Mission.Design.MACH, 0.800) +outputs.set_val(Mission.Design.LIFT_COEFFICIENT, 0.568) + +# Unconverted Values +# AERIN.FLLDG,11000 # Maximum allowable landing field length, ft +# AERIN.FLTO,11000 # Maximum allowable takeoff field length, ft +# AERIN.ITPAER,2 # Aerodynamic data interpolation switch +# AERIN.MYAERO,0 # Controls type of user-supplied aerodynamic data +# AERIN.XLLAM,0 # Turbulent flow or Laminar Flow +# CONFIN.CH,39000 # Maximum cruise altitude, ft +# CONFIN.GW,874099 # Ramp weight +# CONFIN.OFF,0 # Objective function weighting factor for mission fuel +# CONFIN.OFG,1 # Objective function weighting factor for gross weight +# ENGDIN.MAXCR,1 # Maximum power setting used for cruise +# FUSEIN.OSSPAN,86.75 # Outboard semispan, ft +# MISSIN.ALTRAN,200 # Range to alternate airport, n.mi. +# MISSIN.APPRTM,4 # Approach time, min +# MISSIN.CLAMIN,0 # CLAMIN(I) Minimum altitude, ft +# MISSIN.CRALT,45000,25000,1500 # CRALT(I) Maximum or fixed altitude, ft +# MISSIN.CRMACH,0.85,0.6,0 # CRMACH(I) Maximum or fixed Mach number (or velocity, kts) +# MISSIN.DEAMIN,0 # Minimum altitude, ft +# MISSIN.FWF,-0.001 # FWF(I) Climb profile optimization function control parameter +# MISSIN.HOLDTM,30 # Reserve holding time, min +# MISSIN.IATA,0 # Range is adjusted for ATA Traffic Allowance or otherwise +# MISSIN.IFLAG,2 # print flag +# MISSIN.IHOPOS,1 # Hold position switch +# MISSIN.IOC,1,4,4 # IOC(I) Cruise option switch +# MISSIN.IRS,1 # Reserve fuel calculation switch +# MISSIN.IRW,1 # Calculates ramp weight with fixed range or fixed +# MISSIN.ISKAL,1 # Special option used to turn off engine scaling +# MISSIN.ITTFF,1 # Engine deck power setting for takeoff or not +# MISSIN.IVS,1 # Descent option switch +# MISSIN.MSUMPT,1 # Detailed mission summary will be calculated and printed or otherwise +# MISSIN.NCLIMB,1 # Number of climb schedules to be defined +# MISSIN.NCLRES,1 # Climb schedule number used in reserve mission +# MISSIN.NCRHOL,3 # Cruise schedule number for hold +# MISSIN.NCRRES,2 # Cruise schedule number used in reserve mission +# MISSIN.NCRTH,1 # Cruise schedule number for THOLD +# MISSIN.NCRUSE,3 # Number of cruise schedules to be defined +# MISSIN.NPCON,0 # Number of performance constraints - primarily for fighters +# MISSIN.RCIN,300 # Instantaneous rate of climb for ceiling calculation, ft/min +# MISSIN.RESTRP,0.05 # Reserve fuel as a fraction of total trip fuel weight +# MISSIN.TAKOTM,2 # Takeoff time, min +# MISSIN.TAXITM,5 # Taxi in time, min +# MISSIN.TAXOTM,9 # Taxi out time, min +# MISSIN.THOLD,0.1 # Reserve holding time flag +# MISSIN.TIMMAP,2 # Missed approach time, min +# OPTION.IANAL,3 # compute flag +# OPTION.ICOST,0 # cost analysis flag? not in manual +# OPTION.IFITE,3 # should be read in +# OPTION.ILAND,0 # Detailed landing performance or otherwise +# OPTION.INENG,1 # Engine data flag +# OPTION.IPLTTH,0 # Engine data flag +# OPTION.ITAKOF,0 # Detailed takeoff performance or otherwise +# OPTION.IXFL,1 # Cruise, mission and takeoff and landing plot or otherwise +# OPTION.MPRINT,1 # Master print control +# OPTION.NOPRO,0 # Detailed takeoff and climb profiles +# PCONIN.CONALT,35000 # Altitude at which constraint is to be evaluated, ft +# PCONIN.CONLIM,300 # The type of constraint is indicated by ICONTP, and the limiting or target value for the performance indicator being constrained +# PCONIN.CONMCH,0.85 # Velocity at which constraint is to be evaluated, kts +# PCONIN.CONPC,1 # Engine power setting parameter +# PCONIN.ICONSG,2 # Weight at start of mission segment ICONSG is used +# PCONIN.ICONTP,5 # CONLIM Definition +# WTIN.ARFIN,1.952 # Vertical fin theoretical aspect ratio +# WTIN.ISPOWE,0 # Normal FLOPS weight equations or Special equation +# WTIN.NETAW,0 # Number of input wing stations +# WTIN.SWPFIN,39.42 # Vertical fin sweep angle at 25% chord, deg +# WTIN.TCFIN,0.08 # Vertical fin thickness - chord ratio +# WTIN.WINL,0 # Inlet weight for baseline engine if not included in WENG above diff --git a/aviary/models/aircraft/test_aircraft/aircraft_for_bench_FwFm.csv b/aviary/models/aircraft/test_aircraft/aircraft_for_bench_FwFm.csv index c4398317c..6dfa12ff6 100644 --- a/aviary/models/aircraft/test_aircraft/aircraft_for_bench_FwFm.csv +++ b/aviary/models/aircraft/test_aircraft/aircraft_for_bench_FwFm.csv @@ -115,7 +115,7 @@ aircraft:wing:airfoil_technology,1.92669766647637,unitless aircraft:wing:area,1370.0,ft**2 aircraft:wing:aspect_ratio,11.22091,unitless aircraft:wing:bending_material_mass_scaler,1.0,unitless -aircraft:wing:chord_per_semispan,0.31,0.23,0.084,unitless +aircraft:wing:chord_per_semispan_dist,0.31,0.23,0.084,unitless aircraft:wing:composite_fraction,0.2,unitless aircraft:wing:control_surface_area,137,ft**2 aircraft:wing:control_surface_area_ratio,0.1,unitless diff --git a/aviary/models/aircraft/test_aircraft/aircraft_for_bench_FwFm_with_electric.csv b/aviary/models/aircraft/test_aircraft/aircraft_for_bench_FwFm_with_electric.csv index 23d84ce51..c7492a8c4 100644 --- a/aviary/models/aircraft/test_aircraft/aircraft_for_bench_FwFm_with_electric.csv +++ b/aviary/models/aircraft/test_aircraft/aircraft_for_bench_FwFm_with_electric.csv @@ -114,7 +114,7 @@ aircraft:wing:airfoil_technology,1.92669766647637,unitless aircraft:wing:area,1370.0,ft**2 aircraft:wing:aspect_ratio,11.22091,unitless aircraft:wing:bending_material_mass_scaler,1.0,unitless -aircraft:wing:chord_per_semispan,0.31,0.23,0.084,unitless +aircraft:wing:chord_per_semispan_dist,0.31,0.23,0.084,unitless aircraft:wing:composite_fraction,0.2,unitless aircraft:wing:control_surface_area,137,ft**2 aircraft:wing:control_surface_area_ratio,0.1,unitless 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 3be013816..f68c60a13 100644 --- a/aviary/models/aircraft/test_aircraft/aircraft_for_bench_FwGm.csv +++ b/aviary/models/aircraft/test_aircraft/aircraft_for_bench_FwGm.csv @@ -218,7 +218,7 @@ aircraft:vertical_tail:num_tails,1,unitless aircraft:wing:aeroelastic_tailoring_factor,0.0,unitless aircraft:wing:airfoil_technology,1.92669766647637,unitless aircraft:wing:bending_material_mass_scaler,1.0,unitless -aircraft:wing:chord_per_semispan,0.31,0.23,0.084,unitless +aircraft:wing:chord_per_semispan_dist,0.31,0.23,0.084,unitless aircraft:wing:composite_fraction,0.2,unitless aircraft:wing:control_surface_area,137,ft**2 aircraft:wing:control_surface_area_ratio,0.1,unitless diff --git a/aviary/models/aircraft/test_aircraft/aircraft_for_bench_solved2dof.csv b/aviary/models/aircraft/test_aircraft/aircraft_for_bench_solved2dof.csv index cf2998e66..fae5b36ee 100644 --- a/aviary/models/aircraft/test_aircraft/aircraft_for_bench_solved2dof.csv +++ b/aviary/models/aircraft/test_aircraft/aircraft_for_bench_solved2dof.csv @@ -114,7 +114,7 @@ aircraft:wing:airfoil_technology,1.92669766647637,unitless aircraft:wing:area,1370.0,ft**2 aircraft:wing:aspect_ratio,11.22091,unitless aircraft:wing:bending_material_mass_scaler,1.0,unitless -aircraft:wing:chord_per_semispan,0.31,0.23,0.084,unitless +aircraft:wing:chord_per_semispan_dist,0.31,0.23,0.084,unitless aircraft:wing:composite_fraction,0.2,unitless aircraft:wing:control_surface_area,137,ft**2 aircraft:wing:control_surface_area_ratio,0.1,unitless diff --git a/aviary/models/engines/PAX300_baseline_ENGDEK.csv b/aviary/models/engines/PAX300_baseline_ENGDEK.csv new file mode 100644 index 000000000..f73fa4d64 --- /dev/null +++ b/aviary/models/engines/PAX300_baseline_ENGDEK.csv @@ -0,0 +1,654 @@ +# created 10/08/25 at 13:25 by xjiang +# FLOPS-derived engine deck converted from PAX300_baseline_ENGDEK.txt + +Mach Number (input), Altitude (ft, input), Throttle (input), Gross Thrust (lbf, output), Ram Drag (lbf, output), Fuel Flow (lb/h, output), NOx Rate (lb/h, output) + 0.0, 0.0, 23.0, 8396.6, 0.0, 1963.1, 10.6399 + 0.0, 0.0, 26.0, 16791.6, 0.0, 3489.5, 11.5561 + 0.0, 0.0, 29.0, 25187.5, 0.0, 5254.2, 11.5668 + 0.0, 0.0, 32.0, 33583.0, 0.0, 7178.1, 11.9191 + 0.0, 0.0, 35.0, 41978.8, 0.0, 9257.0, 1.2243 + 0.0, 0.0, 38.0, 50374.6, 0.0, 11492.3, 2.4722 + 0.0, 0.0, 41.0, 58770.1, 0.0, 13851.7, 4.5503 + 0.0, 0.0, 44.0, 67166.1, 0.0, 16299.9, 7.6931 + 0.0, 0.0, 47.0, 75561.7, 0.0, 18831.2, 12.1991 + 0.0, 0.0, 50.0, 83957.5, 0.0, 21494.7, 18.7586 + 0.0, 2000.0, 23.0, 8200.2, 0.0, 1879.1, 10.2183 + 0.0, 2000.0, 26.0, 16398.9, 0.0, 3373.9, 10.9749 + 0.0, 2000.0, 29.0, 24598.5, 0.0, 5105.5, 10.9957 + 0.0, 2000.0, 32.0, 32797.5, 0.0, 6990.4, 11.3627 + 0.0, 2000.0, 35.0, 40996.8, 0.0, 9044.8, 1.2651 + 0.0, 2000.0, 38.0, 49196.3, 0.0, 11236.4, 2.5676 + 0.0, 2000.0, 41.0, 57395.4, 0.0, 13567.0, 4.742 + 0.0, 2000.0, 44.0, 65595.2, 0.0, 15957.5, 7.9527 + 0.0, 2000.0, 47.0, 73794.9, 0.0, 18449.2, 12.6551 + 0.0, 2000.0, 50.0, 81993.7, 0.0, 21122.8, 19.8032 + 0.0, 5000.0, 23.0, 7833.6, 0.0, 1747.4, 9.276 + 0.0, 5000.0, 26.0, 15665.5, 0.0, 3178.3, 10.1488 + 0.0, 5000.0, 29.0, 23498.3, 0.0, 4840.9, 10.1852 + 0.0, 5000.0, 32.0, 31331.0, 0.0, 6649.2, 10.5625 + 0.0, 5000.0, 35.0, 39164.0, 0.0, 8632.6, 1.2912 + 0.0, 5000.0, 38.0, 46996.3, 0.0, 10741.6, 2.6245 + 0.0, 5000.0, 41.0, 54829.4, 0.0, 12963.0, 4.8042 + 0.0, 5000.0, 44.0, 62662.2, 0.0, 15263.2, 8.0575 + 0.0, 5000.0, 47.0, 70495.3, 0.0, 17697.3, 12.9971 + 0.0, 5000.0, 50.0, 78327.6, 0.0, 20394.3, 21.1686 + 0.0, 10000.0, 23.0, 6983.4, 0.0, 1502.1, 8.4433 + 0.0, 10000.0, 26.0, 13965.4, 0.0, 2775.3, 8.8709 + 0.0, 10000.0, 29.0, 20948.2, 0.0, 4251.8, 8.9317 + 0.0, 10000.0, 32.0, 27930.7, 0.0, 5866.7, 9.2816 + 0.0, 10000.0, 35.0, 34913.5, 0.0, 7636.6, 1.164 + 0.0, 10000.0, 38.0, 41896.4, 0.0, 9528.1, 2.3706 + 0.0, 10000.0, 41.0, 48879.1, 0.0, 11490.9, 4.2739 + 0.0, 10000.0, 44.0, 55861.8, 0.0, 13550.9, 7.2074 + 0.0, 10000.0, 47.0, 62845.3, 0.0, 15807.7, 12.0305 + 0.0, 10000.0, 50.0, 69827.0, 0.0, 18403.7, 20.5073 + 0.1, 0.0, 21.0, 6606.0, 2839.9, 1515.6, 11.5204 + 0.1, 0.0, 26.0, 19995.8, 4932.0, 3945.0, 11.6363 + 0.1, 0.0, 29.0, 28469.4, 5873.5, 5778.1, 11.707 + 0.1, 0.0, 32.0, 36793.6, 6665.8, 7716.9, 12.1113 + 0.1, 0.0, 35.0, 45020.3, 7360.0, 9793.4, 1.4473 + 0.1, 0.0, 38.0, 53175.3, 7983.8, 11985.3, 2.8021 + 0.1, 0.0, 41.0, 61277.5, 8553.9, 14286.5, 4.973 + 0.1, 0.0, 44.0, 69338.8, 9083.5, 16649.8, 8.1424 + 0.1, 0.0, 47.0, 77365.9, 9578.9, 19083.7, 12.5974 + 0.1, 0.0, 50.0, 85362.2, 10043.2, 21633.5, 18.958 + 0.1, 2000.0, 21.0, 6376.1, 2690.5, 1436.4, 10.8411 + 0.1, 2000.0, 26.0, 19429.2, 4687.1, 3810.7, 11.0438 + 0.1, 2000.0, 29.0, 27698.1, 5585.1, 5604.8, 11.1368 + 0.1, 2000.0, 32.0, 35824.5, 6340.7, 7505.1, 11.5542 + 0.1, 2000.0, 35.0, 43856.7, 7001.6, 9553.8, 1.4942 + 0.1, 2000.0, 38.0, 51822.6, 7596.1, 11703.6, 2.8972 + 0.1, 2000.0, 41.0, 59736.8, 8139.1, 13969.3, 5.1508 + 0.1, 2000.0, 44.0, 67611.9, 8643.9, 16282.8, 8.3882 + 0.1, 2000.0, 47.0, 75454.8, 9115.2, 18684.0, 13.0457 + 0.1, 2000.0, 50.0, 83263.9, 9554.0, 21254.5, 20.0126 + 0.1, 5000.0, 21.0, 6004.6, 2470.0, 1319.3, 9.8697 + 0.1, 5000.0, 26.0, 18459.2, 4320.8, 3590.1, 10.1943 + 0.1, 5000.0, 29.0, 26359.9, 5152.6, 5306.6, 10.3299 + 0.1, 5000.0, 32.0, 34128.3, 5851.8, 7135.9, 10.7472 + 0.1, 5000.0, 35.0, 41808.8, 6463.1, 9109.2, 1.5191 + 0.1, 5000.0, 38.0, 49426.9, 7012.5, 11187.7, 2.9584 + 0.1, 5000.0, 41.0, 56999.4, 7515.6, 13349.6, 5.2137 + 0.1, 5000.0, 44.0, 64535.0, 7982.1, 15580.6, 8.5138 + 0.1, 5000.0, 47.0, 72038.6, 8415.6, 17934.7, 13.4347 + 0.1, 5000.0, 50.0, 79506.1, 8815.2, 20526.3, 21.3718 + 0.1, 10000.0, 21.0, 5268.5, 2103.5, 1120.4, 8.2247 + 0.1, 10000.0, 26.0, 16356.9, 3696.8, 3132.2, 8.9045 + 0.1, 10000.0, 29.0, 23402.8, 4412.5, 4652.9, 9.0674 + 0.1, 10000.0, 32.0, 30333.2, 5013.0, 6292.5, 9.4519 + 0.1, 10000.0, 35.0, 37189.1, 5538.1, 8052.4, 1.3642 + 0.1, 10000.0, 38.0, 43990.1, 6009.5, 9916.7, 2.6624 + 0.1, 10000.0, 41.0, 50752.2, 6442.1, 11831.6, 4.6346 + 0.1, 10000.0, 44.0, 57482.1, 6841.6, 13841.5, 7.6356 + 0.1, 10000.0, 47.0, 64179.1, 7208.7, 16038.3, 12.4978 + 0.1, 10000.0, 50.0, 70842.4, 7541.7, 18528.5, 20.7314 + 0.2, 0.0, 21.0, 10605.0, 7175.8, 1724.4, 13.8686 + 0.2, 0.0, 26.0, 24661.3, 10944.3, 4374.3, 11.8637 + 0.2, 0.0, 29.0, 33268.0, 12693.1, 6271.0, 12.0028 + 0.2, 0.0, 32.0, 41609.1, 14175.8, 8238.8, 12.4551 + 0.2, 0.0, 35.0, 49770.2, 15478.4, 10326.3, 1.6715 + 0.2, 0.0, 38.0, 57802.7, 16652.5, 12500.0, 3.1228 + 0.2, 0.0, 41.0, 65734.7, 17726.2, 14779.6, 5.398 + 0.2, 0.0, 44.0, 73591.8, 18724.9, 17102.8, 8.6487 + 0.2, 0.0, 47.0, 81384.5, 19659.3, 19491.0, 13.1504 + 0.2, 0.0, 50.0, 89115.8, 20532.4, 22013.4, 19.6118 + 0.2, 2000.0, 21.0, 10126.7, 6762.4, 1636.3, 13.1617 + 0.2, 2000.0, 26.0, 23830.1, 10372.9, 4223.7, 11.255 + 0.2, 2000.0, 29.0, 32230.7, 12045.0, 6079.8, 11.4254 + 0.2, 2000.0, 32.0, 40375.8, 13461.6, 8010.4, 11.8851 + 0.2, 2000.0, 35.0, 48347.9, 14704.9, 10064.2, 1.7203 + 0.2, 2000.0, 38.0, 56196.7, 15825.1, 12206.1, 3.2272 + 0.2, 2000.0, 41.0, 63950.9, 16850.1, 14441.9, 5.5758 + 0.2, 2000.0, 44.0, 71632.1, 17803.0, 16727.0, 8.9123 + 0.2, 2000.0, 47.0, 79253.5, 18691.8, 19100.4, 13.6789 + 0.2, 2000.0, 50.0, 86802.9, 19517.2, 21635.9, 20.7276 + 0.2, 5000.0, 21.0, 9405.8, 6166.0, 1505.8, 12.1078 + 0.2, 5000.0, 26.0, 22490.1, 9531.1, 3978.5, 10.3854 + 0.2, 5000.0, 29.0, 30524.7, 11086.1, 5754.1, 10.6104 + 0.2, 5000.0, 32.0, 38319.0, 12400.7, 7618.8, 11.0656 + 0.2, 5000.0, 35.0, 45951.6, 13553.8, 9600.1, 1.7498 + 0.2, 5000.0, 38.0, 53468.5, 14591.5, 11677.4, 3.3022 + 0.2, 5000.0, 41.0, 60899.9, 15543.1, 13822.6, 5.6749 + 0.2, 5000.0, 44.0, 68262.1, 16425.6, 16030.2, 9.094 + 0.2, 5000.0, 47.0, 75557.3, 17241.7, 18383.8, 14.2471 + 0.2, 5000.0, 50.0, 82793.1, 17997.9, 20908.2, 22.0766 + 0.2, 10000.0, 21.0, 8125.7, 5211.2, 1281.4, 10.1727 + 0.2, 10000.0, 26.0, 19783.3, 8125.5, 3469.9, 9.0703 + 0.2, 10000.0, 29.0, 26955.6, 9469.0, 5043.8, 9.3019 + 0.2, 10000.0, 32.0, 33916.9, 10601.3, 6722.2, 9.7353 + 0.2, 10000.0, 35.0, 40739.7, 11594.9, 8491.5, 1.5713 + 0.2, 10000.0, 38.0, 47462.0, 12488.5, 10352.2, 2.9679 + 0.2, 10000.0, 41.0, 54111.1, 13308.6, 12264.8, 5.0626 + 0.2, 10000.0, 44.0, 60696.3, 14063.7, 14281.6, 8.2547 + 0.2, 10000.0, 47.0, 67217.3, 14757.4, 16459.7, 13.2924 + 0.2, 10000.0, 50.0, 73676.7, 15387.6, 18892.9, 21.5133 + 0.25, 0.0, 21.0, 13326.4, 10038.5, 1849.4, 11.1617 + 0.25, 0.0, 26.0, 27620.2, 14468.8, 4605.6, 12.0396 + 0.25, 0.0, 29.0, 36294.5, 16567.4, 6525.9, 12.2118 + 0.25, 0.0, 32.0, 44658.5, 18355.7, 8511.1, 12.686 + 0.25, 0.0, 35.0, 52809.6, 19930.9, 10605.8, 1.7902 + 0.25, 0.0, 38.0, 60806.8, 21352.8, 12782.4, 3.297 + 0.25, 0.0, 41.0, 68683.7, 22654.0, 15060.5, 5.6343 + 0.25, 0.0, 44.0, 76471.3, 23865.5, 17378.3, 8.9576 + 0.25, 0.0, 47.0, 84177.4, 24995.9, 19780.4, 13.5957 + 0.25, 0.0, 50.0, 91810.8, 26053.7, 22292.2, 20.1572 + 0.25, 2000.0, 21.0, 12671.9, 9440.7, 1756.0, 14.7788 + 0.25, 2000.0, 26.0, 26620.7, 13696.0, 4447.1, 11.4154 + 0.25, 2000.0, 29.0, 35093.3, 15706.6, 6326.8, 11.6321 + 0.25, 2000.0, 32.0, 43266.5, 17417.6, 8278.2, 12.1106 + 0.25, 2000.0, 35.0, 51234.3, 18922.9, 10341.5, 1.8447 + 0.25, 2000.0, 38.0, 59054.6, 20281.1, 12488.8, 3.4127 + 0.25, 2000.0, 41.0, 66760.8, 21525.2, 14724.2, 5.8301 + 0.25, 2000.0, 44.0, 74379.2, 22681.2, 17012.7, 9.2625 + 0.25, 2000.0, 47.0, 81918.8, 23757.2, 19402.8, 14.1911 + 0.25, 2000.0, 50.0, 89382.1, 24759.6, 21923.1, 21.3328 + 0.25, 5000.0, 21.0, 11702.6, 8584.2, 1617.3, 13.629 + 0.25, 5000.0, 26.0, 25037.1, 12563.6, 4188.1, 10.5364 + 0.25, 5000.0, 29.0, 33148.3, 14437.8, 5988.1, 10.7965 + 0.25, 5000.0, 32.0, 40975.8, 16028.4, 7876.8, 11.2821 + 0.25, 5000.0, 35.0, 48611.4, 17427.0, 9868.9, 1.878 + 0.25, 5000.0, 38.0, 56107.8, 18686.6, 11957.3, 3.4999 + 0.25, 5000.0, 41.0, 63501.3, 19843.3, 14106.8, 5.9566 + 0.25, 5000.0, 44.0, 70807.7, 20912.8, 16338.6, 9.5315 + 0.25, 5000.0, 47.0, 78036.0, 21904.3, 18691.4, 14.8303 + 0.25, 5000.0, 50.0, 85191.9, 22823.6, 21201.5, 22.7635 + 0.25, 10000.0, 21.0, 10043.9, 7231.7, 1376.5, 11.4702 + 0.25, 10000.0, 26.0, 21940.0, 10691.1, 3651.5, 9.206 + 0.25, 10000.0, 29.0, 29187.0, 12314.2, 5250.8, 9.4678 + 0.25, 10000.0, 32.0, 36184.1, 13687.2, 6949.9, 9.9116 + 0.25, 10000.0, 35.0, 43015.8, 14894.3, 8735.4, 1.6892 + 0.25, 10000.0, 38.0, 49726.6, 15981.2, 10607.1, 3.1508 + 0.25, 10000.0, 41.0, 56347.4, 16977.7, 12538.2, 5.3478 + 0.25, 10000.0, 44.0, 62889.8, 17894.6, 14573.6, 8.6925 + 0.25, 10000.0, 47.0, 69356.6, 18738.8, 16749.0, 13.8634 + 0.25, 10000.0, 50.0, 75747.7, 19505.2, 19167.7, 22.1778 + 0.3, 0.0, 21.0, 16583.1, 13416.7, 1991.5, 11.6656 + 0.3, 0.0, 26.0, 31066.1, 18400.7, 4853.5, 12.2557 + 0.3, 0.0, 29.0, 39811.3, 20813.0, 6811.2, 12.4695 + 0.3, 0.0, 32.0, 48213.2, 22882.2, 8815.6, 12.9694 + 0.3, 0.0, 35.0, 56375.6, 24711.8, 10913.7, 1.9238 + 0.3, 0.0, 38.0, 64359.6, 26363.0, 13111.0, 3.5088 + 0.3, 0.0, 41.0, 72207.7, 27878.5, 15388.0, 5.9196 + 0.3, 0.0, 44.0, 79947.5, 29285.5, 17734.0, 9.4012 + 0.3, 0.0, 47.0, 87599.6, 30602.4, 20142.1, 14.1847 + 0.3, 0.0, 50.0, 95162.4, 31835.1, 22644.9, 20.8557 + 0.3, 2000.0, 21.0, 15712.9, 12595.8, 1891.7, 11.153 + 0.3, 2000.0, 26.0, 29864.5, 17396.1, 4686.6, 11.623 + 0.3, 2000.0, 29.0, 38415.2, 19712.8, 6600.4, 11.883 + 0.3, 2000.0, 32.0, 46632.2, 21695.5, 8574.0, 12.3847 + 0.3, 2000.0, 35.0, 54616.5, 23445.4, 10650.3, 1.9877 + 0.3, 2000.0, 38.0, 62430.4, 25025.2, 12817.2, 3.6375 + 0.3, 2000.0, 41.0, 70113.3, 26474.0, 15067.6, 6.1615 + 0.3, 2000.0, 44.0, 77692.4, 27819.0, 17379.5, 9.7597 + 0.3, 2000.0, 47.0, 85182.9, 29074.3, 19769.9, 14.828 + 0.3, 2000.0, 50.0, 92585.2, 30243.5, 22287.3, 22.1347 + 0.3, 5000.0, 21.0, 14441.3, 11426.1, 1742.8, 9.7203 + 0.3, 5000.0, 26.0, 27992.1, 15931.3, 4414.2, 10.7336 + 0.3, 5000.0, 29.0, 36188.1, 18096.7, 6247.6, 11.0237 + 0.3, 5000.0, 32.0, 44068.4, 19944.7, 8157.1, 11.5409 + 0.3, 5000.0, 35.0, 51724.5, 21572.0, 10173.7, 2.0298 + 0.3, 5000.0, 38.0, 59223.1, 23040.8, 12278.5, 3.7347 + 0.3, 5000.0, 41.0, 66601.0, 24387.7, 14457.7, 6.3338 + 0.3, 5000.0, 44.0, 73881.7, 25635.9, 16706.1, 10.0712 + 0.3, 5000.0, 47.0, 81067.1, 26792.8, 19064.9, 15.5565 + 0.3, 5000.0, 50.0, 88171.1, 27866.6, 21572.3, 23.6652 + 0.3, 10000.0, 21.0, 12326.0, 9599.9, 1483.7, 13.0449 + 0.3, 10000.0, 26.0, 24436.0, 13531.9, 3849.5, 9.3781 + 0.3, 10000.0, 29.0, 31768.9, 15412.7, 5480.9, 9.6699 + 0.3, 10000.0, 32.0, 38820.0, 17011.8, 7198.8, 10.1265 + 0.3, 10000.0, 35.0, 45679.2, 18418.6, 9013.7, 1.8301 + 0.3, 10000.0, 38.0, 52399.5, 19687.2, 10910.1, 3.3821 + 0.3, 10000.0, 41.0, 59014.6, 20849.8, 12867.9, 5.7129 + 0.3, 10000.0, 44.0, 65539.1, 21921.5, 14917.9, 9.2173 + 0.3, 10000.0, 47.0, 71979.6, 22908.1, 17101.5, 14.5756 + 0.3, 10000.0, 50.0, 78324.4, 23803.7, 19518.1, 23.0648 + 0.3, 15000.0, 21.0, 10111.5, 7876.7, 1196.0, 9.9743 + 0.3, 15000.0, 26.0, 20042.0, 11102.8, 3090.2, 8.1522 + 0.3, 15000.0, 29.0, 26055.0, 12646.2, 4396.0, 8.3638 + 0.3, 15000.0, 32.0, 31836.8, 13958.4, 5771.3, 8.7162 + 0.3, 15000.0, 35.0, 37461.2, 15113.0, 7223.8, 1.2105 + 0.3, 15000.0, 38.0, 42971.9, 16154.4, 8740.8, 2.2225 + 0.3, 15000.0, 41.0, 48396.3, 17108.8, 10306.7, 3.7333 + 0.3, 15000.0, 44.0, 53745.5, 17988.6, 11945.4, 5.9942 + 0.3, 15000.0, 47.0, 59025.0, 18799.0, 13692.8, 9.4432 + 0.3, 15000.0, 50.0, 64230.4, 19534.4, 15626.2, 14.8862 + 0.4, 0.0, 21.0, 24803.9, 21818.1, 2322.3, 12.7616 + 0.4, 0.0, 26.0, 39605.6, 27662.6, 5391.2, 12.8711 + 0.4, 0.0, 29.0, 48531.2, 30616.4, 7423.5, 13.1508 + 0.4, 0.0, 32.0, 57066.0, 33179.9, 9508.8, 13.7107 + 0.4, 0.0, 35.0, 65320.1, 35462.3, 11673.4, 2.2789 + 0.4, 0.0, 38.0, 73358.8, 37530.9, 13927.4, 4.0658 + 0.4, 0.0, 41.0, 81235.6, 39435.0, 16259.3, 6.7507 + 0.4, 0.0, 44.0, 88978.8, 41206.6, 18648.9, 10.578 + 0.4, 0.0, 47.0, 96612.8, 42867.0, 21094.6, 15.7725 + 0.4, 0.0, 50.0, 104138.7, 44423.4, 23624.7, 22.8975 + 0.4, 2000.0, 21.0, 23381.5, 20431.6, 2205.9, 12.1636 + 0.4, 2000.0, 26.0, 37892.7, 26092.7, 5205.1, 12.2107 + 0.4, 2000.0, 29.0, 46641.4, 28941.7, 7200.9, 12.5262 + 0.4, 2000.0, 32.0, 55006.9, 31407.3, 9258.8, 13.1007 + 0.4, 2000.0, 35.0, 63096.9, 33597.3, 11405.4, 2.3622 + 0.4, 2000.0, 38.0, 70981.4, 35581.8, 13639.6, 4.238 + 0.4, 2000.0, 41.0, 78706.7, 37407.6, 15946.8, 7.0611 + 0.4, 2000.0, 44.0, 86304.1, 39104.9, 18310.2, 11.0566 + 0.4, 2000.0, 47.0, 93791.9, 40691.9, 20741.2, 16.574 + 0.4, 2000.0, 50.0, 101168.5, 42169.5, 23297.6, 24.4562 + 0.4, 5000.0, 21.0, 21338.3, 18471.0, 2028.7, 11.3366 + 0.4, 5000.0, 26.0, 35292.6, 23823.1, 4900.2, 11.274 + 0.4, 5000.0, 29.0, 43704.6, 26501.0, 6826.0, 11.6289 + 0.4, 5000.0, 32.0, 51747.6, 28809.6, 8823.4, 1.2195 + 0.4, 5000.0, 35.0, 59527.8, 30854.9, 10915.8, 2.4254 + 0.4, 5000.0, 38.0, 67114.5, 32707.1, 13093.6, 4.3813 + 0.4, 5000.0, 41.0, 74552.0, 34410.0, 15336.6, 7.3217 + 0.4, 5000.0, 44.0, 81869.3, 35990.5, 17642.0, 11.4886 + 0.4, 5000.0, 47.0, 89066.3, 37455.4, 20055.4, 17.5383 + 0.4, 5000.0, 50.0, 96161.6, 38816.2, 22601.8, 26.3223 + 0.4, 10000.0, 21.0, 18064.6, 15457.6, 1724.1, 9.4812 + 0.4, 10000.0, 26.0, 30596.3, 20168.6, 4271.0, 9.8426 + 0.4, 10000.0, 29.0, 38150.1, 22508.4, 5998.8, 10.2022 + 0.4, 10000.0, 32.0, 45372.2, 24516.7, 7802.6, 1.0921 + 0.4, 10000.0, 35.0, 52362.5, 26292.9, 9697.0, 2.202 + 0.4, 10000.0, 38.0, 59183.2, 27900.0, 11664.8, 3.9952 + 0.4, 10000.0, 41.0, 65872.5, 29375.1, 13690.9, 6.663 + 0.4, 10000.0, 44.0, 72446.1, 30735.0, 15805.1, 10.6211 + 0.4, 10000.0, 47.0, 78914.5, 31988.5, 18044.5, 16.583 + 0.4, 10000.0, 50.0, 85261.7, 33123.0, 20508.5, 25.7732 + 0.4, 15000.0, 21.0, 14820.2, 12683.5, 1388.5, 12.722 + 0.4, 15000.0, 26.0, 25095.5, 16548.5, 3427.6, 8.5411 + 0.4, 15000.0, 29.0, 31289.0, 18468.6, 4810.2, 8.8079 + 0.4, 15000.0, 32.0, 37210.6, 20116.5, 6254.0, 9.1886 + 0.4, 15000.0, 35.0, 42942.0, 21574.1, 7769.8, 1.452 + 0.4, 15000.0, 38.0, 48534.4, 22893.3, 9343.9, 2.6188 + 0.4, 15000.0, 41.0, 54019.2, 24104.4, 10963.9, 4.3432 + 0.4, 15000.0, 44.0, 59409.1, 25220.8, 12655.1, 6.8934 + 0.4, 15000.0, 47.0, 64712.8, 26250.4, 14444.5, 10.714 + 0.4, 15000.0, 50.0, 69917.6, 27182.3, 16415.5, 16.5946 + 0.4, 20000.0, 21.0, 12064.6, 10326.7, 1110.4, 9.652 + 0.4, 20000.0, 26.0, 20425.4, 13473.5, 2729.0, 7.3892 + 0.4, 20000.0, 29.0, 25464.8, 15036.9, 3826.2, 7.5842 + 0.4, 20000.0, 32.0, 30282.7, 16378.8, 4972.2, 7.8749 + 0.4, 20000.0, 35.0, 34945.9, 17565.9, 6174.9, 0.9486 + 0.4, 20000.0, 38.0, 39496.2, 18640.5, 7423.4, 1.6995 + 0.4, 20000.0, 41.0, 43959.1, 19627.2, 8707.8, 2.8024 + 0.4, 20000.0, 44.0, 48344.6, 20536.9, 10048.7, 4.4271 + 0.4, 20000.0, 47.0, 52659.9, 21376.0, 11466.9, 6.8489 + 0.4, 20000.0, 50.0, 56895.0, 22135.4, 13030.8, 10.5753 + 0.5, 0.0, 21.0, 35364.6, 32496.0, 2796.5, 13.9708 + 0.5, 0.0, 26.0, 50433.6, 38959.4, 6056.7, 13.7205 + 0.5, 0.0, 29.0, 59565.7, 42354.7, 8199.8, 14.0701 + 0.5, 0.0, 32.0, 68296.7, 45348.4, 10351.9, 1.4814 + 0.5, 0.0, 35.0, 76708.4, 48022.9, 12615.4, 2.7673 + 0.5, 0.0, 38.0, 84879.0, 50456.5, 14969.8, 4.8572 + 0.5, 0.0, 41.0, 92863.1, 52703.7, 17395.8, 7.9602 + 0.5, 0.0, 44.0, 100696.1, 54800.3, 19870.7, 12.3254 + 0.5, 0.0, 47.0, 108401.3, 56766.2, 22402.5, 18.2498 + 0.5, 0.0, 50.0, 115982.3, 58611.8, 25012.6, 26.2418 + 0.5, 2000.0, 21.0, 33226.2, 30380.8, 2650.1, 13.2841 + 0.5, 2000.0, 26.0, 48059.0, 36677.4, 5850.5, 13.0114 + 0.5, 2000.0, 29.0, 57042.5, 39970.2, 7956.3, 13.4057 + 0.5, 2000.0, 32.0, 65622.8, 42859.5, 10096.4, 1.5146 + 0.5, 2000.0, 35.0, 73889.3, 45435.0, 12348.3, 2.8851 + 0.5, 2000.0, 38.0, 81922.4, 47777.2, 14690.6, 5.0973 + 0.5, 2000.0, 41.0, 89774.9, 49939.3, 17096.2, 8.3809 + 0.5, 2000.0, 44.0, 97478.2, 51951.6, 19558.8, 13.0247 + 0.5, 2000.0, 47.0, 105054.7, 53836.9, 22080.9, 19.3252 + 0.5, 2000.0, 50.0, 112501.2, 55593.0, 24721.2, 28.2136 + 0.5, 5000.0, 21.0, 30181.6, 27400.8, 2434.5, 12.2906 + 0.5, 5000.0, 26.0, 44524.5, 33401.8, 5512.3, 12.0116 + 0.5, 5000.0, 29.0, 53204.0, 36519.7, 7543.6, 12.4525 + 0.5, 5000.0, 32.0, 61482.6, 39236.9, 9641.5, 1.5317 + 0.5, 5000.0, 35.0, 69460.4, 41653.0, 11851.6, 2.9876 + 0.5, 5000.0, 38.0, 77217.9, 43849.1, 14143.5, 5.319 + 0.5, 5000.0, 41.0, 84804.5, 45873.7, 16494.6, 8.7855 + 0.5, 5000.0, 44.0, 92247.4, 47754.5, 18905.3, 13.6632 + 0.5, 5000.0, 47.0, 99551.3, 49498.3, 21423.3, 20.6692 + 0.5, 5000.0, 50.0, 106739.0, 51124.7, 24058.6, 30.6806 + 0.5, 10000.0, 21.0, 25411.0, 22867.2, 2065.4, 10.7525 + 0.5, 10000.0, 26.0, 38372.6, 28197.5, 4808.5, 10.4836 + 0.5, 10000.0, 29.0, 46207.5, 30944.8, 6629.3, 10.9236 + 0.5, 10000.0, 32.0, 53668.4, 33318.3, 8549.3, 1.3807 + 0.5, 10000.0, 35.0, 60864.6, 35426.6, 10563.5, 2.7382 + 0.5, 10000.0, 38.0, 67866.9, 37341.7, 12642.2, 4.897 + 0.5, 10000.0, 41.0, 74718.4, 39103.0, 14780.0, 8.0962 + 0.5, 10000.0, 44.0, 81425.0, 40724.6, 17006.7, 12.7961 + 0.5, 10000.0, 47.0, 88012.3, 42224.0, 19350.0, 19.7776 + 0.5, 10000.0, 50.0, 94483.7, 43608.3, 21907.3, 30.2925 + 0.5, 15000.0, 21.0, 20849.1, 18764.5, 1661.9, 9.0811 + 0.5, 15000.0, 26.0, 31475.3, 23137.0, 3857.6, 9.0771 + 0.5, 15000.0, 29.0, 37898.5, 25391.1, 5314.9, 9.4099 + 0.5, 15000.0, 32.0, 44015.1, 27338.5, 6851.3, 9.8248 + 0.5, 15000.0, 35.0, 49914.9, 29068.9, 8462.3, 1.7998 + 0.5, 15000.0, 38.0, 55655.7, 30640.8, 10124.8, 3.1998 + 0.5, 15000.0, 41.0, 61273.3, 32086.9, 11834.3, 5.2627 + 0.5, 15000.0, 44.0, 66771.7, 33418.5, 13614.0, 8.2795 + 0.5, 15000.0, 47.0, 72172.6, 34650.0, 15486.5, 12.7408 + 0.5, 15000.0, 50.0, 77478.8, 35787.4, 17530.5, 19.4398 + 0.5, 20000.0, 21.0, 16973.6, 15278.5, 1327.4, 8.0378 + 0.5, 20000.0, 26.0, 25618.0, 18838.0, 3070.0, 7.8366 + 0.5, 20000.0, 29.0, 30843.7, 20673.2, 4226.5, 8.0852 + 0.5, 20000.0, 32.0, 35819.6, 22258.9, 5445.4, 8.4024 + 0.5, 20000.0, 35.0, 40619.1, 23668.0, 6723.4, 1.1715 + 0.5, 20000.0, 38.0, 45289.5, 24948.5, 8041.6, 2.0695 + 0.5, 20000.0, 41.0, 49857.4, 26126.0, 9395.5, 3.3824 + 0.5, 20000.0, 44.0, 54333.2, 27211.7, 10807.1, 5.299 + 0.5, 20000.0, 47.0, 58727.2, 28215.4, 12290.9, 8.1172 + 0.5, 20000.0, 50.0, 63044.4, 29142.6, 13911.0, 12.3421 + 0.5, 25000.0, 21.0, 13702.8, 12335.9, 1052.2, 9.9894 + 0.5, 25000.0, 26.0, 20677.3, 15209.7, 2422.5, 6.7422 + 0.5, 25000.0, 29.0, 24893.3, 16691.6, 3331.6, 6.9262 + 0.5, 25000.0, 32.0, 28907.7, 17972.1, 4289.7, 7.1654 + 0.5, 25000.0, 35.0, 32779.9, 19110.2, 5294.2, 7.4564 + 0.5, 25000.0, 38.0, 36547.8, 20144.5, 6330.3, 1.3244 + 0.5, 25000.0, 41.0, 40233.3, 21095.9, 7393.7, 2.1513 + 0.5, 25000.0, 44.0, 43844.4, 21973.3, 8502.4, 3.3541 + 0.5, 25000.0, 47.0, 47389.8, 22784.4, 9667.3, 5.112 + 0.5, 25000.0, 50.0, 50872.8, 23533.9, 10940.5, 7.7498 + 0.5, 30000.0, 21.0, 10961.8, 9869.4, 827.4, 7.5048 + 0.5, 30000.0, 26.0, 16538.6, 12169.0, 1894.3, 7.046 + 0.5, 30000.0, 29.0, 19909.4, 13354.9, 2601.9, 5.9121 + 0.5, 30000.0, 32.0, 23119.1, 14379.8, 3347.6, 6.0908 + 0.5, 30000.0, 35.0, 26215.1, 15290.8, 4129.2, 6.3121 + 0.5, 30000.0, 38.0, 29227.7, 16118.7, 4935.4, 0.838 + 0.5, 30000.0, 41.0, 32174.5, 16880.5, 5762.6, 1.353 + 0.5, 30000.0, 44.0, 35061.9, 17583.2, 6624.6, 2.098 + 0.5, 30000.0, 47.0, 37896.5, 18232.7, 7531.1, 3.1847 + 0.5, 30000.0, 50.0, 40681.5, 18833.2, 8520.8, 4.8078 + 0.6, 15000.0, 21.0, 28234.3, 26156.1, 2007.4, 10.0462 + 0.6, 15000.0, 26.0, 39305.2, 30992.2, 4364.8, 9.7769 + 0.6, 15000.0, 29.0, 46019.5, 33550.3, 5947.4, 10.1926 + 0.6, 15000.0, 32.0, 52413.4, 35787.4, 7582.9, 1.1786 + 0.6, 15000.0, 35.0, 58554.4, 37772.1, 9327.0, 2.2974 + 0.6, 15000.0, 38.0, 64520.0, 39581.4, 11114.8, 4.0443 + 0.6, 15000.0, 41.0, 70343.1, 41247.9, 12953.7, 6.6207 + 0.6, 15000.0, 44.0, 76076.5, 42825.0, 14855.7, 10.3351 + 0.6, 15000.0, 47.0, 81727.6, 44319.7, 16859.6, 15.8133 + 0.6, 15000.0, 50.0, 87266.1, 45701.8, 19033.3, 23.9629 + 0.6, 20000.0, 21.0, 22987.2, 21297.8, 1601.8, 8.6431 + 0.6, 20000.0, 26.0, 31991.5, 25233.9, 3472.3, 8.4212 + 0.6, 20000.0, 29.0, 37452.5, 27316.2, 4727.7, 8.7349 + 0.6, 20000.0, 32.0, 42653.0, 29137.6, 6024.8, 9.0874 + 0.6, 20000.0, 35.0, 47647.9, 30754.0, 7407.5, 1.4887 + 0.6, 20000.0, 38.0, 52500.3, 32227.6, 8824.9, 2.6049 + 0.6, 20000.0, 41.0, 57236.8, 33585.3, 10282.0, 4.2403 + 0.6, 20000.0, 44.0, 61901.1, 34870.3, 11789.1, 6.5884 + 0.6, 20000.0, 47.0, 66497.5, 36088.1, 13376.8, 10.0383 + 0.6, 20000.0, 50.0, 71003.6, 37215.9, 15096.0, 15.1291 + 0.6, 25000.0, 21.0, 18558.5, 17196.7, 1268.0, 7.6093 + 0.6, 25000.0, 26.0, 25821.3, 20373.9, 2738.4, 7.2292 + 0.6, 25000.0, 29.0, 30226.2, 22055.0, 3725.1, 7.464 + 0.6, 25000.0, 32.0, 34420.8, 23525.7, 4744.3, 7.7308 + 0.6, 25000.0, 35.0, 38449.6, 24830.9, 5831.0, 0.9549 + 0.6, 25000.0, 38.0, 42363.7, 26021.3, 6944.2, 1.6594 + 0.6, 25000.0, 41.0, 46184.3, 27118.2, 8088.3, 2.6856 + 0.6, 25000.0, 44.0, 49946.8, 28156.5, 9271.3, 4.1523 + 0.6, 25000.0, 47.0, 53654.7, 29141.1, 10516.9, 6.2972 + 0.6, 25000.0, 50.0, 57290.5, 30053.3, 11866.2, 9.4464 + 0.6, 30000.0, 21.0, 14847.2, 13759.1, 995.5, 10.5417 + 0.6, 30000.0, 26.0, 20653.4, 16301.2, 2140.1, 7.4886 + 0.6, 30000.0, 29.0, 24174.7, 17646.4, 2907.9, 6.3564 + 0.6, 30000.0, 32.0, 27527.9, 18823.3, 3700.9, 6.556 + 0.6, 30000.0, 35.0, 30748.7, 19868.1, 4546.2, 6.8095 + 0.6, 30000.0, 38.0, 33877.6, 20820.9, 5412.5, 1.046 + 0.6, 30000.0, 41.0, 36932.1, 21699.3, 6301.8, 1.6817 + 0.6, 30000.0, 44.0, 39939.9, 22530.8, 7221.5, 2.5867 + 0.6, 30000.0, 47.0, 42904.6, 23319.4, 8189.6, 3.9045 + 0.6, 30000.0, 50.0, 45811.3, 24050.2, 9238.2, 5.8345 + 0.6, 35000.0, 21.0, 11760.6, 10899.8, 774.7, 7.8311 + 0.6, 35000.0, 26.0, 16357.4, 12914.1, 1656.1, 6.5122 + 0.6, 35000.0, 29.0, 19144.9, 13980.0, 2247.4, 6.987 + 0.6, 35000.0, 32.0, 21799.5, 14912.8, 2857.6, 5.5392 + 0.6, 35000.0, 35.0, 24349.1, 15740.9, 3508.2, 5.7304 + 0.6, 35000.0, 38.0, 26826.2, 16496.3, 4174.7, 5.9629 + 0.6, 35000.0, 41.0, 29244.7, 17192.8, 4859.5, 1.0407 + 0.6, 35000.0, 44.0, 31625.5, 17852.1, 5566.3, 1.5918 + 0.6, 35000.0, 47.0, 33972.3, 18477.5, 6311.3, 2.3925 + 0.6, 35000.0, 50.0, 36273.8, 19057.4, 7117.4, 3.5581 + 0.6, 39000.0, 21.0, 9704.0, 8993.7, 640.8, 7.2796 + 0.6, 39000.0, 26.0, 13498.0, 10656.9, 1363.6, 5.8737 + 0.6, 39000.0, 29.0, 15798.6, 11536.9, 1848.4, 6.3084 + 0.6, 39000.0, 32.0, 17989.5, 12307.1, 2348.6, 6.6983 + 0.6, 39000.0, 35.0, 20093.6, 12990.8, 2882.0, 5.1179 + 0.6, 39000.0, 38.0, 22137.8, 13614.4, 3428.6, 5.325 + 0.6, 39000.0, 41.0, 24133.3, 14189.4, 3989.7, 0.8931 + 0.6, 39000.0, 44.0, 26098.5, 14733.7, 4569.8, 1.3639 + 0.6, 39000.0, 47.0, 28035.3, 15250.1, 5180.5, 2.0455 + 0.6, 39000.0, 50.0, 29934.8, 15729.2, 5841.2, 3.0339 + 0.7, 15000.0, 21.0, 37000.0, 34883.2, 2395.0, 10.8234 + 0.7, 15000.0, 26.0, 48665.2, 40197.8, 4964.6, 10.6455 + 0.7, 15000.0, 29.0, 55763.9, 43062.8, 6699.8, 11.1618 + 0.7, 15000.0, 32.0, 62517.2, 45582.4, 8493.8, 1.5699 + 0.7, 15000.0, 35.0, 68992.3, 47823.8, 10401.6, 3.0258 + 0.7, 15000.0, 38.0, 75331.7, 49930.0, 12358.5, 5.2967 + 0.7, 15000.0, 41.0, 81577.2, 51939.2, 14367.9, 8.6456 + 0.7, 15000.0, 44.0, 87717.1, 53847.0, 16450.9, 13.4708 + 0.7, 15000.0, 47.0, 93746.1, 55643.1, 18647.1, 20.6044 + 0.7, 15000.0, 50.0, 99631.3, 57294.6, 21025.5, 31.2882 + 0.7, 20000.0, 21.0, 30125.1, 28404.7, 1910.0, 9.3726 + 0.7, 20000.0, 26.0, 39611.1, 32729.8, 3948.2, 9.1446 + 0.7, 20000.0, 29.0, 45384.0, 35061.9, 5324.0, 9.5384 + 0.7, 20000.0, 32.0, 50875.7, 37112.8, 6747.1, 1.0205 + 0.7, 20000.0, 35.0, 56141.7, 38938.2, 8259.1, 1.9524 + 0.7, 20000.0, 38.0, 61297.1, 40653.3, 9810.0, 3.3974 + 0.7, 20000.0, 41.0, 66376.8, 42290.2, 11401.6, 5.5145 + 0.7, 20000.0, 44.0, 71370.7, 43844.7, 13051.5, 8.5524 + 0.7, 20000.0, 47.0, 76275.3, 45309.0, 14789.8, 13.0156 + 0.7, 20000.0, 50.0, 81062.8, 46656.1, 16670.6, 19.6645 + 0.7, 25000.0, 21.0, 24322.4, 22936.0, 1510.5, 8.1835 + 0.7, 25000.0, 26.0, 31972.1, 26426.5, 3112.4, 7.8307 + 0.7, 25000.0, 29.0, 36627.6, 28309.2, 4193.4, 8.1281 + 0.7, 25000.0, 32.0, 41056.3, 29964.8, 5311.7, 8.4431 + 0.7, 25000.0, 35.0, 45303.1, 31439.0, 6499.2, 1.2462 + 0.7, 25000.0, 38.0, 49460.7, 32824.1, 7717.0, 2.1547 + 0.7, 25000.0, 41.0, 53557.8, 34146.5, 8966.1, 3.4766 + 0.7, 25000.0, 44.0, 57585.7, 35402.7, 10260.7, 5.3651 + 0.7, 25000.0, 47.0, 61542.1, 36586.6, 11624.3, 8.127 + 0.7, 25000.0, 50.0, 65404.2, 37676.0, 13098.1, 12.2134 + 0.7, 30000.0, 21.0, 19459.3, 18352.0, 1184.4, 7.1626 + 0.7, 30000.0, 26.0, 25573.0, 21144.0, 2431.0, 6.6802 + 0.7, 30000.0, 29.0, 29293.8, 22650.3, 3271.8, 6.9037 + 0.7, 30000.0, 32.0, 32833.0, 23975.0, 4141.9, 7.1405 + 0.7, 30000.0, 35.0, 36227.4, 25154.8, 5065.3, 7.4301 + 0.7, 30000.0, 38.0, 39550.3, 26263.4, 6012.2, 1.3509 + 0.7, 30000.0, 41.0, 42823.9, 27322.2, 6981.6, 2.1644 + 0.7, 30000.0, 44.0, 46044.8, 28328.3, 7988.6, 3.3255 + 0.7, 30000.0, 47.0, 49207.9, 29277.2, 9047.2, 5.0123 + 0.7, 30000.0, 50.0, 52295.4, 30150.3, 10191.2, 7.4912 + 0.7, 35000.0, 21.0, 15414.7, 14539.0, 920.4, 6.2312 + 0.7, 35000.0, 26.0, 20253.6, 16750.8, 1880.2, 6.9587 + 0.7, 35000.0, 29.0, 23198.6, 17944.4, 2527.1, 5.8406 + 0.7, 35000.0, 32.0, 25999.7, 18994.0, 3196.7, 6.017 + 0.7, 35000.0, 35.0, 28686.4, 19929.2, 3907.0, 6.2358 + 0.7, 35000.0, 38.0, 31316.2, 20807.8, 4635.4, 0.8369 + 0.7, 35000.0, 41.0, 33907.4, 21647.4, 5380.7, 1.3321 + 0.7, 35000.0, 44.0, 36457.1, 22445.4, 6154.7, 2.0351 + 0.7, 35000.0, 47.0, 38961.1, 23198.2, 6968.4, 3.0536 + 0.7, 35000.0, 50.0, 41405.1, 23890.9, 7847.7, 4.5425 + 0.7, 39000.0, 21.0, 12719.5, 11997.0, 760.1, 5.5996 + 0.7, 39000.0, 26.0, 16713.2, 13823.2, 1547.2, 6.2785 + 0.7, 39000.0, 29.0, 19143.7, 14808.6, 2077.6, 6.7463 + 0.7, 39000.0, 32.0, 21455.3, 15675.3, 2626.5, 5.373 + 0.7, 39000.0, 35.0, 23672.5, 16447.4, 3208.9, 5.5683 + 0.7, 39000.0, 38.0, 25842.7, 17172.7, 3806.2, 0.7186 + 0.7, 39000.0, 41.0, 27981.0, 17865.8, 4417.2, 1.1414 + 0.7, 39000.0, 44.0, 30085.1, 18524.7, 5051.7, 1.7401 + 0.7, 39000.0, 47.0, 32151.4, 19146.3, 5718.9, 2.6062 + 0.7, 39000.0, 50.0, 34168.7, 19718.5, 6439.3, 3.8672 + 0.7, 43000.0, 21.0, 10492.0, 9895.8, 632.0, 5.0366 + 0.7, 43000.0, 26.0, 13788.2, 11403.5, 1281.3, 5.6847 + 0.7, 43000.0, 29.0, 15794.1, 12217.0, 1718.9, 6.12 + 0.7, 43000.0, 32.0, 17701.9, 12932.5, 2171.5, 6.5075 + 0.7, 43000.0, 35.0, 19531.5, 13569.7, 2652.1, 6.8924 + 0.7, 43000.0, 38.0, 21322.4, 14168.3, 3144.9, 0.6752 + 0.7, 43000.0, 41.0, 23087.2, 14740.3, 3649.6, 1.0717 + 0.7, 43000.0, 44.0, 24823.2, 15284.1, 4172.6, 1.6309 + 0.7, 43000.0, 47.0, 26528.3, 15797.0, 4723.1, 2.4399 + 0.7, 43000.0, 50.0, 28192.7, 16269.0, 5317.6, 3.6153 + 0.75, 25000.0, 21.0, 27546.9, 26138.5, 1641.0, 8.5002 + 0.75, 25000.0, 26.0, 35431.1, 29797.3, 3319.1, 8.1843 + 0.75, 25000.0, 29.0, 40235.1, 31784.2, 4455.8, 8.5168 + 0.75, 25000.0, 32.0, 44806.1, 33538.6, 5630.3, 8.8616 + 0.75, 25000.0, 35.0, 49230.4, 35145.6, 6882.9, 1.4348 + 0.75, 25000.0, 38.0, 53572.6, 36671.1, 8165.2, 2.4798 + 0.75, 25000.0, 41.0, 57842.8, 38124.1, 9479.0, 4.001 + 0.75, 25000.0, 44.0, 62035.5, 39499.5, 10845.5, 6.1843 + 0.75, 25000.0, 47.0, 66143.1, 40790.6, 12284.1, 9.3844 + 0.75, 25000.0, 50.0, 70157.9, 41988.6, 13835.9, 14.1101 + 0.75, 30000.0, 21.0, 22039.6, 20914.9, 1286.1, 7.4373 + 0.75, 30000.0, 26.0, 28340.4, 23841.4, 2591.9, 6.9731 + 0.75, 30000.0, 29.0, 32179.6, 25431.1, 3476.0, 7.2236 + 0.75, 30000.0, 32.0, 35832.4, 26834.6, 4389.7, 7.4834 + 0.75, 30000.0, 35.0, 39368.2, 28120.5, 5363.8, 0.9037 + 0.75, 30000.0, 38.0, 42838.7, 29341.7, 6360.4, 1.5508 + 0.75, 30000.0, 41.0, 46251.8, 30505.2, 7381.3, 2.4868 + 0.75, 30000.0, 44.0, 49603.4, 31606.9, 8442.7, 3.8239 + 0.75, 30000.0, 47.0, 52887.4, 32641.7, 9559.6, 5.7728 + 0.75, 30000.0, 50.0, 56096.0, 33600.9, 10763.7, 8.6348 + 0.75, 35000.0, 21.0, 17459.2, 16569.8, 998.7, 6.4692 + 0.75, 35000.0, 26.0, 22445.8, 18888.0, 2004.0, 7.21 + 0.75, 35000.0, 29.0, 25484.4, 20147.7, 2684.2, 6.1032 + 0.75, 35000.0, 32.0, 28375.2, 21259.8, 3387.4, 6.2971 + 0.75, 35000.0, 35.0, 31173.6, 22279.0, 4136.5, 6.53 + 0.75, 35000.0, 38.0, 33920.1, 23246.8, 4903.3, 0.9586 + 0.75, 35000.0, 41.0, 36621.9, 24169.5, 5687.9, 1.5266 + 0.75, 35000.0, 44.0, 39275.0, 25043.5, 6503.5, 2.3342 + 0.75, 35000.0, 47.0, 41875.3, 25865.0, 7361.3, 3.5066 + 0.75, 35000.0, 50.0, 44414.1, 26625.0, 8286.6, 5.2204 + 0.75, 39000.0, 21.0, 14406.8, 13673.0, 824.4, 5.8174 + 0.75, 39000.0, 26.0, 18522.4, 15587.0, 1648.7, 6.506 + 0.75, 39000.0, 29.0, 21030.1, 16627.1, 2206.4, 6.9937 + 0.75, 39000.0, 32.0, 23415.8, 17545.3, 2782.8, 5.6229 + 0.75, 39000.0, 35.0, 25725.1, 18386.7, 3397.1, 5.8303 + 0.75, 39000.0, 38.0, 27991.7, 19185.7, 4025.8, 0.8223 + 0.75, 39000.0, 41.0, 30221.2, 19947.4, 4669.1, 1.307 + 0.75, 39000.0, 44.0, 32410.8, 20669.2, 5337.6, 1.994 + 0.75, 39000.0, 47.0, 34556.4, 21347.2, 6041.1, 2.9906 + 0.75, 39000.0, 50.0, 36651.8, 21975.1, 6799.2, 4.4421 + 0.75, 43000.0, 21.0, 11884.0, 11278.4, 685.1, 5.2379 + 0.75, 43000.0, 26.0, 15280.9, 12858.7, 1365.1, 5.8932 + 0.75, 43000.0, 29.0, 17350.7, 13717.4, 1825.1, 6.3463 + 0.75, 43000.0, 32.0, 19319.7, 14475.4, 2300.5, 6.7499 + 0.75, 43000.0, 35.0, 21225.3, 15169.8, 2807.5, 5.2592 + 0.75, 43000.0, 38.0, 23095.8, 15829.2, 3326.2, 0.7724 + 0.75, 43000.0, 41.0, 24935.6, 16457.8, 3857.1, 1.2264 + 0.75, 43000.0, 44.0, 26742.6, 17053.6, 4408.7, 1.8684 + 0.75, 43000.0, 47.0, 28513.2, 17613.3, 4989.0, 2.7994 + 0.75, 43000.0, 50.0, 30242.4, 18131.4, 5614.5, 4.1526 + 0.8, 25000.0, 21.0, 31001.9, 29565.5, 1772.3, 8.8361 + 0.8, 25000.0, 26.0, 39148.9, 33403.3, 3535.5, 8.5767 + 0.8, 25000.0, 29.0, 44118.0, 35499.4, 4736.3, 8.9447 + 0.8, 25000.0, 32.0, 48906.5, 37415.1, 5977.6, 9.3229 + 0.8, 25000.0, 35.0, 53548.3, 39184.0, 7304.0, 1.6615 + 0.8, 25000.0, 38.0, 58097.9, 40861.0, 8657.7, 2.8706 + 0.8, 25000.0, 41.0, 62562.1, 42452.1, 10049.2, 4.6437 + 0.8, 25000.0, 44.0, 66936.3, 43953.0, 11496.2, 7.1917 + 0.8, 25000.0, 47.0, 71216.5, 45360.8, 13020.3, 10.9401 + 0.8, 25000.0, 50.0, 75414.8, 46686.4, 14659.3, 16.4535 + 0.8, 30000.0, 21.0, 24804.5, 23657.5, 1388.4, 7.7278 + 0.8, 30000.0, 26.0, 31314.9, 26727.0, 2760.3, 7.2981 + 0.8, 30000.0, 29.0, 35285.9, 28404.0, 3694.3, 7.5753 + 0.8, 30000.0, 32.0, 39112.5, 29936.7, 4659.4, 7.8615 + 0.8, 30000.0, 35.0, 42821.7, 31351.9, 5691.3, 1.0439 + 0.8, 30000.0, 38.0, 46458.1, 32694.5, 6743.2, 1.7907 + 0.8, 30000.0, 41.0, 50026.4, 33968.7, 7824.3, 2.8791 + 0.8, 30000.0, 44.0, 53523.3, 35171.3, 8948.0, 4.4353 + 0.8, 30000.0, 47.0, 56944.9, 36299.4, 10130.9, 6.7136 + 0.8, 30000.0, 50.0, 60299.8, 37360.3, 11402.8, 10.0427 + 0.8, 35000.0, 21.0, 19650.0, 18743.0, 1077.6, 6.7204 + 0.8, 35000.0, 26.0, 24802.1, 21174.5, 2133.6, 7.4797 + 0.8, 35000.0, 29.0, 27944.7, 22503.2, 2852.1, 6.3914 + 0.8, 35000.0, 32.0, 30972.8, 23717.5, 3594.6, 6.6053 + 0.8, 35000.0, 35.0, 33908.3, 24839.1, 4388.3, 6.8519 + 0.8, 35000.0, 38.0, 36786.1, 25903.4, 5197.2, 1.1035 + 0.8, 35000.0, 41.0, 39610.7, 26913.9, 6028.0, 1.7622 + 0.8, 35000.0, 44.0, 42378.9, 27868.1, 6891.5, 2.7 + 0.8, 35000.0, 47.0, 45087.5, 28763.0, 7799.9, 4.0661 + 0.8, 35000.0, 50.0, 47741.9, 29603.8, 8776.6, 6.0512 + 0.8, 39000.0, 21.0, 16214.8, 15466.6, 889.0, 6.0466 + 0.8, 39000.0, 26.0, 20467.0, 17474.1, 1755.0, 6.7501 + 0.8, 39000.0, 29.0, 23060.6, 18571.2, 2344.1, 7.2594 + 0.8, 39000.0, 32.0, 25559.7, 19573.7, 2952.7, 5.8977 + 0.8, 39000.0, 35.0, 27982.2, 20499.7, 3603.6, 6.117 + 0.8, 39000.0, 38.0, 30357.1, 21378.3, 4266.9, 0.9461 + 0.8, 39000.0, 41.0, 32688.1, 22212.7, 4948.1, 1.5077 + 0.8, 39000.0, 44.0, 34972.7, 23000.6, 5655.8, 2.3049 + 0.8, 39000.0, 47.0, 37207.9, 23739.6, 6400.4, 3.4647 + 0.8, 39000.0, 50.0, 39398.3, 24433.6, 7200.9, 5.1479 + 0.8, 43000.0, 21.0, 13375.6, 12758.1, 738.3, 5.4492 + 0.8, 43000.0, 26.0, 16885.2, 14415.5, 1452.7, 6.1166 + 0.8, 43000.0, 29.0, 19025.7, 15321.2, 1938.5, 6.5888 + 0.8, 43000.0, 32.0, 21088.2, 16148.8, 2440.7, 7.0117 + 0.8, 43000.0, 35.0, 23087.3, 16913.1, 2977.8, 5.5195 + 0.8, 43000.0, 38.0, 25047.1, 17638.2, 3525.1, 0.8881 + 0.8, 43000.0, 41.0, 26970.6, 18326.8, 4087.2, 1.414 + 0.8, 43000.0, 44.0, 28856.0, 18977.1, 4671.1, 2.1587 + 0.8, 43000.0, 47.0, 30700.5, 19586.9, 5285.5, 3.2417 + 0.8, 43000.0, 50.0, 32508.1, 20159.7, 5945.8, 4.811 + 0.85, 30000.0, 21.0, 27755.3, 26581.6, 1490.3, 8.0347 + 0.85, 30000.0, 26.0, 34499.5, 29804.9, 2936.1, 7.6579 + 0.85, 30000.0, 29.0, 38670.9, 31628.8, 3929.6, 7.9545 + 0.85, 30000.0, 32.0, 42710.0, 33320.5, 4956.8, 8.275 + 0.85, 30000.0, 35.0, 46614.3, 34877.3, 6050.0, 1.2114 + 0.85, 30000.0, 38.0, 50433.3, 36349.2, 7165.6, 2.0818 + 0.85, 30000.0, 41.0, 54173.6, 37740.6, 8315.8, 3.3605 + 0.85, 30000.0, 44.0, 57827.9, 39048.5, 9509.6, 5.189 + 0.85, 30000.0, 47.0, 61415.3, 40288.9, 10766.6, 7.8675 + 0.85, 30000.0, 50.0, 64936.6, 41462.9, 12114.9, 11.7784 + 0.85, 35000.0, 21.0, 21988.0, 21060.1, 1156.2, 6.9851 + 0.85, 35000.0, 26.0, 27324.8, 23613.2, 2269.0, 7.7688 + 0.85, 35000.0, 29.0, 30625.7, 25058.2, 3033.2, 6.7025 + 0.85, 35000.0, 32.0, 33822.0, 26398.6, 3823.2, 6.9423 + 0.85, 35000.0, 35.0, 36911.5, 27632.2, 4664.3, 7.2058 + 0.85, 35000.0, 38.0, 39934.1, 28799.1, 5522.0, 1.2794 + 0.85, 35000.0, 41.0, 42893.9, 29902.9, 6404.7, 2.0498 + 0.85, 35000.0, 44.0, 45788.1, 30940.9, 7322.6, 3.1499 + 0.85, 35000.0, 47.0, 48626.6, 31923.9, 8287.9, 4.7514 + 0.85, 35000.0, 50.0, 51413.2, 32854.7, 9322.9, 7.0732 + 0.85, 39000.0, 21.0, 18144.4, 17378.8, 953.4, 6.2875 + 0.85, 39000.0, 26.0, 22548.9, 19486.7, 1865.9, 7.0116 + 0.85, 39000.0, 29.0, 25273.0, 20679.6, 2492.5, 5.9812 + 0.85, 39000.0, 32.0, 27910.8, 21786.4, 3140.2, 6.1977 + 0.85, 39000.0, 35.0, 30460.5, 22804.9, 3829.8, 6.432 + 0.85, 39000.0, 38.0, 32954.8, 23768.2, 4533.1, 1.0957 + 0.85, 39000.0, 41.0, 35397.4, 24679.6, 5256.8, 1.7519 + 0.85, 39000.0, 44.0, 37786.0, 25536.8, 6009.1, 2.6866 + 0.85, 39000.0, 47.0, 40128.6, 26348.6, 6800.0, 4.0455 + 0.85, 39000.0, 50.0, 42427.6, 27116.6, 7648.4, 6.013 + 0.85, 43000.0, 21.0, 14967.4, 14335.7, 791.4, 5.6707 + 0.85, 43000.0, 26.0, 18602.8, 16076.0, 1544.2, 6.3558 + 0.85, 43000.0, 29.0, 20850.9, 17060.7, 2061.1, 6.8454 + 0.85, 43000.0, 32.0, 23028.0, 17974.4, 2595.4, 7.2944 + 0.85, 43000.0, 35.0, 25132.1, 18815.0, 3164.4, 5.8055 + 0.85, 43000.0, 38.0, 27190.5, 19610.1, 3744.7, 1.0281 + 0.85, 43000.0, 41.0, 29206.1, 20362.2, 4341.9, 1.6423 + 0.85, 43000.0, 44.0, 31177.2, 21069.7, 4962.6, 2.5154 + 0.85, 43000.0, 47.0, 33110.2, 21739.5, 5615.2, 3.7828 + 0.85, 43000.0, 50.0, 35007.5, 22373.5, 6315.0, 5.6183 + 0.9, 35000.0, 21.0, 24475.3, 23522.8, 1234.1, 7.2684 + 0.9, 35000.0, 26.0, 30064.1, 26254.5, 2412.7, 6.8042 + 0.9, 35000.0, 29.0, 33566.2, 27851.8, 3230.4, 7.0401 + 0.9, 35000.0, 32.0, 36947.7, 29328.5, 4074.1, 7.3108 + 0.9, 35000.0, 35.0, 40206.7, 30682.6, 4967.6, 0.8729 + 0.9, 35000.0, 38.0, 43386.9, 31958.1, 5881.0, 1.4937 + 0.9, 35000.0, 41.0, 46494.7, 33160.1, 6823.0, 2.4043 + 0.9, 35000.0, 44.0, 49529.2, 34290.3, 7801.5, 3.7048 + 0.9, 35000.0, 47.0, 52522.4, 35379.0, 8829.7, 5.5968 + 0.9, 35000.0, 50.0, 55455.7, 36407.6, 9930.9, 8.3404 + 0.9, 39000.0, 21.0, 20197.0, 19411.3, 1017.3, 6.5448 + 0.9, 39000.0, 26.0, 24809.2, 21666.4, 1983.8, 7.2909 + 0.9, 39000.0, 29.0, 27699.4, 22985.1, 2654.1, 6.2825 + 0.9, 39000.0, 32.0, 30490.0, 24204.3, 3345.8, 6.5259 + 0.9, 39000.0, 35.0, 33179.4, 25322.3, 4078.3, 0.7486 + 0.9, 39000.0, 38.0, 35803.7, 26375.3, 4827.3, 1.2781 + 0.9, 39000.0, 41.0, 38368.5, 27367.8, 5599.4, 2.0528 + 0.9, 39000.0, 44.0, 40872.6, 28301.0, 6401.4, 3.1569 + 0.9, 39000.0, 47.0, 43342.5, 29199.7, 7244.0, 4.7603 + 0.9, 39000.0, 50.0, 45763.1, 30049.0, 8146.3, 7.0805 + 0.9, 43000.0, 21.0, 16660.8, 16012.5, 844.0, 5.9067 + 0.9, 43000.0, 26.0, 20467.6, 17874.3, 1641.4, 6.6112 + 0.9, 43000.0, 29.0, 22852.8, 18962.8, 2194.4, 7.122 + 0.9, 43000.0, 32.0, 25155.9, 19969.3, 2765.0, 5.8854 + 0.9, 43000.0, 35.0, 27375.4, 20892.0, 3369.5, 0.703 + 0.9, 43000.0, 38.0, 29541.0, 21761.1, 3987.4, 1.1986 + 0.9, 43000.0, 41.0, 31657.4, 22580.1, 4624.7, 1.9236 + 0.9, 43000.0, 44.0, 33723.8, 23350.3, 5286.3, 2.9545 + 0.9, 43000.0, 47.0, 35761.8, 24091.9, 5981.5, 4.4497 + 0.9, 43000.0, 50.0, 37759.5, 24793.0, 6725.8, 6.6133 diff --git a/aviary/subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv b/aviary/subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv index b8d7aa138..6a51f8faa 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv +++ b/aviary/subsystems/aerodynamics/flops_based/test/data/high_wing_single_aisle.csv @@ -100,7 +100,7 @@ aircraft:wing:airfoil_technology,1.01,unitless #check aircraft:wing:area,1480,ft**2 aircraft:wing:aspect_ratio_reference,0.01,unitless #check aircraft:wing:bending_material_mass_scaler,1.01,unitless #check -aircraft:wing:chord_per_semispan,0.13,0.115,0.06,unitless +aircraft:wing:chord_per_semispan_dist,0.13,0.115,0.06,unitless aircraft:wing:composite_fraction,0.01,unitless #check aircraft:wing:dihedral,-1.0,deg aircraft:wing:control_surface_area_ratio,0.2234,unitless diff --git a/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py b/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py index 200cd72a7..fa044e20d 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py +++ b/aviary/subsystems/aerodynamics/gasp_based/gaspaero.py @@ -697,7 +697,7 @@ def compute(self, inputs, outputs): ufac = (1 + lift_ratio) ** 2 / ( sigstr * (lift_ratio / bbar) ** 2 + 2 * sigma * lift_ratio / bbar + 1 ) - else: + elif design_type is AircraftTypes.BLENDED_WING_BODY: # Modify for tailless "BWB" if bbar < 0.01 * wingspan: bbar = 1.0 @@ -2515,7 +2515,7 @@ def setup(self): ), promotes=['*'], ) - else: + elif design_type is AircraftTypes.TRANSPORT: self.add_subsystem( 'aero_setup', AeroSetup( @@ -2538,7 +2538,7 @@ def setup(self): BWBLiftCoeffClean(output_alpha=self.options['output_alpha'], num_nodes=nn), promotes=['*'], ) - else: + elif design_type is AircraftTypes.TRANSPORT: self.add_subsystem( 'lift_coef', LiftCoeffClean(output_alpha=self.options['output_alpha'], num_nodes=nn), @@ -2594,7 +2594,7 @@ def setup(self): ), promotes=['*'], ) - else: + elif design_type is AircraftTypes.TRANSPORT: self.add_subsystem( 'aero_setup', AeroSetup( @@ -2661,7 +2661,7 @@ def setup(self): promotes_inputs=['*'], promotes_outputs=['*'], ) - else: + elif design_type is AircraftTypes.TRANSPORT: self.add_subsystem( 'lift_coef', LiftCoeff(num_nodes=nn), diff --git a/aviary/subsystems/aerodynamics/gasp_based/test/test_common.py b/aviary/subsystems/aerodynamics/gasp_based/test/test_common.py index cf7b53f6b..97a7da079 100644 --- a/aviary/subsystems/aerodynamics/gasp_based/test/test_common.py +++ b/aviary/subsystems/aerodynamics/gasp_based/test/test_common.py @@ -110,7 +110,7 @@ class TestTanhRampComp(unittest.TestCase): def test_tanh_ramp_up(self): p = om.Problem() - nn = 1000 + nn = 100 c = TanhRampComp(time_units='s', num_nodes=nn) @@ -135,12 +135,12 @@ def test_tanh_ramp_up(self): thruput = p.get_val('tanh_ramp.thruput') - assert_near_equal(thruput[250], desired=30, tolerance=0.01) - assert_near_equal(thruput[275], desired=35, tolerance=0.01) - assert_near_equal(thruput[300], desired=40, tolerance=0.01) + assert_near_equal(thruput[25], desired=30, tolerance=0.01) + assert_near_equal(thruput[27], desired=33.6, tolerance=0.01) + assert_near_equal(thruput[30], desired=40, tolerance=0.01) - assert_near_equal(thruput[500:], desired=40 * np.ones((500, 1)), tolerance=0.01) - assert_near_equal(thruput[:200], desired=30 * np.ones((200, 1)), tolerance=0.01) + assert_near_equal(thruput[50:], desired=40 * np.ones((50, 1)), tolerance=0.01) + assert_near_equal(thruput[:20], desired=30 * np.ones((20, 1)), tolerance=0.01) self.assertTrue(np.all(thruput >= 30)) self.assertTrue(np.all(thruput <= 40)) @@ -150,7 +150,7 @@ def test_tanh_ramp_up(self): def test_tanh_ramp_down(self): p = om.Problem() - nn = 1000 + nn = 100 c = TanhRampComp(time_units='s', num_nodes=nn) @@ -175,12 +175,12 @@ def test_tanh_ramp_down(self): thruput = p.get_val('tanh_ramp.thruput')[:, 0] - assert_near_equal(thruput[250], desired=40, tolerance=0.01) - assert_near_equal(thruput[275], desired=35, tolerance=0.01) - assert_near_equal(thruput[300], desired=30, tolerance=0.01) + assert_near_equal(thruput[25], desired=40, tolerance=0.01) + assert_near_equal(thruput[27], desired=36.4, tolerance=0.01) + assert_near_equal(thruput[30], desired=30, tolerance=0.01) - assert_near_equal(thruput[500:], desired=30 * np.ones(500), tolerance=0.01) - assert_near_equal(thruput[:200], desired=40 * np.ones(200), tolerance=0.01) + assert_near_equal(thruput[50:], desired=30 * np.ones(50), tolerance=0.01) + assert_near_equal(thruput[:20], desired=40 * np.ones(20), tolerance=0.01) self.assertTrue(np.all(thruput >= 30)) self.assertTrue(np.all(thruput <= 40)) diff --git a/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py b/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py index 07017d268..856795eb3 100644 --- a/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py +++ b/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py @@ -65,7 +65,7 @@ class PrepGeomTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): class PreMission(om.Group): def initialize(self): diff --git a/aviary/subsystems/geometry/gasp_based/size_group.py b/aviary/subsystems/geometry/gasp_based/size_group.py index 251f1f0d4..469af8285 100644 --- a/aviary/subsystems/geometry/gasp_based/size_group.py +++ b/aviary/subsystems/geometry/gasp_based/size_group.py @@ -27,7 +27,7 @@ def setup(self): promotes_inputs=['*'], promotes_outputs=['*'], ) - else: + elif design_type is AircraftTypes.TRANSPORT: self.add_subsystem( 'fuselage', FuselageGroup(), @@ -41,7 +41,7 @@ def setup(self): BWBWingGroup(), promotes=['*'], ) - else: + elif design_type is AircraftTypes.TRANSPORT: self.add_subsystem( 'wing', WingGroup(), @@ -61,7 +61,7 @@ def setup(self): promotes_inputs=['*'], promotes_outputs=['*'], ) - else: + elif design_type is AircraftTypes.TRANSPORT: self.add_subsystem( 'engine', EngineSize(), diff --git a/aviary/subsystems/geometry/gasp_based/wing.py b/aviary/subsystems/geometry/gasp_based/wing.py index 34b38fa16..c9365c294 100644 --- a/aviary/subsystems/geometry/gasp_based/wing.py +++ b/aviary/subsystems/geometry/gasp_based/wing.py @@ -1828,7 +1828,7 @@ def compute(self, inputs, outputs): if design_type is AircraftTypes.BLENDED_WING_BODY: cabin_height = body_width * inputs[Aircraft.Fuselage.HEIGHT_TO_WIDTH_RATIO] b_fus = 0.5 * (body_width - cabin_height) + cabin_height * sqt - else: + elif design_type is AircraftTypes.TRANSPORT: b_fus = body_width * sqt wingspan = inputs[Aircraft.Wing.SPAN] @@ -1870,7 +1870,7 @@ def compute_partials(self, inputs, J): if design_type is AircraftTypes.BLENDED_WING_BODY: cabin_height = body_width * height_to_width b_fus = 0.5 * (body_width - cabin_height) + cabin_height * sqt - else: + elif design_type is AircraftTypes.TRANSPORT: b_fus = body_width * sqt wingspan = inputs[Aircraft.Wing.SPAN] diff --git a/aviary/subsystems/mass/flops_based/fuselage.py b/aviary/subsystems/mass/flops_based/fuselage.py index d8b8a08ff..21a3293cf 100644 --- a/aviary/subsystems/mass/flops_based/fuselage.py +++ b/aviary/subsystems/mass/flops_based/fuselage.py @@ -2,8 +2,9 @@ from aviary.constants import GRAV_ENGLISH_LBM from aviary.subsystems.mass.flops_based.distributed_prop import distributed_engine_count_factor +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 +from aviary.variable_info.variables import Aircraft, Mission, Settings class TransportFuselageMass(om.ExplicitComponent): @@ -144,3 +145,242 @@ def compute_partials(self, inputs, J): * mass_scaler / GRAV_ENGLISH_LBM ) + + +class BWBFuselageMass(om.ExplicitComponent): + """ + Computes the mass of the fuselage for BWB aircraft. The methodology + is based on the FLOPS weight equations, modified to output mass instead + of weight. + """ + + def initialize(self): + add_aviary_option(self, Settings.VERBOSITY) + + def setup(self): + add_aviary_input(self, Mission.Design.GROSS_MASS, units='lbm') + add_aviary_input(self, Aircraft.Fuselage.CABIN_AREA, units='ft**2') + + add_aviary_output(self, Aircraft.Fuselage.MASS, units='lbm') + + def setup_partials(self): + self.declare_partials(Aircraft.Fuselage.MASS, '*') + + def compute(self, inputs, outputs): + verbosity = self.options[Settings.VERBOSITY] + gross_weight = inputs[Mission.Design.GROSS_MASS] * GRAV_ENGLISH_LBM + cabin_area = inputs[Aircraft.Fuselage.CABIN_AREA] + if gross_weight <= 0.0: + if verbosity > Verbosity.BRIEF: + print('Mission.Design.GROSS_MASS must be positive.') + + outputs[Aircraft.Fuselage.MASS] = 1.8 * gross_weight**0.167 * cabin_area**1.06 + + def compute_partials(self, inputs, J): + gross_weight = inputs[Mission.Design.GROSS_MASS] * GRAV_ENGLISH_LBM + cabin_area = inputs[Aircraft.Fuselage.CABIN_AREA] + J[Aircraft.Fuselage.MASS, Mission.Design.GROSS_MASS] = ( + 0.167 * 1.8 * gross_weight**-0.833 * cabin_area**1.06 + ) + J[Aircraft.Fuselage.MASS, Aircraft.Fuselage.CABIN_AREA] = ( + 1.06 * 1.8 * gross_weight**0.167 * cabin_area**0.06 + ) + + +class BWBAftBodyMass(om.ExplicitComponent): + """Mass of aft body for BWB aircraft""" + + def initialize(self): + add_aviary_option(self, Settings.VERBOSITY) + add_aviary_option(self, Aircraft.Engine.NUM_FUSELAGE_ENGINES) + + def setup(self): + add_aviary_input(self, Mission.Design.GROSS_MASS, units='lbm') + add_aviary_input(self, Aircraft.Fuselage.PLANFORM_AREA, units='ft**2') + add_aviary_input(self, Aircraft.Fuselage.CABIN_AREA, units='ft**2') + add_aviary_input(self, Aircraft.Fuselage.LENGTH, units='ft') + add_aviary_input(self, Aircraft.Wing.ROOT_CHORD, units='ft') + add_aviary_input(self, Aircraft.Wing.COMPOSITE_FRACTION, units='unitless') + self.add_input( + 'Rear_spar_percent_chord', + 0.7, + units='unitless', + desc='RSPSOB: Rear spar percent chord for BWB at side of body', + ) + self.add_input( + 'Rear_spar_percent_chord_centerline', + 0.7, + units='unitless', + desc='RSPCHD: Rear spar percent chord for BWB at fuselage centerline', + ) + + add_aviary_output(self, Aircraft.Fuselage.AFTBODY_MASS, units='lbm') + add_aviary_output(self, Aircraft.Wing.BWB_AFTBODY_MASS, units='lbm') + + def setup_partials(self): + self.declare_partials( + Aircraft.Fuselage.AFTBODY_MASS, + [ + Mission.Design.GROSS_MASS, + Aircraft.Fuselage.PLANFORM_AREA, + Aircraft.Fuselage.CABIN_AREA, + Aircraft.Fuselage.LENGTH, + Aircraft.Wing.ROOT_CHORD, + 'Rear_spar_percent_chord', + 'Rear_spar_percent_chord_centerline', + ], + ) + self.declare_partials( + Aircraft.Wing.BWB_AFTBODY_MASS, + [ + Mission.Design.GROSS_MASS, + Aircraft.Fuselage.PLANFORM_AREA, + Aircraft.Fuselage.CABIN_AREA, + Aircraft.Fuselage.LENGTH, + Aircraft.Wing.ROOT_CHORD, + Aircraft.Wing.COMPOSITE_FRACTION, + 'Rear_spar_percent_chord', + 'Rear_spar_percent_chord_centerline', + ], + ) + + def compute(self, inputs, outputs): + verbosity = self.options[Settings.VERBOSITY] + num_fuse_eng = self.options[Aircraft.Engine.NUM_FUSELAGE_ENGINES] + gross_weight = inputs[Mission.Design.GROSS_MASS] * GRAV_ENGLISH_LBM + fuse_area = inputs[Aircraft.Fuselage.PLANFORM_AREA] + cabin_area = inputs[Aircraft.Fuselage.CABIN_AREA] + length = inputs[Aircraft.Fuselage.LENGTH] + root_chord = inputs[Aircraft.Wing.ROOT_CHORD] + rear_spar_percent_chord = inputs['Rear_spar_percent_chord'] + rear_spar_percent_chord_centerline = inputs['Rear_spar_percent_chord_centerline'] + comp_frac = inputs[Aircraft.Wing.COMPOSITE_FRACTION] + + if rear_spar_percent_chord <= 0.0 or rear_spar_percent_chord >= 1.0: + if verbosity > Verbosity.BRIEF: + print('Rear_spar_percent_chord must be within 0 and 1.') + if rear_spar_percent_chord_centerline <= 0.0 or rear_spar_percent_chord_centerline >= 1.0: + if verbosity > Verbosity.BRIEF: + print('Rear_spar_percent_chord_centerline must be within 0 and 1.') + if length <= 0.0: + if verbosity > Verbosity.BRIEF: + print('Aircraft.Fuselage.LENGTH must be positive.') + + aftbody_area = fuse_area - cabin_area + aftbody_tr = ((1.0 - rear_spar_percent_chord) * root_chord / rear_spar_percent_chord) / ( + (1.0 - rear_spar_percent_chord_centerline) * length + ) + aftbody_weight = ( + (1.0 + 0.05 * num_fuse_eng) + * 0.53 + * aftbody_area + * gross_weight**0.2 + * (0.5 + aftbody_tr) + ) + aftbody_weight_adjusted = aftbody_weight * (1.0 - 0.17 * comp_frac) + outputs[Aircraft.Fuselage.AFTBODY_MASS] = aftbody_weight / GRAV_ENGLISH_LBM + outputs[Aircraft.Wing.BWB_AFTBODY_MASS] = aftbody_weight_adjusted / GRAV_ENGLISH_LBM + + def compute_partials(self, inputs, J): + num_fuse_eng = self.options[Aircraft.Engine.NUM_FUSELAGE_ENGINES] + gross_weight = inputs[Mission.Design.GROSS_MASS] * GRAV_ENGLISH_LBM + fuse_area = inputs[Aircraft.Fuselage.PLANFORM_AREA] + cabin_area = inputs[Aircraft.Fuselage.CABIN_AREA] + length = inputs[Aircraft.Fuselage.LENGTH] + root_chord = inputs[Aircraft.Wing.ROOT_CHORD] + rear_spar_percent_chord = inputs['Rear_spar_percent_chord'] + rear_spar_percent_chord_centerline = inputs['Rear_spar_percent_chord_centerline'] + comp_frac = inputs[Aircraft.Wing.COMPOSITE_FRACTION] + fac = 1.0 - 0.17 * comp_frac + + aftbody_area = fuse_area - cabin_area + aftbody_tr = ((1.0 - rear_spar_percent_chord) * root_chord / rear_spar_percent_chord) / ( + (1.0 - rear_spar_percent_chord_centerline) * length + ) + aftbody_weight = ( + (1.0 + 0.05 * num_fuse_eng) + * 0.53 + * aftbody_area + * gross_weight**0.2 + * (0.5 + aftbody_tr) + ) + + J[Aircraft.Fuselage.AFTBODY_MASS, Mission.Design.GROSS_MASS] = ( + 0.2 + * (1.0 + 0.05 * num_fuse_eng) + * 0.53 + * aftbody_area + * gross_weight**-0.8 + * (0.5 + aftbody_tr) + ) + J[Aircraft.Wing.BWB_AFTBODY_MASS, Mission.Design.GROSS_MASS] = ( + J[Aircraft.Fuselage.AFTBODY_MASS, Mission.Design.GROSS_MASS] * fac + ) + J[Aircraft.Fuselage.AFTBODY_MASS, Aircraft.Fuselage.PLANFORM_AREA] = ( + (1.0 + 0.05 * num_fuse_eng) * 0.53 * gross_weight**0.2 * (0.5 + aftbody_tr) + ) + J[Aircraft.Wing.BWB_AFTBODY_MASS, Aircraft.Fuselage.PLANFORM_AREA] = ( + J[Aircraft.Fuselage.AFTBODY_MASS, Aircraft.Fuselage.PLANFORM_AREA] * fac + ) + J[Aircraft.Fuselage.AFTBODY_MASS, Aircraft.Fuselage.CABIN_AREA] = ( + -(1.0 + 0.05 * num_fuse_eng) * 0.53 * gross_weight**0.2 * (0.5 + aftbody_tr) + ) + J[Aircraft.Wing.BWB_AFTBODY_MASS, Aircraft.Fuselage.CABIN_AREA] = ( + J[Aircraft.Fuselage.AFTBODY_MASS, Aircraft.Fuselage.CABIN_AREA] * fac + ) + daftbody_tr_droot_chord = ((1.0 - rear_spar_percent_chord) / rear_spar_percent_chord) / ( + (1.0 - rear_spar_percent_chord_centerline) * length + ) + J[Aircraft.Fuselage.AFTBODY_MASS, Aircraft.Wing.ROOT_CHORD] = ( + (1.0 + 0.05 * num_fuse_eng) + * 0.53 + * aftbody_area + * gross_weight**0.2 + * daftbody_tr_droot_chord + ) + J[Aircraft.Wing.BWB_AFTBODY_MASS, Aircraft.Wing.ROOT_CHORD] = ( + J[Aircraft.Fuselage.AFTBODY_MASS, Aircraft.Wing.ROOT_CHORD] * fac + ) + daftbody_tr_dlength = -( + (1.0 - rear_spar_percent_chord) * root_chord / rear_spar_percent_chord + ) / ((1.0 - rear_spar_percent_chord_centerline) * length**2) + J[Aircraft.Fuselage.AFTBODY_MASS, Aircraft.Fuselage.LENGTH] = ( + (1.0 + 0.05 * num_fuse_eng) + * 0.53 + * aftbody_area + * gross_weight**0.2 + * daftbody_tr_dlength + ) + J[Aircraft.Wing.BWB_AFTBODY_MASS, Aircraft.Fuselage.LENGTH] = ( + J[Aircraft.Fuselage.AFTBODY_MASS, Aircraft.Fuselage.LENGTH] * fac + ) + daftbody_tr_drspc = ( + -1.0 + / rear_spar_percent_chord**2 + * root_chord + / ((1.0 - rear_spar_percent_chord_centerline) * length) + ) + J[Aircraft.Fuselage.AFTBODY_MASS, 'Rear_spar_percent_chord'] = ( + (1.0 + 0.05 * num_fuse_eng) + * 0.53 + * aftbody_area + * gross_weight**0.2 + * daftbody_tr_drspc + ) + J[Aircraft.Wing.BWB_AFTBODY_MASS, 'Rear_spar_percent_chord'] = ( + J[Aircraft.Fuselage.AFTBODY_MASS, 'Rear_spar_percent_chord'] * fac + ) + daftbody_tr_drspcc = ( + (1.0 - rear_spar_percent_chord) * root_chord / rear_spar_percent_chord + ) / ((1.0 - rear_spar_percent_chord_centerline) ** 2 * length) + J[Aircraft.Fuselage.AFTBODY_MASS, 'Rear_spar_percent_chord_centerline'] = ( + (1.0 + 0.05 * num_fuse_eng) + * 0.53 + * aftbody_area + * gross_weight**0.2 + * daftbody_tr_drspcc + ) + J[Aircraft.Wing.BWB_AFTBODY_MASS, 'Rear_spar_percent_chord_centerline'] = ( + J[Aircraft.Fuselage.AFTBODY_MASS, 'Rear_spar_percent_chord_centerline'] * fac + ) + J[Aircraft.Wing.BWB_AFTBODY_MASS, Aircraft.Wing.COMPOSITE_FRACTION] = -0.17 * aftbody_weight diff --git a/aviary/subsystems/mass/flops_based/mass_premission.py b/aviary/subsystems/mass/flops_based/mass_premission.py index a5cff0546..ce210aaaa 100644 --- a/aviary/subsystems/mass/flops_based/mass_premission.py +++ b/aviary/subsystems/mass/flops_based/mass_premission.py @@ -21,9 +21,14 @@ from aviary.subsystems.mass.flops_based.furnishings import ( AltFurnishingsGroupMass, AltFurnishingsGroupMassBase, + BWBFurnishingsGroupMass, TransportFurnishingsGroupMass, ) -from aviary.subsystems.mass.flops_based.fuselage import AltFuselageMass, TransportFuselageMass +from aviary.subsystems.mass.flops_based.fuselage import ( + AltFuselageMass, + BWBFuselageMass, + TransportFuselageMass, +) from aviary.subsystems.mass.flops_based.horizontal_tail import ( AltHorizontalTailMass, HorizontalTailMass, @@ -54,6 +59,7 @@ ) from aviary.subsystems.mass.flops_based.vertical_tail import AltVerticalTailMass, VerticalTailMass from aviary.subsystems.mass.flops_based.wing_group import WingMassGroup +from aviary.variable_info.enums import AircraftTypes from aviary.variable_info.functions import add_aviary_option from aviary.variable_info.variables import Aircraft @@ -67,9 +73,11 @@ class MassPremission(om.Group): def initialize(self): add_aviary_option(self, Aircraft.Design.USE_ALT_MASS) + add_aviary_option(self, Aircraft.Design.TYPE) def setup(self): alt_mass = self.options[Aircraft.Design.USE_ALT_MASS] + design_type = self.options[Aircraft.Design.TYPE] self.add_subsystem('cargo', CargoMass(), promotes_inputs=['*'], promotes_outputs=['*']) @@ -137,12 +145,20 @@ def setup(self): promotes_outputs=['*'], ) - self.add_subsystem( - 'furnishings', - AltFurnishingsGroupMass(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) + if design_type == AircraftTypes.BLENDED_WING_BODY: + self.add_subsystem( + 'furnishings', + BWBFurnishingsGroupMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + else: + self.add_subsystem( + 'furnishings', + AltFurnishingsGroupMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) self.add_subsystem( 'hydraulics', @@ -192,12 +208,20 @@ def setup(self): promotes_outputs=['*'], ) - self.add_subsystem( - 'furnishings', - TransportFurnishingsGroupMass(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) + if design_type == AircraftTypes.BLENDED_WING_BODY: + self.add_subsystem( + 'furnishings', + BWBFurnishingsGroupMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + else: + self.add_subsystem( + 'furnishings', + TransportFurnishingsGroupMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) self.add_subsystem( 'hydraulics', @@ -267,16 +291,28 @@ def setup(self): 'surf_ctrl', AltSurfaceControlMass(), promotes_inputs=['*'], promotes_outputs=['*'] ) - self.add_subsystem( - 'fuselage', - AltFuselageMass(), - promotes_inputs=[ - '*', - ], - promotes_outputs=[ - '*', - ], - ) + if design_type == AircraftTypes.BLENDED_WING_BODY: + self.add_subsystem( + 'fuselage', + BWBFuselageMass(), + promotes_inputs=[ + '*', + ], + promotes_outputs=[ + '*', + ], + ) + else: + self.add_subsystem( + 'fuselage', + AltFuselageMass(), + promotes_inputs=[ + '*', + ], + promotes_outputs=[ + '*', + ], + ) self.add_subsystem( 'htail', @@ -298,16 +334,28 @@ def setup(self): 'surf_ctrl', SurfaceControlMass(), promotes_inputs=['*'], promotes_outputs=['*'] ) - self.add_subsystem( - 'fuselage', - TransportFuselageMass(), - promotes_inputs=[ - '*', - ], - promotes_outputs=[ - '*', - ], - ) + if design_type == AircraftTypes.BLENDED_WING_BODY: + self.add_subsystem( + 'fuselage', + BWBFuselageMass(), + promotes_inputs=[ + '*', + ], + promotes_outputs=[ + '*', + ], + ) + else: + self.add_subsystem( + 'fuselage', + TransportFuselageMass(), + promotes_inputs=[ + '*', + ], + promotes_outputs=[ + '*', + ], + ) self.add_subsystem( 'htail', diff --git a/aviary/subsystems/mass/flops_based/test/test_air_conditioning.py b/aviary/subsystems/mass/flops_based/test/test_air_conditioning.py index f2f488a14..f22ca8a4e 100644 --- a/aviary/subsystems/mass/flops_based/test/test_air_conditioning.py +++ b/aviary/subsystems/mass/flops_based/test/test_air_conditioning.py @@ -2,6 +2,7 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials +from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized from aviary.subsystems.mass.flops_based.air_conditioning import AltAirCondMass, TransportAirCondMass @@ -16,11 +17,12 @@ from aviary.variable_info.variables import Aircraft +@use_tempdirs class TransportAirCondMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -93,6 +95,7 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +@use_tempdirs class AltAirCondMassTest(unittest.TestCase): """Tests alternate air conditioning mass calculation.""" @@ -161,5 +164,43 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +@use_tempdirs +class BWBTransportAirCondMassTest(unittest.TestCase): + def setUp(self): + self.prob = om.Problem() + + def test_case(self): + """Test TransportAirCondMass component for BWB""" + case_name = 'BWB1aFLOPS' + prob = self.prob + + prob.model.add_subsystem( + 'air_cond', + TransportAirCondMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model_options['*'] = get_flops_options(case_name) + + prob.setup(check=False, force_alloc_complex=True) + + flops_validation_test( + prob, + case_name, + input_keys=[ + Aircraft.AirConditioning.MASS_SCALER, + Aircraft.Avionics.MASS, + Aircraft.Fuselage.MAX_HEIGHT, + Aircraft.Fuselage.PLANFORM_AREA, + ], + output_keys=Aircraft.AirConditioning.MASS, + aviary_option_keys=[Aircraft.CrewPayload.Design.NUM_PASSENGERS], + version=Version.TRANSPORT, # TODO: Version.BWB + tol=3.0e-4, + atol=1e-11, + ) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_anti_icing.py b/aviary/subsystems/mass/flops_based/test/test_anti_icing.py index e8339c11c..980de53ae 100644 --- a/aviary/subsystems/mass/flops_based/test/test_anti_icing.py +++ b/aviary/subsystems/mass/flops_based/test/test_anti_icing.py @@ -3,11 +3,13 @@ import numpy as np import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal +from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized from aviary.subsystems.mass.flops_based.anti_icing import AntiIcingMass from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import ( + Version, flops_validation_test, get_flops_case_names, get_flops_options, @@ -16,11 +18,12 @@ from aviary.variable_info.variables import Aircraft +@use_tempdirs class AntiIcingMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -163,5 +166,45 @@ def test_case_2(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +class BWBAntiIcingMassTest(unittest.TestCase): + def setUp(self): + self.prob = om.Problem() + + def test_case(self): + """test AntiIcingMass component for BWB""" + case_name = 'BWB1aFLOPS' + prob = self.prob + + prob.model.add_subsystem( + 'anti_icing', + AntiIcingMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + options = get_flops_options('BWB1aFLOPS') + options[Aircraft.Engine.NUM_ENGINES] = np.array([3]) + options[Aircraft.Propulsion.TOTAL_NUM_ENGINES] = 3 + + prob.model_options['*'] = options + + prob.setup(check=False, force_alloc_complex=True) + + flops_validation_test( + prob, + case_name, + input_keys=[ + Aircraft.AntiIcing.MASS_SCALER, + Aircraft.Fuselage.MAX_WIDTH, + Aircraft.Nacelle.AVG_DIAMETER, + Aircraft.Wing.SPAN, + Aircraft.Wing.SWEEP, + ], + output_keys=Aircraft.AntiIcing.MASS, + version=Version.TRANSPORT, # TODO: Version.BWB + tol=3.0e-3, + ) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_apu.py b/aviary/subsystems/mass/flops_based/test/test_apu.py index 92abe3c3e..ccadbb1b2 100644 --- a/aviary/subsystems/mass/flops_based/test/test_apu.py +++ b/aviary/subsystems/mass/flops_based/test/test_apu.py @@ -2,11 +2,13 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials +from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized from aviary.subsystems.mass.flops_based.apu import TransportAPUMass from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import ( + Version, flops_validation_test, get_flops_case_names, get_flops_options, @@ -15,11 +17,12 @@ from aviary.variable_info.variables import Aircraft +@use_tempdirs class APUMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -77,5 +80,34 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +class BWBAPUMassTest(unittest.TestCase): + def setUp(self): + self.prob = om.Problem() + + def test_case(self): + case_name = 'BWB1aFLOPS' + prob = self.prob + + prob.model.add_subsystem( + 'apu', + TransportAPUMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model_options['*'] = get_flops_options(case_name, preprocess=False) + + prob.setup(check=False, force_alloc_complex=True) + + flops_validation_test( + prob, + case_name, + input_keys=[Aircraft.APU.MASS_SCALER, Aircraft.Fuselage.PLANFORM_AREA], + output_keys=Aircraft.APU.MASS, + version=Version.TRANSPORT, # TODO: Version.BWB + tol=5.0e-4, + ) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_avionics.py b/aviary/subsystems/mass/flops_based/test/test_avionics.py index b56fc86cb..afa24a98b 100644 --- a/aviary/subsystems/mass/flops_based/test/test_avionics.py +++ b/aviary/subsystems/mass/flops_based/test/test_avionics.py @@ -1,10 +1,12 @@ import unittest import openmdao.api as om -from openmdao.utils.assert_utils import assert_check_partials +from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal +from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized from aviary.subsystems.mass.flops_based.avionics import TransportAvionicsMass +from aviary.utils.aviary_values import AviaryValues from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import ( flops_validation_test, @@ -12,16 +14,18 @@ get_flops_options, print_case, ) +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Aircraft, Mission +@use_tempdirs class TransportAvionicsMassTest(unittest.TestCase): """Tests transport/GA avionics mass calculation.""" def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -85,5 +89,42 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +@use_tempdirs +class BWBTransportAvionicsMassTest(unittest.TestCase): + """Test BWB fuselage mass""" + + def setUp(self): + self.prob = om.Problem() + + def test_case1(self): + aviary_options = AviaryValues() + aviary_options.set_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW, 2, units='unitless') + prob = self.prob + + prob.model.add_subsystem( + 'avionics', + TransportAvionicsMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model.set_input_defaults(Aircraft.Avionics.MASS_SCALER, val=1.0, units='unitless') + prob.model.set_input_defaults( + Aircraft.Fuselage.PLANFORM_AREA, val=7390.26743215, units='ft**2' + ) + prob.model.set_input_defaults(Mission.Design.RANGE, val=7750.0, units='NM') + + setup_model_options(self.prob, aviary_options) + self.prob.setup(check=False, force_alloc_complex=True) + + prob.run_model() + + tol = 1e-8 + assert_near_equal(self.prob[Aircraft.Avionics.MASS], 2896.22381695, tol) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data, atol=1e-10, rtol=1e-10) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_cargo.py b/aviary/subsystems/mass/flops_based/test/test_cargo.py index cf7cd295c..a887e9aa9 100644 --- a/aviary/subsystems/mass/flops_based/test/test_cargo.py +++ b/aviary/subsystems/mass/flops_based/test/test_cargo.py @@ -1,12 +1,15 @@ import unittest import openmdao.api as om +from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal +from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized from aviary.subsystems.mass.flops_based.cargo import CargoMass from aviary.utils.aviary_values import AviaryValues from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import do_validation_test, print_case +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Aircraft cargo_test_data = {} @@ -24,6 +27,7 @@ cargo_data_sets = [key for key in cargo_test_data] +@use_tempdirs class CargoMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() @@ -66,5 +70,44 @@ def test_IO(self): assert_match_varnames(self.prob.model) +@use_tempdirs +class BWBCargoMassTest(unittest.TestCase): + """Test BWB cargo mass""" + + def setUp(self): + self.prob = om.Problem() + + def test_case1(self): + aviary_options = AviaryValues() + aviary_options.set_val(Aircraft.CrewPayload.BAGGAGE_MASS_PER_PASSENGER, 44, units='lbm') + aviary_options.set_val(Aircraft.CrewPayload.MASS_PER_PASSENGER, 165, units='lbm') + aviary_options.set_val(Aircraft.CrewPayload.NUM_PASSENGERS, 468, units='unitless') + prob = self.prob + + prob.model.add_subsystem( + 'cargo', + CargoMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model.set_input_defaults(Aircraft.CrewPayload.WING_CARGO, val=0.0, units='lbm') + prob.model.set_input_defaults(Aircraft.CrewPayload.MISC_CARGO, val=0.0, units='lbm') + + setup_model_options(self.prob, aviary_options) + self.prob.setup(check=False, force_alloc_complex=True) + + prob.run_model() + + tol = 1e-8 + assert_near_equal(self.prob[Aircraft.CrewPayload.BAGGAGE_MASS], 20592.0, tol) + assert_near_equal(self.prob[Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS], 97812.0, tol) + assert_near_equal(self.prob[Aircraft.CrewPayload.CARGO_MASS], 0.0, tol) + assert_near_equal(self.prob[Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS], 97812.0, tol) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data, atol=1e-10, rtol=1e-10) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_cargo_containers.py b/aviary/subsystems/mass/flops_based/test/test_cargo_containers.py index 2a7c7e566..cae154cc1 100644 --- a/aviary/subsystems/mass/flops_based/test/test_cargo_containers.py +++ b/aviary/subsystems/mass/flops_based/test/test_cargo_containers.py @@ -1,10 +1,12 @@ import unittest import openmdao.api as om -from openmdao.utils.assert_utils import assert_check_partials +from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal +from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized from aviary.subsystems.mass.flops_based.cargo_containers import TransportCargoContainersMass +from aviary.utils.aviary_values import AviaryValues from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import ( flops_validation_test, @@ -12,9 +14,11 @@ get_flops_options, print_case, ) +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Aircraft +@use_tempdirs class CargoContainerMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() @@ -50,6 +54,7 @@ def test_IO(self): assert_match_varnames(self.prob.model) +@use_tempdirs class CargoContainerMassTest2(unittest.TestCase): """Test mass-weight conversion.""" @@ -82,5 +87,39 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +@use_tempdirs +class BWBCargoContainersMassTest(unittest.TestCase): + """Test BWB cargo containers mass""" + + def setUp(self): + self.prob = om.Problem() + + def test_case1(self): + prob = self.prob + + prob.model.add_subsystem( + 'cargo_containers', + TransportCargoContainersMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model.set_input_defaults( + Aircraft.CrewPayload.CARGO_CONTAINER_MASS_SCALER, val=1.0, units='unitless' + ) + prob.model.set_input_defaults(Aircraft.CrewPayload.CARGO_MASS, val=0.0, units='lbm') + prob.model.set_input_defaults(Aircraft.CrewPayload.BAGGAGE_MASS, val=20592.0, units='lbm') + + self.prob.setup(check=False, force_alloc_complex=True) + + prob.run_model() + + tol = 1e-8 + assert_near_equal(self.prob[Aircraft.CrewPayload.CARGO_CONTAINER_MASS], 3850.0, tol) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data, atol=1e-10, rtol=1e-10) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_crew.py b/aviary/subsystems/mass/flops_based/test/test_crew.py index e8bf532e3..282681c54 100644 --- a/aviary/subsystems/mass/flops_based/test/test_crew.py +++ b/aviary/subsystems/mass/flops_based/test/test_crew.py @@ -1,11 +1,13 @@ import unittest import openmdao.api as om +from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized from aviary.subsystems.mass.flops_based.crew import FlightCrewMass, NonFlightCrewMass from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import ( + Version, flops_validation_test, get_flops_case_names, get_flops_options, @@ -14,11 +16,12 @@ from aviary.variable_info.variables import Aircraft +@use_tempdirs class NonFlightCrewMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -45,11 +48,12 @@ def test_IO(self): assert_match_varnames(self.prob.model) +@use_tempdirs class FlightCrewMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -76,5 +80,65 @@ def test_IO(self): assert_match_varnames(self.prob.model) +@use_tempdirs +class BWBNonFlightCrewMassTest(unittest.TestCase): + def setUp(self): + self.prob = om.Problem() + + def test_case(self): + case_name = 'BWB1aFLOPS' + prob = self.prob + + prob.model.add_subsystem( + 'non_flight_crew', + NonFlightCrewMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model_options['*'] = get_flops_options(case_name, preprocess=False) + + prob.setup(check=False, force_alloc_complex=True) + + flops_validation_test( + prob, + case_name, + input_keys=Aircraft.CrewPayload.NON_FLIGHT_CREW_MASS_SCALER, + output_keys=Aircraft.CrewPayload.NON_FLIGHT_CREW_MASS, + version=Version.TRANSPORT, # TODO: Version.BWB + atol=1e-11, + ) + + +@use_tempdirs +class BWBFlightCrewMassTest(unittest.TestCase): + def setUp(self): + self.prob = om.Problem() + + def test_case(self): + case_name = 'BWB1aFLOPS' + prob = self.prob + + prob.model.add_subsystem( + 'flight_crew', + FlightCrewMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + + prob.setup(check=False, force_alloc_complex=True) + + flops_validation_test( + prob, + case_name, + input_keys=Aircraft.CrewPayload.FLIGHT_CREW_MASS_SCALER, + output_keys=Aircraft.CrewPayload.FLIGHT_CREW_MASS, + version=Version.TRANSPORT, # TODO: Version.BWB + atol=1e-11, + ) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_electrical.py b/aviary/subsystems/mass/flops_based/test/test_electrical.py index f5b385468..af6ce386b 100644 --- a/aviary/subsystems/mass/flops_based/test/test_electrical.py +++ b/aviary/subsystems/mass/flops_based/test/test_electrical.py @@ -2,6 +2,7 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials +from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized from aviary.subsystems.mass.flops_based.electrical import AltElectricalMass, ElectricalMass @@ -16,6 +17,7 @@ from aviary.variable_info.variables import Aircraft +@use_tempdirs class ElectricMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() @@ -133,6 +135,7 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +@use_tempdirs class AltElectricMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() @@ -166,5 +169,44 @@ def test_IO(self): assert_match_varnames(self.prob.model) +@use_tempdirs +class BWBElectricMassTest(unittest.TestCase): + def setUp(self): + self.prob = om.Problem() + + def test_case(self): + case_name = 'BWB1aFLOPS' + prob = self.prob + + prob.model.add_subsystem( + 'electric_test', + ElectricalMass(), + promotes_outputs=[ + Aircraft.Electrical.MASS, + ], + promotes_inputs=[ + Aircraft.Fuselage.LENGTH, + Aircraft.Fuselage.MAX_WIDTH, + Aircraft.Electrical.MASS_SCALER, + ], + ) + + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + + prob.setup(check=False, force_alloc_complex=True) + + flops_validation_test( + self.prob, + case_name, + input_keys=[ + Aircraft.Fuselage.LENGTH, + Aircraft.Fuselage.MAX_WIDTH, + Aircraft.Electrical.MASS_SCALER, + ], + output_keys=Aircraft.Electrical.MASS, + version=Version.TRANSPORT, # TODO: Version.BWB + ) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_empty_margin.py b/aviary/subsystems/mass/flops_based/test/test_empty_margin.py index 21a1663df..39f4f7fb2 100644 --- a/aviary/subsystems/mass/flops_based/test/test_empty_margin.py +++ b/aviary/subsystems/mass/flops_based/test/test_empty_margin.py @@ -1,11 +1,13 @@ import unittest import openmdao.api as om +from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized from aviary.subsystems.mass.flops_based.empty_margin import EmptyMassMargin from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import ( + Version, flops_validation_test, get_flops_case_names, get_flops_options, @@ -14,11 +16,12 @@ from aviary.variable_info.variables import Aircraft +@use_tempdirs class EmptyMassMarginTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -51,5 +54,44 @@ def test_IO(self): assert_match_varnames(self.prob.model) +@use_tempdirs +class BWBEmptyMassMarginTest(unittest.TestCase): + def setUp(self): + self.prob = om.Problem() + + def test_case(self): + case_name = 'BWB1aFLOPS' + prob = self.prob + + prob.model.add_subsystem( + 'margin', + EmptyMassMargin(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + + prob.setup(check=False, force_alloc_complex=True) + + flops_validation_test( + prob, + case_name, + input_keys=[ + Aircraft.Propulsion.MASS, + Aircraft.Design.STRUCTURE_MASS, + Aircraft.Design.SYSTEMS_EQUIP_MASS, + Aircraft.Design.EMPTY_MASS_MARGIN_SCALER, + ], + output_keys=Aircraft.Design.EMPTY_MASS_MARGIN, + version=Version.TRANSPORT, # TODO: Version.BWB + tol=1e-3, + atol=2e-11, + ) + + def test_IO(self): + assert_match_varnames(self.prob.model) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_engine.py b/aviary/subsystems/mass/flops_based/test/test_engine.py index 06ffcb2d2..108f883a3 100644 --- a/aviary/subsystems/mass/flops_based/test/test_engine.py +++ b/aviary/subsystems/mass/flops_based/test/test_engine.py @@ -3,6 +3,7 @@ import numpy as np import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal +from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized from aviary.subsystems.mass.flops_based.engine import EngineMass @@ -12,6 +13,7 @@ from aviary.utils.preprocessors import preprocess_propulsion from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import ( + Version, flops_validation_test, get_flops_case_names, get_flops_options, @@ -20,11 +22,12 @@ from aviary.variable_info.variables import Aircraft, Settings +@use_tempdirs class EngineMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -135,5 +138,46 @@ def test_IO(self): assert_match_varnames(self.prob.model) +@use_tempdirs +class BWBEngineMassTest(unittest.TestCase): + def setUp(self): + self.prob = om.Problem() + + def test_case(self): + case_name = 'BWB1aFLOPS' + prob = self.prob + + prob.model.add_subsystem( + 'engine_mass', + EngineMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + + prob.setup(check=False, force_alloc_complex=True) + prob.set_val(Aircraft.Engine.MASS_SCALER, val=np.ones(1)) + + flops_validation_test( + prob, + case_name, + input_keys=[ + Aircraft.Engine.SCALED_SLS_THRUST, + Aircraft.Engine.ADDITIONAL_MASS, + Aircraft.Propulsion.TOTAL_ENGINE_MASS, + ], + output_keys=[ + Aircraft.Engine.MASS, + Aircraft.Engine.ADDITIONAL_MASS, + Aircraft.Propulsion.TOTAL_ENGINE_MASS, + ], + list_inputs=True, + list_outputs=True, + version=Version.TRANSPORT, # TODO: Version.BWB + rtol=1e-10, + ) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_engine_controls.py b/aviary/subsystems/mass/flops_based/test/test_engine_controls.py index d0b1c1225..d1ab9050b 100644 --- a/aviary/subsystems/mass/flops_based/test/test_engine_controls.py +++ b/aviary/subsystems/mass/flops_based/test/test_engine_controls.py @@ -2,11 +2,13 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials +from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized from aviary.subsystems.mass.flops_based.engine_controls import TransportEngineCtrlsMass from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import ( + Version, flops_validation_test, get_flops_case_names, get_flops_options, @@ -15,13 +17,16 @@ from aviary.variable_info.variables import Aircraft +@use_tempdirs class BasicTransportEngineCtrlsTest(unittest.TestCase): """Test the BasicTransportEngineCtrls component.""" def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(omit='AdvancedSingleAisle'), name_func=print_case) + @parameterized.expand( + get_flops_case_names(omit=['AdvancedSingleAisle', 'BWB1aFLOPS']), name_func=print_case + ) def test_case(self, case_name): prob = self.prob @@ -80,5 +85,38 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +@use_tempdirs +class BWBBasicTransportEngineCtrlsTest(unittest.TestCase): + """Test the BasicTransportEngineCtrls component.""" + + def setUp(self): + self.prob = om.Problem() + + def test_case(self): + case_name = 'BWB1aFLOPS' + prob = self.prob + + prob.model.add_subsystem( + 'engine_ctrls', + TransportEngineCtrlsMass(), + promotes_outputs=['*'], + promotes_inputs=['*'], + ) + + prob.model_options['*'] = get_flops_options(case_name, preprocess=True) + + prob.setup(force_alloc_complex=True) + + flops_validation_test( + prob, + case_name, + input_keys=[Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST], + output_keys=Aircraft.Propulsion.TOTAL_ENGINE_CONTROLS_MASS, + version=Version.TRANSPORT, # TODO: Version.BWB + atol=2e-12, + excludes=['size_prop.*'], + ) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_engine_oil.py b/aviary/subsystems/mass/flops_based/test/test_engine_oil.py index e61cb04eb..b87361525 100644 --- a/aviary/subsystems/mass/flops_based/test/test_engine_oil.py +++ b/aviary/subsystems/mass/flops_based/test/test_engine_oil.py @@ -2,6 +2,7 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials +from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized from aviary.subsystems.mass.flops_based.engine_oil import AltEngineOilMass, TransportEngineOilMass @@ -16,13 +17,14 @@ from aviary.variable_info.variables import Aircraft +@use_tempdirs class TransportEngineOilMassTest(unittest.TestCase): """Tests transport/GA engine oil mass calculation.""" def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -90,6 +92,7 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +@use_tempdirs class AltEngineOilMassTest(unittest.TestCase): """Tests alternate engine oil mass calculation.""" @@ -163,5 +166,43 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +class BWBTransportEngineOilMassTest(unittest.TestCase): + """Tests transport/GA engine oil mass calculation.""" + + def setUp(self): + self.prob = om.Problem() + + def test_case(self): + case_name = 'BWB1aFLOPS' + prob = self.prob + + options = { + Aircraft.Propulsion.TOTAL_NUM_ENGINES: 3, + } + + prob.model.add_subsystem( + 'engine_oil', + TransportEngineOilMass(**options), + promotes_outputs=['*'], + promotes_inputs=['*'], + ) + + prob.model_options['*'] = options + + prob.setup(check=False, force_alloc_complex=True) + + flops_validation_test( + prob, + case_name, + input_keys=[ + Aircraft.Propulsion.ENGINE_OIL_MASS_SCALER, + Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, + ], + output_keys=[Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS], + version=Version.TRANSPORT, # TODO: Version.BWB + tol=4.0e-3, + ) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_engine_pod.py b/aviary/subsystems/mass/flops_based/test/test_engine_pod.py index cee855047..ba4926ae7 100644 --- a/aviary/subsystems/mass/flops_based/test/test_engine_pod.py +++ b/aviary/subsystems/mass/flops_based/test/test_engine_pod.py @@ -3,11 +3,13 @@ import numpy as np import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal +from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized from aviary.subsystems.mass.flops_based.engine_pod import EnginePodMass from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import ( + Version, flops_validation_test, get_flops_case_names, get_flops_inputs, @@ -16,6 +18,7 @@ from aviary.variable_info.variables import Aircraft +@use_tempdirs class EnginePodMassTest(unittest.TestCase): """Tests the engine pod mass needed for the detailed wing calculation.""" @@ -24,7 +27,9 @@ def setUp(self): # Only cases that use detailed wing weight. @parameterized.expand( - get_flops_case_names(omit=['LargeSingleAisle2FLOPS', 'LargeSingleAisle2FLOPSalt']), + get_flops_case_names( + omit=['LargeSingleAisle2FLOPS', 'LargeSingleAisle2FLOPSalt', 'BWB1aFLOPS'] + ), name_func=print_case, ) def test_case(self, case_name): @@ -100,8 +105,53 @@ def test_IO(self): assert_match_varnames(self.prob.model) +class BWBEnginePodMassTest(unittest.TestCase): + """Tests the engine pod mass needed for the detailed wing calculation.""" + + def setUp(self): + self.prob = om.Problem() + + def test_case(self): + case_name = 'BWB1aFLOPS' + prob = self.prob + + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.Engine.NUM_ENGINES: inputs.get_val(Aircraft.Engine.NUM_ENGINES), + } + + prob.model.add_subsystem( + 'engine_pod', EnginePodMass(), promotes_outputs=['*'], promotes_inputs=['*'] + ) + + prob.model_options['*'] = options + + prob.setup(check=False, force_alloc_complex=True) + + # Tol not that tight, but it is unclear where the pod mass values in files come from, + # since they aren't printed in the FLOPS output. + flops_validation_test( + prob, + case_name, + input_keys=[ + Aircraft.Electrical.MASS, + Aircraft.Fuel.FUEL_SYSTEM_MASS, + Aircraft.Hydraulics.MASS, + Aircraft.Instruments.MASS, + Aircraft.Nacelle.MASS, + Aircraft.Propulsion.TOTAL_ENGINE_CONTROLS_MASS, + Aircraft.Engine.MASS, + Aircraft.Propulsion.TOTAL_STARTER_MASS, + Aircraft.Engine.THRUST_REVERSERS_MASS, + Aircraft.Engine.SCALED_SLS_THRUST, + Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, + ], + output_keys=Aircraft.Engine.POD_MASS, + version=Version.BWB, # TODO: Version.BWB, + tol=3e-3, + ) + + if __name__ == '__main__': unittest.main() - # test = EnginePodMassTest() - # test.setUp() - # test.test_case_multiengine() diff --git a/aviary/subsystems/mass/flops_based/test/test_fuel_capacity.py b/aviary/subsystems/mass/flops_based/test/test_fuel_capacity.py index a0a6db7b5..fc05f857f 100644 --- a/aviary/subsystems/mass/flops_based/test/test_fuel_capacity.py +++ b/aviary/subsystems/mass/flops_based/test/test_fuel_capacity.py @@ -1,6 +1,7 @@ import unittest import openmdao.api as om +from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from parameterized import parameterized from aviary.subsystems.mass.flops_based.fuel_capacity import ( diff --git a/aviary/subsystems/mass/flops_based/test/test_fuel_system.py b/aviary/subsystems/mass/flops_based/test/test_fuel_system.py index f4d7f2a30..68aa0473f 100644 --- a/aviary/subsystems/mass/flops_based/test/test_fuel_system.py +++ b/aviary/subsystems/mass/flops_based/test/test_fuel_system.py @@ -2,6 +2,7 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials +from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized from aviary.subsystems.mass.flops_based.fuel_system import ( @@ -19,6 +20,7 @@ from aviary.variable_info.variables import Aircraft, Mission +@use_tempdirs class AltFuelSystemTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() @@ -89,11 +91,12 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +@use_tempdirs class TransportFuelSystemTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -166,5 +169,41 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +class BWBTransportFuelSystemTest(unittest.TestCase): + def setUp(self): + self.prob = om.Problem() + + def ttest_case(self): + case_name = 'BWB1aFLOPS' + prob = self.prob + + inputs = get_flops_inputs(case_name, preprocess=True) + + options = { + Aircraft.Propulsion.TOTAL_NUM_ENGINES: inputs.get_val( + Aircraft.Propulsion.TOTAL_NUM_ENGINES + ), + Mission.Constraints.MAX_MACH: inputs.get_val(Mission.Constraints.MAX_MACH), + } + + prob.model.add_subsystem( + 'bwb_transport_fuel_sys_test', + TransportFuelSystemMass(**options), + promotes_outputs=['*'], + promotes_inputs=['*'], + ) + + prob.setup(check=False, force_alloc_complex=True) + + flops_validation_test( + prob, + case_name, + input_keys=[Aircraft.Fuel.FUEL_SYSTEM_MASS_SCALER, Aircraft.Fuel.TOTAL_CAPACITY], + output_keys=Aircraft.Fuel.FUEL_SYSTEM_MASS, + version=Version.BWB, # TODO: Version.BWB + tol=8.0e-4, + ) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_furnishings.py b/aviary/subsystems/mass/flops_based/test/test_furnishings.py index e2875aa11..290a0fe46 100644 --- a/aviary/subsystems/mass/flops_based/test/test_furnishings.py +++ b/aviary/subsystems/mass/flops_based/test/test_furnishings.py @@ -28,7 +28,7 @@ class TransportFurnishingsGroupMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob diff --git a/aviary/subsystems/mass/flops_based/test/test_fuselage.py b/aviary/subsystems/mass/flops_based/test/test_fuselage.py index 25595ccd2..a15dcdd1b 100644 --- a/aviary/subsystems/mass/flops_based/test/test_fuselage.py +++ b/aviary/subsystems/mass/flops_based/test/test_fuselage.py @@ -1,10 +1,16 @@ import unittest import openmdao.api as om -from openmdao.utils.assert_utils import assert_check_partials +from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from parameterized import parameterized -from aviary.subsystems.mass.flops_based.fuselage import AltFuselageMass, TransportFuselageMass +from aviary.subsystems.mass.flops_based.fuselage import ( + AltFuselageMass, + BWBAftBodyMass, + BWBFuselageMass, + TransportFuselageMass, +) +from aviary.utils.aviary_values import AviaryValues from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import ( Version, @@ -13,14 +19,15 @@ get_flops_options, print_case, ) -from aviary.variable_info.variables import Aircraft +from aviary.variable_info.functions import setup_model_options +from aviary.variable_info.variables import Aircraft, Mission class FuselageMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -148,5 +155,76 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +class BWBFuselageMassTest(unittest.TestCase): + """Test BWB fuselage mass""" + + def setUp(self): + self.prob = om.Problem() + + def test_case1(self): + prob = self.prob + + prob.model.add_subsystem( + 'fuselage', + BWBFuselageMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model.set_input_defaults(Mission.Design.GROSS_MASS, val=874099, units='lbm') + prob.model.set_input_defaults(Aircraft.Fuselage.CABIN_AREA, val=5173.187, units='ft**2') + + self.prob.setup(check=False, force_alloc_complex=True) + + prob.run_model() + + tol = 1e-8 + assert_near_equal(self.prob[Aircraft.Fuselage.MASS], 152790.65666018, tol) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data, atol=1e-10, rtol=1e-10) + + +class BWBAftBodyMassTest(unittest.TestCase): + """Test BWB aft body mass""" + + def setUp(self): + self.prob = om.Problem() + + def test_case1(self): + aviary_options = AviaryValues() + aviary_options.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, 3, units='unitless') + prob = self.prob + + prob.model.add_subsystem( + 'aftbody', + BWBAftBodyMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model.set_input_defaults(Mission.Design.GROSS_MASS, val=874099, units='lbm') + prob.model.set_input_defaults(Aircraft.Fuselage.PLANFORM_AREA, val=7390.267, units='ft**2') + prob.model.set_input_defaults(Aircraft.Fuselage.CABIN_AREA, val=5173.187, units='ft**2') + prob.model.set_input_defaults(Aircraft.Fuselage.LENGTH, val=137.5, units='ft') + prob.model.set_input_defaults(Aircraft.Wing.ROOT_CHORD, val=63.96, units='ft') + prob.model.set_input_defaults(Aircraft.Wing.COMPOSITE_FRACTION, 1.0, units='unitless') + + setup_model_options(self.prob, aviary_options) + self.prob.setup(check=False, force_alloc_complex=True) + + prob.run_model() + + tol = 1e-8 + assert_near_equal(self.prob[Aircraft.Fuselage.AFTBODY_MASS], 24278.05868511, tol) + assert_near_equal(self.prob[Aircraft.Wing.BWB_AFTBODY_MASS], 20150.78870864, tol) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data, atol=1e-10, rtol=1e-10) + + if __name__ == '__main__': - unittest.main() + # unittest.main() + test = BWBAftBodyMassTest() + test.setUp() + test.test_case1() diff --git a/aviary/subsystems/mass/flops_based/test/test_horizontail_tail.py b/aviary/subsystems/mass/flops_based/test/test_horizontail_tail.py index 13eed0339..945d77cc3 100644 --- a/aviary/subsystems/mass/flops_based/test/test_horizontail_tail.py +++ b/aviary/subsystems/mass/flops_based/test/test_horizontail_tail.py @@ -22,7 +22,7 @@ class ExplicitHorizontalTailMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob diff --git a/aviary/subsystems/mass/flops_based/test/test_hydraulics.py b/aviary/subsystems/mass/flops_based/test/test_hydraulics.py index 465f1cfe4..0d09e378b 100644 --- a/aviary/subsystems/mass/flops_based/test/test_hydraulics.py +++ b/aviary/subsystems/mass/flops_based/test/test_hydraulics.py @@ -25,7 +25,7 @@ class TransportHydraulicsGroupMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob diff --git a/aviary/subsystems/mass/flops_based/test/test_instruments.py b/aviary/subsystems/mass/flops_based/test/test_instruments.py index 8e5237cb4..e7500040a 100644 --- a/aviary/subsystems/mass/flops_based/test/test_instruments.py +++ b/aviary/subsystems/mass/flops_based/test/test_instruments.py @@ -19,7 +19,7 @@ class TransportInstrumentsMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob diff --git a/aviary/subsystems/mass/flops_based/test/test_landing_gear.py b/aviary/subsystems/mass/flops_based/test/test_landing_gear.py index 2cc50e4d3..b310d0ddc 100644 --- a/aviary/subsystems/mass/flops_based/test/test_landing_gear.py +++ b/aviary/subsystems/mass/flops_based/test/test_landing_gear.py @@ -25,7 +25,7 @@ class LandingGearMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob diff --git a/aviary/subsystems/mass/flops_based/test/test_landing_mass.py b/aviary/subsystems/mass/flops_based/test/test_landing_mass.py index ca46bdad3..6e74220aa 100644 --- a/aviary/subsystems/mass/flops_based/test/test_landing_mass.py +++ b/aviary/subsystems/mass/flops_based/test/test_landing_mass.py @@ -17,7 +17,9 @@ class LandingMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(omit='LargeSingleAisle1FLOPS'), name_func=print_case) + @parameterized.expand( + get_flops_case_names(omit=['LargeSingleAisle1FLOPS', 'BWB1aFLOPS']), name_func=print_case + ) def test_case(self, case_name): prob = self.prob prob.model.add_subsystem('landing_mass', LandingMass(), promotes=['*']) diff --git a/aviary/subsystems/mass/flops_based/test/test_mass_summation.py b/aviary/subsystems/mass/flops_based/test/test_mass_summation.py index cb9859661..046895f70 100644 --- a/aviary/subsystems/mass/flops_based/test/test_mass_summation.py +++ b/aviary/subsystems/mass/flops_based/test/test_mass_summation.py @@ -25,7 +25,7 @@ class TotalSummationTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob diff --git a/aviary/subsystems/mass/flops_based/test/test_misc_engine.py b/aviary/subsystems/mass/flops_based/test/test_misc_engine.py index 88d412fc7..8c6c6e615 100644 --- a/aviary/subsystems/mass/flops_based/test/test_misc_engine.py +++ b/aviary/subsystems/mass/flops_based/test/test_misc_engine.py @@ -24,7 +24,7 @@ class MiscEngineMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob diff --git a/aviary/subsystems/mass/flops_based/test/test_nacelle.py b/aviary/subsystems/mass/flops_based/test/test_nacelle.py index 46aa59375..c5194e11c 100644 --- a/aviary/subsystems/mass/flops_based/test/test_nacelle.py +++ b/aviary/subsystems/mass/flops_based/test/test_nacelle.py @@ -24,7 +24,7 @@ class NacelleMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob diff --git a/aviary/subsystems/mass/flops_based/test/test_paint.py b/aviary/subsystems/mass/flops_based/test/test_paint.py index b0bd8dcf4..c4d054d07 100644 --- a/aviary/subsystems/mass/flops_based/test/test_paint.py +++ b/aviary/subsystems/mass/flops_based/test/test_paint.py @@ -17,7 +17,7 @@ class PaintMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob diff --git a/aviary/subsystems/mass/flops_based/test/test_passenger_service.py b/aviary/subsystems/mass/flops_based/test/test_passenger_service.py index c350fd06c..e122efbd5 100644 --- a/aviary/subsystems/mass/flops_based/test/test_passenger_service.py +++ b/aviary/subsystems/mass/flops_based/test/test_passenger_service.py @@ -23,7 +23,7 @@ class PassengerServiceMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob diff --git a/aviary/subsystems/mass/flops_based/test/test_starter.py b/aviary/subsystems/mass/flops_based/test/test_starter.py index 74e3ee876..0daae11dd 100644 --- a/aviary/subsystems/mass/flops_based/test/test_starter.py +++ b/aviary/subsystems/mass/flops_based/test/test_starter.py @@ -20,7 +20,9 @@ class TransportStarterMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(omit='AdvancedSingleAisle'), name_func=print_case) + @parameterized.expand( + get_flops_case_names(omit=['AdvancedSingleAisle', 'BWB1aFLOPS']), name_func=print_case + ) def test_case_1(self, case_name): prob = self.prob diff --git a/aviary/subsystems/mass/flops_based/test/test_surface_controls.py b/aviary/subsystems/mass/flops_based/test/test_surface_controls.py index 98948493f..7f6b4a062 100644 --- a/aviary/subsystems/mass/flops_based/test/test_surface_controls.py +++ b/aviary/subsystems/mass/flops_based/test/test_surface_controls.py @@ -1,13 +1,14 @@ import unittest import openmdao.api as om -from openmdao.utils.assert_utils import assert_check_partials +from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from parameterized import parameterized from aviary.subsystems.mass.flops_based.surface_controls import ( AltSurfaceControlMass, SurfaceControlMass, ) +from aviary.utils.aviary_values import AviaryValues from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import ( Version, @@ -17,13 +18,15 @@ print_case, ) from aviary.variable_info.variables import Aircraft, Mission +from aviary.variable_info.functions import setup_model_options +from aviary.variable_info.variables import Aircraft, Mission, Settings class SurfaceCtrlMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -144,5 +147,37 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +class BWBSurfaceCtrlMassTest(unittest.TestCase): + def setUp(self): + aviary_options = AviaryValues() + aviary_options.set_val(Settings.VERBOSITY, 1, units='unitless') + aviary_options.set_val(Mission.Constraints.MAX_MACH, val=0.85, units='unitless') + prob = self.prob = om.Problem() + prob.model.add_subsystem('surf_ctrl', SurfaceControlMass(), promotes=['*']) + + prob.model.set_input_defaults(Mission.Design.GROSS_MASS, 874099, units='lbm') + prob.model.set_input_defaults( + Aircraft.Wing.SURFACE_CONTROL_MASS_SCALER, 1.0, units='unitless' + ) + prob.model.set_input_defaults( + Aircraft.Wing.CONTROL_SURFACE_AREA_RATIO, 0.333, units='unitless' + ) + prob.model.set_input_defaults(Aircraft.Wing.AREA, 16555.972297926455, units='ft**2') + + setup_model_options(self.prob, aviary_options) + prob.setup(check=False, force_alloc_complex=True) + + def test_case(self): + prob = self.prob + prob.run_model() + + tol = 1e-9 + assert_near_equal(prob[Aircraft.Wing.SURFACE_CONTROL_MASS], 14152.3734702, tol) + assert_near_equal(prob[Aircraft.Wing.CONTROL_SURFACE_AREA], 5513.13877521, tol) + + partial_data = prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_thrust_reverser.py b/aviary/subsystems/mass/flops_based/test/test_thrust_reverser.py index 67be045a7..a61bda352 100644 --- a/aviary/subsystems/mass/flops_based/test/test_thrust_reverser.py +++ b/aviary/subsystems/mass/flops_based/test/test_thrust_reverser.py @@ -24,7 +24,7 @@ def setUp(self): self.prob = om.Problem() @parameterized.expand( - get_flops_case_names(omit=['LargeSingleAisle1FLOPS', 'AdvancedSingleAisle']), + get_flops_case_names(omit=['LargeSingleAisle1FLOPS', 'AdvancedSingleAisle', 'BWB1aFLOPS']), name_func=print_case, ) def test_case(self, case_name): diff --git a/aviary/subsystems/mass/flops_based/test/test_unusable_fuel.py b/aviary/subsystems/mass/flops_based/test/test_unusable_fuel.py index 9727e20f1..d3663b08d 100644 --- a/aviary/subsystems/mass/flops_based/test/test_unusable_fuel.py +++ b/aviary/subsystems/mass/flops_based/test/test_unusable_fuel.py @@ -25,7 +25,7 @@ class TransportUnusableFuelMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob diff --git a/aviary/subsystems/mass/flops_based/test/test_vertical_tail.py b/aviary/subsystems/mass/flops_based/test/test_vertical_tail.py index 07d29bf3c..e49e0819a 100644 --- a/aviary/subsystems/mass/flops_based/test/test_vertical_tail.py +++ b/aviary/subsystems/mass/flops_based/test/test_vertical_tail.py @@ -20,7 +20,7 @@ class VerticalTailMassTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob diff --git a/aviary/subsystems/mass/flops_based/test/test_wing_common.py b/aviary/subsystems/mass/flops_based/test/test_wing_common.py index b416113f4..321258781 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_common.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_common.py @@ -2,20 +2,25 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials +from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from parameterized import parameterized from aviary.subsystems.mass.flops_based.wing_common import ( + BWBWingMiscMass, WingBendingMass, WingMiscMass, WingShearControlMass, ) + +from aviary.variable_info.functions import setup_model_options +from aviary.utils.aviary_values import AviaryValues from aviary.utils.test_utils.variable_test import assert_match_varnames from aviary.validation_cases.validation_tests import ( flops_validation_test, get_flops_case_names, print_case, ) -from aviary.variable_info.variables import Aircraft, Mission +from aviary.variable_info.variables import Aircraft, Mission, Settings class WingShearControlMassTest(unittest.TestCase): @@ -30,7 +35,7 @@ def setUp(self): prob.setup(check=False, force_alloc_complex=True) - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -94,7 +99,7 @@ def setUp(self): prob.setup(check=False, force_alloc_complex=True) - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -161,7 +166,7 @@ def setUp(self): prob.setup(check=False, force_alloc_complex=True) - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -233,5 +238,120 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) +class BWBWingMiscMassTest(unittest.TestCase): + def setUp(self): + aviary_options = AviaryValues() + aviary_options.set_val(Settings.VERBOSITY, 1, units='unitless') + aviary_options.set_val(Aircraft.Design.TYPE, val='BWB', units='unitless') + prob = self.prob = om.Problem() + prob.model.add_subsystem( + 'wing_misc', + BWBWingMiscMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model.set_input_defaults(Aircraft.Wing.COMPOSITE_FRACTION, 1.0, units='unitless') + prob.model.set_input_defaults('calculated_wing_area', 9165.7048657769119, units='ft**2') + prob.model.set_input_defaults(Aircraft.Wing.MISC_MASS_SCALER, 1.0, units='unitless') + + setup_model_options(self.prob, aviary_options) + prob.setup(check=False, force_alloc_complex=True) + + def test_case(self): + prob = self.prob + prob.run_model() + # In FLOPS, W3 = 21498.833077784657 + assert_near_equal(prob[Aircraft.Wing.MISC_MASS], 21498.83307778, 1e-9) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) + + +class BWBShearControlMassTest(unittest.TestCase): + def setUp(self): + aviary_options = AviaryValues() + aviary_options.set_val(Settings.VERBOSITY, 1, units='unitless') + aviary_options.set_val(Aircraft.Design.TYPE, val='BWB', units='unitless') + prob = self.prob = om.Problem() + prob.model.add_subsystem( + 'wing_sc', + WingShearControlMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model.set_input_defaults(Mission.Design.GROSS_MASS, 874099, units='lbm') + prob.model.set_input_defaults(Aircraft.Wing.COMPOSITE_FRACTION, 1.0, units='unitless') + prob.model.set_input_defaults( + Aircraft.Wing.CONTROL_SURFACE_AREA, 5513.13877521, units='ft**2' + ) + prob.model.set_input_defaults( + Aircraft.Wing.SHEAR_CONTROL_MASS_SCALER, 1.0, units='unitless' + ) + + setup_model_options(self.prob, aviary_options) + prob.setup(check=False, force_alloc_complex=True) + + def test_case(self): + prob = self.prob + prob.run_model() + # FLOPS W2 = 38779.214997388881 + assert_near_equal(prob[Aircraft.Wing.SHEAR_CONTROL_MASS], 38779.21499739, 1e-9) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) + + +class BWBWingBendingMassTest(unittest.TestCase): + def setUp(self): + aviary_options = AviaryValues() + aviary_options.set_val(Settings.VERBOSITY, 1, units='unitless') + aviary_options.set_val(Aircraft.Fuselage.NUM_FUSELAGES, val=1, units='unitless') + prob = self.prob = om.Problem() + prob.model.add_subsystem( + 'wing_bending', + WingBendingMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model.set_input_defaults(Mission.Design.GROSS_MASS, 874099, units='lbm') + prob.model.set_input_defaults(Aircraft.Wing.COMPOSITE_FRACTION, 1.0, units='unitless') + prob.model.set_input_defaults( + Aircraft.Wing.SHEAR_CONTROL_MASS_SCALER, 1.0, units='unitless' + ) + prob.model.set_input_defaults( + Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, 0.0, units='unitless' + ) + prob.model.set_input_defaults( + Aircraft.Wing.BENDING_MATERIAL_FACTOR, 2.68745091, units='unitless' + ) + prob.model.set_input_defaults( + Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER, 1.0, units='unitless' + ) + prob.model.set_input_defaults(Aircraft.Wing.ENG_POD_INERTIA_FACTOR, 1.0, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.LOAD_FRACTION, 0.5311, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.MISC_MASS, 21498.83307778, units='lbm') + prob.model.set_input_defaults(Aircraft.Wing.MISC_MASS_SCALER, 1.0, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.SHEAR_CONTROL_MASS, 38779.2149974, units='lbm') + prob.model.set_input_defaults(Aircraft.Wing.SPAN, 238.080049, units='ft') + prob.model.set_input_defaults(Aircraft.Wing.SWEEP, 35.7, units='deg') + prob.model.set_input_defaults(Aircraft.Wing.ULTIMATE_LOAD_FACTOR, 3.75, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.VAR_SWEEP_MASS_PENALTY, 0.0, units='unitless') + + setup_model_options(self.prob, aviary_options) + prob.setup(check=False, force_alloc_complex=True) + + def test_case(self): + prob = self.prob + prob.run_model() + tol = 1e-9 + assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_MASS], 6313.44762977, tol) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) + + if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py index 681b10ae1..0e50951e7 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py @@ -5,7 +5,10 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from parameterized import parameterized -from aviary.subsystems.mass.flops_based.wing_detailed import DetailedWingBendingFact +from aviary.subsystems.mass.flops_based.wing_detailed import ( + BWBDetailedWingBendingFact, + DetailedWingBendingFact, +) from aviary.subsystems.propulsion.engine_deck import EngineDeck from aviary.utils.aviary_values import AviaryValues from aviary.utils.preprocessors import preprocess_propulsion @@ -16,6 +19,7 @@ get_flops_inputs, print_case, ) +from aviary.variable_info.functions import setup_model_options from aviary.variable_info.variables import Aircraft, Mission, Settings @@ -25,7 +29,9 @@ def setUp(self): # Skip model that doesn't use detailed wing. @parameterized.expand( - get_flops_case_names(omit=['LargeSingleAisle2FLOPS', 'LargeSingleAisle2FLOPSalt']), + get_flops_case_names( + omit=['LargeSingleAisle2FLOPS', 'LargeSingleAisle2FLOPSalt', 'BWB1aFLOPS'] + ), name_func=print_case, ) def test_case(self, case_name): @@ -413,9 +419,193 @@ def test_IO(self): assert_match_varnames(self.prob.model) +class BWBDetailedWingBendingTest1(unittest.TestCase): + """The BWB detailed wing bending material factor when detailed wing data is not provided.""" + + def setUp(self): + self.prob = om.Problem() + + def test_case1(self): + prob = self.prob + + aviary_options = AviaryValues() + aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, [3], units='unitless') + aviary_options.set_val(Aircraft.Engine.NUM_WING_ENGINES, [0], units='unitless') + aviary_options.set_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, 0, units='unitless') + aviary_options.set_val( + Aircraft.Wing.INPUT_STATION_DIST, [0.0, 32.29, 1.0], units='unitless' + ) + aviary_options.set_val(Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL, 2.0, units='unitless') + aviary_options.set_val(Aircraft.Wing.NUM_INTEGRATION_STATIONS, 50, units='unitless') + + prob.model.add_subsystem( + 'fuselage', + BWBDetailedWingBendingFact(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model.set_input_defaults(Mission.Design.GROSS_MASS, val=874099, units='lbm') + prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO, 3.4488821, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO_REF, 3.4488821, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.STRUT_BRACING_FACTOR, 0.0, units='unitless') + prob.model.set_input_defaults( + Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, 0.0, units='unitless' + ) + prob.model.set_input_defaults(Aircraft.Wing.THICKNESS_TO_CHORD, 0.11, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.THICKNESS_TO_CHORD_REF, 0.11, units='unitless') + + setup_model_options(self.prob, aviary_options) + prob.setup(check=False, force_alloc_complex=True) + + prob.set_val(Aircraft.Engine.POD_MASS, np.array([0]), units='lbm') + prob.set_val(Aircraft.Wing.SPAN, val=238.080049) + + wing_location = np.zeros(0) + wing_location = np.append(wing_location, [0.0]) + prob.set_val(Aircraft.Engine.WING_LOCATIONS, wing_location) + + prob.set_val('BWB_CHORD_PER_SEMISPAN_DIST', [137.5, 91.3717, 14.2848], units='unitless') + prob.set_val('BWB_THICKNESS_TO_CHORD_DIST', [0.11, 0.11, 0.11], units='unitless') + prob.set_val('BWB_LOAD_PATH_SWEEP_DIST', [0.0, 15.337244816, 15.337244816], units='deg') + + prob.run_model() + + BENDING_MATERIAL_FACTOR = prob.get_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR) + pod_inertia = prob.get_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR) + + BENDING_MATERIAL_FACTOR_expected = 2.68745091 # FLOPS W = 2.6874568870727225 + pod_inertia_expected = 1.0 + assert_near_equal(BENDING_MATERIAL_FACTOR, BENDING_MATERIAL_FACTOR_expected, tolerance=1e-9) + assert_near_equal(prob.get_val('calculated_wing_area'), 9165.70396358, tolerance=1e-9) + # current BWB data set does not check the following + assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) + + +class BWBDetailedWingBendingTest2(unittest.TestCase): + """The BWB detailed wing bending material factor when detailed wing data is provided.""" + + def setUp(self): + self.prob = om.Problem() + + def test_case1(self): + prob = self.prob + + aviary_options = AviaryValues() + aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, [3], units='unitless') + aviary_options.set_val(Aircraft.Engine.NUM_WING_ENGINES, [0], units='unitless') + aviary_options.set_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, 0, units='unitless') + aviary_options.set_val( + Aircraft.Wing.INPUT_STATION_DIST, + [ + 0, + 40.110378036763386, + 0.58970640947549269, + 0.62389754201920156, + 0.65808867456291043, + 0.6922798071066194, + 0.72647093965032838, + 0.76059368992894993, + 0.79485320473774623, + 0.82904433728145521, + 0.86323546982516419, + 0.89742660236887306, + 0.93154935264749461, + 0.96580886745629091, + 0.99999999999999989, + ], + units='unitless', + ) + aviary_options.set_val(Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL, 2.0, units='unitless') + aviary_options.set_val(Aircraft.Wing.NUM_INTEGRATION_STATIONS, 100, units='unitless') + + prob.model.add_subsystem( + 'fuselage', + BWBDetailedWingBendingFact(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model.set_input_defaults(Mission.Design.GROSS_MASS, val=874099, units='lbm') + prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO, 3.4488821, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO_REF, 3.4488821, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.STRUT_BRACING_FACTOR, 0.0, units='unitless') + prob.model.set_input_defaults( + Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, 0.0, units='unitless' + ) + prob.model.set_input_defaults(Aircraft.Wing.THICKNESS_TO_CHORD, 0.11, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.THICKNESS_TO_CHORD_REF, 0.11, units='unitless') + + setup_model_options(self.prob, aviary_options) + prob.setup(check=False, force_alloc_complex=True) + + prob.set_val(Aircraft.Engine.POD_MASS, np.array([0]), units='lbm') + prob.set_val(Aircraft.Wing.SPAN, val=253.72075607352679) + + wing_location = np.zeros(0) + wing_location = np.append(wing_location, [0.0]) + prob.set_val(Aircraft.Engine.WING_LOCATIONS, wing_location) + + prob.set_val( + 'BWB_CHORD_PER_SEMISPAN_DIST', + [ + 112.3001936860821, + 55, + 0.30710475250759373, + 0.26559671759953107, + 0.22682397329496512, + 0.19735121704228803, + 0.17348580652677914, + 0.15515935948335116, + 0.14503878425041333, + 0.13560203166834967, + 0.12602851455611114, + 0.11652337970896007, + 0.10701824486180898, + 0.0975131100146579, + 0.088007975167506816, + ], + units='unitless', + ) + prob.set_val( + 'BWB_THICKNESS_TO_CHORD_DIST', + [ + 0.11, + 0.11, + 0.1132, + 0.0928, + 0.0822, + 0.0764, + 0.0742, + 0.0746, + 0.0758, + 0.0758, + 0.0756, + 0.0756, + 0.0758, + 0.076, + 0.076, + ], + units='unitless', + ) + prob.set_val( + 'BWB_LOAD_PATH_SWEEP_DIST', + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 42.9, 42.9, 42.9, 42.9, 42.9, 42.9, 42.9], + units='deg', + ) + + prob.run_model() + + BENDING_MATERIAL_FACTOR = prob.get_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR) + pod_inertia = prob.get_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR) + + BENDING_MATERIAL_FACTOR_expected = 3.93931503 # FLOPS W=3.9724796254619563 + pod_inertia_expected = 1.0 + assert_near_equal(BENDING_MATERIAL_FACTOR, BENDING_MATERIAL_FACTOR_expected, tolerance=1e-9) + assert_near_equal(prob.get_val('calculated_wing_area'), 5399.4057051, tolerance=1e-9) + # current BWB data set does not check the following + assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) + + if __name__ == '__main__': unittest.main() - # test = DetailedWingBendingTest() - # test.setUp() - # test.test_case(case_name='LargeSingleAisle1FLOPS') - # test.test_case_multiengine() diff --git a/aviary/subsystems/mass/flops_based/test/test_wing_group.py b/aviary/subsystems/mass/flops_based/test/test_wing_group.py new file mode 100644 index 000000000..3bd9acd3b --- /dev/null +++ b/aviary/subsystems/mass/flops_based/test/test_wing_group.py @@ -0,0 +1,121 @@ +import unittest + +import openmdao.api as om +from openmdao.utils.assert_utils import assert_near_equal +from aviary.subsystems.mass.flops_based.wing_group import WingMassGroup +from aviary.utils.aviary_values import AviaryValues +from aviary.variable_info.functions import setup_model_options +from aviary.variable_info.variables import Aircraft, Mission, Settings + + +class BWBWingGroupTest(unittest.TestCase): + def setUp(self): + aviary_options = AviaryValues() + aviary_options.set_val(Settings.VERBOSITY, 1, units='unitless') + aviary_options.set_val(Aircraft.Design.TYPE, val='BWB', units='unitless') + aviary_options.set_val(Aircraft.Wing.DETAILED_WING, val=True, units='unitless') + aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, [3], units='unitless') + aviary_options.set_val(Aircraft.Engine.NUM_WING_ENGINES, [0], units='unitless') + aviary_options.set_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, 0, units='unitless') + aviary_options.set_val( + Aircraft.Wing.INPUT_STATION_DIST, [0.0, 32.29, 1.0], units='unitless' + ) + aviary_options.set_val(Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL, 2.0, units='unitless') + aviary_options.set_val(Aircraft.Wing.NUM_INTEGRATION_STATIONS, 50, units='unitless') + aviary_options.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, 3, units='unitless') + + prob = self.prob = om.Problem() + self.prob.model.add_subsystem( + 'wing_group', + WingMassGroup(), + promotes_inputs=['*'], + promotes_outputs=['aircraft:*'], + ) + + # EnginePodMass + prob.model.set_input_defaults(Mission.Design.GROSS_MASS, 874099, units='lbm') + prob.model.set_input_defaults(Aircraft.Electrical.MASS, 0, units='lbm') + prob.model.set_input_defaults(Aircraft.Fuel.FUEL_SYSTEM_MASS, 0, units='lbm') + prob.model.set_input_defaults(Aircraft.Hydraulics.MASS, 0, units='lbm') + prob.model.set_input_defaults(Aircraft.Instruments.MASS, 0, units='lbm') + prob.model.set_input_defaults(Aircraft.Nacelle.MASS, [0], units='lbm') + prob.model.set_input_defaults( + Aircraft.Propulsion.TOTAL_ENGINE_CONTROLS_MASS, 0, units='lbm' + ) + prob.model.set_input_defaults(Aircraft.Engine.MASS, [0], units='lbm') + prob.model.set_input_defaults(Aircraft.Propulsion.TOTAL_STARTER_MASS, 0, units='lbm') + prob.model.set_input_defaults(Aircraft.Engine.THRUST_REVERSERS_MASS, 0, units='lbm') + prob.model.set_input_defaults(Aircraft.Engine.SCALED_SLS_THRUST, [70000], units='lbf') + prob.model.set_input_defaults( + Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, 1900000.0, units='lbf' + ) + # BWBDetailedWingBendingFact + prob.model.set_input_defaults( + 'BWB_LOAD_PATH_SWEEP_DIST', [0.0, 15.337244816, 15.337244816], units='deg' + ) + prob.model.set_input_defaults( + 'BWB_THICKNESS_TO_CHORD_DIST', [0.11, 0.11, 0.11], units='unitless' + ) + prob.model.set_input_defaults( + 'BWB_CHORD_PER_SEMISPAN_DIST', [137.5, 91.3717, 14.2848], units='unitless' + ) + prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO, 3.4488821, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO_REF, 3.4488821, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.STRUT_BRACING_FACTOR, 0.0, units='unitless') + prob.model.set_input_defaults( + Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, 0.0, units='unitless' + ) + prob.model.set_input_defaults(Aircraft.Wing.THICKNESS_TO_CHORD, 0.11, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.THICKNESS_TO_CHORD_REF, 0.11, units='unitless') + # WingMiscMass + prob.model.set_input_defaults(Aircraft.Wing.COMPOSITE_FRACTION, 1.0, units='unitless') + # prob.model.set_input_defaults(Aircraft.Wing.AREA, 16555.972297926455, units='ft**2') + prob.model.set_input_defaults(Aircraft.Wing.MISC_MASS_SCALER, 1.0, units='unitless') + # WingShearControlMass + prob.model.set_input_defaults( + Aircraft.Wing.CONTROL_SURFACE_AREA, 5513.13877521, units='ft**2' + ) + prob.model.set_input_defaults( + Aircraft.Wing.SHEAR_CONTROL_MASS_SCALER, 1.0, units='unitless' + ) + # WingBendingMass + prob.model.set_input_defaults( + Aircraft.Wing.BENDING_MATERIAL_MASS_SCALER, 1.0, units='unitless' + ) + prob.model.set_input_defaults(Aircraft.Wing.ENG_POD_INERTIA_FACTOR, 1.0, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.LOAD_FRACTION, 0.5311, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.SPAN, 238.080049, units='ft') + prob.model.set_input_defaults(Aircraft.Wing.SWEEP, 35.7, units='deg') + prob.model.set_input_defaults(Aircraft.Wing.ULTIMATE_LOAD_FACTOR, 3.75, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.VAR_SWEEP_MASS_PENALTY, 0.0, units='unitless') + # WingBendingMass + # BWBAftBodyMass + prob.model.set_input_defaults(Aircraft.Fuselage.PLANFORM_AREA, val=7390.267, units='ft**2') + prob.model.set_input_defaults(Aircraft.Fuselage.CABIN_AREA, val=5173.187, units='ft**2') + prob.model.set_input_defaults(Aircraft.Fuselage.LENGTH, val=137.5, units='ft') + prob.model.set_input_defaults(Aircraft.Wing.ROOT_CHORD, val=63.96, units='ft') + prob.model.set_input_defaults('Rear_spar_percent_chord', 0.7, units='unitless') + prob.model.set_input_defaults('Rear_spar_percent_chord_centerline', 0.7, units='unitless') + + setup_model_options(self.prob, aviary_options) + prob.setup(check=False, force_alloc_complex=True) + + def test_case1(self): + prob = self.prob + prob.run_model() + tol = 1e-9 + assert_near_equal(prob[Aircraft.Engine.POD_MASS], 0.0, tol) + assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_FACTOR], 2.68745091, tol) + assert_near_equal(prob[Aircraft.Wing.MISC_MASS], 21498.82990355, tol) + assert_near_equal(prob[Aircraft.Wing.SHEAR_CONTROL_MASS], 38779.21499739, tol) + assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_MASS], 6313.4476585, tol) + assert_near_equal(prob[Aircraft.Fuselage.AFTBODY_MASS], 24278.05868511, tol) + assert_near_equal(prob[Aircraft.Wing.BWB_AFTBODY_MASS], 20150.78870864, tol) + assert_near_equal(prob[Aircraft.Wing.MASS], 86742.28126808, tol) + + +if __name__ == '__main__': + # unittest.main() + test = BWBWingGroupTest() + test.setUp() + test.test_case1() diff --git a/aviary/subsystems/mass/flops_based/wing_common.py b/aviary/subsystems/mass/flops_based/wing_common.py index 0850db114..6591d5c84 100644 --- a/aviary/subsystems/mass/flops_based/wing_common.py +++ b/aviary/subsystems/mass/flops_based/wing_common.py @@ -2,8 +2,9 @@ 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.variable_info.variables import Aircraft, Mission, Settings class WingBendingMass(om.ExplicitComponent): @@ -25,7 +26,7 @@ def setup(self): add_aviary_input(self, Aircraft.Wing.LOAD_FRACTION, units='unitless') add_aviary_input(self, Aircraft.Wing.MISC_MASS, units='lbm') add_aviary_input(self, Aircraft.Wing.MISC_MASS_SCALER, units='unitless') - add_aviary_input(self, Aircraft.Wing.SHEAR_CONTROL_MASS) + add_aviary_input(self, Aircraft.Wing.SHEAR_CONTROL_MASS, units='lbm') add_aviary_input(self, Aircraft.Wing.SHEAR_CONTROL_MASS_SCALER, units='unitless') add_aviary_input(self, Aircraft.Wing.SPAN, units='ft') add_aviary_input(self, Aircraft.Wing.SWEEP, units='deg') @@ -226,14 +227,11 @@ class WingShearControlMass(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aircraft_type', - default='Transport', - values=['Transport', 'HWB', 'GA'], - desc='Aircfaft type: Tranpsport, HWB, or GA', - ) + add_aviary_option(self, Aircraft.Design.TYPE) + add_aviary_option(self, Settings.VERBOSITY) def setup(self): + design_type = self.options[Aircraft.Design.TYPE] add_aviary_input(self, Aircraft.Wing.COMPOSITE_FRACTION, units='unitless') add_aviary_input(self, Aircraft.Wing.CONTROL_SURFACE_AREA, units='ft**2') add_aviary_input(self, Mission.Design.GROSS_MASS, units='lbm') @@ -241,13 +239,11 @@ def setup(self): add_aviary_output(self, Aircraft.Wing.SHEAR_CONTROL_MASS, units='lbm') - if (self.options['aircraft_type'] == 'Transport') or ( - self.options['aircraft_type'] == 'HWB' - ): + if design_type in [AircraftTypes.BLENDED_WING_BODY, AircraftTypes.TRANSPORT]: self.A3 = 0.68 self.A4 = 0.34 self.A5 = 0.60 - elif self.options['aircraft_type'] == 'GA': + elif design_type is AircraftTypes.GENERAL_AVIATION: self.A3 = 0.25 self.A4 = 0.50 self.A5 = 0.50 @@ -311,31 +307,33 @@ class WingMiscMass(om.ExplicitComponent): """ def initialize(self): - self.options.declare( - 'aircraft_type', - default='Transport', - values=['Transport', 'HWB', 'GA'], - desc='Aircfaft type: Tranpsport, HWB, or GA', - ) + add_aviary_option(self, Aircraft.Design.TYPE) + add_aviary_option(self, Settings.VERBOSITY) def setup(self): + design_type = self.options[Aircraft.Design.TYPE] add_aviary_input(self, Aircraft.Wing.COMPOSITE_FRACTION, units='unitless') add_aviary_input(self, Aircraft.Wing.AREA, units='ft**2') add_aviary_input(self, Aircraft.Wing.MISC_MASS_SCALER, units='unitless') add_aviary_output(self, Aircraft.Wing.MISC_MASS, units='lbm') - if (self.options['aircraft_type'] == 'Transport') or ( - self.options['aircraft_type'] == 'HWB' - ): + if design_type is AircraftTypes.TRANSPORT: self.A6 = 0.035 self.A7 = 1.50 - elif self.options['aircraft_type'] == 'GA': + elif design_type is AircraftTypes.GENERAL_AVIATION: self.A6 = 0.16 self.A7 = 1.2 def setup_partials(self): - self.declare_partials('*', '*') + self.declare_partials( + Aircraft.Wing.MISC_MASS, + [ + Aircraft.Wing.COMPOSITE_FRACTION, + Aircraft.Wing.MISC_MASS_SCALER, + Aircraft.Wing.AREA, + ], + ) def compute(self, inputs, outputs): comp_frac = inputs[Aircraft.Wing.COMPOSITE_FRACTION] @@ -367,6 +365,65 @@ def compute_partials(self, inputs, J): ) +class BWBWingMiscMass(om.ExplicitComponent): + """ + Calculates the mass of wing miscellaneous material. The methodology is + based on the FLOPS weight equations, modified to output mass instead of weight. + """ + + def initialize(self): + add_aviary_option(self, Settings.VERBOSITY) + + def setup(self): + add_aviary_input(self, Aircraft.Wing.COMPOSITE_FRACTION, units='unitless') + add_aviary_input(self, Aircraft.Wing.MISC_MASS_SCALER, units='unitless') + self.add_input('calculated_wing_area', units='ft**2') + + add_aviary_output(self, Aircraft.Wing.MISC_MASS, units='lbm') + + self.A6 = 0.035 + self.A7 = 1.50 + + def setup_partials(self): + self.declare_partials( + Aircraft.Wing.MISC_MASS, + [ + Aircraft.Wing.COMPOSITE_FRACTION, + Aircraft.Wing.MISC_MASS_SCALER, + 'calculated_wing_area', + ], + ) + + def compute(self, inputs, outputs): + comp_frac = inputs[Aircraft.Wing.COMPOSITE_FRACTION] + area = inputs['calculated_wing_area'] + scaler = inputs[Aircraft.Wing.MISC_MASS_SCALER] + + outputs[Aircraft.Wing.MISC_MASS] = ( + self.A6 * (1.0 - 0.3 * comp_frac) * area**self.A7 * scaler / GRAV_ENGLISH_LBM + ) + + def compute_partials(self, inputs, J): + comp_frac = inputs[Aircraft.Wing.COMPOSITE_FRACTION] + area = inputs['calculated_wing_area'] + scaler = inputs[Aircraft.Wing.MISC_MASS_SCALER] + + J[Aircraft.Wing.MISC_MASS, Aircraft.Wing.COMPOSITE_FRACTION] = ( + -0.3 * self.A6 * area**self.A7 * scaler / GRAV_ENGLISH_LBM + ) + J[Aircraft.Wing.MISC_MASS, 'calculated_wing_area'] = ( + self.A6 + * (1.0 - 0.3 * comp_frac) + * self.A7 + * area ** (self.A7 - 1) + * scaler + / GRAV_ENGLISH_LBM + ) + J[Aircraft.Wing.MISC_MASS, Aircraft.Wing.MISC_MASS_SCALER] = ( + self.A6 * (1.0 - 0.3 * comp_frac) * area**self.A7 / GRAV_ENGLISH_LBM + ) + + class WingTotalMass(om.ExplicitComponent): """Computation of wing mass using FLOPS-based detailed wing mass equations.""" diff --git a/aviary/subsystems/mass/flops_based/wing_detailed.py b/aviary/subsystems/mass/flops_based/wing_detailed.py index 29e8adec6..b02c7478b 100644 --- a/aviary/subsystems/mass/flops_based/wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/wing_detailed.py @@ -256,3 +256,289 @@ def compute(self, inputs, outputs): inertia_factor_prod = 0.84 outputs[Aircraft.Wing.ENG_POD_INERTIA_FACTOR] = inertia_factor_prod + + +class BWBDetailedWingBendingFact(om.ExplicitComponent): + """ + Computation of wing bending factor and engine inertia relief factor + used for FLOPS-based detailed wing mass estimation for BWB aircraft. + + This is basically the same as DetailedWingBendingFact except the following: + + - Aircraft.Wing.LOAD_PATH_SWEEP_DIST is replaced by BWB_LOAD_PATH_SWEEP_DIST + - Aircraft.Wing.THICKNESS_TO_CHORD_DIST is replaced by BWB_THICKNESS_TO_CHORD_DIST + - Aircraft.Wing.CHORD_PER_SEMISPAN_DIST is replaced by BWB_CHORD_PER_SEMISPAN_DIST + """ + + # Basically, Engine.WING_LOCATIONS is ignored if there are one or fewer wing engines + + def initialize(self): + add_aviary_option(self, Aircraft.Engine.NUM_ENGINES) + add_aviary_option(self, Aircraft.Engine.NUM_WING_ENGINES) + add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) + add_aviary_option(self, Aircraft.Wing.INPUT_STATION_DIST) + add_aviary_option(self, Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL) + add_aviary_option(self, Aircraft.Wing.NUM_INTEGRATION_STATIONS) + + def setup(self): + input_station_dist = self.options[Aircraft.Wing.INPUT_STATION_DIST] + num_input_stations = len(input_station_dist) + total_num_wing_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES] + num_engine_type = len(self.options[Aircraft.Engine.NUM_ENGINES]) + + self.add_input('BWB_LOAD_PATH_SWEEP_DIST', shape=num_input_stations, units='deg') + self.add_input('BWB_THICKNESS_TO_CHORD_DIST', shape=num_input_stations, units='unitless') + self.add_input('BWB_CHORD_PER_SEMISPAN_DIST', shape=num_input_stations, units='unitless') + add_aviary_input(self, Mission.Design.GROSS_MASS, units='lbm') + add_aviary_input(self, Aircraft.Engine.POD_MASS, shape=num_engine_type, units='lbm') + add_aviary_input(self, Aircraft.Wing.ASPECT_RATIO, units='unitless') + add_aviary_input(self, Aircraft.Wing.ASPECT_RATIO_REF, units='unitless') + add_aviary_input(self, Aircraft.Wing.STRUT_BRACING_FACTOR, units='unitless') + add_aviary_input(self, Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, units='unitless') + add_aviary_input(self, Aircraft.Wing.SPAN, units='ft') + + if total_num_wing_engines > 1: + add_aviary_input( + self, + Aircraft.Engine.WING_LOCATIONS, + shape=int(total_num_wing_engines / 2), + units='unitless', + ) + else: + add_aviary_input(self, Aircraft.Engine.WING_LOCATIONS, units='unitless') + + add_aviary_input(self, Aircraft.Wing.THICKNESS_TO_CHORD, units='unitless') + add_aviary_input(self, Aircraft.Wing.THICKNESS_TO_CHORD_REF, units='unitless') + + add_aviary_output(self, Aircraft.Wing.BENDING_MATERIAL_FACTOR, units='unitless') + add_aviary_output(self, Aircraft.Wing.ENG_POD_INERTIA_FACTOR, units='unitless') + self.add_output('calculated_wing_area', units='ft**2') + + def setup_partials(self): + # TODO: Analytic derivs will be challenging, but possible. + self.declare_partials('*', '*', method='cs') + + def compute(self, inputs, outputs): + num_integration_stations = self.options[Aircraft.Wing.NUM_INTEGRATION_STATIONS] + num_wing_engines = self.options[Aircraft.Engine.NUM_WING_ENGINES] + num_engine_type = len(num_wing_engines) + wingspan = inputs[Aircraft.Wing.SPAN][0] + + input_station_dist = self.options[Aircraft.Wing.INPUT_STATION_DIST] + # inp_stations = np.array(input_station_dist) + inp_stations_mod = [] + for x in input_station_dist: + if x > 1.0: + inp_stations_mod.append(2 * x / wingspan) + else: + inp_stations_mod.append(x) + inp_stations_mod = np.array(inp_stations_mod) + # For BWB, always start from inp_stations_mod[1], not inp_stations_mod[0] + inp_stations_mod = inp_stations_mod[1:] + + # TODO: Support all options for this parameter. + # 0.0 : input distribution + # 1.0 : triangular distribution + # 2.0 : elliptical distribution (default) + # 3.0 : rectangular distribution + # 1.0-2.0 : blend of triangular and elliptical + # 2.0-3.0 : blend of elliptical and rectangular + load_distribution_factor = self.options[Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL] + + load_path_sweep = inputs['BWB_LOAD_PATH_SWEEP_DIST'] + load_path_sweep_mod = np.array(load_path_sweep[1:]) + + ar = inputs[Aircraft.Wing.ASPECT_RATIO] + arref = inputs[Aircraft.Wing.ASPECT_RATIO_REF] + chord = inputs['BWB_CHORD_PER_SEMISPAN_DIST'] + chord_mod = [] + for x in chord: + if x > 5.0: + chord_mod.append(2 * x / wingspan) + else: + chord_mod.append(x * arref[0] / ar[0]) + chord_mod = np.array(chord_mod) + + engine_locations = inputs[Aircraft.Engine.WING_LOCATIONS] + gross_mass = inputs[Mission.Design.GROSS_MASS] + # NOTE pod mass assumed the same for wing/non-wing mounted engines, only using + # wing mounted pods here + pod_mass = inputs[Aircraft.Engine.POD_MASS] + fstrt = inputs[Aircraft.Wing.STRUT_BRACING_FACTOR] + faert = inputs[Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR] + + thickness_to_chord = inputs['BWB_THICKNESS_TO_CHORD_DIST'] + tc = inputs[Aircraft.Wing.THICKNESS_TO_CHORD] + tcref = inputs[Aircraft.Wing.THICKNESS_TO_CHORD_REF] + thickness_to_chord_mod = [] + for x in thickness_to_chord: + thickness_to_chord_mod.append(x * tcref[0] / tc[0]) + thickness_to_chord_mod = np.array(thickness_to_chord_mod) + + # NOTE changes to FLOPS routines based on LEAPS1 improved multiengine effort + # odd numbers of wing mounted engines assume the "odd" engine out is not on the + # wing and is ignored + # TODO There are also no checks that number of engine locations is consistent with + # half of number of wing mounted engines, which should get added to preprocessor + + target_dy = (inp_stations_mod[-1] - inp_stations_mod[0]) / num_integration_stations + stations_per_section = np.floor(np.abs(np.diff(inp_stations_mod) / target_dy + 0.5)) + stations_per_section[-1] += 1 # add one more point to the last section + integration_stations = np.empty(0, dtype=chord.dtype) + sweep_int_stations = np.empty(0, dtype=chord.dtype) + + for i, val in enumerate(inp_stations_mod[1:]): + endpoint = i == len(inp_stations_mod) - 2 + per_section = int(stations_per_section[i]) + integration_stations = np.append( + integration_stations, + np.linspace(inp_stations_mod[i], val, per_section, endpoint=endpoint), + ) + sweep_int_stations = np.append( + sweep_int_stations, load_path_sweep_mod[i] * np.ones(per_section) + ) + + dy = np.diff(integration_stations) + avg_sweep = np.sum( + (dy[0:] + 2.0 * integration_stations[0:-1]) * dy[0:] * sweep_int_stations[0:-1] + ) + + # TODO: add all load_distribution_factor options + if load_distribution_factor == 1: + load_intensity = 1.0 - integration_stations + elif load_distribution_factor == 2: + load_intensity = np.sqrt(1.0 - integration_stations**2) + elif load_distribution_factor == 3: + load_intensity = np.ones(num_integration_stations + 1) + else: + raise om.AnalysisError( + f'{load_distribution_factor} is not a valid value for ' + f'{Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL}, it must be "1", "2", or "3".' + ) + + chord_interp = InterpND( + method='slinear', points=(inp_stations_mod), x_interp=integration_stations + ) + chord_int_stations = chord_interp.evaluate_spline(chord_mod[1:], compute_derivative=False) + if arref > 0.0: + # Scale + chord_int_stations *= arref / ar + + del_load = ( + dy + * ( + chord_int_stations[:-1] * (2 * load_intensity[:-1] + load_intensity[1:]) + + chord_int_stations[1:] * (2 * load_intensity[1:] + load_intensity[:-1]) + ) + / 6 + ) + + el = np.sum(del_load) + + del_moment = ( + dy**2 + * ( + chord_int_stations[:-1] * (load_intensity[:-1] + load_intensity[1:]) + + chord_int_stations[1:] * (3 * load_intensity[1:] + load_intensity[:-1]) + ) + / 12 + ) + + load_path_length = np.flip( + np.append(np.zeros(1, chord.dtype), np.cumsum(np.flip(del_load)[:-1])) + ) + csw = 1.0 / np.cos(sweep_int_stations[:-1] * np.pi / 180.0) + emi = (del_moment + dy * load_path_length) * csw + # em = np.sum(emi) + + tc_interp = InterpND( + method='slinear', points=(inp_stations_mod), x_interp=integration_stations + ) + tc_int_stations = tc_interp.evaluate_spline(thickness_to_chord, compute_derivative=False) + if tcref > 0.0: + tc_int_stations *= tc / tcref + + total_moment = np.cumsum(emi[::-1])[::-1] + + bma = total_moment * csw / (chord_int_stations[:-1] * tc_int_stations[:-1]) + + pm = np.sum((bma[:-1] + bma[1:]) * dy[:-1] * 0.5) + + s = np.sum((chord_int_stations[:-1] + chord_int_stations[1:]) * dy * 0.5) + # calculated aspect ratio and calculated wing area + calc_ar = 2.0 / s + calc_area = wingspan**2 / calc_ar + outputs['calculated_wing_area'] = calc_area + + btb = 4 * pm / el + + sa = np.sin(avg_sweep * np.pi / 180.0) + if calc_ar <= 5.0: + caya = 0.0 + else: + caya = calc_ar - 5.0 + + den = calc_ar ** (0.25 * fstrt) * ( + 1.0 + (0.5 * faert - 0.16 * fstrt) * sa**2 + 0.03 * caya * (1.0 - 0.5 * faert) * sa + ) + bt = btb / den + + outputs[Aircraft.Wing.BENDING_MATERIAL_FACTOR] = bt + + if np.sum(num_wing_engines) > 0: + # TODO: the rest is not checked. + inertia_factor = np.zeros(num_engine_type, dtype=chord.dtype) + eel = np.zeros(len(dy) + 1, dtype=chord.dtype) + + # idx is the index where this engine type begins in location list + idx = 0 + # i is the counter for which engine model we are checking + for i in range(num_engine_type): + # idx2 is the last index for the range of engines of this type + idx2 = idx + int(num_wing_engines[i] / 2) + if num_wing_engines[i] > 1: + # engine locations must be in order from wing root to tip + eng_loc = np.sort(engine_locations[idx:idx2]) + + else: + continue + + if eng_loc[0] <= integration_stations[0]: + inertia_factor[i] = 1.0 + + elif eng_loc[0] >= integration_stations[-1]: + inertia_factor[i] = 0.84 + + else: + eel[:] = 0.0 + # Find all points on integration station before first engine + loc = np.where(integration_stations < eng_loc[0])[0] + eel[loc] = 1.0 + + delme = dy * eel[1:] + + delme[loc[-1]] = eng_loc[0] - integration_stations[loc[-1]] + + eem = delme * csw + eem = np.cumsum(eem[::-1])[::-1] + + ea = eem * csw / (chord_int_stations[:-1] * tc_int_stations[:-1]) + + bte = 8 * np.sum((ea[:-1] + ea[1:]) * dy[:-1] * 0.5) + + inertia_factor_i = 1 - bte / bt[0] * pod_mass[i] / gross_mass[0] + # avoid passing an array into specific index of inertia_factor + inertia_factor[i] = inertia_factor_i + + # increment idx to next engine set + idx = idx2 + + # LEAPS updated multiengine routine applies each engine pod's factor + # multiplicatively, and enforces a minimum bound of 0.84 + inertia_factor_prod = np.prod(inertia_factor) + if inertia_factor_prod < 0.84: + inertia_factor_prod = 0.84 + else: + inertia_factor_prod = 1.0 + + outputs[Aircraft.Wing.ENG_POD_INERTIA_FACTOR] = inertia_factor_prod diff --git a/aviary/subsystems/mass/flops_based/wing_group.py b/aviary/subsystems/mass/flops_based/wing_group.py index 12eaa3cc7..e0e5ed286 100644 --- a/aviary/subsystems/mass/flops_based/wing_group.py +++ b/aviary/subsystems/mass/flops_based/wing_group.py @@ -1,14 +1,20 @@ import openmdao.api as om from aviary.subsystems.mass.flops_based.engine_pod import EnginePodMass +from aviary.subsystems.mass.flops_based.fuselage import BWBAftBodyMass from aviary.subsystems.mass.flops_based.wing_common import ( + BWBWingMiscMass, WingBendingMass, WingMiscMass, WingShearControlMass, WingTotalMass, ) -from aviary.subsystems.mass.flops_based.wing_detailed import DetailedWingBendingFact +from aviary.subsystems.mass.flops_based.wing_detailed import ( + BWBDetailedWingBendingFact, + DetailedWingBendingFact, +) from aviary.subsystems.mass.flops_based.wing_simple import SimpleWingBendingFact +from aviary.variable_info.enums import AircraftTypes from aviary.variable_info.functions import add_aviary_option from aviary.variable_info.variables import Aircraft @@ -21,8 +27,11 @@ def initialize(self): # variable_info/functions.py, add_aviary_output() # default to None instead of default value add_aviary_option(self, Aircraft.Wing.DETAILED_WING) + add_aviary_option(self, Aircraft.Design.TYPE) def setup(self): + design_type = self.options[Aircraft.Design.TYPE] + self.add_subsystem( 'engine_pod_mass', EnginePodMass(), @@ -31,12 +40,20 @@ def setup(self): ) if self.options[Aircraft.Wing.DETAILED_WING]: - self.add_subsystem( - 'wing_bending_material_factor', - DetailedWingBendingFact(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) + if design_type == AircraftTypes.BLENDED_WING_BODY: + self.add_subsystem( + 'wing_bending_material_factor', + BWBDetailedWingBendingFact(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + else: + self.add_subsystem( + 'wing_bending_material_factor', + DetailedWingBendingFact(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) else: self.add_subsystem( @@ -46,9 +63,14 @@ def setup(self): promotes_outputs=['*'], ) - self.add_subsystem( - 'wing_misc', WingMiscMass(), promotes_inputs=['*'], promotes_outputs=['*'] - ) + if design_type == AircraftTypes.BLENDED_WING_BODY: + self.add_subsystem( + 'wing_misc', BWBWingMiscMass(), promotes_inputs=['*'], promotes_outputs=['*'] + ) + else: + self.add_subsystem( + 'wing_misc', WingMiscMass(), promotes_inputs=['*'], promotes_outputs=['*'] + ) self.add_subsystem( 'wing_shear_control', @@ -64,6 +86,14 @@ def setup(self): promotes_outputs=['*'], ) + if design_type == AircraftTypes.BLENDED_WING_BODY: + self.add_subsystem( + 'aftbody', + BWBAftBodyMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + self.add_subsystem( 'wing_total', WingTotalMass(), promotes_inputs=['*'], promotes_outputs=['*'] ) diff --git a/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py b/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py index d741cd6a5..46a755d45 100644 --- a/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py +++ b/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py @@ -1448,7 +1448,7 @@ def setup(self): promotes_inputs=['*'], promotes_outputs=['*'], ) - else: + elif design_type is AircraftTypes.TRANSPORT: self.add_subsystem( 'equip', EquipMassGroup(), diff --git a/aviary/subsystems/mass/gasp_based/fuel.py b/aviary/subsystems/mass/gasp_based/fuel.py index 78c6b4868..a9086e9d3 100644 --- a/aviary/subsystems/mass/gasp_based/fuel.py +++ b/aviary/subsystems/mass/gasp_based/fuel.py @@ -1633,7 +1633,7 @@ def setup(self): promotes_inputs=['*'], promotes_outputs=['*'], ) - else: + elif design_type is AircraftTypes.TRANSPORT: self.add_subsystem( 'fuselage', FuselageMass(), diff --git a/aviary/subsystems/mass/gasp_based/mass_premission.py b/aviary/subsystems/mass/gasp_based/mass_premission.py index 71b6fed56..838ee067c 100644 --- a/aviary/subsystems/mass/gasp_based/mass_premission.py +++ b/aviary/subsystems/mass/gasp_based/mass_premission.py @@ -49,7 +49,7 @@ def setup(self): if design_type is AircraftTypes.BLENDED_WING_BODY: fuel_mass_inputs = fuel_mass_fixed_mass_values - else: + 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 @@ -61,7 +61,7 @@ def setup(self): promotes_inputs=['*'], promotes_outputs=['*'], ) - else: + elif design_type is AircraftTypes.TRANSPORT: self.add_subsystem( 'design_load', DesignLoadGroup(), @@ -90,7 +90,7 @@ def setup(self): promotes_inputs=['*'], promotes_outputs=['*'], ) - else: + elif design_type is AircraftTypes.TRANSPORT: self.add_subsystem( 'wing_mass', WingMassGroup(), diff --git a/aviary/subsystems/propulsion/test/test_propulsion_premission.py b/aviary/subsystems/propulsion/test/test_propulsion_premission.py index 51950e9fe..e3a59c674 100644 --- a/aviary/subsystems/propulsion/test/test_propulsion_premission.py +++ b/aviary/subsystems/propulsion/test/test_propulsion_premission.py @@ -108,9 +108,39 @@ def test_propulsion_sum(self): assert_check_partials(partial_data, atol=1e-10, rtol=1e-10) +class BWBPropulsionPreMissionTest(unittest.TestCase): + def setUp(self): + self.prob = om.Problem() + + def ttest_case(self): + """work in progress""" + options = get_flops_inputs('BWB1aFLOPS') + options.set_val(Settings.VERBOSITY, 0) + options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([3])) + + self.prob.model = PropulsionPreMission( + aviary_options=options, engine_models=[build_engine_deck(options)] + ) + + self.prob.model.set_input_defaults(Aircraft.Engine.SCALE_FACTOR, np.ones(1)) + + setup_model_options(self.prob, options) + + self.prob.setup(force_alloc_complex=True) + # self.prob.set_val(Aircraft.Engine.SCALED_SLS_THRUST, options.get_val( + # Aircraft.Engine.SCALED_SLS_THRUST, units='lbf')) + + self.prob.run_model() + + sls_thrust = self.prob.get_val(Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST) + + expected_sls_thrust = np.array([54602.0]) + + assert_near_equal(sls_thrust, expected_sls_thrust, tolerance=1e-10) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data, atol=1e-10, rtol=1e-10) + + if __name__ == '__main__': unittest.main() - # test = PropulsionPreMissionTest() - # test.setUp() - # test.test_multi_engine() - # test.test_case() diff --git a/aviary/subsystems/test/test_flops_based_premission.py b/aviary/subsystems/test/test_flops_based_premission.py index 82e90846d..a8a60ea47 100644 --- a/aviary/subsystems/test/test_flops_based_premission.py +++ b/aviary/subsystems/test/test_flops_based_premission.py @@ -25,7 +25,7 @@ class PreMissionGroupTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) + @parameterized.expand(get_flops_case_names(omit='BWB1aFLOPS'), name_func=print_case) def test_case(self, case_name): flops_inputs = get_flops_inputs(case_name) flops_outputs = get_flops_outputs(case_name) diff --git a/aviary/utils/test/data/converter_test_N3CC_FLOPS.csv b/aviary/utils/test/data/converter_test_N3CC_FLOPS.csv index 865861f53..8e4e2004d 100644 --- a/aviary/utils/test/data/converter_test_N3CC_FLOPS.csv +++ b/aviary/utils/test/data/converter_test_N3CC_FLOPS.csv @@ -116,7 +116,7 @@ aircraft:wing:aspect_ratio,11.5587605382765,1.0,0.0,0.0,0.0,0.0,unitless aircraft:wing:aspect_ratio_reference,11.5587605382765,unitless aircraft:wing:bending_material_mass_scaler,1.0,unitless aircraft:wing:bwb_aft_body_mass_scaler,1.0,unitless -aircraft:wing:chord_per_semispan,0.273522534166506,0.204274849507037,0.0888152947868224,0.0725353313595661,unitless +aircraft:wing:chord_per_semispan_dist,0.273522534166506,0.204274849507037,0.0888152947868224,0.0725353313595661,unitless aircraft:wing:composite_fraction,0.33333,unitless aircraft:wing:control_surface_area_ratio,0.333,unitless aircraft:wing:detailed_wing,True,unitless diff --git a/aviary/validation_cases/validation_data/flops_data/FLOPS_Test_Data.py b/aviary/validation_cases/validation_data/flops_data/FLOPS_Test_Data.py index 81d8925c6..453f1d6a0 100644 --- a/aviary/validation_cases/validation_data/flops_data/FLOPS_Test_Data.py +++ b/aviary/validation_cases/validation_data/flops_data/FLOPS_Test_Data.py @@ -14,6 +14,7 @@ MultiEngineSingleAisle, ) from aviary.models.aircraft.advanced_single_aisle.advanced_single_aisle_data import N3CC +from aviary.models.aircraft.blended_wing_body.bwb_1a_FLOPS_data import BWB1aFLOPS FLOPS_Test_Data = {} @@ -22,6 +23,7 @@ FLOPS_Test_Data['LargeSingleAisle2FLOPSdw'] = LargeSingleAisle2FLOPSdw FLOPS_Test_Data['LargeSingleAisle2FLOPSalt'] = LargeSingleAisle2FLOPSalt FLOPS_Test_Data['AdvancedSingleAisle'] = N3CC +FLOPS_Test_Data['BWB1aFLOPS'] = BWB1aFLOPS # We don't have full date for this yet, but might still want to run one in a single unit test. FLOPS_Lacking_Test_Data = {} diff --git a/aviary/variable_info/enums.py b/aviary/variable_info/enums.py index b15abbdb3..dd0d42be4 100644 --- a/aviary/variable_info/enums.py +++ b/aviary/variable_info/enums.py @@ -6,6 +6,7 @@ class AircraftTypes(Enum): TRANSPORT = 'transport' BLENDED_WING_BODY = 'BWB' + GENERAL_AVIATION = 'GA' # incomplete in FLOPS, unavailable in GASP class AlphaModes(Enum): diff --git a/aviary/variable_info/variables.py b/aviary/variable_info/variables.py index 6a4735628..21f52adfd 100644 --- a/aviary/variable_info/variables.py +++ b/aviary/variable_info/variables.py @@ -521,7 +521,7 @@ class Wing: CENTER_DISTANCE = 'aircraft:wing:center_distance' CHARACTERISTIC_LENGTH = 'aircraft:wing:characteristic_length' CHOOSE_FOLD_LOCATION = 'aircraft:wing:choose_fold_location' - CHORD_PER_SEMISPAN_DIST = 'aircraft:wing:chord_per_semispan' + CHORD_PER_SEMISPAN_DIST = 'aircraft:wing:chord_per_semispan_dist' COMPOSITE_FRACTION = 'aircraft:wing:composite_fraction' CONTROL_SURFACE_AREA = 'aircraft:wing:control_surface_area' CONTROL_SURFACE_AREA_RATIO = 'aircraft:wing:control_surface_area_ratio'