From 4c4b5faee22f020fc0f36bb1182822758d140937 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 24 Apr 2026 12:57:58 -0400 Subject: [PATCH 01/21] work in progress: investigation of partials --- .../bwb_detailed_FLOPS_data.py | 84 +++++----- .../geometry/flops_based/fuselage.py | 13 +- .../flops_based/test/test_fuselage.py | 30 ++-- .../flops_based/test/test_prep_geom.py | 72 ++++----- .../flops_based/test/test_wing_detailed.py | 146 +++++++++++++++++- .../mass/flops_based/wing_detailed.py | 21 +++ .../test/test_flops_based_premission.py | 11 +- 7 files changed, 272 insertions(+), 105 deletions(-) diff --git a/aviary/models/aircraft/blended_wing_body/bwb_detailed_FLOPS_data.py b/aviary/models/aircraft/blended_wing_body/bwb_detailed_FLOPS_data.py index d6c9aa9a4..43041148c 100644 --- a/aviary/models/aircraft/blended_wing_body/bwb_detailed_FLOPS_data.py +++ b/aviary/models/aircraft/blended_wing_body/bwb_detailed_FLOPS_data.py @@ -299,17 +299,17 @@ # --------------------------- # In FLOPS, DOWE = 411552.31557733245 because DOWE = WOWE -outputs.set_val(Aircraft.Design.EMPTY_MASS, 390555.9072055, 'lbm') # DOWE +outputs.set_val(Aircraft.Design.EMPTY_MASS, 387978.09236156, 'lbm') # DOWE outputs.set_val(Aircraft.Design.EMPTY_MASS_MARGIN, 0.0, 'lbm') # WMARG -outputs.set_val(Aircraft.Design.STRUCTURE_MASS, 240989.11337145, 'lbm') # WSTRCT 240989.14132753 -outputs.set_val(Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, 90644.95111232, 'lbm') # WSYS -outputs.set_val(Aircraft.Design.TOTAL_WETTED_AREA, 26208.46595187, 'ft**2') # TWET +outputs.set_val(Aircraft.Design.STRUCTURE_MASS, 238976.54475555, 'lbm') # WSTRCT 240989.14132753 +outputs.set_val(Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, 90114.25264997, 'lbm') # WSYS +outputs.set_val(Aircraft.Design.TOTAL_WETTED_AREA, 26036.62112878, 'ft**2') # TWET outputs.set_val(Aircraft.Design.TOUCHDOWN_MASS_MAX, 699279.2, 'lbm') # WLDG = GW*WRATIO -outputs.set_val(Aircraft.AirConditioning.MASS, 3897.6527857555625, 'lbm') # WAC -outputs.set_val(Aircraft.AntiIcing.MASS, 562.09100951165135, 'lbm') # WAI -outputs.set_val(Aircraft.APU.MASS, 2125.8280135763703, 'lbm') # WAPU -outputs.set_val(Aircraft.Avionics.MASS, 2778.5110590964073, 'lbm') # WAVONC +outputs.set_val(Aircraft.AirConditioning.MASS, 3871.27698278, 'lbm') # WAC +outputs.set_val(Aircraft.AntiIcing.MASS, 560.04037229, 'lbm') # WAI +outputs.set_val(Aircraft.APU.MASS, 2122.95946345, 'lbm') # WAPU +outputs.set_val(Aircraft.Avionics.MASS, 2763.47804131, 'lbm') # WAVONC outputs.set_val(Aircraft.BWB.NUM_BAYS, 7.0, 'unitless') # NBAY outputs.set_val(Aircraft.Canard.CHARACTERISTIC_LENGTH, 0.0, 'ft') # EL[-1] @@ -327,31 +327,31 @@ outputs.set_val(Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS, 97812.0, 'lbm') # WPASS+WPBAG+WCARGO outputs.set_val(Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, 97812.0, 'lbm') # WPASS+WPBAG -outputs.set_val(Aircraft.Electrical.MASS, 4291.4778106479534, 'lbm') # WELEC +outputs.set_val(Aircraft.Electrical.MASS, 4277.63057018, 'lbm') # WELEC -outputs.set_val(Aircraft.Fuel.TOTAL_CAPACITY, 1197720.2419621395, 'lbm') # FMXTOT -outputs.set_val(Aircraft.Fuel.FUEL_SYSTEM_MASS, 5444.9572934402777, 'lbm') # WFSYS +outputs.set_val(Aircraft.Fuel.TOTAL_CAPACITY, 1184642.3647993, 'lbm') # FMXTOT +outputs.set_val(Aircraft.Fuel.FUEL_SYSTEM_MASS, 5410.39486929, 'lbm') # WFSYS outputs.set_val(Aircraft.Fuel.UNUSABLE_FUEL_MASS, 1732.78186198, 'lbm') # WUF -outputs.set_val(Aircraft.Fuel.WING_FUEL_CAPACITY, 1197720.2419621395, 'lbm') # FULWMX +outputs.set_val(Aircraft.Fuel.WING_FUEL_CAPACITY, 1184642.3647993, 'lbm') # FULWMX outputs.set_val(Aircraft.Fins.MASS, 3159.3781042368792, 'lbm') # WFIN -outputs.set_val(Aircraft.Furnishings.MASS, 57747.97136452, 'lbm') # WFURN +outputs.set_val(Aircraft.Furnishings.MASS, 57402.19908931, 'lbm') # WFURN -outputs.set_val(Aircraft.Fuselage.CABIN_AREA, 4697.33181006, 'ft**2') # ACABIN -ref_diameter = 46.2868886894979 +outputs.set_val(Aircraft.Fuselage.CABIN_AREA, 4638.43963915, 'ft**2') # ACABIN +ref_diameter = 45.88190626 outputs.set_val(Aircraft.Fuselage.REF_DIAMETER, ref_diameter, 'ft') # XD -outputs.set_val(Aircraft.Fuselage.CHARACTERISTIC_LENGTH, 112.3001936860821, 'ft') # EL(4) +outputs.set_val(Aircraft.Fuselage.CHARACTERISTIC_LENGTH, 111.76379613, 'ft') # EL(4) outputs.set_val(Aircraft.Fuselage.CROSS_SECTION, np.pi * (ref_diameter / 2.0) ** 2.0, 'ft**2') -outputs.set_val(Aircraft.Fuselage.DIAMETER_TO_WING_SPAN, 0.18243240878599712) # DB -outputs.set_val(Aircraft.Fuselage.FINENESS, 2.4261771932742167) # FR(4) -outputs.set_val(Aircraft.Fuselage.LENGTH_TO_DIAMETER, 2.4261771932742167) # BODYLD -outputs.set_val(Aircraft.Fuselage.MASS, 137935.30594648936, 'lbm') # WFUSE -outputs.set_val(Aircraft.Fuselage.MAX_HEIGHT, 12.35302131, 'ft') # DF -outputs.set_val(Aircraft.Fuselage.PLANFORM_AREA, 6710.4740143724875, 'ft**2') # FPAREA -outputs.set_val(Aircraft.Fuselage.AFTBODY_MASS, 18736.55008878, 'lbm') # WAFTB +outputs.set_val(Aircraft.Fuselage.DIAMETER_TO_WING_SPAN, 0.18137306) # DB +outputs.set_val(Aircraft.Fuselage.FINENESS, 2.43590132) # FR(4) +outputs.set_val(Aircraft.Fuselage.LENGTH_TO_DIAMETER, 2.43590132) # BODYLD +outputs.set_val(Aircraft.Fuselage.MASS, 136102.89191481, 'lbm') # WFUSE +outputs.set_val(Aircraft.Fuselage.MAX_HEIGHT, 12.29401757, 'ft') # DF +outputs.set_val(Aircraft.Fuselage.PLANFORM_AREA, 6626.34234164, 'ft**2') # FPAREA +outputs.set_val(Aircraft.Fuselage.AFTBODY_MASS, 18545.58195235, 'lbm') # WAFTB outputs.set_val(Aircraft.Fuselage.LENGTH, 112.3001936860821, 'ft') # XL outputs.set_val(Aircraft.Fuselage.MAX_WIDTH, 80.220756073526772, 'ft') # WF -outputs.set_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH, 78.61013558, 'ft') # XLP +outputs.set_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH, 78.23465729, 'ft') # XLP outputs.set_val(Aircraft.HorizontalTail.CHARACTERISTIC_LENGTH, 0.0, 'ft') # EL(2) outputs.set_val(Aircraft.HorizontalTail.FINENESS, 0.11) # FR(2) @@ -360,9 +360,9 @@ outputs.set_val(Aircraft.Design.EMPENNAGE_MASS, 3159.3781042368792, 'lbm') -outputs.set_val(Aircraft.Hydraulics.MASS, 6200.37391189, 'lbm') # WHYD +outputs.set_val(Aircraft.Hydraulics.MASS, 6133.98944949, 'lbm') # WHYD -outputs.set_val(Aircraft.Instruments.MASS, 1309.88942193, 'lbm') # WIN +outputs.set_val(Aircraft.Instruments.MASS, 1300.50317605, 'lbm') # WIN outputs.set_val(Aircraft.LandingGear.MAIN_GEAR_MASS, 28200.322805698346, 'lbm') # WLGM outputs.set_val(Aircraft.LandingGear.NOSE_GEAR_MASS, 2698.6740002098945, 'lbm') # WLGN @@ -377,7 +377,7 @@ outputs.set_val(Aircraft.Paint.MASS, 0.0, 'lbm') # WPAINT, WTPNT -outputs.set_val(Aircraft.Propulsion.MASS, 58921.857380417721, 'lbm') # WPRO +outputs.set_val(Aircraft.Propulsion.MASS, 58887.29495605, 'lbm') # WPRO outputs.set_val(Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, 70000.0 * 3, 'lbf') outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 3) outputs.set_val(Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS, 346.93557352, 'lbm') # WOIL @@ -406,27 +406,27 @@ outputs.set_val(Aircraft.VerticalTail.MASS, 0.0, 'lbm') # WVT outputs.set_val(Aircraft.VerticalTail.WETTED_AREA, 0.0, 'ft**2') -outputs.set_val(Aircraft.Wing.BWB_AFTBODY_MASS, 15551.33657368, 'lbm') # W4 -outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR, 3.9705868) # FLOPS BT = 3.9724796254619563 -outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS, 8856.083631, 'lbm') # W1 -outputs.set_val(Aircraft.Wing.CHARACTERISTIC_LENGTH, 47.72916456, 'ft') # EL(1) -outputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA, 4032.5967, 'ft**2') # SFLAP +outputs.set_val(Aircraft.Wing.BWB_AFTBODY_MASS, 15392.83302045, 'lbm') # W4 +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR, 3.98518394) # FLOPS BT = 3.9724796254619563 +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS, 8916.98295485, 'lbm') # W1 +outputs.set_val(Aircraft.Wing.CHARACTERISTIC_LENGTH, 47.53827645, 'ft') # EL(1) +outputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA, 4004.57409956, 'ft**2') # SFLAP outputs.set_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR, 1.0) # CAYE outputs.set_val(Aircraft.Wing.FINENESS, 0.11) # FR(1) outputs.set_val(Aircraft.Wing.MISC_MASS, 9720.4199027685518, 'lbm') # W3 -outputs.set_val(Aircraft.Wing.SHEAR_CONTROL_MASS, 34867.592407371565, 'lbm') # W2 -outputs.set_val(Aircraft.Wing.SURFACE_CONTROL_MASS, 11731.15573539, 'lbm') # WSC -outputs.set_val(Aircraft.Wing.ASPECT_RATIO, 5.36951675) # AR -outputs.set_val(Aircraft.Wing.ASPECT_RATIO_REFERENCE, 5.36951675) # ARREF -outputs.set_val(Aircraft.Wing.MASS, 68995.43251482, 'lbm') # WWING 68995.460470895763 +outputs.set_val(Aircraft.Wing.SHEAR_CONTROL_MASS, 34785.04205251, 'lbm') # W2 +outputs.set_val(Aircraft.Wing.SURFACE_CONTROL_MASS, 11682.1755051, 'lbm') # WSC +outputs.set_val(Aircraft.Wing.ASPECT_RATIO, 5.37550108) # AR +outputs.set_val(Aircraft.Wing.ASPECT_RATIO_REFERENCE, 5.37550108) # ARREF +outputs.set_val(Aircraft.Wing.MASS, 68815.27793059, 'lbm') # WWING 68995.460470895763 outputs.set_val(Aircraft.Wing.ROOT_CHORD, 38.5, 'ft') # XLW -outputs.set_val(Aircraft.Wing.AREA, 12109.879719468739, 'ft**2') # SW -outputs.set_val(Aircraft.Wing.LOAD_FRACTION, 0.46761341784858923) # PCTL -outputs.set_val(Aircraft.Wing.WETTED_AREA, 24713.661297561481, 'ft**2') # SWET(1) +outputs.set_val(Aircraft.Wing.AREA, 12025.74804674, 'ft**2') # SW +outputs.set_val(Aircraft.Wing.LOAD_FRACTION, 0.47039383) # PCTL +outputs.set_val(Aircraft.Wing.WETTED_AREA, 24541.8164668, 'ft**2') # SWET(1) outputs.set_val(Aircraft.Wing.SPAN, 253.720756, 'ft') # SPAN = WF+OSSPAN*2 outputs.set_val(Mission.USEFUL_LOAD, 20996.3933862, 'lbm') outputs.set_val(Aircraft.Design.MACH, 0.800) -outputs.set_val(Mission.OPERATING_MASS, 411552.29917206, 'lbm') # WOWE -outputs.set_val(Mission.ZERO_FUEL_MASS, 509364.29917206, 'lbm') # WZF +outputs.set_val(Mission.OPERATING_MASS, 408966.86445029, 'lbm') # WOWE +outputs.set_val(Mission.ZERO_FUEL_MASS, 506778.86445029, 'lbm') # WZF diff --git a/aviary/subsystems/geometry/flops_based/fuselage.py b/aviary/subsystems/geometry/flops_based/fuselage.py index efc0aa749..1fbce07b5 100644 --- a/aviary/subsystems/geometry/flops_based/fuselage.py +++ b/aviary/subsystems/geometry/flops_based/fuselage.py @@ -632,7 +632,7 @@ def compute(self, inputs, outputs): area_service = num_lavas * area_lava + num_galleys * area_galley + num_closets * area_closet # Estimate number of bays based on these areas - num_bays = int(0.5 + (area_seats + area_service) / 550.0) + num_bays = (area_seats + area_service) / 550.0 if num_bays > num_bays_max and num_bays_max > 0: num_bays = num_bays_max @@ -658,32 +658,33 @@ def compute(self, inputs, outputs): pax_compart_length = root_chord + tan_sweep * max_width / 2.0 # Enforce maximum number of bays - num_bays_tmp = 0.5 + max_width / bay_width_nom + num_bays_tmp = max_width / bay_width_nom if num_bays_tmp[0].real > num_bays_max and num_bays_max > 0: num_bays = num_bays_max else: - num_bays = int(num_bays_tmp[0].real) + num_bays = num_bays_tmp[0].real # Enforce maximum bay width bay_width = max_width / num_bays if bay_width > bay_width_max and bay_width_max > 0.0: bay_width = bay_width_max - num_bays_tmp = 0.999 + max_width / bay_width + num_bays_tmp = max_width / bay_width if num_bays_tmp.real > num_bays_max and num_bays_max > 0: num_bays = num_bays_max max_width = num_bays_max * bay_width pax_compart_length = area_cabin / max_width + tan_sweep * max_width / 4.0 root_chord = pax_compart_length - tan_sweep * max_width / 2.0 else: - num_bays = smooth_int_tanh(num_bays_tmp, mu=40.0) + num_bays = num_bays_tmp - if num_bays_loc == num_bays: + if np.abs(num_bays_loc - num_bays) < 0.00001: break iter = iter + 1 if iter > 100: warnings.warn(f'Number of iteration exceeded 100.') break + num_bays = smooth_int_tanh(num_bays, mu=40.0) length = pax_compart_length / rear_spar_percent_chord max_height = height_to_width * length outputs[Aircraft.BWB.NUM_BAYS] = num_bays diff --git a/aviary/subsystems/geometry/flops_based/test/test_fuselage.py b/aviary/subsystems/geometry/flops_based/test/test_fuselage.py index 3983328a9..69b6e204f 100644 --- a/aviary/subsystems/geometry/flops_based/test/test_fuselage.py +++ b/aviary/subsystems/geometry/flops_based/test/test_fuselage.py @@ -146,22 +146,22 @@ def test_case1(self): prob.run_model() num_bays = prob.get_val(Aircraft.BWB.NUM_BAYS) - assert_near_equal(num_bays, 7, tolerance=1e-9) + assert_near_equal(num_bays, 6.99994448, tolerance=1e-5) fuselage_length = prob.get_val(Aircraft.Fuselage.LENGTH) - assert_near_equal(fuselage_length, 112.30019369, tolerance=1e-9) + assert_near_equal(fuselage_length, 111.76379613, tolerance=1e-9) pax_compart_length = prob.get_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH) - assert_near_equal(pax_compart_length, 78.61013558, tolerance=1e-9) + assert_near_equal(pax_compart_length, 78.23465729, tolerance=1e-9) fuselage_width = prob.get_val(Aircraft.Fuselage.MAX_WIDTH) - assert_near_equal(fuselage_width, 80.22075607, tolerance=1e-9) + assert_near_equal(fuselage_width, 79.46979495, tolerance=1e-9) fuselage_height = prob.get_val(Aircraft.Fuselage.MAX_HEIGHT) - assert_near_equal(fuselage_height, 12.35302131, tolerance=1e-9) + assert_near_equal(fuselage_height, 12.29401757, tolerance=1e-9) cabin_area = prob.get_val(Aircraft.Fuselage.CABIN_AREA) - assert_near_equal(cabin_area, 4697.33181006, tolerance=1e-9) + assert_near_equal(cabin_area, 4638.43963915, tolerance=1e-9) root_chord = prob.get_val(Aircraft.Wing.ROOT_CHORD) assert_near_equal(root_chord, 38.5, tolerance=1e-9) @@ -194,23 +194,23 @@ def test_case2(self): prob.set_val('Rear_spar_percent_chord', val=0.7, units='unitless') prob.run_model() - fuselage_width = prob.get_val(Aircraft.Fuselage.MAX_WIDTH) - assert_near_equal(fuselage_width, 49.77182929, tolerance=1e-9) - num_bays = prob.get_val(Aircraft.BWB.NUM_BAYS) - assert_near_equal(num_bays, 4, tolerance=1e-9) + assert_near_equal(num_bays, 4, tolerance=1e-5) + + fuselage_width = prob.get_val(Aircraft.Fuselage.MAX_WIDTH) + assert_near_equal(fuselage_width, 50.17622787, tolerance=1e-9) fuselage_length = prob.get_val(Aircraft.Fuselage.LENGTH) - assert_near_equal(fuselage_length, 116.57609631, tolerance=1e-9) + assert_near_equal(fuselage_length, 117.07640514, tolerance=1e-9) pax_compart_length = prob.get_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH) - assert_near_equal(pax_compart_length, 81.60326742, tolerance=1e-9) + assert_near_equal(pax_compart_length, 81.9534836, tolerance=1e-9) fuselage_height = prob.get_val(Aircraft.Fuselage.MAX_HEIGHT) - assert_near_equal(fuselage_height, 12.82337059, tolerance=1e-9) + assert_near_equal(fuselage_height, 12.87840457, tolerance=1e-9) cabin_area = prob.get_val(Aircraft.Fuselage.CABIN_AREA) - assert_near_equal(cabin_area, 2988.87966179, tolerance=1e-9) + assert_near_equal(cabin_area, 3021.9507202, tolerance=1e-9) root_chord = prob.get_val(Aircraft.Wing.ROOT_CHORD) assert_near_equal(root_chord, 38.5, tolerance=1e-9) @@ -251,7 +251,7 @@ def test_case3(self): assert_near_equal(fuselage_width, 40.0, tolerance=1e-9) num_bays = prob.get_val(Aircraft.BWB.NUM_BAYS) - assert_near_equal(num_bays, 4.0, tolerance=1e-9) + assert_near_equal(num_bays, 4.0, tolerance=1e-5) fuselage_length = prob.get_val(Aircraft.Fuselage.LENGTH) assert_near_equal(fuselage_length, 131.4890549, tolerance=1e-9) 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 8c7030a35..126aa06ba 100644 --- a/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py +++ b/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py @@ -1209,38 +1209,38 @@ def test_case1(self): # BWBDetailedCabinLayout num_bays = prob.get_val(Aircraft.BWB.NUM_BAYS) - assert_near_equal(num_bays, [7], tolerance=1e-9) + assert_near_equal(num_bays, 6.99994448, tolerance=1e-9) fuselage_length = prob.get_val(Aircraft.Fuselage.LENGTH) - assert_near_equal(fuselage_length, 112.30019369, tolerance=1e-9) + assert_near_equal(fuselage_length, 111.76379613, tolerance=1e-9) pax_compart_length = prob.get_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH) - assert_near_equal(pax_compart_length, 78.61013558, tolerance=1e-9) + assert_near_equal(pax_compart_length, 78.23465729, tolerance=1e-9) fuselage_width = prob.get_val(Aircraft.Fuselage.MAX_WIDTH) - assert_near_equal(fuselage_width, 80.22075607, tolerance=1e-9) + assert_near_equal(fuselage_width, 79.46979495, tolerance=1e-9) fuselage_height = prob.get_val(Aircraft.Fuselage.MAX_HEIGHT) - assert_near_equal(fuselage_height, 12.35302131, tolerance=1e-9) + assert_near_equal(fuselage_height, 12.29401757, tolerance=1e-9) cabin_area = prob.get_val(Aircraft.Fuselage.CABIN_AREA) - assert_near_equal(cabin_area, 4697.33181006, tolerance=1e-9) + assert_near_equal(cabin_area, 4638.43963915, tolerance=1e-9) root_chord = prob.get_val(Aircraft.Wing.ROOT_CHORD) assert_near_equal(root_chord, 38.5, tolerance=1e-9) # BWBUpdateDetailedWingDist out1 = prob.get_val('BWB_CHORD_PER_SEMISPAN_DISTRIBUTION') exp1 = [ - 112.3001936861, + 111.763796, 55.0, - 0.3071047525, - 0.2655967176, - 0.2268239733, - 0.197351217, - 0.1734858065, - 0.1551593595, - 0.1450387842, - 0.1356020317, - 0.1260285145, - 0.1165233797, - 0.1070182448, - 0.09751311, - 0.0880079752, + 0.308016418, + 0.266385163, + 0.227497318, + 0.197937070, + 0.174000813, + 0.155619962, + 0.145469344, + 0.136004577, + 0.126402640, + 0.116869289, + 0.107335937, + 0.0978025855, + 0.0882692339, ] assert_near_equal(out1, exp1, tolerance=1e-8) @@ -1269,31 +1269,31 @@ def test_case1(self): assert_near_equal(out3, exp3, tolerance=1e-8) # BWBFuselagePrelim - assert_near_equal(prob.get_val(Aircraft.Fuselage.REF_DIAMETER), 46.28688869, tolerance=1e-8) + assert_near_equal(prob.get_val(Aircraft.Fuselage.REF_DIAMETER), 45.88190626, tolerance=1e-8) assert_near_equal( - prob.get_val(Aircraft.Fuselage.PLANFORM_AREA), 6710.47401437, tolerance=1e-8 + prob.get_val(Aircraft.Fuselage.PLANFORM_AREA), 6626.34234164, tolerance=1e-8 ) # BWBWingPrelim - assert_near_equal(prob.get_val(Aircraft.Wing.AREA), 12109.8797157, tolerance=1e-8) - assert_near_equal(prob.get_val(Aircraft.Wing.ASPECT_RATIO), 5.36951675, tolerance=1e-8) - assert_near_equal(prob.get_val(Aircraft.Wing.LOAD_FRACTION), 0.46761342, tolerance=1e-8) + assert_near_equal(prob.get_val(Aircraft.Wing.AREA), 12025.74804674, tolerance=1e-8) + assert_near_equal(prob.get_val(Aircraft.Wing.ASPECT_RATIO), 5.37550108, tolerance=1e-8) + assert_near_equal(prob.get_val(Aircraft.Wing.LOAD_FRACTION), 0.47039383, tolerance=1e-8) # PrelimWettedArea assert_near_equal( - prob.get_val('prelim_swet.prep_geom:_Names:CROOT'), 72.0855305, tolerance=1e-8 + prob.get_val('prelim_swet.prep_geom:_Names:CROOT'), 71.79215992, tolerance=1e-8 ) assert_near_equal( - prob.get_val('prelim_swet.prep_geom:_Names:CROOTB'), 63.02467273, tolerance=1e-8 + prob.get_val('prelim_swet.prep_geom:_Names:CROOTB'), 62.82057802, tolerance=1e-8 ) assert_near_equal( - prob.get_val('prelim_swet.prep_geom:_Names:CROTM'), 0.87430407, tolerance=1e-8 + prob.get_val('prelim_swet.prep_geom:_Names:CROTM'), 0.87503396, tolerance=1e-8 ) assert_near_equal(prob.get_val('prelim_swet.prep_geom:_Names:CROTVT'), 0.0, tolerance=1e-7) assert_near_equal(prob.get_val('prelim_swet.prep_geom:_Names:CRTHTB'), 0.0, tolerance=1e-8) assert_near_equal(prob.get_val('prelim_swet.prep_geom:_Names:SPANHT'), 0.0, tolerance=1e-8) assert_near_equal(prob.get_val('prelim_swet.prep_geom:_Names:SPANVT'), 0.0, tolerance=1e-8) assert_near_equal( - prob.get_val('prelim_swet.prep_geom:_Names:XDX'), 46.28688869, tolerance=1e-8 + prob.get_val('prelim_swet.prep_geom:_Names:XDX'), 45.88190626, tolerance=1e-8 ) assert_near_equal( prob.get_val('prelim_swet.prep_geom:_Names:XMULT'), 2.04257, tolerance=1e-8 @@ -1305,7 +1305,7 @@ def test_case1(self): prob.get_val('prelim_swet.prep_geom:_Names:XMULTV'), 2.04257, tolerance=1e-8 ) # BWBWingWettedArea - assert_near_equal(prob.get_val(Aircraft.Wing.WETTED_AREA), 24713.66128988, tolerance=1e-8) + assert_near_equal(prob.get_val(Aircraft.Wing.WETTED_AREA), 24541.8164668, tolerance=1e-8) # TailWettedArea assert_near_equal(prob.get_val(Aircraft.HorizontalTail.WETTED_AREA), 0.0, tolerance=1e-8) assert_near_equal(prob.get_val(Aircraft.VerticalTail.WETTED_AREA), 0.0, tolerance=1e-8) @@ -1314,11 +1314,11 @@ def test_case1(self): # _FuselageRatios assert_near_equal( prob.get_val(Aircraft.Fuselage.DIAMETER_TO_WING_SPAN), - 0.18243241, + 0.1813730618, tolerance=1e-8, ) assert_near_equal( - prob.get_val(Aircraft.Fuselage.LENGTH_TO_DIAMETER), 2.42617719, tolerance=1e-8 + prob.get_val(Aircraft.Fuselage.LENGTH_TO_DIAMETER), 2.43590132, tolerance=1e-8 ) # NacelleWettedArea assert_near_equal( @@ -1329,7 +1329,7 @@ def test_case1(self): assert_near_equal(prob.get_val(Aircraft.Canard.WETTED_AREA), 0.0, tolerance=1e-8) # BWBWingCharacteristicLength assert_near_equal( - prob.get_val(Aircraft.Wing.CHARACTERISTIC_LENGTH), 47.72916456, tolerance=1e-8 + prob.get_val(Aircraft.Wing.CHARACTERISTIC_LENGTH), 47.53827645, tolerance=1e-8 ) assert_near_equal(prob.get_val(Aircraft.Wing.FINENESS), 0.11, tolerance=1e-8) # NacelleCharacteristicLength @@ -1341,9 +1341,9 @@ def test_case1(self): assert_near_equal(prob.get_val(Aircraft.Canard.CHARACTERISTIC_LENGTH), 0.0, tolerance=1e-8) assert_near_equal(prob.get_val(Aircraft.Canard.FINENESS), 0.0, tolerance=1e-8) assert_near_equal( - prob.get_val(Aircraft.Fuselage.CHARACTERISTIC_LENGTH), 112.30019369, tolerance=1e-8 + prob.get_val(Aircraft.Fuselage.CHARACTERISTIC_LENGTH), 111.76379613, tolerance=1e-8 ) - assert_near_equal(prob.get_val(Aircraft.Fuselage.FINENESS), 2.42617719, tolerance=1e-8) + assert_near_equal(prob.get_val(Aircraft.Fuselage.FINENESS), 2.43590132, tolerance=1e-8) assert_near_equal( prob.get_val(Aircraft.HorizontalTail.CHARACTERISTIC_LENGTH), 0.0, tolerance=1e-8 ) @@ -1354,7 +1354,7 @@ def test_case1(self): assert_near_equal(prob.get_val(Aircraft.VerticalTail.FINENESS), 0.11, tolerance=1e-8) # TotalWettedArea assert_near_equal( - prob.get_val(Aircraft.Design.TOTAL_WETTED_AREA), 26208.46595188, tolerance=1e-8 + prob.get_val(Aircraft.Design.TOTAL_WETTED_AREA), 26036.62112878, tolerance=1e-8 ) 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 e07f29d83..8d1e5e9e0 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py @@ -496,8 +496,10 @@ def test_case1(self): # current BWB data set does not check the following assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data, atol=8e-10, rtol=1e-10) + -@use_tempdirs class BWBDetailedWingBendingTest(unittest.TestCase): """The BWB detailed wing bending material factor when detailed wing data is provided.""" @@ -610,6 +612,15 @@ def test_case1(self): # current BWB data set does not check the following assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) + partial_data = prob.check_partials( + out_stream=None, + compact_print=True, + show_only_incorrect=True, + form='central', + method='fd', + ) + assert_check_partials(partial_data, atol=1e-3, rtol=1e-4) + def test_case2(self): """ bwb300_baseline @@ -696,6 +707,137 @@ def test_case2(self): # current BWB data set does not check the following assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) + partial_data = prob.check_partials( + out_stream=None, + compact_print=True, + show_only_incorrect=True, + form='central', + method='fd', + ) + assert_check_partials(partial_data, atol=1e-3, rtol=1e-4) + + def test_case3(self): + """ + bwb detailed + """ + 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_DISTRIBUTION, + [0.0, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.6499, 0.7, 0.75, 0.8, 0.85, 0.8999, 0.95, 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' + ) # 100 okay + aviary_options.set_val(Aircraft.BWB.DETAILED_WING_PROVIDED, True, units='unitless') + + prob.model.add_subsystem( + 'bending', + BWBDetailedWingBendingFact(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO, 5.37550108, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO_REFERENCE, 0.0, 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_REFERENCE, 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([19301.2621248]), units='lbm') + prob.set_val(Aircraft.Wing.SPAN, val=252.96979495033787) + prob.set_val(Aircraft.Fuselage.MAX_WIDTH, 79.46979495033786, 'ft') + + 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_DISTRIBUTION', + [ + 111.763796, + 55.0000000, + 0.308016418, + 0.266385163, + 0.227497318, + 0.197937070, + 0.174000813, + 0.155619962, + 0.145469344, + 0.136004577, + 0.126402640, + 0.116869289, + 0.107335937, + 0.0978025855, + 0.0882692339, + ], + units='unitless', + ) + prob.set_val( + 'BWB_THICKNESS_TO_CHORD_DISTRIBUTION', + [ + 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_DISTRIBUTION', + [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], + 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.98518394 + 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.40570654, tolerance=1e-9) + # current BWB data set does not check the following + assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) + + partial_data = prob.check_partials( + out_stream=None, + compact_print=True, + show_only_incorrect=True, + form='central', + method='fd', + ) + assert_check_partials(partial_data, atol=1e-3, rtol=1e-4) + if __name__ == '__main__': - unittest.main() + # unittest.main() + test = BWBDetailedWingBendingTest() + test.setUp() + test.test_case4() diff --git a/aviary/subsystems/mass/flops_based/wing_detailed.py b/aviary/subsystems/mass/flops_based/wing_detailed.py index e9e6f1c9b..dfe4cbdec 100644 --- a/aviary/subsystems/mass/flops_based/wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/wing_detailed.py @@ -334,6 +334,15 @@ def setup(self): add_aviary_output(self, Aircraft.Wing.ENG_POD_INERTIA_FACTOR, units='unitless') self.add_output('calculated_wing_area', units='ft**2') + # self.add_output('btb', units='unitless') + # self.add_output('den', units='unitless') + self.add_output('pm', units='unitless') + # self.add_output('del_load', units='unitless') + # self.add_output('del_moment', units='unitless') + # self.add_output('calc_ar', units='unitless') + # self.add_output('csw', shape=48, units='unitless') + # self.add_output('total_moment', shape=50, units='unitless') + def setup_partials(self): # TODO: Analytic derivs will be challenging, but possible. self.declare_partials('*', '*', method='cs') @@ -361,6 +370,9 @@ def compute(self, inputs, outputs): bwb_input_station_dist[0] = 0.0 bwb_input_station_dist[1] = width / 2.0 inp_stations_mod = [] + import pdb + + # pdb.set_trace() for x in bwb_input_station_dist: if x > 1.0: inp_stations_mod.append(2 * x / wingspan) @@ -521,6 +533,15 @@ def compute(self, inputs, outputs): ) bt = btb / den + # pdb.set_trace() + # outputs['del_load'] = del_load + # outputs['del_moment'] = del_moment + # outputs['total_moment'] = total_moment + # outputs['csw'] = csw + # outputs['calc_ar'] = calc_ar + outputs['pm'] = pm + # outputs['btb'] = btb + # outputs['den'] = den outputs[Aircraft.Wing.BENDING_MATERIAL_FACTOR] = bt engine_locations = inputs[Aircraft.Engine.WING_LOCATIONS] diff --git a/aviary/subsystems/test/test_flops_based_premission.py b/aviary/subsystems/test/test_flops_based_premission.py index bb14f4e2c..3780004cf 100644 --- a/aviary/subsystems/test/test_flops_based_premission.py +++ b/aviary/subsystems/test/test_flops_based_premission.py @@ -216,8 +216,11 @@ class BWBPreMissionGroupTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(only=bwb_cases), name_func=print_case) - def test_case_all_subsystems(self, case_name): + # @parameterized.expand(get_flops_case_names(only=bwb_cases), name_func=print_case) + def test_case_all_subsystems( + self, + ): + case_name = 'BWBdetailedFLOPS' flops_inputs = get_flops_inputs(case_name) flops_outputs = get_flops_outputs(case_name) @@ -1228,7 +1231,7 @@ def test_case_all_subsystems(self): if __name__ == '__main__': - unittest.main() + # unittest.main() test = BWBPreMissionGroupTest() test.setUp() - # test.test_case_all_subsystems() + test.test_case_all_subsystems() From 37d9a4d4ab3561238d33c5775db79527f5efca3b Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 24 Apr 2026 18:02:27 -0400 Subject: [PATCH 02/21] work in progress: add a Temp class for testing --- .../flops_based/test/test_wing_detailed.py | 222 +++++++++++++++++- .../mass/flops_based/wing_detailed.py | 151 ++++++++---- 2 files changed, 325 insertions(+), 48 deletions(-) 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 8d1e5e9e0..613abf44d 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py @@ -9,6 +9,7 @@ from aviary.subsystems.mass.flops_based.wing_detailed import ( BWBDetailedWingBendingFact, DetailedWingBendingFact, + Temp, ) from aviary.subsystems.propulsion.engine_deck import EngineDeck from aviary.utils.aviary_values import AviaryValues @@ -835,9 +836,226 @@ def test_case3(self): ) assert_check_partials(partial_data, atol=1e-3, rtol=1e-4) + def test_case4(self): + """ + bwb detailed + """ + 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_DISTRIBUTION, + [0.0, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.6499, 0.7, 0.75, 0.8, 0.85, 0.8999, 0.95, 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, 100, units='unitless' + ) # 100 okay + aviary_options.set_val(Aircraft.BWB.DETAILED_WING_PROVIDED, True, units='unitless') + + prob.model.add_subsystem( + 'bending', + BWBDetailedWingBendingFact(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO, 5.37550108, units='unitless') + prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO_REFERENCE, 0.0, 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_REFERENCE, 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([19301.2621248]), units='lbm') + prob.set_val(Aircraft.Wing.SPAN, val=252.96979495033787) + prob.set_val(Aircraft.Fuselage.MAX_WIDTH, 79.46979495033786, 'ft') + + 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_DISTRIBUTION', + [ + 111.763796, + 55.0000000, + 0.308016418, + 0.266385163, + 0.227497318, + 0.197937070, + 0.174000813, + 0.155619962, + 0.145469344, + 0.136004577, + 0.126402640, + 0.116869289, + 0.107335937, + 0.0978025855, + 0.0882692339, + ], + units='unitless', + ) + prob.set_val( + 'BWB_THICKNESS_TO_CHORD_DISTRIBUTION', + [ + 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_DISTRIBUTION', + [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], + 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.98692904 + pod_inertia_expected = 1.0 + assert_near_equal(BENDING_MATERIAL_FACTOR, BENDING_MATERIAL_FACTOR_expected, tolerance=1e-8) + assert_near_equal(prob.get_val('calculated_wing_area'), 5399.40570654, tolerance=1e-9) + # current BWB data set does not check the following + assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) + + partial_data = prob.check_partials( + out_stream=None, + compact_print=True, + show_only_incorrect=True, + form='central', + method='fd', + ) + assert_check_partials(partial_data, atol=1e-3, rtol=1e-4) + + +class TempTest(unittest.TestCase): + def setUp(self): + self.prob = om.Problem() + + def test_case_50(self): + """ + bwb detailed + """ + prob = self.prob + + aviary_options = AviaryValues() + aviary_options.set_val( + Aircraft.Wing.INPUT_STATION_DISTRIBUTION, + [0.0, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.6499, 0.7, 0.75, 0.8, 0.85, 0.8999, 0.95, 1.0], + units='unitless', + ) + aviary_options.set_val( + Aircraft.Wing.NUM_INTEGRATION_STATIONS, 50, units='unitless' + ) # 100 okay + + prob.model.add_subsystem( + 'bending', + Temp(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + setup_model_options(self.prob, aviary_options) + prob.setup(check=False, force_alloc_complex=True) + + prob.set_val(Aircraft.Wing.SPAN, val=252.96979495033787) + prob.set_val(Aircraft.Fuselage.MAX_WIDTH, 79.46979495033786, 'ft') + + prob.set_val( + 'BWB_LOAD_PATH_SWEEP_DISTRIBUTION', + [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], + units='deg', + ) + + prob.run_model() + + partial_data = prob.check_partials( + out_stream=None, + compact_print=True, + show_only_incorrect=True, + form='central', + method='fd', + ) + assert_check_partials(partial_data, atol=1e-3, rtol=1e-4) + + def test_case_100(self): + """ + bwb detailed + """ + prob = self.prob + + aviary_options = AviaryValues() + aviary_options.set_val( + Aircraft.Wing.INPUT_STATION_DISTRIBUTION, + [0.0, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.6499, 0.7, 0.75, 0.8, 0.85, 0.8999, 0.95, 1.0], + units='unitless', + ) + aviary_options.set_val( + Aircraft.Wing.NUM_INTEGRATION_STATIONS, 100, units='unitless' + ) # 100 okay + + prob.model.add_subsystem( + 'bending', + Temp(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + setup_model_options(self.prob, aviary_options) + prob.setup(check=False, force_alloc_complex=True) + + prob.set_val(Aircraft.Wing.SPAN, val=252.96979495033787) + prob.set_val(Aircraft.Fuselage.MAX_WIDTH, 79.46979495033786, 'ft') + + prob.set_val( + 'BWB_LOAD_PATH_SWEEP_DISTRIBUTION', + [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], + units='deg', + ) + + prob.run_model() + + partial_data = prob.check_partials( + out_stream=None, + compact_print=True, + show_only_incorrect=True, + form='central', + method='fd', + ) + assert_check_partials(partial_data, atol=1e-3, rtol=1e-4) + if __name__ == '__main__': # unittest.main() - test = BWBDetailedWingBendingTest() + test = TempTest() test.setUp() - test.test_case4() + test.test_case_50() # sum_csw wrt aircraft:wing:span = 1365107.76591427 + # test.test_case_100() # sum_csw wrt aircraft:wing:span = 0.0 diff --git a/aviary/subsystems/mass/flops_based/wing_detailed.py b/aviary/subsystems/mass/flops_based/wing_detailed.py index dfe4cbdec..7335acad9 100644 --- a/aviary/subsystems/mass/flops_based/wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/wing_detailed.py @@ -290,7 +290,6 @@ def initialize(self): add_aviary_option(self, Aircraft.Wing.INPUT_STATION_DISTRIBUTION) add_aviary_option(self, Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL) add_aviary_option(self, Aircraft.Wing.NUM_INTEGRATION_STATIONS) - add_aviary_option(self, Aircraft.BWB.DETAILED_WING_PROVIDED) add_aviary_option(self, Settings.VERBOSITY) def setup(self): @@ -334,15 +333,6 @@ def setup(self): add_aviary_output(self, Aircraft.Wing.ENG_POD_INERTIA_FACTOR, units='unitless') self.add_output('calculated_wing_area', units='ft**2') - # self.add_output('btb', units='unitless') - # self.add_output('den', units='unitless') - self.add_output('pm', units='unitless') - # self.add_output('del_load', units='unitless') - # self.add_output('del_moment', units='unitless') - # self.add_output('calc_ar', units='unitless') - # self.add_output('csw', shape=48, units='unitless') - # self.add_output('total_moment', shape=50, units='unitless') - def setup_partials(self): # TODO: Analytic derivs will be challenging, but possible. self.declare_partials('*', '*', method='cs') @@ -359,25 +349,25 @@ def compute(self, inputs, outputs): bwb_input_station_dist = np.array( self.options[Aircraft.Wing.INPUT_STATION_DISTRIBUTION], dtype=float ) - if not self.options[Aircraft.BWB.DETAILED_WING_PROVIDED]: - bwb_input_station_dist[1] = width / 2.0 - else: - bwb_input_station_dist = np.where( - bwb_input_station_dist <= 1.0, - bwb_input_station_dist * rate_span + width / wingspan, # if x <= 1.0 - bwb_input_station_dist + width / 2.0, # else - ) - bwb_input_station_dist[0] = 0.0 - bwb_input_station_dist[1] = width / 2.0 - inp_stations_mod = [] - import pdb - - # pdb.set_trace() - for x in bwb_input_station_dist: - if x > 1.0: - inp_stations_mod.append(2 * x / wingspan) - else: - inp_stations_mod.append(x) + bwb_input_station_dist = np.where( + bwb_input_station_dist <= 1.0, + bwb_input_station_dist * rate_span + width / wingspan, # if x <= 1.0 + bwb_input_station_dist + width / 2.0, # else + ) + bwb_input_station_dist[0] = 0.0 + bwb_input_station_dist[1] = width / 2.0 + + # in FLOPS, this is a step before calling BNDMAT + inp_stations_mod = np.where( + bwb_input_station_dist > 1.0, + 2 * bwb_input_station_dist / wingspan, + bwb_input_station_dist, + ) + # for x in bwb_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:] @@ -404,13 +394,18 @@ def compute(self, inputs, outputs): 'Assume it is the same as Aircraft.Wing.ASPECT_RATIO.' ) chord = inputs['BWB_CHORD_PER_SEMISPAN_DISTRIBUTION'] - 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) + # chord_mod = [] + chord_mod = np.where( + chord > 5.0, + 2 * chord / wingspan, + chord, + ) + # 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) fstrt = inputs[Aircraft.Wing.STRUT_BRACING_FACTOR] faert = inputs[Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR] @@ -497,7 +492,7 @@ def compute(self, inputs, outputs): ) csw = 1.0 / np.cos(sweep_int_stations[:-1] * np.pi / 180.0) emi = (del_moment + dy * load_path_length[1:]) * csw - em = np.sum(emi) + # em = np.sum(emi) tc_interp = InterpND( method='slinear', points=(inp_stations_mod), x_interp=integration_stations @@ -533,15 +528,6 @@ def compute(self, inputs, outputs): ) bt = btb / den - # pdb.set_trace() - # outputs['del_load'] = del_load - # outputs['del_moment'] = del_moment - # outputs['total_moment'] = total_moment - # outputs['csw'] = csw - # outputs['calc_ar'] = calc_ar - outputs['pm'] = pm - # outputs['btb'] = btb - # outputs['den'] = den outputs[Aircraft.Wing.BENDING_MATERIAL_FACTOR] = bt engine_locations = inputs[Aircraft.Engine.WING_LOCATIONS] @@ -606,3 +592,76 @@ def compute(self, inputs, outputs): inertia_factor_prod = 1.0 outputs[Aircraft.Wing.ENG_POD_INERTIA_FACTOR] = inertia_factor_prod + + +class Temp(om.ExplicitComponent): + def initialize(self): + add_aviary_option(self, Aircraft.Wing.INPUT_STATION_DISTRIBUTION) + add_aviary_option(self, Aircraft.Wing.NUM_INTEGRATION_STATIONS) + add_aviary_option(self, Settings.VERBOSITY) + + def setup(self): + input_station_distribution = self.options[Aircraft.Wing.INPUT_STATION_DISTRIBUTION] + num_input_stations = len(input_station_distribution) + + self.add_input( + 'BWB_LOAD_PATH_SWEEP_DISTRIBUTION', shape=num_input_stations - 1, units='deg' + ) + add_aviary_input(self, Aircraft.Wing.SPAN, units='ft') + add_aviary_input(self, Aircraft.Fuselage.MAX_WIDTH, units='ft') + + self.add_output('sum_csw', units='unitless') + + 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] + width = inputs[Aircraft.Fuselage.MAX_WIDTH][0] + wingspan = inputs[Aircraft.Wing.SPAN][0] + rate_span = (wingspan - width) / wingspan + + bwb_input_station_dist = np.array( + self.options[Aircraft.Wing.INPUT_STATION_DISTRIBUTION], dtype=float + ) + + bwb_input_station_dist = np.where( + bwb_input_station_dist <= 1.0, + bwb_input_station_dist * rate_span + width / wingspan, # if x <= 1.0 + bwb_input_station_dist + width / 2.0, # else + ) + bwb_input_station_dist[0] = 0.0 + bwb_input_station_dist[1] = width / 2.0 + + inp_stations_mod = np.where( + bwb_input_station_dist > 1.0, + 2 * bwb_input_station_dist / wingspan, + bwb_input_station_dist, + ) + 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:] + + load_path_sweep = inputs['BWB_LOAD_PATH_SWEEP_DISTRIBUTION'] + load_path_sweep_mod = np.array(load_path_sweep[1:]) + + 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=load_path_sweep.dtype) + sweep_int_stations = np.empty(0, dtype=load_path_sweep.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) + ) + + csw = 1.0 / np.cos(sweep_int_stations[:-1] * np.pi / 180.0) + outputs['sum_csw'] = np.sum(csw) From c9926d56f138fb2d3eb276a8cb792f6f82de67c4 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 24 Apr 2026 22:19:38 -0400 Subject: [PATCH 03/21] exclude bending material factor because it causes high partials. See test_wing_detailed.py --- aviary/subsystems/test/test_flops_based_premission.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aviary/subsystems/test/test_flops_based_premission.py b/aviary/subsystems/test/test_flops_based_premission.py index 3780004cf..93b6b1563 100644 --- a/aviary/subsystems/test/test_flops_based_premission.py +++ b/aviary/subsystems/test/test_flops_based_premission.py @@ -429,6 +429,7 @@ def test_case_all_subsystems( rtol=1e-6, check_values=True, check_partials=True, + excludes=['*bending_material_factor*'], ) def test_case_geom(self): From 24a223582aca31da5cacfb580e5e3eadc91da80a Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 24 Apr 2026 22:32:38 -0400 Subject: [PATCH 04/21] minor update to BWBDetailedWingBendingFact and investigation of partial of Aircraft.Wing.BENDING_MATERIAL_FACTOR --- .../flops_based/test/test_wing_detailed.py | 254 +----------------- .../mass/flops_based/wing_detailed.py | 84 ------ 2 files changed, 6 insertions(+), 332 deletions(-) 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 613abf44d..1c088f2ca 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py @@ -9,7 +9,6 @@ from aviary.subsystems.mass.flops_based.wing_detailed import ( BWBDetailedWingBendingFact, DetailedWingBendingFact, - Temp, ) from aviary.subsystems.propulsion.engine_deck import EngineDeck from aviary.utils.aviary_values import AviaryValues @@ -497,10 +496,8 @@ def test_case1(self): # current BWB data set does not check the following assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) - partial_data = self.prob.check_partials(out_stream=None, method='cs') - assert_check_partials(partial_data, atol=8e-10, rtol=1e-10) - +@use_tempdirs class BWBDetailedWingBendingTest(unittest.TestCase): """The BWB detailed wing bending material factor when detailed wing data is provided.""" @@ -613,15 +610,6 @@ def test_case1(self): # current BWB data set does not check the following assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) - partial_data = prob.check_partials( - out_stream=None, - compact_print=True, - show_only_incorrect=True, - form='central', - method='fd', - ) - assert_check_partials(partial_data, atol=1e-3, rtol=1e-4) - def test_case2(self): """ bwb300_baseline @@ -708,18 +696,9 @@ def test_case2(self): # current BWB data set does not check the following assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) - partial_data = prob.check_partials( - out_stream=None, - compact_print=True, - show_only_incorrect=True, - form='central', - method='fd', - ) - assert_check_partials(partial_data, atol=1e-3, rtol=1e-4) - def test_case3(self): """ - bwb detailed + bwb detailed, investigation of partial of Aircraft.Wing.BENDING_MATERIAL_FACTOR """ prob = self.prob @@ -734,9 +713,8 @@ def test_case3(self): ) 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' - ) # 100 okay - aviary_options.set_val(Aircraft.BWB.DETAILED_WING_PROVIDED, True, units='unitless') + Aircraft.Wing.NUM_INTEGRATION_STATIONS, 80, units='unitless' + ) # 71 - 100 okay prob.model.add_subsystem( 'bending', @@ -820,126 +798,7 @@ def test_case3(self): 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.98518394 - 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.40570654, tolerance=1e-9) - # current BWB data set does not check the following - assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) - - partial_data = prob.check_partials( - out_stream=None, - compact_print=True, - show_only_incorrect=True, - form='central', - method='fd', - ) - assert_check_partials(partial_data, atol=1e-3, rtol=1e-4) - - def test_case4(self): - """ - bwb detailed - """ - 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_DISTRIBUTION, - [0.0, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.6499, 0.7, 0.75, 0.8, 0.85, 0.8999, 0.95, 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, 100, units='unitless' - ) # 100 okay - aviary_options.set_val(Aircraft.BWB.DETAILED_WING_PROVIDED, True, units='unitless') - - prob.model.add_subsystem( - 'bending', - BWBDetailedWingBendingFact(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) - - prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO, 5.37550108, units='unitless') - prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO_REFERENCE, 0.0, 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_REFERENCE, 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([19301.2621248]), units='lbm') - prob.set_val(Aircraft.Wing.SPAN, val=252.96979495033787) - prob.set_val(Aircraft.Fuselage.MAX_WIDTH, 79.46979495033786, 'ft') - - 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_DISTRIBUTION', - [ - 111.763796, - 55.0000000, - 0.308016418, - 0.266385163, - 0.227497318, - 0.197937070, - 0.174000813, - 0.155619962, - 0.145469344, - 0.136004577, - 0.126402640, - 0.116869289, - 0.107335937, - 0.0978025855, - 0.0882692339, - ], - units='unitless', - ) - prob.set_val( - 'BWB_THICKNESS_TO_CHORD_DISTRIBUTION', - [ - 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_DISTRIBUTION', - [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], - 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.98692904 + BENDING_MATERIAL_FACTOR_expected = 3.98618988 pod_inertia_expected = 1.0 assert_near_equal(BENDING_MATERIAL_FACTOR, BENDING_MATERIAL_FACTOR_expected, tolerance=1e-8) assert_near_equal(prob.get_val('calculated_wing_area'), 5399.40570654, tolerance=1e-9) @@ -956,106 +815,5 @@ def test_case4(self): assert_check_partials(partial_data, atol=1e-3, rtol=1e-4) -class TempTest(unittest.TestCase): - def setUp(self): - self.prob = om.Problem() - - def test_case_50(self): - """ - bwb detailed - """ - prob = self.prob - - aviary_options = AviaryValues() - aviary_options.set_val( - Aircraft.Wing.INPUT_STATION_DISTRIBUTION, - [0.0, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.6499, 0.7, 0.75, 0.8, 0.85, 0.8999, 0.95, 1.0], - units='unitless', - ) - aviary_options.set_val( - Aircraft.Wing.NUM_INTEGRATION_STATIONS, 50, units='unitless' - ) # 100 okay - - prob.model.add_subsystem( - 'bending', - Temp(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) - - setup_model_options(self.prob, aviary_options) - prob.setup(check=False, force_alloc_complex=True) - - prob.set_val(Aircraft.Wing.SPAN, val=252.96979495033787) - prob.set_val(Aircraft.Fuselage.MAX_WIDTH, 79.46979495033786, 'ft') - - prob.set_val( - 'BWB_LOAD_PATH_SWEEP_DISTRIBUTION', - [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], - units='deg', - ) - - prob.run_model() - - partial_data = prob.check_partials( - out_stream=None, - compact_print=True, - show_only_incorrect=True, - form='central', - method='fd', - ) - assert_check_partials(partial_data, atol=1e-3, rtol=1e-4) - - def test_case_100(self): - """ - bwb detailed - """ - prob = self.prob - - aviary_options = AviaryValues() - aviary_options.set_val( - Aircraft.Wing.INPUT_STATION_DISTRIBUTION, - [0.0, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.6499, 0.7, 0.75, 0.8, 0.85, 0.8999, 0.95, 1.0], - units='unitless', - ) - aviary_options.set_val( - Aircraft.Wing.NUM_INTEGRATION_STATIONS, 100, units='unitless' - ) # 100 okay - - prob.model.add_subsystem( - 'bending', - Temp(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) - - setup_model_options(self.prob, aviary_options) - prob.setup(check=False, force_alloc_complex=True) - - prob.set_val(Aircraft.Wing.SPAN, val=252.96979495033787) - prob.set_val(Aircraft.Fuselage.MAX_WIDTH, 79.46979495033786, 'ft') - - prob.set_val( - 'BWB_LOAD_PATH_SWEEP_DISTRIBUTION', - [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], - units='deg', - ) - - prob.run_model() - - partial_data = prob.check_partials( - out_stream=None, - compact_print=True, - show_only_incorrect=True, - form='central', - method='fd', - ) - assert_check_partials(partial_data, atol=1e-3, rtol=1e-4) - - if __name__ == '__main__': - # unittest.main() - test = TempTest() - test.setUp() - test.test_case_50() # sum_csw wrt aircraft:wing:span = 1365107.76591427 - # test.test_case_100() # sum_csw wrt aircraft:wing:span = 0.0 + unittest.main() diff --git a/aviary/subsystems/mass/flops_based/wing_detailed.py b/aviary/subsystems/mass/flops_based/wing_detailed.py index 7335acad9..717ba1647 100644 --- a/aviary/subsystems/mass/flops_based/wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/wing_detailed.py @@ -363,11 +363,6 @@ def compute(self, inputs, outputs): 2 * bwb_input_station_dist / wingspan, bwb_input_station_dist, ) - # for x in bwb_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:] @@ -400,12 +395,6 @@ def compute(self, inputs, outputs): 2 * chord / wingspan, chord, ) - # 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) fstrt = inputs[Aircraft.Wing.STRUT_BRACING_FACTOR] faert = inputs[Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR] @@ -592,76 +581,3 @@ def compute(self, inputs, outputs): inertia_factor_prod = 1.0 outputs[Aircraft.Wing.ENG_POD_INERTIA_FACTOR] = inertia_factor_prod - - -class Temp(om.ExplicitComponent): - def initialize(self): - add_aviary_option(self, Aircraft.Wing.INPUT_STATION_DISTRIBUTION) - add_aviary_option(self, Aircraft.Wing.NUM_INTEGRATION_STATIONS) - add_aviary_option(self, Settings.VERBOSITY) - - def setup(self): - input_station_distribution = self.options[Aircraft.Wing.INPUT_STATION_DISTRIBUTION] - num_input_stations = len(input_station_distribution) - - self.add_input( - 'BWB_LOAD_PATH_SWEEP_DISTRIBUTION', shape=num_input_stations - 1, units='deg' - ) - add_aviary_input(self, Aircraft.Wing.SPAN, units='ft') - add_aviary_input(self, Aircraft.Fuselage.MAX_WIDTH, units='ft') - - self.add_output('sum_csw', units='unitless') - - 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] - width = inputs[Aircraft.Fuselage.MAX_WIDTH][0] - wingspan = inputs[Aircraft.Wing.SPAN][0] - rate_span = (wingspan - width) / wingspan - - bwb_input_station_dist = np.array( - self.options[Aircraft.Wing.INPUT_STATION_DISTRIBUTION], dtype=float - ) - - bwb_input_station_dist = np.where( - bwb_input_station_dist <= 1.0, - bwb_input_station_dist * rate_span + width / wingspan, # if x <= 1.0 - bwb_input_station_dist + width / 2.0, # else - ) - bwb_input_station_dist[0] = 0.0 - bwb_input_station_dist[1] = width / 2.0 - - inp_stations_mod = np.where( - bwb_input_station_dist > 1.0, - 2 * bwb_input_station_dist / wingspan, - bwb_input_station_dist, - ) - 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:] - - load_path_sweep = inputs['BWB_LOAD_PATH_SWEEP_DISTRIBUTION'] - load_path_sweep_mod = np.array(load_path_sweep[1:]) - - 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=load_path_sweep.dtype) - sweep_int_stations = np.empty(0, dtype=load_path_sweep.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) - ) - - csw = 1.0 / np.cos(sweep_int_stations[:-1] * np.pi / 180.0) - outputs['sum_csw'] = np.sum(csw) From 9a05b6628d0f1f6e84b9b3475beabb75be49193e Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 29 Apr 2026 11:31:42 -0400 Subject: [PATCH 05/21] update test data due to BWBDetailedCabinLayout update --- .../geometry/flops_based/fuselage.py | 11 +- .../test/test_flops_based_premission.py | 181 +++++++++--------- .../benchmark_tests/test_bwb_FwFm.py | 6 +- 3 files changed, 98 insertions(+), 100 deletions(-) diff --git a/aviary/subsystems/geometry/flops_based/fuselage.py b/aviary/subsystems/geometry/flops_based/fuselage.py index 1fbce07b5..98369c30e 100644 --- a/aviary/subsystems/geometry/flops_based/fuselage.py +++ b/aviary/subsystems/geometry/flops_based/fuselage.py @@ -601,7 +601,7 @@ def compute(self, inputs, outputs): if seat_pitch_economy <= 0: seat_pitch_economy = 32.0 # inch - # Determine unit seat areas for each type of passenger + # Determine unit seat areas for each type of passenger (ft**2) area_seat_business = bay_width_nom * seat_pitch_business / 12.0 / num_seat_abreast_business area_seat_first = bay_width_nom * seat_pitch_first / 12.0 / num_seat_abreast_first area_seat_economy = bay_width_nom * seat_pitch_economy / 12.0 / num_seat_abreast_economy @@ -636,16 +636,17 @@ def compute(self, inputs, outputs): if num_bays > num_bays_max and num_bays_max > 0: num_bays = num_bays_max - num_bays_loc = num_bays + # num_bays_loc = num_bays iter = 0 + bay_width = bay_width_nom while True: num_bays_loc = num_bays # Cabin area wasted due to slanted != side wall - area_waste = num_bays * tan_sweep * (bay_width_nom / 2.0) ** 2 + area_waste = num_bays * tan_sweep * (bay_width / 2.0) ** 2 # Aisle area for horseshoe (5'), cross (2') and rear (3') aisles # Aisles only go to center of outboard bays, hence num_bays-1 - area_aisle = 10.0 * (num_bays - 1) * bay_width_nom + area_aisle = 10.0 * (num_bays - 1) * bay_width # Total pressurized cabin area area_cabin = area_seats + area_service + area_waste + area_aisle @@ -658,7 +659,7 @@ def compute(self, inputs, outputs): pax_compart_length = root_chord + tan_sweep * max_width / 2.0 # Enforce maximum number of bays - num_bays_tmp = max_width / bay_width_nom + num_bays_tmp = max_width / bay_width if num_bays_tmp[0].real > num_bays_max and num_bays_max > 0: num_bays = num_bays_max else: diff --git a/aviary/subsystems/test/test_flops_based_premission.py b/aviary/subsystems/test/test_flops_based_premission.py index 93b6b1563..6e1d809cc 100644 --- a/aviary/subsystems/test/test_flops_based_premission.py +++ b/aviary/subsystems/test/test_flops_based_premission.py @@ -780,46 +780,46 @@ def test_case_geom(self): # BWBComputeDetailedWingDist assert_near_equal(prob[Aircraft.Wing.SPAN], 253.720756, tol) # DetailedCabinLayout - assert_near_equal(prob[Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH], 78.61013558, tol) + assert_near_equal(prob[Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH], 78.23465729, tol) assert_near_equal(prob[Aircraft.Wing.ROOT_CHORD], 38.5, tol) - assert_near_equal(prob[Aircraft.Fuselage.CABIN_AREA], 4697.33181006, tol) - assert_near_equal(prob[Aircraft.Fuselage.MAX_HEIGHT], 12.35302131, tol) + assert_near_equal(prob[Aircraft.Fuselage.CABIN_AREA], 4638.43963915, tol) + assert_near_equal(prob[Aircraft.Fuselage.MAX_HEIGHT], 12.29401757, tol) assert_near_equal(prob[Aircraft.BWB.NUM_BAYS], 7.0, tol) # BWBFuselagePrelim - assert_near_equal(prob[Aircraft.Fuselage.REF_DIAMETER], 46.2868886894979, tol) - assert_near_equal(prob[Aircraft.Fuselage.PLANFORM_AREA], 6710.4740143724875, tol) + assert_near_equal(prob[Aircraft.Fuselage.REF_DIAMETER], 45.88190626, tol) + assert_near_equal(prob[Aircraft.Fuselage.PLANFORM_AREA], 6626.34234164, tol) # BWBWingPrelim - assert_near_equal(prob[Aircraft.Wing.AREA], 12109.879719468739, tol) - assert_near_equal(prob[Aircraft.Wing.ASPECT_RATIO], 5.36951675, tol) - assert_near_equal(prob[Aircraft.Wing.ASPECT_RATIO_REFERENCE], 5.36951675, tol) - assert_near_equal(prob[Aircraft.Wing.LOAD_FRACTION], 0.46761341784858923, tol) + assert_near_equal(prob[Aircraft.Wing.AREA], 12059.52621246, tol) + assert_near_equal(prob[Aircraft.Wing.ASPECT_RATIO], 5.39216403, tol) + assert_near_equal(prob[Aircraft.Wing.ASPECT_RATIO_REFERENCE], 5.39216403, tol) + assert_near_equal(prob[Aircraft.Wing.LOAD_FRACTION], 0.47167013, tol) # BWBWingWettedArea - assert_near_equal(prob[Aircraft.Wing.WETTED_AREA], 24713.66129084, tol) + assert_near_equal(prob[Aircraft.Wing.WETTED_AREA], 24610.64920629, tol) # TailWettedArea assert_near_equal(prob[Aircraft.HorizontalTail.WETTED_AREA], 0.0, tol) assert_near_equal(prob[Aircraft.VerticalTail.WETTED_AREA], 0.0, tol) # _FuselageRatios - assert_near_equal(prob[Aircraft.Fuselage.DIAMETER_TO_WING_SPAN], 0.18243240878599712, tol) - assert_near_equal(prob[Aircraft.Fuselage.LENGTH_TO_DIAMETER], 2.4261771932742167, tol) + assert_near_equal(prob[Aircraft.Fuselage.DIAMETER_TO_WING_SPAN], 0.18083624, tol) + assert_near_equal(prob[Aircraft.Fuselage.LENGTH_TO_DIAMETER], 2.43590132, tol) # NacelleWettedArea assert_near_equal(prob[Aircraft.Nacelle.WETTED_AREA], 498.26822066, tol) assert_near_equal(prob[Aircraft.Nacelle.TOTAL_WETTED_AREA], 3 * 498.26822066, tol) # Canard assert_near_equal(prob[Aircraft.Canard.WETTED_AREA], 0.0, tol) # BWBWingCharacteristicLength - assert_near_equal(prob[Aircraft.Wing.CHARACTERISTIC_LENGTH], 47.72916456, tol) + assert_near_equal(prob[Aircraft.Wing.CHARACTERISTIC_LENGTH], 47.53070424, tol) assert_near_equal(prob[Aircraft.Wing.FINENESS], 0.11, tol) # OtherCharacteristicLengths assert_near_equal(prob[Aircraft.Canard.CHARACTERISTIC_LENGTH], 0.0, tol) assert_near_equal(prob[Aircraft.Canard.FINENESS], 0.0, tol) - assert_near_equal(prob[Aircraft.Fuselage.CHARACTERISTIC_LENGTH], 112.3001936860821, tol) - assert_near_equal(prob[Aircraft.Fuselage.FINENESS], 2.4261771932742167, tol) + assert_near_equal(prob[Aircraft.Fuselage.CHARACTERISTIC_LENGTH], 111.76379613, tol) + assert_near_equal(prob[Aircraft.Fuselage.FINENESS], 2.43590132, tol) assert_near_equal(prob[Aircraft.HorizontalTail.CHARACTERISTIC_LENGTH], 0.0, tol) assert_near_equal(prob[Aircraft.HorizontalTail.FINENESS], 0.11, tol) assert_near_equal(prob[Aircraft.Nacelle.CHARACTERISTIC_LENGTH], [15.68611614], tol) assert_near_equal(prob[Aircraft.Nacelle.FINENESS], [1.38269353], tol) # TotalWettedArea - assert_near_equal(prob[Aircraft.Design.TOTAL_WETTED_AREA], 26208.46595187, tol) + assert_near_equal(prob[Aircraft.Design.TOTAL_WETTED_AREA], 26105.45386827, tol) def test_case_geom_mass(self): """ @@ -862,40 +862,40 @@ def test_case_geom_mass(self): # TransportEngineCtrlsMass assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_CONTROLS_MASS], 206.36860226, tol) # TransportAvionicsMass - assert_near_equal(prob[Aircraft.Avionics.MASS], 2778.5110590964073, tol) + assert_near_equal(prob[Aircraft.Avionics.MASS], 2763.47804131, tol) # FuelCapacityGroup - assert_near_equal(prob[Aircraft.Fuel.WING_FUEL_CAPACITY], 1197720.2419621395, tol) - assert_near_equal(prob[Aircraft.Fuel.TOTAL_CAPACITY], 1197720.2419621395, tol) + assert_near_equal(prob[Aircraft.Fuel.WING_FUEL_CAPACITY], 1187780.58456809, tol) + assert_near_equal(prob[Aircraft.Fuel.TOTAL_CAPACITY], 1187780.58456809, tol) # EngineMass assert_near_equal(prob[Aircraft.Engine.MASS], 17825.63336233, tol) assert_near_equal(prob[Aircraft.Engine.ADDITIONAL_MASS], 0.0, tol) assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_MASS], 53476.90008698, tol) # TransportFuelSystemMass - assert_near_equal(prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 5444.9572934402777, tol) + assert_near_equal(prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 5418.70316, tol) # TransportAirCondMass - assert_near_equal(prob[Aircraft.AirConditioning.MASS], 3897.6527857555625, tol) + assert_near_equal(prob[Aircraft.AirConditioning.MASS], 3871.27698278, tol) # TransportEngineOilMass assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS], 346.93557352, tol) # BWBFurnishingsGroupMass - assert_near_equal(prob[Aircraft.Furnishings.MASS], 57747.97136452, tol) + assert_near_equal(prob[Aircraft.Furnishings.MASS], 57402.19908931, tol) # TransportHydraulicsGroupMass - assert_near_equal(prob[Aircraft.Hydraulics.MASS], 6200.37391189, tol) + assert_near_equal(prob[Aircraft.Hydraulics.MASS], 6139.65550426, tol) # PassengerServiceMass assert_near_equal( prob[Aircraft.CrewPayload.PASSENGER_SERVICE_MASS], 10806.675950702213, tol ) # ElectricalMass - assert_near_equal(prob[Aircraft.Electrical.MASS], 4291.4778106479534, tol) + assert_near_equal(prob[Aircraft.Electrical.MASS], 4277.63057018, tol) # AntiIcingMass - assert_near_equal(prob[Aircraft.AntiIcing.MASS], 562.09100951165135, tol) + assert_near_equal(prob[Aircraft.AntiIcing.MASS], 560.96510604, tol) # TransportAPUMass - assert_near_equal(prob[Aircraft.APU.MASS], 2125.8280135763703, tol) + assert_near_equal(prob[Aircraft.APU.MASS], 2122.95946345, tol) # NonFlightCrewMass assert_near_equal(prob[Aircraft.CrewPayload.CABIN_CREW_MASS], 3810.0, tol) # FlightCrewMass assert_near_equal(prob[Aircraft.CrewPayload.FLIGHT_CREW_MASS], 450.0, tol) # TransportInstrumentMass - assert_near_equal(prob[Aircraft.Instruments.MASS], 1309.88942193, tol) + assert_near_equal(prob[Aircraft.Instruments.MASS], 1300.50317605, tol) # EngineMiscMass assert_near_equal(prob[Aircraft.Propulsion.TOTAL_MISC_MASS], 0.0, tol) # NacelleMass @@ -908,10 +908,10 @@ def test_case_geom_mass(self): # LandingMassGroup assert_near_equal(prob[Aircraft.Design.TOUCHDOWN_MASS_MAX], 699279.2, tol) # SurfaceControlMass - assert_near_equal(prob[Aircraft.Wing.SURFACE_CONTROL_MASS], 11731.15573539, tol) - assert_near_equal(prob[Aircraft.Wing.CONTROL_SURFACE_AREA], 4032.5967, tol) + assert_near_equal(prob[Aircraft.Wing.SURFACE_CONTROL_MASS], 11701.85233893, tol) + assert_near_equal(prob[Aircraft.Wing.CONTROL_SURFACE_AREA], 4015.82222875, tol) # BWBFuselageMass - assert_near_equal(prob[Aircraft.Fuselage.MASS], 137935.30594648936, tol) + assert_near_equal(prob[Aircraft.Fuselage.MASS], 136102.89191481, tol) # HorizontalTailMass assert_near_equal(prob[Aircraft.HorizontalTail.MASS], 0.0, tol) # VerticalTailMass @@ -922,30 +922,30 @@ def test_case_geom_mass(self): assert_near_equal(prob[Aircraft.Fins.MASS], 3159.3781042368792, tol) # WingMassGroup # BWBDetailedWingBendingFact - assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_FACTOR], 3.9705868, tol) + assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_FACTOR], 4.00585433, tol) assert_near_equal(prob[Aircraft.Wing.ENG_POD_INERTIA_FACTOR], 1.0, tol) # BWBWingMiscMass - assert_near_equal(prob[Aircraft.Wing.MISC_MASS], 9720.4199027685518, tol) + assert_near_equal(prob[Aircraft.Wing.MISC_MASS], 9811.77743845, tol) # WingShearControlMass - assert_near_equal(prob[Aircraft.Wing.SHEAR_CONTROL_MASS], 34867.592407371565, tol) + assert_near_equal(prob[Aircraft.Wing.SHEAR_CONTROL_MASS], 34818.23098605, tol) # WingBendingMass - assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_MASS], 8856.01080887, tol) + assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_MASS], 9010.03041908, tol) # BWBAftBodyMass - assert_near_equal(prob[Aircraft.Fuselage.AFTBODY_MASS], 18736.55008878, tol) - assert_near_equal(prob[Aircraft.Wing.BWB_AFTBODY_MASS], 15551.33657368, tol) + assert_near_equal(prob[Aircraft.Fuselage.AFTBODY_MASS], 18545.58195235, tol) + assert_near_equal(prob[Aircraft.Wing.BWB_AFTBODY_MASS], 15392.83302045, tol) # MassSummation # StructureMass - assert_near_equal(prob[Aircraft.Design.STRUCTURE_MASS], 240989.04053718, tol) + assert_near_equal(prob[Aircraft.Design.STRUCTURE_MASS], 239194.13868898, tol) # PropulsionMass - assert_near_equal(prob[Aircraft.Propulsion.MASS], 58921.857380417721, tol) + assert_near_equal(prob[Aircraft.Propulsion.MASS], 58895.60324675, tol) # SystemsEquipMass - assert_near_equal(prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 90644.95111232, tol) + assert_near_equal(prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 90140.52027232, tol) # EmptyMass - assert_near_equal(prob[Aircraft.Design.EMPTY_MASS], 390555.83436783, tol) + assert_near_equal(prob[Aircraft.Design.EMPTY_MASS], 388230.26220806, tol) # OperatingMass - assert_near_equal(prob[Mission.OPERATING_MASS], 411552.22633412, tol) + assert_near_equal(prob[Mission.OPERATING_MASS], 409221.81531426, tol) # ZeroFuelMass - assert_near_equal(prob[Mission.ZERO_FUEL_MASS], 509364.22633412, tol) + assert_near_equal(prob[Mission.ZERO_FUEL_MASS], 507033.81531426, tol) def test_case_all_subsystems(self): """ @@ -978,8 +978,8 @@ def test_case_all_subsystems(self): assert_near_equal(prob[Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST], 70000.0 * 3, tol) # Aerodynamics # Design - assert_near_equal(prob[Aircraft.Design.MACH], 0.89489036, tol) - assert_near_equal(prob[Aircraft.Design.LIFT_COEFFICIENT], 0.42836987, tol) + assert_near_equal(prob[Aircraft.Design.MACH], 0.89471085, tol) + assert_near_equal(prob[Aircraft.Design.LIFT_COEFFICIENT], 0.42922096, tol) @use_tempdirs @@ -1026,49 +1026,49 @@ def test_case_geom(self): # BWBComputeDetailedWingDist assert_near_equal(prob[Aircraft.Wing.SPAN], 186.631829293424, tol) # DetailedCabinLayout - assert_near_equal(prob[Aircraft.Fuselage.MAX_WIDTH], 49.77182929, tolerance=1e-9) - assert_near_equal(prob[Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH], 81.60326742, tol) + assert_near_equal(prob[Aircraft.Fuselage.MAX_WIDTH], 50.17622787, tolerance=1e-9) + assert_near_equal(prob[Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH], 81.9534836, tol) assert_near_equal(prob[Aircraft.Wing.ROOT_CHORD], 38.5, tol) - assert_near_equal(prob[Aircraft.Fuselage.CABIN_AREA], 2988.879661796, tol) - assert_near_equal(prob[Aircraft.Fuselage.MAX_HEIGHT], 20.89043646, tol) + assert_near_equal(prob[Aircraft.Fuselage.CABIN_AREA], 3021.9507202, tol) + assert_near_equal(prob[Aircraft.Fuselage.MAX_HEIGHT], 20.9800918, tol) assert_near_equal(prob[Aircraft.BWB.NUM_BAYS], 4.0, tol) # BWBFuselagePrelim - assert_near_equal(prob[Aircraft.Fuselage.REF_DIAMETER], 35.33113288, tol) - assert_near_equal(prob[Aircraft.Fuselage.PLANFORM_AREA], 4269.82808827, tol) + assert_near_equal(prob[Aircraft.Fuselage.REF_DIAMETER], 35.57815983, tol) + assert_near_equal(prob[Aircraft.Fuselage.PLANFORM_AREA], 4317.07245743, tol) # BWBWingPrelim - assert_near_equal(prob[Aircraft.Wing.AREA], 8421.7146805052689, tol) - assert_near_equal(prob[Aircraft.Wing.ASPECT_RATIO], 4.84361005, tol) + assert_near_equal(prob[Aircraft.Wing.AREA], 8454.35056774, tol) + assert_near_equal(prob[Aircraft.Wing.ASPECT_RATIO], 4.82172761, tol) assert_near_equal( - prob['AIRCRAFT_DATA_OVERRIDE:aircraft:wing:aspect_ratio_reference'], 4.84361005, tol + prob['AIRCRAFT_DATA_OVERRIDE:aircraft:wing:aspect_ratio_reference'], 4.82172761, tol ) # assert_near_equal(prob[Aircraft.Wing.LOAD_FRACTION], 0.46761341784858923, tol) # _BWBWing - assert_near_equal(prob[Aircraft.Wing.WETTED_AREA], 17302.04910213, tol) + assert_near_equal(prob[Aircraft.Wing.WETTED_AREA], 17370.05552974, tol) # _Tail assert_near_equal(prob[Aircraft.HorizontalTail.WETTED_AREA], 983.26501, tol) assert_near_equal(prob[Aircraft.VerticalTail.WETTED_AREA], 125.0, tol) # _FuselageRatios - assert_near_equal(prob[Aircraft.Fuselage.DIAMETER_TO_WING_SPAN], 0.18930926, tol) - assert_near_equal(prob[Aircraft.Fuselage.LENGTH_TO_DIAMETER], 3.29952897, tol) + assert_near_equal(prob[Aircraft.Fuselage.DIAMETER_TO_WING_SPAN], 0.19063286, tol) + assert_near_equal(prob[Aircraft.Fuselage.LENGTH_TO_DIAMETER], 3.29068186, tol) # Nacelles assert_near_equal(prob[Aircraft.Nacelle.WETTED_AREA], 613.74211034217353, tol) assert_near_equal(prob[Aircraft.Nacelle.TOTAL_WETTED_AREA], 2 * 613.7421103421735, tol) # Canard assert_near_equal(prob[Aircraft.Canard.WETTED_AREA], 0.0, tol) # BWBWingCharacteristicLength - assert_near_equal(prob[Aircraft.Wing.CHARACTERISTIC_LENGTH], 45.124750222881779, tol) + assert_near_equal(prob[Aircraft.Wing.CHARACTERISTIC_LENGTH], 45.29961797, tol) assert_near_equal(prob[Aircraft.Wing.FINENESS], 0.11, tol) # OtherCharacteristicLengths assert_near_equal(prob[Aircraft.Canard.CHARACTERISTIC_LENGTH], 0.0, tol) assert_near_equal(prob[Aircraft.Canard.FINENESS], 0.0, tol) - assert_near_equal(prob[Aircraft.Fuselage.CHARACTERISTIC_LENGTH], 116.5760963133181, tol) - assert_near_equal(prob[Aircraft.Fuselage.FINENESS], 3.2995289656062941, tol) + assert_near_equal(prob[Aircraft.Fuselage.CHARACTERISTIC_LENGTH], 117.07640514, tol) + assert_near_equal(prob[Aircraft.Fuselage.FINENESS], 3.29068186, tol) assert_near_equal(prob[Aircraft.HorizontalTail.CHARACTERISTIC_LENGTH], 26.45751311065, tol) assert_near_equal(prob[Aircraft.HorizontalTail.FINENESS], 0.1, tol) assert_near_equal(prob[Aircraft.Nacelle.CHARACTERISTIC_LENGTH], [17.367966592444596], tol) assert_near_equal(prob[Aircraft.Nacelle.FINENESS], [1.3761635770546583], tol) # TotalWettedArea - assert_near_equal(prob[Aircraft.Design.TOTAL_WETTED_AREA], 19637.79833526, tol) + assert_near_equal(prob[Aircraft.Design.TOTAL_WETTED_AREA], 19705.80476042, tol) def test_case_geom_mass(self): """ @@ -1112,38 +1112,38 @@ def test_case_geom_mass(self): # TransportEngineCtrlsMass assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_CONTROLS_MASS], 153.81807436, tol) # TransportAvionicsMass - assert_near_equal(prob[Aircraft.Avionics.MASS], 2280.13561342, tol) + assert_near_equal(prob[Aircraft.Avionics.MASS], 2290.95007773, tol) # FuelCapacityGroup - assert_near_equal(prob[Aircraft.Fuel.WING_FUEL_CAPACITY], 787493.65267018, tol) - assert_near_equal(prob[Aircraft.Fuel.TOTAL_CAPACITY], 787493.65267018, tol) + assert_near_equal(prob[Aircraft.Fuel.WING_FUEL_CAPACITY], 793608.88038917, tol) + assert_near_equal(prob[Aircraft.Fuel.TOTAL_CAPACITY], 793608.88038917, tol) # EngineMass assert_near_equal(prob[Aircraft.Engine.MASS], 44541.857940875525 / 2, tol) assert_near_equal(prob[Aircraft.Engine.ADDITIONAL_MASS], 0.0, tol) assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_MASS], 44541.857940875525, tol) # TransportFuelSystemMass - assert_near_equal(prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 3656.7260445688612, tol) + assert_near_equal(prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 3673.16899646, tol) # TransportAirCondMass - assert_near_equal(prob[Aircraft.AirConditioning.MASS], 3781.61256774, tol) + assert_near_equal(prob[Aircraft.AirConditioning.MASS], 3807.20118967, tol) # TransportEngineOilMass assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS], 267.39241429019251, tol) # BWBFurnishingsGroupMass - assert_near_equal(prob[Aircraft.Furnishings.MASS], 52096.553437128503, tol) + assert_near_equal(prob[Aircraft.Furnishings.MASS], 52410.94244865, tol) # TransportHydraulicsGroupMass - assert_near_equal(prob[Aircraft.Hydraulics.MASS], 3962.6923427813854, tol) + assert_near_equal(prob[Aircraft.Hydraulics.MASS], 3996.6384617, tol) # PassengerServiceMass assert_near_equal(prob[Aircraft.CrewPayload.PASSENGER_SERVICE_MASS], 7029.593528180887, tol) # ElectricalMass - assert_near_equal(prob[Aircraft.Electrical.MASS], 2646.52723481, tol) + assert_near_equal(prob[Aircraft.Electrical.MASS], 2654.06975307, tol) # AntiIcingMass - assert_near_equal(prob[Aircraft.AntiIcing.MASS], 400.3921819029477, tol) + assert_near_equal(prob[Aircraft.AntiIcing.MASS], 400.99917573, tol) # TransportAPUMass - assert_near_equal(prob[Aircraft.APU.MASS], 1578.8098560285962, tol) + assert_near_equal(prob[Aircraft.APU.MASS], 1581.00217211, tol) # NonFlightCrewMass assert_near_equal(prob[Aircraft.CrewPayload.CABIN_CREW_MASS], 1640.0, tol) # FlightCrewMass assert_near_equal(prob[Aircraft.CrewPayload.FLIGHT_CREW_MASS], 450.0, tol) # TransportInstrumentMass - assert_near_equal(prob[Aircraft.Instruments.MASS], 961.543462363, tol) + assert_near_equal(prob[Aircraft.Instruments.MASS], 967.59344999, tol) # EngineMiscMass assert_near_equal(prob[Aircraft.Propulsion.TOTAL_MISC_MASS], 0.0, tol) # NacelleMass @@ -1156,10 +1156,10 @@ def test_case_geom_mass(self): # LandingMassGroup assert_near_equal(prob[Aircraft.Design.TOUCHDOWN_MASS_MAX], 420000.0, tol) # SurfaceControlMass - assert_near_equal(prob[Aircraft.Wing.SURFACE_CONTROL_MASS], 8093.1997108029764, tol) - assert_near_equal(prob[Aircraft.Wing.CONTROL_SURFACE_AREA], 2526.5144041515805, tol) + assert_near_equal(prob[Aircraft.Wing.SURFACE_CONTROL_MASS], 8112.00284687, tol) + assert_near_equal(prob[Aircraft.Wing.CONTROL_SURFACE_AREA], 2536.30517032, tol) # BWBFuselageMass - assert_near_equal(prob[Aircraft.Fuselage.MASS], 80216.313556241628, tol) + assert_near_equal(prob[Aircraft.Fuselage.MASS], 81157.44843467, tol) # HorizontalTailMass assert_near_equal(prob[Aircraft.HorizontalTail.MASS], 6444.9988831532046, tol) # VerticalTailMass @@ -1170,30 +1170,30 @@ def test_case_geom_mass(self): assert_near_equal(prob[Aircraft.Fins.MASS], 2822.1415450307886, tol) # WingMassGroup # BWBDetailedWingBendingFact, In FLOPS run, 6.7996347825592336 - assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_FACTOR], 6.79961928, tol) + assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_FACTOR], 6.75079525, tol) assert_near_equal(prob[Aircraft.Wing.ENG_POD_INERTIA_FACTOR], 1.0, tol) # BWBWingMiscMass - assert_near_equal(prob[Aircraft.Wing.MISC_MASS], 6975.77622754, tol) + assert_near_equal(prob[Aircraft.Wing.MISC_MASS], 6938.99205472, tol) # WingShearControlMass - assert_near_equal(prob[Aircraft.Wing.SHEAR_CONTROL_MASS], 24461.161868706797, tol) + assert_near_equal(prob[Aircraft.Wing.SHEAR_CONTROL_MASS], 24493.35004333, tol) # WingBendingMass - assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_MASS], 18001.88182061, tol) + assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_MASS], 17876.82972382, tol) # BWBAftBodyMass - assert_near_equal(prob[Aircraft.Fuselage.AFTBODY_MASS], 10384.964957095559, tol) - assert_near_equal(prob[Aircraft.Wing.BWB_AFTBODY_MASS], 8884.3375208, tol) + assert_near_equal(prob[Aircraft.Fuselage.AFTBODY_MASS], 10478.08779866, tol) + assert_near_equal(prob[Aircraft.Wing.BWB_AFTBODY_MASS], 8964.00411176, tol) # MassSummation # StructureMass 158921.83401643133 - assert_near_equal(prob[Aircraft.Design.STRUCTURE_MASS], 167099.36823103, tol) + assert_near_equal(prob[Aircraft.Design.STRUCTURE_MASS], 167990.52160543, tol) # PropulsionMass - assert_near_equal(prob[Aircraft.Propulsion.MASS], 48198.583985444384, tol) + assert_near_equal(prob[Aircraft.Propulsion.MASS], 48215.02693733, tol) # SystemsEquipMass - assert_near_equal(prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 75801.466406974854, tol) + assert_near_equal(prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 76221.39957552, tol) # EmptyMass - assert_near_equal(prob[Aircraft.Design.EMPTY_MASS], 291099.46121048, tol) + assert_near_equal(prob[Aircraft.Design.EMPTY_MASS], 292426.94811828, tol) # OperatingMass - assert_near_equal(prob[Mission.OPERATING_MASS], 325301.28625612, tol) + assert_near_equal(prob[Mission.OPERATING_MASS], 326632.14480333, tol) # ZeroFuelMass - assert_near_equal(prob[Mission.ZERO_FUEL_MASS], 388001.28625612, tol) + assert_near_equal(prob[Mission.ZERO_FUEL_MASS], 389332.14480333, tol) # FinMass assert_near_equal(prob[Aircraft.Fins.MASS], 2822.14154503, tol) @@ -1227,12 +1227,9 @@ def test_case_all_subsystems(self): # Only aero parameters are checked because geometry and mass are checked in test_case_geom() already. tol = 1e-4 # Design - assert_near_equal(prob[Aircraft.Design.MACH], 0.89939238, tol) - assert_near_equal(prob[Aircraft.Design.LIFT_COEFFICIENT], 0.40810915, tol) + assert_near_equal(prob[Aircraft.Design.MACH], 0.8995951, tol) + assert_near_equal(prob[Aircraft.Design.LIFT_COEFFICIENT], 0.40724438, tol) if __name__ == '__main__': - # unittest.main() - test = BWBPreMissionGroupTest() - test.setUp() - test.test_case_all_subsystems() + unittest.main() diff --git a/aviary/validation_cases/benchmark_tests/test_bwb_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bwb_FwFm.py index a0ede1e4b..6ee911dc8 100644 --- a/aviary/validation_cases/benchmark_tests/test_bwb_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bwb_FwFm.py @@ -198,19 +198,19 @@ def test_bench_bwb300_FwFm_SNOPT(self): # There are no truth values for these. assert_near_equal( prob.get_val(Mission.GROSS_MASS, units='lbm'), - 615233.67861433, + 618370.76963151, tolerance=rtol, ) assert_near_equal( prob.get_val(Mission.OPERATING_MASS, units='lbm'), - 327094.09117139, + 328794.4056369, tolerance=rtol, ) assert_near_equal( prob.get_val(Mission.TOTAL_FUEL, units='lbm'), - 225439.58744294, + 226876.36399461, tolerance=rtol, ) From d2390090628ebcbfb3f67006e1df6c72ea6afe30 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 29 Apr 2026 14:40:56 -0400 Subject: [PATCH 06/21] added a comment --- aviary/subsystems/mass/flops_based/test/test_wing_detailed.py | 2 ++ 1 file changed, 2 insertions(+) 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 a753a636c..c0fe1dad8 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py @@ -699,6 +699,8 @@ def test_case2(self): def test_case3(self): """ bwb detailed, investigation of partial of Aircraft.Wing.BENDING_MATERIAL_FACTOR + To see the problem, create sum_csw = np.sum(csw) as an output and see its partials. + Even if slinear is replaced by lagrange2, still get high partials. """ prob = self.prob From 304cfd2103fb019a139d23a32d800140635eb165 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 29 Apr 2026 14:43:02 -0400 Subject: [PATCH 07/21] updated the computation of num_bays --- .../geometry/flops_based/fuselage.py | 31 ++++++++++++++++--- .../flops_based/test/test_fuselage.py | 2 +- .../test/test_flops_based_premission.py | 13 ++++---- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/aviary/subsystems/geometry/flops_based/fuselage.py b/aviary/subsystems/geometry/flops_based/fuselage.py index 98369c30e..6e037117c 100644 --- a/aviary/subsystems/geometry/flops_based/fuselage.py +++ b/aviary/subsystems/geometry/flops_based/fuselage.py @@ -4,7 +4,7 @@ import numpy as np import openmdao.api as om -from aviary.utils.math import smooth_int_tanh, d_smooth_int_tanh +from aviary.utils.math import smooth_int_tanh, d_smooth_int_tanh, smooth_min, d_smooth_min from aviary.variable_info.enums import Verbosity from aviary.variable_info.functions import add_aviary_input, add_aviary_option, add_aviary_output from aviary.variable_info.variables import Aircraft, Mission, Settings @@ -449,6 +449,14 @@ def setup_partials(self): ], ) + self.declare_partials( + of=[Aircraft.BWB.NUM_BAYS], + wrt=[ + Aircraft.Fuselage.MAX_WIDTH, + Aircraft.Fuselage.SIDEBODY_THICKNESS_TO_CHORD, + ], + ) + def compute(self, inputs, outputs): verbosity = self.options[Settings.VERBOSITY] @@ -477,15 +485,16 @@ def compute(self, inputs, outputs): # Enforce maximum number of bays num_bays_max = self.options[Aircraft.BWB.MAX_NUM_BAYS] - num_bays = int(0.5 + max_width / bay_width_nom) - if num_bays.real > num_bays_max and num_bays_max > 0: - num_bays = num_bays_max - outputs[Aircraft.BWB.NUM_BAYS] = smooth_int_tanh(num_bays, mu=20.0) + if num_bays_max > 0: + num_bays = smooth_min(max_width / bay_width_nom, num_bays_max, mu=50.0) + else: + num_bays = max_width / bay_width_nom outputs[Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH] = pax_compart_length outputs[Aircraft.Wing.ROOT_CHORD] = root_chord outputs[Aircraft.Fuselage.CABIN_AREA] = area_cabin outputs[Aircraft.Fuselage.MAX_HEIGHT] = max_height + outputs[Aircraft.BWB.NUM_BAYS] = smooth_int_tanh(num_bays, mu=20.0) def compute_partials(self, inputs, J): length = inputs[Aircraft.Fuselage.LENGTH] @@ -495,6 +504,16 @@ def compute_partials(self, inputs, J): tan_sweep = np.tan(sweep / 57.296) pax_compart_length = rear_spar_percent_chord * length height_to_width = inputs[Aircraft.Fuselage.SIDEBODY_THICKNESS_TO_CHORD] + bay_width_nom = 12.0 + + num_bays_max = self.options[Aircraft.BWB.MAX_NUM_BAYS] + dnum_bays_dmax_width = 1.0 / bay_width_nom + if num_bays_max > 0: + dnum_bays_dmax_width = ( + d_smooth_min(max_width / bay_width_nom, num_bays_max, mu=50.0) / bay_width_nom + ) + else: + dnum_bays_dmax_width = 1.0 / bay_width_nom J[Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH, Aircraft.Fuselage.LENGTH] = ( rear_spar_percent_chord @@ -522,6 +541,8 @@ def compute_partials(self, inputs, J): J[Aircraft.Fuselage.MAX_HEIGHT, Aircraft.Fuselage.LENGTH] = height_to_width J[Aircraft.Fuselage.MAX_HEIGHT, Aircraft.Fuselage.SIDEBODY_THICKNESS_TO_CHORD] = length + J[Aircraft.BWB.NUM_BAYS, Aircraft.Fuselage.MAX_WIDTH] = dnum_bays_dmax_width + class BWBDetailedCabinLayout(om.ExplicitComponent): """Compute BWB fuselage dimensions using cabin seat information.""" diff --git a/aviary/subsystems/geometry/flops_based/test/test_fuselage.py b/aviary/subsystems/geometry/flops_based/test/test_fuselage.py index 69b6e204f..7960e0958 100644 --- a/aviary/subsystems/geometry/flops_based/test/test_fuselage.py +++ b/aviary/subsystems/geometry/flops_based/test/test_fuselage.py @@ -98,7 +98,7 @@ def test_case1(self): prob.run_model() num_bays = prob.get_val(Aircraft.BWB.NUM_BAYS) - assert_near_equal(num_bays, [5], tolerance=1e-9) + assert_near_equal(num_bays, [5.00872038], tolerance=1e-9) pax_compart_length = prob.get_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH) assert_near_equal(pax_compart_length, 96.25, tolerance=1e-9) root_chord = prob.get_val(Aircraft.Wing.ROOT_CHORD) diff --git a/aviary/subsystems/test/test_flops_based_premission.py b/aviary/subsystems/test/test_flops_based_premission.py index 6e1d809cc..62dae894d 100644 --- a/aviary/subsystems/test/test_flops_based_premission.py +++ b/aviary/subsystems/test/test_flops_based_premission.py @@ -536,7 +536,7 @@ def test_case_geom(self): assert_near_equal(prob[Aircraft.Wing.ROOT_CHORD], 63.96, tol) assert_near_equal(prob[Aircraft.Fuselage.CABIN_AREA], 5173.187202504683, tol) assert_near_equal(prob[Aircraft.Fuselage.MAX_HEIGHT], 15.125, tol) - assert_near_equal(prob[Aircraft.BWB.NUM_BAYS], 5.0, 1e-4) + assert_near_equal(prob[Aircraft.BWB.NUM_BAYS], 5.00872038, 1e-4) # BWBFuselagePrelim assert_near_equal(prob[Aircraft.Fuselage.REF_DIAMETER], 39.8525, tol) assert_near_equal(prob[Aircraft.Fuselage.PLANFORM_AREA], 7390.267432149546, tol) @@ -629,7 +629,7 @@ def test_case_geom_mass(self): # TransportEngineOilMass assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS], 346.93557352, tol) # BWBFurnishingsGroupMass - assert_near_equal(prob[Aircraft.Furnishings.MASS], 61482.097969438299, tol) + assert_near_equal(prob[Aircraft.Furnishings.MASS], 61509.57919465, tol) # TransportHydraulicsGroupMass assert_near_equal(prob[Aircraft.Hydraulics.MASS], 7368.5077321194321, tol) # PassengerServiceMass @@ -691,9 +691,7 @@ def test_case_geom_mass(self): # PropulsionMass assert_near_equal(prob[Aircraft.Propulsion.MASS], 61597.102467771889, tol) # SystemsEquipMass - assert_near_equal( - prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 98848.9061107412710, tol - ) + assert_near_equal(prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 98876.385842, tol) # EmptyMass assert_near_equal(prob[Aircraft.Design.EMPTY_MASS], 434037.32820147, tol) # OperatingMass @@ -1232,4 +1230,7 @@ def test_case_all_subsystems(self): if __name__ == '__main__': - unittest.main() + # unittest.main() + test = BWBPreMissionGroupCSVTest1() + test.setUp() + test.test_case_geom_mass() From c55f2c5f2df79b67a9dbd925b3fe71048614a974 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 29 Apr 2026 18:46:14 -0400 Subject: [PATCH 08/21] update data due to the change of num_bays --- .../geometry/flops_based/test/test_prep_geom.py | 2 +- aviary/subsystems/test/test_flops_based_premission.py | 7 +++---- .../validation_data/test_data/bwb_detailed_FLOPS_data.py | 8 ++++---- 3 files changed, 8 insertions(+), 9 deletions(-) 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 07c967f06..e82e26014 100644 --- a/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py +++ b/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py @@ -913,7 +913,7 @@ def test_case1(self): # BWBSimpleCabinLayout num_bays = prob.get_val(Aircraft.BWB.NUM_BAYS) - assert_near_equal(num_bays, [5], tolerance=1e-9) + assert_near_equal(num_bays, [5.00872038], tolerance=1e-9) pax_compart_length = prob.get_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH) assert_near_equal(pax_compart_length, 96.25, tolerance=1e-8) root_chord = prob.get_val(Aircraft.Wing.ROOT_CHORD) diff --git a/aviary/subsystems/test/test_flops_based_premission.py b/aviary/subsystems/test/test_flops_based_premission.py index 62dae894d..c11ed4404 100644 --- a/aviary/subsystems/test/test_flops_based_premission.py +++ b/aviary/subsystems/test/test_flops_based_premission.py @@ -284,6 +284,8 @@ def test_case_all_subsystems( input_keys=[], output_keys=[ # Geometry + # BWBComputeDetailedWingDist + Aircraft.Wing.SPAN, # BWBSimpleCabinLayout Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH, Aircraft.Wing.ROOT_CHORD, @@ -1230,7 +1232,4 @@ def test_case_all_subsystems(self): if __name__ == '__main__': - # unittest.main() - test = BWBPreMissionGroupCSVTest1() - test.setUp() - test.test_case_geom_mass() + unittest.main() diff --git a/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py b/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py index 42d13d91b..2415e2bb1 100644 --- a/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py +++ b/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py @@ -329,7 +329,7 @@ outputs.set_val(Aircraft.Fuel.TOTAL_CAPACITY, 1184642.3647993, 'lbm') # FMXTOT outputs.set_val(Aircraft.Fuel.FUEL_SYSTEM_MASS, 5410.39486929, 'lbm') # WFSYS -outputs.set_val(Aircraft.Fuel.UNUSABLE_FUEL_MASS, 1732.78186198, 'lbm') # WUF +outputs.set_val(Aircraft.Fuel.UNUSABLE_FUEL_MASS, 1725.1605645, 'lbm') # WUF outputs.set_val(Aircraft.Fuel.WING_FUEL_CAPACITY, 1184642.3647993, 'lbm') # FULWMX outputs.set_val(Aircraft.Fins.MASS, 3159.3781042368792, 'lbm') # WFIN @@ -347,8 +347,8 @@ outputs.set_val(Aircraft.Fuselage.MAX_HEIGHT, 12.29401757, 'ft') # DF outputs.set_val(Aircraft.Fuselage.PLANFORM_AREA, 6626.34234164, 'ft**2') # FPAREA outputs.set_val(Aircraft.Fuselage.AFTBODY_MASS, 18545.58195235, 'lbm') # WAFTB -outputs.set_val(Aircraft.Fuselage.LENGTH, 112.3001936860821, 'ft') # XL -outputs.set_val(Aircraft.Fuselage.MAX_WIDTH, 80.220756073526772, 'ft') # WF +outputs.set_val(Aircraft.Fuselage.LENGTH, 111.76379613, 'ft') # XL +outputs.set_val(Aircraft.Fuselage.MAX_WIDTH, 79.46979495, 'ft') # WF outputs.set_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH, 78.23465729, 'ft') # XLP outputs.set_val(Aircraft.HorizontalTail.CHARACTERISTIC_LENGTH, 0.0, 'ft') # EL(2) @@ -421,7 +421,7 @@ outputs.set_val(Aircraft.Wing.AREA, 12025.74804674, 'ft**2') # SW outputs.set_val(Aircraft.Wing.LOAD_FRACTION, 0.47039383) # PCTL outputs.set_val(Aircraft.Wing.WETTED_AREA, 24541.8164668, 'ft**2') # SWET(1) -outputs.set_val(Aircraft.Wing.SPAN, 253.720756, 'ft') # SPAN = WF+OSSPAN*2 +outputs.set_val(Aircraft.Wing.SPAN, 252.96979495033787, 'ft') # SPAN = WF+OSSPAN*2 outputs.set_val(Mission.USEFUL_LOAD, 20996.3933862, 'lbm') From e735ba8c01ccc63e241e1f5a56ec7d74b66072b0 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 29 Apr 2026 20:10:02 -0400 Subject: [PATCH 09/21] update data due to the change of num_bays --- .../validation_data/test_data/bwb_detailed_FLOPS_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py b/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py index 2415e2bb1..fb7e056a5 100644 --- a/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py +++ b/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py @@ -423,7 +423,7 @@ outputs.set_val(Aircraft.Wing.WETTED_AREA, 24541.8164668, 'ft**2') # SWET(1) outputs.set_val(Aircraft.Wing.SPAN, 252.96979495033787, 'ft') # SPAN = WF+OSSPAN*2 -outputs.set_val(Mission.USEFUL_LOAD, 20996.3933862, 'lbm') +outputs.set_val(Mission.USEFUL_LOAD, 20988.77208872, 'lbm') outputs.set_val(Aircraft.Design.MACH, 0.800) outputs.set_val(Mission.OPERATING_MASS, 408966.86445029, 'lbm') # WOWE From a3afc1e04369d80ed6e457b199ec6d53446e3359 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Wed, 29 Apr 2026 20:13:03 -0400 Subject: [PATCH 10/21] update data due to the change of num_bays --- .../mass/flops_based/test/test_mass_summation.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) 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 e60511ec7..a012fdc52 100644 --- a/aviary/subsystems/mass/flops_based/test/test_mass_summation.py +++ b/aviary/subsystems/mass/flops_based/test/test_mass_summation.py @@ -33,11 +33,8 @@ class TotalSummationTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - # @parameterized.expand(get_flops_case_names(), name_func=print_case) - def test_case( - self, - ): - case_name = 'BWBdetailedFLOPS' + @parameterized.expand(get_flops_case_names(), name_func=print_case) + def test_case(self, case_name): prob = self.prob prob.model.add_subsystem( @@ -249,7 +246,4 @@ def test_case_multiengine(self): if __name__ == '__main__': - # unittest.main() - test = TotalSummationTest() - test.setUp() - test.test_case() + unittest.main() From 3c5f823a4fe2cf8f6ffc93597f9eb961ddc08b5d Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 30 Apr 2026 12:50:55 -0400 Subject: [PATCH 11/21] smnall improvement of num_bay computation --- .../geometry/flops_based/fuselage.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/aviary/subsystems/geometry/flops_based/fuselage.py b/aviary/subsystems/geometry/flops_based/fuselage.py index 6e037117c..8627046ed 100644 --- a/aviary/subsystems/geometry/flops_based/fuselage.py +++ b/aviary/subsystems/geometry/flops_based/fuselage.py @@ -581,6 +581,7 @@ def setup_partials(self): self.declare_partials('*', '*', method='cs') def compute(self, inputs, outputs): + verbosity = self.options[Settings.VERBOSITY] rear_spar_percent_chord = inputs['Rear_spar_percent_chord'] sweep = inputs[Aircraft.BWB.PASSENGER_LEADING_EDGE_SWEEP] height_to_width = inputs[Aircraft.Fuselage.SIDEBODY_THICKNESS_TO_CHORD] @@ -657,12 +658,11 @@ def compute(self, inputs, outputs): if num_bays > num_bays_max and num_bays_max > 0: num_bays = num_bays_max - # num_bays_loc = num_bays iter = 0 bay_width = bay_width_nom while True: num_bays_loc = num_bays - # Cabin area wasted due to slanted != side wall + # Cabin area wasted due to slanted != side wall area_waste = num_bays * tan_sweep * (bay_width / 2.0) ** 2 # Aisle area for horseshoe (5'), cross (2') and rear (3') aisles @@ -680,30 +680,30 @@ def compute(self, inputs, outputs): pax_compart_length = root_chord + tan_sweep * max_width / 2.0 # Enforce maximum number of bays - num_bays_tmp = max_width / bay_width - if num_bays_tmp[0].real > num_bays_max and num_bays_max > 0: + num_bays = max_width[0] / bay_width + if num_bays.real > num_bays_max and num_bays_max > 0: num_bays = num_bays_max - else: - num_bays = num_bays_tmp[0].real # Enforce maximum bay width - bay_width = max_width / num_bays + bay_width = max_width[0] / num_bays + import pdb + + pdb.set_trace() if bay_width > bay_width_max and bay_width_max > 0.0: bay_width = bay_width_max - num_bays_tmp = max_width / bay_width - if num_bays_tmp.real > num_bays_max and num_bays_max > 0: + num_bays = max_width[0] / bay_width + if num_bays.real > num_bays_max and num_bays_max > 0: num_bays = num_bays_max max_width = num_bays_max * bay_width pax_compart_length = area_cabin / max_width + tan_sweep * max_width / 4.0 root_chord = pax_compart_length - tan_sweep * max_width / 2.0 - else: - num_bays = num_bays_tmp if np.abs(num_bays_loc - num_bays) < 0.00001: break iter = iter + 1 if iter > 100: - warnings.warn(f'Number of iteration exceeded 100.') + if verbosity > Verbosity.BRIEF: + warnings.warn(f'Number of iteration in BWBDetailedCabinLayout exceeded 100.') break num_bays = smooth_int_tanh(num_bays, mu=40.0) From 5a957f7107e1033a1411c09016e9dcfe2d6435a4 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 30 Apr 2026 13:23:21 -0400 Subject: [PATCH 12/21] minor update --- aviary/subsystems/geometry/flops_based/fuselage.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/aviary/subsystems/geometry/flops_based/fuselage.py b/aviary/subsystems/geometry/flops_based/fuselage.py index 8627046ed..0142e5e06 100644 --- a/aviary/subsystems/geometry/flops_based/fuselage.py +++ b/aviary/subsystems/geometry/flops_based/fuselage.py @@ -686,9 +686,6 @@ def compute(self, inputs, outputs): # Enforce maximum bay width bay_width = max_width[0] / num_bays - import pdb - - pdb.set_trace() if bay_width > bay_width_max and bay_width_max > 0.0: bay_width = bay_width_max num_bays = max_width[0] / bay_width From 5cf9ce51a3fa9386350c4581643ecc7942128307 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 30 Apr 2026 14:05:40 -0400 Subject: [PATCH 13/21] minor update --- aviary/subsystems/geometry/flops_based/fuselage.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/aviary/subsystems/geometry/flops_based/fuselage.py b/aviary/subsystems/geometry/flops_based/fuselage.py index 0142e5e06..6f0f5f8f0 100644 --- a/aviary/subsystems/geometry/flops_based/fuselage.py +++ b/aviary/subsystems/geometry/flops_based/fuselage.py @@ -715,5 +715,3 @@ def compute(self, inputs, outputs): outputs[Aircraft.Fuselage.MAX_HEIGHT] = max_height outputs[Aircraft.Wing.ROOT_CHORD] = root_chord outputs['bay_width'] = bay_width - - # For improvement on using int function on num_bays, see issue #1084. From 33570b504921460abc9c3a90dc4a741f13174e84 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Thu, 30 Apr 2026 20:25:11 -0400 Subject: [PATCH 14/21] allow Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL to be anything in [1,3] --- .../flops_based/test/test_wing_detailed.py | 3 - .../mass/flops_based/wing_detailed.py | 86 +++++++++---------- aviary/variable_info/variable_meta_data.py | 2 +- 3 files changed, 44 insertions(+), 47 deletions(-) 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 c0fe1dad8..9ac5b2596 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py @@ -819,6 +819,3 @@ def test_case3(self): if __name__ == '__main__': unittest.main() - # test = DetailedWingBendingTest() - # test.setUp() - # test.test_extreme_engine_loc() diff --git a/aviary/subsystems/mass/flops_based/wing_detailed.py b/aviary/subsystems/mass/flops_based/wing_detailed.py index 717ba1647..2fd43f737 100644 --- a/aviary/subsystems/mass/flops_based/wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/wing_detailed.py @@ -5,7 +5,45 @@ from aviary.variable_info.enums import Verbosity from aviary.variable_info.functions import add_aviary_input, add_aviary_option, add_aviary_output -from aviary.variable_info.variables import Aircraft, Mission, Settings +from aviary.variable_info.variables import Aircraft, Settings + + +def load_intensity_by_factor(load_dist_factor, intn_stations): + """ + Calculate load intensity at wing integration stations for the given load_dist_factor. + + Parameters: + load_dist_factor (float): 0 or 1 <= load_dist_factor <= 3. + 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 + intn_stations (array): integration stations + + Note: In FLOPS, load_dist_factor can be 0 in which case load intensities are computed + based on input pressure distribution. + """ + if load_dist_factor == 1: + load_intensity = 1.0 - intn_stations + elif load_dist_factor == 2: + load_intensity = np.sqrt(1.0 - intn_stations**2) + elif load_dist_factor == 3: + load_intensity = np.ones(intn_stations + 1) + elif 1 < load_dist_factor < 2: + load_intensity = (load_intensity - 1.0) * np.sqrt(1.0 - intn_stations**2) + ( + 2.0 - load_intensity + ) * (1.0 - intn_stations) + elif 2 < load_dist_factor < 3: + load_intensity = (3.0 - load_intensity) * np.sqrt(1.0 - intn_stations**2) + ( + load_intensity - 2.0 + ) * np.ones(intn_stations + 1) + else: + raise om.AnalysisError( + f'{load_dist_factor} is not a valid value for ' + f'{Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL}, it must be between 1 and 3 (inclusive).' + ) + return load_intensity class DetailedWingBendingFact(om.ExplicitComponent): @@ -85,15 +123,6 @@ def compute(self, inputs, outputs): num_wing_engines = self.options[Aircraft.Engine.NUM_WING_ENGINES] num_engine_type = len(num_wing_engines) - # 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[Aircraft.Wing.LOAD_PATH_SWEEP_DISTRIBUTION] thickness_to_chord = inputs[Aircraft.Wing.THICKNESS_TO_CHORD_DISTRIBUTION] chord = inputs[Aircraft.Wing.CHORD_PER_SEMISPAN_DISTRIBUTION] @@ -138,18 +167,8 @@ def compute(self, inputs, outputs): (dy[1:] + 2.0 * integration_stations[1:-1]) * dy[1:] * sweep_int_stations[1:-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".' - ) + load_distribution_factor = self.options[Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL] + load_intensity = load_intensity_by_factor(load_distribution_factor, integration_stations) chord_interp = InterpND( method='slinear', points=(inp_stations), x_interp=integration_stations @@ -367,15 +386,6 @@ def compute(self, inputs, outputs): # 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_DISTRIBUTION'] load_path_sweep_mod = np.array(load_path_sweep[1:]) @@ -435,18 +445,8 @@ def compute(self, inputs, outputs): (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".' - ) + load_distribution_factor = self.options[Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL] + load_intensity = load_intensity_by_factor(load_distribution_factor, integration_stations) chord_interp = InterpND( method='slinear', points=(inp_stations_mod), x_interp=integration_stations diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index 4ef9a792b..fcd24b9b8 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -5690,7 +5690,7 @@ 'FLOPS': 'WTIN.PDIST', # ['&DEFINE.WTIN.PDIST', 'WDEF.PDIST'], }, units='unitless', - desc='controls spatial distribution of integration stations for detailed wing', + desc='controls spatial distribution of integration stations for detailed wing, in [1, 3]', default_value=2.0, option=True, ) From 373d1f2be0dca95b637ca8442807d36101dbc483 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 1 May 2026 11:05:35 -0400 Subject: [PATCH 15/21] roll back to main --- .../geometry/flops_based/fuselage.py | 66 +++--- .../flops_based/test/test_fuselage.py | 32 +-- .../flops_based/test/test_prep_geom.py | 74 +++---- .../flops_based/test/test_mass_summation.py | 12 +- .../flops_based/test/test_wing_detailed.py | 120 ----------- .../mass/flops_based/wing_detailed.py | 50 +++-- .../test/test_flops_based_premission.py | 197 +++++++++--------- .../benchmark_tests/test_bwb_FwFm.py | 6 +- .../test_data/bwb_detailed_FLOPS_data.py | 94 ++++----- 9 files changed, 261 insertions(+), 390 deletions(-) diff --git a/aviary/subsystems/geometry/flops_based/fuselage.py b/aviary/subsystems/geometry/flops_based/fuselage.py index 6f0f5f8f0..efc0aa749 100644 --- a/aviary/subsystems/geometry/flops_based/fuselage.py +++ b/aviary/subsystems/geometry/flops_based/fuselage.py @@ -4,7 +4,7 @@ import numpy as np import openmdao.api as om -from aviary.utils.math import smooth_int_tanh, d_smooth_int_tanh, smooth_min, d_smooth_min +from aviary.utils.math import smooth_int_tanh, d_smooth_int_tanh from aviary.variable_info.enums import Verbosity from aviary.variable_info.functions import add_aviary_input, add_aviary_option, add_aviary_output from aviary.variable_info.variables import Aircraft, Mission, Settings @@ -449,14 +449,6 @@ def setup_partials(self): ], ) - self.declare_partials( - of=[Aircraft.BWB.NUM_BAYS], - wrt=[ - Aircraft.Fuselage.MAX_WIDTH, - Aircraft.Fuselage.SIDEBODY_THICKNESS_TO_CHORD, - ], - ) - def compute(self, inputs, outputs): verbosity = self.options[Settings.VERBOSITY] @@ -485,16 +477,15 @@ def compute(self, inputs, outputs): # Enforce maximum number of bays num_bays_max = self.options[Aircraft.BWB.MAX_NUM_BAYS] - if num_bays_max > 0: - num_bays = smooth_min(max_width / bay_width_nom, num_bays_max, mu=50.0) - else: - num_bays = max_width / bay_width_nom + num_bays = int(0.5 + max_width / bay_width_nom) + if num_bays.real > num_bays_max and num_bays_max > 0: + num_bays = num_bays_max + outputs[Aircraft.BWB.NUM_BAYS] = smooth_int_tanh(num_bays, mu=20.0) outputs[Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH] = pax_compart_length outputs[Aircraft.Wing.ROOT_CHORD] = root_chord outputs[Aircraft.Fuselage.CABIN_AREA] = area_cabin outputs[Aircraft.Fuselage.MAX_HEIGHT] = max_height - outputs[Aircraft.BWB.NUM_BAYS] = smooth_int_tanh(num_bays, mu=20.0) def compute_partials(self, inputs, J): length = inputs[Aircraft.Fuselage.LENGTH] @@ -504,16 +495,6 @@ def compute_partials(self, inputs, J): tan_sweep = np.tan(sweep / 57.296) pax_compart_length = rear_spar_percent_chord * length height_to_width = inputs[Aircraft.Fuselage.SIDEBODY_THICKNESS_TO_CHORD] - bay_width_nom = 12.0 - - num_bays_max = self.options[Aircraft.BWB.MAX_NUM_BAYS] - dnum_bays_dmax_width = 1.0 / bay_width_nom - if num_bays_max > 0: - dnum_bays_dmax_width = ( - d_smooth_min(max_width / bay_width_nom, num_bays_max, mu=50.0) / bay_width_nom - ) - else: - dnum_bays_dmax_width = 1.0 / bay_width_nom J[Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH, Aircraft.Fuselage.LENGTH] = ( rear_spar_percent_chord @@ -541,8 +522,6 @@ def compute_partials(self, inputs, J): J[Aircraft.Fuselage.MAX_HEIGHT, Aircraft.Fuselage.LENGTH] = height_to_width J[Aircraft.Fuselage.MAX_HEIGHT, Aircraft.Fuselage.SIDEBODY_THICKNESS_TO_CHORD] = length - J[Aircraft.BWB.NUM_BAYS, Aircraft.Fuselage.MAX_WIDTH] = dnum_bays_dmax_width - class BWBDetailedCabinLayout(om.ExplicitComponent): """Compute BWB fuselage dimensions using cabin seat information.""" @@ -581,7 +560,6 @@ def setup_partials(self): self.declare_partials('*', '*', method='cs') def compute(self, inputs, outputs): - verbosity = self.options[Settings.VERBOSITY] rear_spar_percent_chord = inputs['Rear_spar_percent_chord'] sweep = inputs[Aircraft.BWB.PASSENGER_LEADING_EDGE_SWEEP] height_to_width = inputs[Aircraft.Fuselage.SIDEBODY_THICKNESS_TO_CHORD] @@ -623,7 +601,7 @@ def compute(self, inputs, outputs): if seat_pitch_economy <= 0: seat_pitch_economy = 32.0 # inch - # Determine unit seat areas for each type of passenger (ft**2) + # Determine unit seat areas for each type of passenger area_seat_business = bay_width_nom * seat_pitch_business / 12.0 / num_seat_abreast_business area_seat_first = bay_width_nom * seat_pitch_first / 12.0 / num_seat_abreast_first area_seat_economy = bay_width_nom * seat_pitch_economy / 12.0 / num_seat_abreast_economy @@ -654,20 +632,20 @@ def compute(self, inputs, outputs): area_service = num_lavas * area_lava + num_galleys * area_galley + num_closets * area_closet # Estimate number of bays based on these areas - num_bays = (area_seats + area_service) / 550.0 + num_bays = int(0.5 + (area_seats + area_service) / 550.0) if num_bays > num_bays_max and num_bays_max > 0: num_bays = num_bays_max + num_bays_loc = num_bays iter = 0 - bay_width = bay_width_nom while True: num_bays_loc = num_bays - # Cabin area wasted due to slanted != side wall - area_waste = num_bays * tan_sweep * (bay_width / 2.0) ** 2 + # Cabin area wasted due to slanted != side wall + area_waste = num_bays * tan_sweep * (bay_width_nom / 2.0) ** 2 # Aisle area for horseshoe (5'), cross (2') and rear (3') aisles # Aisles only go to center of outboard bays, hence num_bays-1 - area_aisle = 10.0 * (num_bays - 1) * bay_width + area_aisle = 10.0 * (num_bays - 1) * bay_width_nom # Total pressurized cabin area area_cabin = area_seats + area_service + area_waste + area_aisle @@ -680,30 +658,32 @@ def compute(self, inputs, outputs): pax_compart_length = root_chord + tan_sweep * max_width / 2.0 # Enforce maximum number of bays - num_bays = max_width[0] / bay_width - if num_bays.real > num_bays_max and num_bays_max > 0: + num_bays_tmp = 0.5 + max_width / bay_width_nom + if num_bays_tmp[0].real > num_bays_max and num_bays_max > 0: num_bays = num_bays_max + else: + num_bays = int(num_bays_tmp[0].real) # Enforce maximum bay width - bay_width = max_width[0] / num_bays + bay_width = max_width / num_bays if bay_width > bay_width_max and bay_width_max > 0.0: bay_width = bay_width_max - num_bays = max_width[0] / bay_width - if num_bays.real > num_bays_max and num_bays_max > 0: + num_bays_tmp = 0.999 + max_width / bay_width + if num_bays_tmp.real > num_bays_max and num_bays_max > 0: num_bays = num_bays_max max_width = num_bays_max * bay_width pax_compart_length = area_cabin / max_width + tan_sweep * max_width / 4.0 root_chord = pax_compart_length - tan_sweep * max_width / 2.0 + else: + num_bays = smooth_int_tanh(num_bays_tmp, mu=40.0) - if np.abs(num_bays_loc - num_bays) < 0.00001: + if num_bays_loc == num_bays: break iter = iter + 1 if iter > 100: - if verbosity > Verbosity.BRIEF: - warnings.warn(f'Number of iteration in BWBDetailedCabinLayout exceeded 100.') + warnings.warn(f'Number of iteration exceeded 100.') break - num_bays = smooth_int_tanh(num_bays, mu=40.0) length = pax_compart_length / rear_spar_percent_chord max_height = height_to_width * length outputs[Aircraft.BWB.NUM_BAYS] = num_bays @@ -715,3 +695,5 @@ def compute(self, inputs, outputs): outputs[Aircraft.Fuselage.MAX_HEIGHT] = max_height outputs[Aircraft.Wing.ROOT_CHORD] = root_chord outputs['bay_width'] = bay_width + + # For improvement on using int function on num_bays, see issue #1084. diff --git a/aviary/subsystems/geometry/flops_based/test/test_fuselage.py b/aviary/subsystems/geometry/flops_based/test/test_fuselage.py index 7960e0958..3983328a9 100644 --- a/aviary/subsystems/geometry/flops_based/test/test_fuselage.py +++ b/aviary/subsystems/geometry/flops_based/test/test_fuselage.py @@ -98,7 +98,7 @@ def test_case1(self): prob.run_model() num_bays = prob.get_val(Aircraft.BWB.NUM_BAYS) - assert_near_equal(num_bays, [5.00872038], tolerance=1e-9) + assert_near_equal(num_bays, [5], tolerance=1e-9) pax_compart_length = prob.get_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH) assert_near_equal(pax_compart_length, 96.25, tolerance=1e-9) root_chord = prob.get_val(Aircraft.Wing.ROOT_CHORD) @@ -146,22 +146,22 @@ def test_case1(self): prob.run_model() num_bays = prob.get_val(Aircraft.BWB.NUM_BAYS) - assert_near_equal(num_bays, 6.99994448, tolerance=1e-5) + assert_near_equal(num_bays, 7, tolerance=1e-9) fuselage_length = prob.get_val(Aircraft.Fuselage.LENGTH) - assert_near_equal(fuselage_length, 111.76379613, tolerance=1e-9) + assert_near_equal(fuselage_length, 112.30019369, tolerance=1e-9) pax_compart_length = prob.get_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH) - assert_near_equal(pax_compart_length, 78.23465729, tolerance=1e-9) + assert_near_equal(pax_compart_length, 78.61013558, tolerance=1e-9) fuselage_width = prob.get_val(Aircraft.Fuselage.MAX_WIDTH) - assert_near_equal(fuselage_width, 79.46979495, tolerance=1e-9) + assert_near_equal(fuselage_width, 80.22075607, tolerance=1e-9) fuselage_height = prob.get_val(Aircraft.Fuselage.MAX_HEIGHT) - assert_near_equal(fuselage_height, 12.29401757, tolerance=1e-9) + assert_near_equal(fuselage_height, 12.35302131, tolerance=1e-9) cabin_area = prob.get_val(Aircraft.Fuselage.CABIN_AREA) - assert_near_equal(cabin_area, 4638.43963915, tolerance=1e-9) + assert_near_equal(cabin_area, 4697.33181006, tolerance=1e-9) root_chord = prob.get_val(Aircraft.Wing.ROOT_CHORD) assert_near_equal(root_chord, 38.5, tolerance=1e-9) @@ -194,23 +194,23 @@ def test_case2(self): prob.set_val('Rear_spar_percent_chord', val=0.7, units='unitless') prob.run_model() - num_bays = prob.get_val(Aircraft.BWB.NUM_BAYS) - assert_near_equal(num_bays, 4, tolerance=1e-5) - fuselage_width = prob.get_val(Aircraft.Fuselage.MAX_WIDTH) - assert_near_equal(fuselage_width, 50.17622787, tolerance=1e-9) + assert_near_equal(fuselage_width, 49.77182929, tolerance=1e-9) + + num_bays = prob.get_val(Aircraft.BWB.NUM_BAYS) + assert_near_equal(num_bays, 4, tolerance=1e-9) fuselage_length = prob.get_val(Aircraft.Fuselage.LENGTH) - assert_near_equal(fuselage_length, 117.07640514, tolerance=1e-9) + assert_near_equal(fuselage_length, 116.57609631, tolerance=1e-9) pax_compart_length = prob.get_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH) - assert_near_equal(pax_compart_length, 81.9534836, tolerance=1e-9) + assert_near_equal(pax_compart_length, 81.60326742, tolerance=1e-9) fuselage_height = prob.get_val(Aircraft.Fuselage.MAX_HEIGHT) - assert_near_equal(fuselage_height, 12.87840457, tolerance=1e-9) + assert_near_equal(fuselage_height, 12.82337059, tolerance=1e-9) cabin_area = prob.get_val(Aircraft.Fuselage.CABIN_AREA) - assert_near_equal(cabin_area, 3021.9507202, tolerance=1e-9) + assert_near_equal(cabin_area, 2988.87966179, tolerance=1e-9) root_chord = prob.get_val(Aircraft.Wing.ROOT_CHORD) assert_near_equal(root_chord, 38.5, tolerance=1e-9) @@ -251,7 +251,7 @@ def test_case3(self): assert_near_equal(fuselage_width, 40.0, tolerance=1e-9) num_bays = prob.get_val(Aircraft.BWB.NUM_BAYS) - assert_near_equal(num_bays, 4.0, tolerance=1e-5) + assert_near_equal(num_bays, 4.0, tolerance=1e-9) fuselage_length = prob.get_val(Aircraft.Fuselage.LENGTH) assert_near_equal(fuselage_length, 131.4890549, tolerance=1e-9) 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 e82e26014..5679e5a84 100644 --- a/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py +++ b/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py @@ -913,7 +913,7 @@ def test_case1(self): # BWBSimpleCabinLayout num_bays = prob.get_val(Aircraft.BWB.NUM_BAYS) - assert_near_equal(num_bays, [5.00872038], tolerance=1e-9) + assert_near_equal(num_bays, [5], tolerance=1e-9) pax_compart_length = prob.get_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH) assert_near_equal(pax_compart_length, 96.25, tolerance=1e-8) root_chord = prob.get_val(Aircraft.Wing.ROOT_CHORD) @@ -1210,38 +1210,38 @@ def test_case1(self): # BWBDetailedCabinLayout num_bays = prob.get_val(Aircraft.BWB.NUM_BAYS) - assert_near_equal(num_bays, 6.99994448, tolerance=1e-9) + assert_near_equal(num_bays, [7], tolerance=1e-9) fuselage_length = prob.get_val(Aircraft.Fuselage.LENGTH) - assert_near_equal(fuselage_length, 111.76379613, tolerance=1e-9) + assert_near_equal(fuselage_length, 112.30019369, tolerance=1e-9) pax_compart_length = prob.get_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH) - assert_near_equal(pax_compart_length, 78.23465729, tolerance=1e-9) + assert_near_equal(pax_compart_length, 78.61013558, tolerance=1e-9) fuselage_width = prob.get_val(Aircraft.Fuselage.MAX_WIDTH) - assert_near_equal(fuselage_width, 79.46979495, tolerance=1e-9) + assert_near_equal(fuselage_width, 80.22075607, tolerance=1e-9) fuselage_height = prob.get_val(Aircraft.Fuselage.MAX_HEIGHT) - assert_near_equal(fuselage_height, 12.29401757, tolerance=1e-9) + assert_near_equal(fuselage_height, 12.35302131, tolerance=1e-9) cabin_area = prob.get_val(Aircraft.Fuselage.CABIN_AREA) - assert_near_equal(cabin_area, 4638.43963915, tolerance=1e-9) + assert_near_equal(cabin_area, 4697.33181006, tolerance=1e-9) root_chord = prob.get_val(Aircraft.Wing.ROOT_CHORD) assert_near_equal(root_chord, 38.5, tolerance=1e-9) # BWBUpdateDetailedWingDist out1 = prob.get_val('BWB_CHORD_PER_SEMISPAN_DISTRIBUTION') exp1 = [ - 111.763796, + 112.3001936861, 55.0, - 0.308016418, - 0.266385163, - 0.227497318, - 0.197937070, - 0.174000813, - 0.155619962, - 0.145469344, - 0.136004577, - 0.126402640, - 0.116869289, - 0.107335937, - 0.0978025855, - 0.0882692339, + 0.3071047525, + 0.2655967176, + 0.2268239733, + 0.197351217, + 0.1734858065, + 0.1551593595, + 0.1450387842, + 0.1356020317, + 0.1260285145, + 0.1165233797, + 0.1070182448, + 0.09751311, + 0.0880079752, ] assert_near_equal(out1, exp1, tolerance=1e-8) @@ -1270,31 +1270,31 @@ def test_case1(self): assert_near_equal(out3, exp3, tolerance=1e-8) # BWBFuselagePrelim - assert_near_equal(prob.get_val(Aircraft.Fuselage.REF_DIAMETER), 45.88190626, tolerance=1e-8) + assert_near_equal(prob.get_val(Aircraft.Fuselage.REF_DIAMETER), 46.28688869, tolerance=1e-8) assert_near_equal( - prob.get_val(Aircraft.Fuselage.PLANFORM_AREA), 6626.34234164, tolerance=1e-8 + prob.get_val(Aircraft.Fuselage.PLANFORM_AREA), 6710.47401437, tolerance=1e-8 ) # BWBWingPrelim - assert_near_equal(prob.get_val(Aircraft.Wing.AREA), 12025.74804674, tolerance=1e-8) - assert_near_equal(prob.get_val(Aircraft.Wing.ASPECT_RATIO), 5.37550108, tolerance=1e-8) - assert_near_equal(prob.get_val(Aircraft.Wing.LOAD_FRACTION), 0.47039383, tolerance=1e-8) + assert_near_equal(prob.get_val(Aircraft.Wing.AREA), 12109.8797157, tolerance=1e-8) + assert_near_equal(prob.get_val(Aircraft.Wing.ASPECT_RATIO), 5.36951675, tolerance=1e-8) + assert_near_equal(prob.get_val(Aircraft.Wing.LOAD_FRACTION), 0.46761342, tolerance=1e-8) # PrelimWettedArea assert_near_equal( - prob.get_val('prelim_swet.prep_geom:_Names:CROOT'), 71.79215992, tolerance=1e-8 + prob.get_val('prelim_swet.prep_geom:_Names:CROOT'), 72.0855305, tolerance=1e-8 ) assert_near_equal( - prob.get_val('prelim_swet.prep_geom:_Names:CROOTB'), 62.82057802, tolerance=1e-8 + prob.get_val('prelim_swet.prep_geom:_Names:CROOTB'), 63.02467273, tolerance=1e-8 ) assert_near_equal( - prob.get_val('prelim_swet.prep_geom:_Names:CROTM'), 0.87503396, tolerance=1e-8 + prob.get_val('prelim_swet.prep_geom:_Names:CROTM'), 0.87430407, tolerance=1e-8 ) assert_near_equal(prob.get_val('prelim_swet.prep_geom:_Names:CROTVT'), 0.0, tolerance=1e-7) assert_near_equal(prob.get_val('prelim_swet.prep_geom:_Names:CRTHTB'), 0.0, tolerance=1e-8) assert_near_equal(prob.get_val('prelim_swet.prep_geom:_Names:SPANHT'), 0.0, tolerance=1e-8) assert_near_equal(prob.get_val('prelim_swet.prep_geom:_Names:SPANVT'), 0.0, tolerance=1e-8) assert_near_equal( - prob.get_val('prelim_swet.prep_geom:_Names:XDX'), 45.88190626, tolerance=1e-8 + prob.get_val('prelim_swet.prep_geom:_Names:XDX'), 46.28688869, tolerance=1e-8 ) assert_near_equal( prob.get_val('prelim_swet.prep_geom:_Names:XMULT'), 2.04257, tolerance=1e-8 @@ -1306,7 +1306,7 @@ def test_case1(self): prob.get_val('prelim_swet.prep_geom:_Names:XMULTV'), 2.04257, tolerance=1e-8 ) # BWBWingWettedArea - assert_near_equal(prob.get_val(Aircraft.Wing.WETTED_AREA), 24541.8164668, tolerance=1e-8) + assert_near_equal(prob.get_val(Aircraft.Wing.WETTED_AREA), 24713.66128988, tolerance=1e-8) # TailWettedArea assert_near_equal(prob.get_val(Aircraft.HorizontalTail.WETTED_AREA), 0.0, tolerance=1e-8) assert_near_equal(prob.get_val(Aircraft.VerticalTail.WETTED_AREA), 0.0, tolerance=1e-8) @@ -1315,11 +1315,11 @@ def test_case1(self): # _FuselageRatios assert_near_equal( prob.get_val(Aircraft.Fuselage.DIAMETER_TO_WING_SPAN), - 0.1813730618, + 0.18243241, tolerance=1e-8, ) assert_near_equal( - prob.get_val(Aircraft.Fuselage.LENGTH_TO_DIAMETER), 2.43590132, tolerance=1e-8 + prob.get_val(Aircraft.Fuselage.LENGTH_TO_DIAMETER), 2.42617719, tolerance=1e-8 ) # NacelleWettedArea assert_near_equal( @@ -1330,7 +1330,7 @@ def test_case1(self): assert_near_equal(prob.get_val(Aircraft.Canard.WETTED_AREA), 0.0, tolerance=1e-8) # BWBWingCharacteristicLength assert_near_equal( - prob.get_val(Aircraft.Wing.CHARACTERISTIC_LENGTH), 47.53827645, tolerance=1e-8 + prob.get_val(Aircraft.Wing.CHARACTERISTIC_LENGTH), 47.72916456, tolerance=1e-8 ) assert_near_equal(prob.get_val(Aircraft.Wing.FINENESS), 0.11, tolerance=1e-8) # NacelleCharacteristicLength @@ -1342,9 +1342,9 @@ def test_case1(self): assert_near_equal(prob.get_val(Aircraft.Canard.CHARACTERISTIC_LENGTH), 0.0, tolerance=1e-8) assert_near_equal(prob.get_val(Aircraft.Canard.FINENESS), 0.0, tolerance=1e-8) assert_near_equal( - prob.get_val(Aircraft.Fuselage.CHARACTERISTIC_LENGTH), 111.76379613, tolerance=1e-8 + prob.get_val(Aircraft.Fuselage.CHARACTERISTIC_LENGTH), 112.30019369, tolerance=1e-8 ) - assert_near_equal(prob.get_val(Aircraft.Fuselage.FINENESS), 2.43590132, tolerance=1e-8) + assert_near_equal(prob.get_val(Aircraft.Fuselage.FINENESS), 2.42617719, tolerance=1e-8) assert_near_equal( prob.get_val(Aircraft.HorizontalTail.CHARACTERISTIC_LENGTH), 0.0, tolerance=1e-8 ) @@ -1355,7 +1355,7 @@ def test_case1(self): assert_near_equal(prob.get_val(Aircraft.VerticalTail.FINENESS), 0.11, tolerance=1e-8) # TotalWettedArea assert_near_equal( - prob.get_val(Aircraft.Design.TOTAL_WETTED_AREA), 26036.62112878, tolerance=1e-8 + prob.get_val(Aircraft.Design.TOTAL_WETTED_AREA), 26208.46595188, tolerance=1e-8 ) 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 a012fdc52..e60511ec7 100644 --- a/aviary/subsystems/mass/flops_based/test/test_mass_summation.py +++ b/aviary/subsystems/mass/flops_based/test/test_mass_summation.py @@ -33,8 +33,11 @@ class TotalSummationTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - @parameterized.expand(get_flops_case_names(), name_func=print_case) - def test_case(self, case_name): + # @parameterized.expand(get_flops_case_names(), name_func=print_case) + def test_case( + self, + ): + case_name = 'BWBdetailedFLOPS' prob = self.prob prob.model.add_subsystem( @@ -246,4 +249,7 @@ def test_case_multiengine(self): if __name__ == '__main__': - unittest.main() + # unittest.main() + test = TotalSummationTest() + test.setUp() + test.test_case() 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 9ac5b2596..e07f29d83 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py @@ -696,126 +696,6 @@ def test_case2(self): # current BWB data set does not check the following assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) - def test_case3(self): - """ - bwb detailed, investigation of partial of Aircraft.Wing.BENDING_MATERIAL_FACTOR - To see the problem, create sum_csw = np.sum(csw) as an output and see its partials. - Even if slinear is replaced by lagrange2, still get high partials. - """ - 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_DISTRIBUTION, - [0.0, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.6499, 0.7, 0.75, 0.8, 0.85, 0.8999, 0.95, 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, 80, units='unitless' - ) # 71 - 100 okay - - prob.model.add_subsystem( - 'bending', - BWBDetailedWingBendingFact(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) - - prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO, 5.37550108, units='unitless') - prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO_REFERENCE, 0.0, 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_REFERENCE, 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([19301.2621248]), units='lbm') - prob.set_val(Aircraft.Wing.SPAN, val=252.96979495033787) - prob.set_val(Aircraft.Fuselage.MAX_WIDTH, 79.46979495033786, 'ft') - - 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_DISTRIBUTION', - [ - 111.763796, - 55.0000000, - 0.308016418, - 0.266385163, - 0.227497318, - 0.197937070, - 0.174000813, - 0.155619962, - 0.145469344, - 0.136004577, - 0.126402640, - 0.116869289, - 0.107335937, - 0.0978025855, - 0.0882692339, - ], - units='unitless', - ) - prob.set_val( - 'BWB_THICKNESS_TO_CHORD_DISTRIBUTION', - [ - 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_DISTRIBUTION', - [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], - 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.98618988 - pod_inertia_expected = 1.0 - assert_near_equal(BENDING_MATERIAL_FACTOR, BENDING_MATERIAL_FACTOR_expected, tolerance=1e-8) - assert_near_equal(prob.get_val('calculated_wing_area'), 5399.40570654, tolerance=1e-9) - # current BWB data set does not check the following - assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) - - partial_data = prob.check_partials( - out_stream=None, - compact_print=True, - show_only_incorrect=True, - form='central', - method='fd', - ) - assert_check_partials(partial_data, atol=1e-3, rtol=1e-4) - if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/flops_based/wing_detailed.py b/aviary/subsystems/mass/flops_based/wing_detailed.py index 2fd43f737..e22f16f37 100644 --- a/aviary/subsystems/mass/flops_based/wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/wing_detailed.py @@ -309,6 +309,7 @@ def initialize(self): add_aviary_option(self, Aircraft.Wing.INPUT_STATION_DISTRIBUTION) add_aviary_option(self, Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL) add_aviary_option(self, Aircraft.Wing.NUM_INTEGRATION_STATIONS) + add_aviary_option(self, Aircraft.BWB.DETAILED_WING_PROVIDED) add_aviary_option(self, Settings.VERBOSITY) def setup(self): @@ -359,8 +360,6 @@ def setup_partials(self): def compute(self, inputs, outputs): verbosity = self.options[Settings.VERBOSITY] 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) width = inputs[Aircraft.Fuselage.MAX_WIDTH][0] wingspan = inputs[Aircraft.Wing.SPAN][0] rate_span = (wingspan - width) / wingspan @@ -368,20 +367,22 @@ def compute(self, inputs, outputs): bwb_input_station_dist = np.array( self.options[Aircraft.Wing.INPUT_STATION_DISTRIBUTION], dtype=float ) - bwb_input_station_dist = np.where( - bwb_input_station_dist <= 1.0, - bwb_input_station_dist * rate_span + width / wingspan, # if x <= 1.0 - bwb_input_station_dist + width / 2.0, # else - ) - bwb_input_station_dist[0] = 0.0 - bwb_input_station_dist[1] = width / 2.0 - - # in FLOPS, this is a step before calling BNDMAT - inp_stations_mod = np.where( - bwb_input_station_dist > 1.0, - 2 * bwb_input_station_dist / wingspan, - bwb_input_station_dist, - ) + if not self.options[Aircraft.BWB.DETAILED_WING_PROVIDED]: + bwb_input_station_dist[1] = width / 2.0 + else: + bwb_input_station_dist = np.where( + bwb_input_station_dist <= 1.0, + bwb_input_station_dist * rate_span + width / wingspan, # if x <= 1.0 + bwb_input_station_dist + width / 2.0, # else + ) + bwb_input_station_dist[0] = 0.0 + bwb_input_station_dist[1] = width / 2.0 + inp_stations_mod = [] + for x in bwb_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:] @@ -399,12 +400,13 @@ def compute(self, inputs, outputs): 'Assume it is the same as Aircraft.Wing.ASPECT_RATIO.' ) chord = inputs['BWB_CHORD_PER_SEMISPAN_DISTRIBUTION'] - # chord_mod = [] - chord_mod = np.where( - chord > 5.0, - 2 * chord / wingspan, - chord, - ) + 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) fstrt = inputs[Aircraft.Wing.STRUT_BRACING_FACTOR] faert = inputs[Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR] @@ -481,7 +483,7 @@ def compute(self, inputs, outputs): ) csw = 1.0 / np.cos(sweep_int_stations[:-1] * np.pi / 180.0) emi = (del_moment + dy * load_path_length[1:]) * csw - # em = np.sum(emi) + em = np.sum(emi) tc_interp = InterpND( method='slinear', points=(inp_stations_mod), x_interp=integration_stations @@ -519,6 +521,8 @@ def compute(self, inputs, outputs): outputs[Aircraft.Wing.BENDING_MATERIAL_FACTOR] = bt + num_wing_engines = self.options[Aircraft.Engine.NUM_WING_ENGINES] + num_engine_type = len(num_wing_engines) engine_locations = inputs[Aircraft.Engine.WING_LOCATIONS] gross_mass = inputs[Aircraft.Design.GROSS_MASS] # NOTE pod mass assumed the same for wing/non-wing mounted engines, only using diff --git a/aviary/subsystems/test/test_flops_based_premission.py b/aviary/subsystems/test/test_flops_based_premission.py index c11ed4404..bb14f4e2c 100644 --- a/aviary/subsystems/test/test_flops_based_premission.py +++ b/aviary/subsystems/test/test_flops_based_premission.py @@ -216,11 +216,8 @@ class BWBPreMissionGroupTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - # @parameterized.expand(get_flops_case_names(only=bwb_cases), name_func=print_case) - def test_case_all_subsystems( - self, - ): - case_name = 'BWBdetailedFLOPS' + @parameterized.expand(get_flops_case_names(only=bwb_cases), name_func=print_case) + def test_case_all_subsystems(self, case_name): flops_inputs = get_flops_inputs(case_name) flops_outputs = get_flops_outputs(case_name) @@ -284,8 +281,6 @@ def test_case_all_subsystems( input_keys=[], output_keys=[ # Geometry - # BWBComputeDetailedWingDist - Aircraft.Wing.SPAN, # BWBSimpleCabinLayout Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH, Aircraft.Wing.ROOT_CHORD, @@ -431,7 +426,6 @@ def test_case_all_subsystems( rtol=1e-6, check_values=True, check_partials=True, - excludes=['*bending_material_factor*'], ) def test_case_geom(self): @@ -538,7 +532,7 @@ def test_case_geom(self): assert_near_equal(prob[Aircraft.Wing.ROOT_CHORD], 63.96, tol) assert_near_equal(prob[Aircraft.Fuselage.CABIN_AREA], 5173.187202504683, tol) assert_near_equal(prob[Aircraft.Fuselage.MAX_HEIGHT], 15.125, tol) - assert_near_equal(prob[Aircraft.BWB.NUM_BAYS], 5.00872038, 1e-4) + assert_near_equal(prob[Aircraft.BWB.NUM_BAYS], 5.0, 1e-4) # BWBFuselagePrelim assert_near_equal(prob[Aircraft.Fuselage.REF_DIAMETER], 39.8525, tol) assert_near_equal(prob[Aircraft.Fuselage.PLANFORM_AREA], 7390.267432149546, tol) @@ -631,7 +625,7 @@ def test_case_geom_mass(self): # TransportEngineOilMass assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS], 346.93557352, tol) # BWBFurnishingsGroupMass - assert_near_equal(prob[Aircraft.Furnishings.MASS], 61509.57919465, tol) + assert_near_equal(prob[Aircraft.Furnishings.MASS], 61482.097969438299, tol) # TransportHydraulicsGroupMass assert_near_equal(prob[Aircraft.Hydraulics.MASS], 7368.5077321194321, tol) # PassengerServiceMass @@ -693,7 +687,9 @@ def test_case_geom_mass(self): # PropulsionMass assert_near_equal(prob[Aircraft.Propulsion.MASS], 61597.102467771889, tol) # SystemsEquipMass - assert_near_equal(prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 98876.385842, tol) + assert_near_equal( + prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 98848.9061107412710, tol + ) # EmptyMass assert_near_equal(prob[Aircraft.Design.EMPTY_MASS], 434037.32820147, tol) # OperatingMass @@ -780,46 +776,46 @@ def test_case_geom(self): # BWBComputeDetailedWingDist assert_near_equal(prob[Aircraft.Wing.SPAN], 253.720756, tol) # DetailedCabinLayout - assert_near_equal(prob[Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH], 78.23465729, tol) + assert_near_equal(prob[Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH], 78.61013558, tol) assert_near_equal(prob[Aircraft.Wing.ROOT_CHORD], 38.5, tol) - assert_near_equal(prob[Aircraft.Fuselage.CABIN_AREA], 4638.43963915, tol) - assert_near_equal(prob[Aircraft.Fuselage.MAX_HEIGHT], 12.29401757, tol) + assert_near_equal(prob[Aircraft.Fuselage.CABIN_AREA], 4697.33181006, tol) + assert_near_equal(prob[Aircraft.Fuselage.MAX_HEIGHT], 12.35302131, tol) assert_near_equal(prob[Aircraft.BWB.NUM_BAYS], 7.0, tol) # BWBFuselagePrelim - assert_near_equal(prob[Aircraft.Fuselage.REF_DIAMETER], 45.88190626, tol) - assert_near_equal(prob[Aircraft.Fuselage.PLANFORM_AREA], 6626.34234164, tol) + assert_near_equal(prob[Aircraft.Fuselage.REF_DIAMETER], 46.2868886894979, tol) + assert_near_equal(prob[Aircraft.Fuselage.PLANFORM_AREA], 6710.4740143724875, tol) # BWBWingPrelim - assert_near_equal(prob[Aircraft.Wing.AREA], 12059.52621246, tol) - assert_near_equal(prob[Aircraft.Wing.ASPECT_RATIO], 5.39216403, tol) - assert_near_equal(prob[Aircraft.Wing.ASPECT_RATIO_REFERENCE], 5.39216403, tol) - assert_near_equal(prob[Aircraft.Wing.LOAD_FRACTION], 0.47167013, tol) + assert_near_equal(prob[Aircraft.Wing.AREA], 12109.879719468739, tol) + assert_near_equal(prob[Aircraft.Wing.ASPECT_RATIO], 5.36951675, tol) + assert_near_equal(prob[Aircraft.Wing.ASPECT_RATIO_REFERENCE], 5.36951675, tol) + assert_near_equal(prob[Aircraft.Wing.LOAD_FRACTION], 0.46761341784858923, tol) # BWBWingWettedArea - assert_near_equal(prob[Aircraft.Wing.WETTED_AREA], 24610.64920629, tol) + assert_near_equal(prob[Aircraft.Wing.WETTED_AREA], 24713.66129084, tol) # TailWettedArea assert_near_equal(prob[Aircraft.HorizontalTail.WETTED_AREA], 0.0, tol) assert_near_equal(prob[Aircraft.VerticalTail.WETTED_AREA], 0.0, tol) # _FuselageRatios - assert_near_equal(prob[Aircraft.Fuselage.DIAMETER_TO_WING_SPAN], 0.18083624, tol) - assert_near_equal(prob[Aircraft.Fuselage.LENGTH_TO_DIAMETER], 2.43590132, tol) + assert_near_equal(prob[Aircraft.Fuselage.DIAMETER_TO_WING_SPAN], 0.18243240878599712, tol) + assert_near_equal(prob[Aircraft.Fuselage.LENGTH_TO_DIAMETER], 2.4261771932742167, tol) # NacelleWettedArea assert_near_equal(prob[Aircraft.Nacelle.WETTED_AREA], 498.26822066, tol) assert_near_equal(prob[Aircraft.Nacelle.TOTAL_WETTED_AREA], 3 * 498.26822066, tol) # Canard assert_near_equal(prob[Aircraft.Canard.WETTED_AREA], 0.0, tol) # BWBWingCharacteristicLength - assert_near_equal(prob[Aircraft.Wing.CHARACTERISTIC_LENGTH], 47.53070424, tol) + assert_near_equal(prob[Aircraft.Wing.CHARACTERISTIC_LENGTH], 47.72916456, tol) assert_near_equal(prob[Aircraft.Wing.FINENESS], 0.11, tol) # OtherCharacteristicLengths assert_near_equal(prob[Aircraft.Canard.CHARACTERISTIC_LENGTH], 0.0, tol) assert_near_equal(prob[Aircraft.Canard.FINENESS], 0.0, tol) - assert_near_equal(prob[Aircraft.Fuselage.CHARACTERISTIC_LENGTH], 111.76379613, tol) - assert_near_equal(prob[Aircraft.Fuselage.FINENESS], 2.43590132, tol) + assert_near_equal(prob[Aircraft.Fuselage.CHARACTERISTIC_LENGTH], 112.3001936860821, tol) + assert_near_equal(prob[Aircraft.Fuselage.FINENESS], 2.4261771932742167, tol) assert_near_equal(prob[Aircraft.HorizontalTail.CHARACTERISTIC_LENGTH], 0.0, tol) assert_near_equal(prob[Aircraft.HorizontalTail.FINENESS], 0.11, tol) assert_near_equal(prob[Aircraft.Nacelle.CHARACTERISTIC_LENGTH], [15.68611614], tol) assert_near_equal(prob[Aircraft.Nacelle.FINENESS], [1.38269353], tol) # TotalWettedArea - assert_near_equal(prob[Aircraft.Design.TOTAL_WETTED_AREA], 26105.45386827, tol) + assert_near_equal(prob[Aircraft.Design.TOTAL_WETTED_AREA], 26208.46595187, tol) def test_case_geom_mass(self): """ @@ -862,40 +858,40 @@ def test_case_geom_mass(self): # TransportEngineCtrlsMass assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_CONTROLS_MASS], 206.36860226, tol) # TransportAvionicsMass - assert_near_equal(prob[Aircraft.Avionics.MASS], 2763.47804131, tol) + assert_near_equal(prob[Aircraft.Avionics.MASS], 2778.5110590964073, tol) # FuelCapacityGroup - assert_near_equal(prob[Aircraft.Fuel.WING_FUEL_CAPACITY], 1187780.58456809, tol) - assert_near_equal(prob[Aircraft.Fuel.TOTAL_CAPACITY], 1187780.58456809, tol) + assert_near_equal(prob[Aircraft.Fuel.WING_FUEL_CAPACITY], 1197720.2419621395, tol) + assert_near_equal(prob[Aircraft.Fuel.TOTAL_CAPACITY], 1197720.2419621395, tol) # EngineMass assert_near_equal(prob[Aircraft.Engine.MASS], 17825.63336233, tol) assert_near_equal(prob[Aircraft.Engine.ADDITIONAL_MASS], 0.0, tol) assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_MASS], 53476.90008698, tol) # TransportFuelSystemMass - assert_near_equal(prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 5418.70316, tol) + assert_near_equal(prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 5444.9572934402777, tol) # TransportAirCondMass - assert_near_equal(prob[Aircraft.AirConditioning.MASS], 3871.27698278, tol) + assert_near_equal(prob[Aircraft.AirConditioning.MASS], 3897.6527857555625, tol) # TransportEngineOilMass assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS], 346.93557352, tol) # BWBFurnishingsGroupMass - assert_near_equal(prob[Aircraft.Furnishings.MASS], 57402.19908931, tol) + assert_near_equal(prob[Aircraft.Furnishings.MASS], 57747.97136452, tol) # TransportHydraulicsGroupMass - assert_near_equal(prob[Aircraft.Hydraulics.MASS], 6139.65550426, tol) + assert_near_equal(prob[Aircraft.Hydraulics.MASS], 6200.37391189, tol) # PassengerServiceMass assert_near_equal( prob[Aircraft.CrewPayload.PASSENGER_SERVICE_MASS], 10806.675950702213, tol ) # ElectricalMass - assert_near_equal(prob[Aircraft.Electrical.MASS], 4277.63057018, tol) + assert_near_equal(prob[Aircraft.Electrical.MASS], 4291.4778106479534, tol) # AntiIcingMass - assert_near_equal(prob[Aircraft.AntiIcing.MASS], 560.96510604, tol) + assert_near_equal(prob[Aircraft.AntiIcing.MASS], 562.09100951165135, tol) # TransportAPUMass - assert_near_equal(prob[Aircraft.APU.MASS], 2122.95946345, tol) + assert_near_equal(prob[Aircraft.APU.MASS], 2125.8280135763703, tol) # NonFlightCrewMass assert_near_equal(prob[Aircraft.CrewPayload.CABIN_CREW_MASS], 3810.0, tol) # FlightCrewMass assert_near_equal(prob[Aircraft.CrewPayload.FLIGHT_CREW_MASS], 450.0, tol) # TransportInstrumentMass - assert_near_equal(prob[Aircraft.Instruments.MASS], 1300.50317605, tol) + assert_near_equal(prob[Aircraft.Instruments.MASS], 1309.88942193, tol) # EngineMiscMass assert_near_equal(prob[Aircraft.Propulsion.TOTAL_MISC_MASS], 0.0, tol) # NacelleMass @@ -908,10 +904,10 @@ def test_case_geom_mass(self): # LandingMassGroup assert_near_equal(prob[Aircraft.Design.TOUCHDOWN_MASS_MAX], 699279.2, tol) # SurfaceControlMass - assert_near_equal(prob[Aircraft.Wing.SURFACE_CONTROL_MASS], 11701.85233893, tol) - assert_near_equal(prob[Aircraft.Wing.CONTROL_SURFACE_AREA], 4015.82222875, tol) + assert_near_equal(prob[Aircraft.Wing.SURFACE_CONTROL_MASS], 11731.15573539, tol) + assert_near_equal(prob[Aircraft.Wing.CONTROL_SURFACE_AREA], 4032.5967, tol) # BWBFuselageMass - assert_near_equal(prob[Aircraft.Fuselage.MASS], 136102.89191481, tol) + assert_near_equal(prob[Aircraft.Fuselage.MASS], 137935.30594648936, tol) # HorizontalTailMass assert_near_equal(prob[Aircraft.HorizontalTail.MASS], 0.0, tol) # VerticalTailMass @@ -922,30 +918,30 @@ def test_case_geom_mass(self): assert_near_equal(prob[Aircraft.Fins.MASS], 3159.3781042368792, tol) # WingMassGroup # BWBDetailedWingBendingFact - assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_FACTOR], 4.00585433, tol) + assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_FACTOR], 3.9705868, tol) assert_near_equal(prob[Aircraft.Wing.ENG_POD_INERTIA_FACTOR], 1.0, tol) # BWBWingMiscMass - assert_near_equal(prob[Aircraft.Wing.MISC_MASS], 9811.77743845, tol) + assert_near_equal(prob[Aircraft.Wing.MISC_MASS], 9720.4199027685518, tol) # WingShearControlMass - assert_near_equal(prob[Aircraft.Wing.SHEAR_CONTROL_MASS], 34818.23098605, tol) + assert_near_equal(prob[Aircraft.Wing.SHEAR_CONTROL_MASS], 34867.592407371565, tol) # WingBendingMass - assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_MASS], 9010.03041908, tol) + assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_MASS], 8856.01080887, tol) # BWBAftBodyMass - assert_near_equal(prob[Aircraft.Fuselage.AFTBODY_MASS], 18545.58195235, tol) - assert_near_equal(prob[Aircraft.Wing.BWB_AFTBODY_MASS], 15392.83302045, tol) + assert_near_equal(prob[Aircraft.Fuselage.AFTBODY_MASS], 18736.55008878, tol) + assert_near_equal(prob[Aircraft.Wing.BWB_AFTBODY_MASS], 15551.33657368, tol) # MassSummation # StructureMass - assert_near_equal(prob[Aircraft.Design.STRUCTURE_MASS], 239194.13868898, tol) + assert_near_equal(prob[Aircraft.Design.STRUCTURE_MASS], 240989.04053718, tol) # PropulsionMass - assert_near_equal(prob[Aircraft.Propulsion.MASS], 58895.60324675, tol) + assert_near_equal(prob[Aircraft.Propulsion.MASS], 58921.857380417721, tol) # SystemsEquipMass - assert_near_equal(prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 90140.52027232, tol) + assert_near_equal(prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 90644.95111232, tol) # EmptyMass - assert_near_equal(prob[Aircraft.Design.EMPTY_MASS], 388230.26220806, tol) + assert_near_equal(prob[Aircraft.Design.EMPTY_MASS], 390555.83436783, tol) # OperatingMass - assert_near_equal(prob[Mission.OPERATING_MASS], 409221.81531426, tol) + assert_near_equal(prob[Mission.OPERATING_MASS], 411552.22633412, tol) # ZeroFuelMass - assert_near_equal(prob[Mission.ZERO_FUEL_MASS], 507033.81531426, tol) + assert_near_equal(prob[Mission.ZERO_FUEL_MASS], 509364.22633412, tol) def test_case_all_subsystems(self): """ @@ -978,8 +974,8 @@ def test_case_all_subsystems(self): assert_near_equal(prob[Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST], 70000.0 * 3, tol) # Aerodynamics # Design - assert_near_equal(prob[Aircraft.Design.MACH], 0.89471085, tol) - assert_near_equal(prob[Aircraft.Design.LIFT_COEFFICIENT], 0.42922096, tol) + assert_near_equal(prob[Aircraft.Design.MACH], 0.89489036, tol) + assert_near_equal(prob[Aircraft.Design.LIFT_COEFFICIENT], 0.42836987, tol) @use_tempdirs @@ -1026,49 +1022,49 @@ def test_case_geom(self): # BWBComputeDetailedWingDist assert_near_equal(prob[Aircraft.Wing.SPAN], 186.631829293424, tol) # DetailedCabinLayout - assert_near_equal(prob[Aircraft.Fuselage.MAX_WIDTH], 50.17622787, tolerance=1e-9) - assert_near_equal(prob[Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH], 81.9534836, tol) + assert_near_equal(prob[Aircraft.Fuselage.MAX_WIDTH], 49.77182929, tolerance=1e-9) + assert_near_equal(prob[Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH], 81.60326742, tol) assert_near_equal(prob[Aircraft.Wing.ROOT_CHORD], 38.5, tol) - assert_near_equal(prob[Aircraft.Fuselage.CABIN_AREA], 3021.9507202, tol) - assert_near_equal(prob[Aircraft.Fuselage.MAX_HEIGHT], 20.9800918, tol) + assert_near_equal(prob[Aircraft.Fuselage.CABIN_AREA], 2988.879661796, tol) + assert_near_equal(prob[Aircraft.Fuselage.MAX_HEIGHT], 20.89043646, tol) assert_near_equal(prob[Aircraft.BWB.NUM_BAYS], 4.0, tol) # BWBFuselagePrelim - assert_near_equal(prob[Aircraft.Fuselage.REF_DIAMETER], 35.57815983, tol) - assert_near_equal(prob[Aircraft.Fuselage.PLANFORM_AREA], 4317.07245743, tol) + assert_near_equal(prob[Aircraft.Fuselage.REF_DIAMETER], 35.33113288, tol) + assert_near_equal(prob[Aircraft.Fuselage.PLANFORM_AREA], 4269.82808827, tol) # BWBWingPrelim - assert_near_equal(prob[Aircraft.Wing.AREA], 8454.35056774, tol) - assert_near_equal(prob[Aircraft.Wing.ASPECT_RATIO], 4.82172761, tol) + assert_near_equal(prob[Aircraft.Wing.AREA], 8421.7146805052689, tol) + assert_near_equal(prob[Aircraft.Wing.ASPECT_RATIO], 4.84361005, tol) assert_near_equal( - prob['AIRCRAFT_DATA_OVERRIDE:aircraft:wing:aspect_ratio_reference'], 4.82172761, tol + prob['AIRCRAFT_DATA_OVERRIDE:aircraft:wing:aspect_ratio_reference'], 4.84361005, tol ) # assert_near_equal(prob[Aircraft.Wing.LOAD_FRACTION], 0.46761341784858923, tol) # _BWBWing - assert_near_equal(prob[Aircraft.Wing.WETTED_AREA], 17370.05552974, tol) + assert_near_equal(prob[Aircraft.Wing.WETTED_AREA], 17302.04910213, tol) # _Tail assert_near_equal(prob[Aircraft.HorizontalTail.WETTED_AREA], 983.26501, tol) assert_near_equal(prob[Aircraft.VerticalTail.WETTED_AREA], 125.0, tol) # _FuselageRatios - assert_near_equal(prob[Aircraft.Fuselage.DIAMETER_TO_WING_SPAN], 0.19063286, tol) - assert_near_equal(prob[Aircraft.Fuselage.LENGTH_TO_DIAMETER], 3.29068186, tol) + assert_near_equal(prob[Aircraft.Fuselage.DIAMETER_TO_WING_SPAN], 0.18930926, tol) + assert_near_equal(prob[Aircraft.Fuselage.LENGTH_TO_DIAMETER], 3.29952897, tol) # Nacelles assert_near_equal(prob[Aircraft.Nacelle.WETTED_AREA], 613.74211034217353, tol) assert_near_equal(prob[Aircraft.Nacelle.TOTAL_WETTED_AREA], 2 * 613.7421103421735, tol) # Canard assert_near_equal(prob[Aircraft.Canard.WETTED_AREA], 0.0, tol) # BWBWingCharacteristicLength - assert_near_equal(prob[Aircraft.Wing.CHARACTERISTIC_LENGTH], 45.29961797, tol) + assert_near_equal(prob[Aircraft.Wing.CHARACTERISTIC_LENGTH], 45.124750222881779, tol) assert_near_equal(prob[Aircraft.Wing.FINENESS], 0.11, tol) # OtherCharacteristicLengths assert_near_equal(prob[Aircraft.Canard.CHARACTERISTIC_LENGTH], 0.0, tol) assert_near_equal(prob[Aircraft.Canard.FINENESS], 0.0, tol) - assert_near_equal(prob[Aircraft.Fuselage.CHARACTERISTIC_LENGTH], 117.07640514, tol) - assert_near_equal(prob[Aircraft.Fuselage.FINENESS], 3.29068186, tol) + assert_near_equal(prob[Aircraft.Fuselage.CHARACTERISTIC_LENGTH], 116.5760963133181, tol) + assert_near_equal(prob[Aircraft.Fuselage.FINENESS], 3.2995289656062941, tol) assert_near_equal(prob[Aircraft.HorizontalTail.CHARACTERISTIC_LENGTH], 26.45751311065, tol) assert_near_equal(prob[Aircraft.HorizontalTail.FINENESS], 0.1, tol) assert_near_equal(prob[Aircraft.Nacelle.CHARACTERISTIC_LENGTH], [17.367966592444596], tol) assert_near_equal(prob[Aircraft.Nacelle.FINENESS], [1.3761635770546583], tol) # TotalWettedArea - assert_near_equal(prob[Aircraft.Design.TOTAL_WETTED_AREA], 19705.80476042, tol) + assert_near_equal(prob[Aircraft.Design.TOTAL_WETTED_AREA], 19637.79833526, tol) def test_case_geom_mass(self): """ @@ -1112,38 +1108,38 @@ def test_case_geom_mass(self): # TransportEngineCtrlsMass assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_CONTROLS_MASS], 153.81807436, tol) # TransportAvionicsMass - assert_near_equal(prob[Aircraft.Avionics.MASS], 2290.95007773, tol) + assert_near_equal(prob[Aircraft.Avionics.MASS], 2280.13561342, tol) # FuelCapacityGroup - assert_near_equal(prob[Aircraft.Fuel.WING_FUEL_CAPACITY], 793608.88038917, tol) - assert_near_equal(prob[Aircraft.Fuel.TOTAL_CAPACITY], 793608.88038917, tol) + assert_near_equal(prob[Aircraft.Fuel.WING_FUEL_CAPACITY], 787493.65267018, tol) + assert_near_equal(prob[Aircraft.Fuel.TOTAL_CAPACITY], 787493.65267018, tol) # EngineMass assert_near_equal(prob[Aircraft.Engine.MASS], 44541.857940875525 / 2, tol) assert_near_equal(prob[Aircraft.Engine.ADDITIONAL_MASS], 0.0, tol) assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_MASS], 44541.857940875525, tol) # TransportFuelSystemMass - assert_near_equal(prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 3673.16899646, tol) + assert_near_equal(prob[Aircraft.Fuel.FUEL_SYSTEM_MASS], 3656.7260445688612, tol) # TransportAirCondMass - assert_near_equal(prob[Aircraft.AirConditioning.MASS], 3807.20118967, tol) + assert_near_equal(prob[Aircraft.AirConditioning.MASS], 3781.61256774, tol) # TransportEngineOilMass assert_near_equal(prob[Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS], 267.39241429019251, tol) # BWBFurnishingsGroupMass - assert_near_equal(prob[Aircraft.Furnishings.MASS], 52410.94244865, tol) + assert_near_equal(prob[Aircraft.Furnishings.MASS], 52096.553437128503, tol) # TransportHydraulicsGroupMass - assert_near_equal(prob[Aircraft.Hydraulics.MASS], 3996.6384617, tol) + assert_near_equal(prob[Aircraft.Hydraulics.MASS], 3962.6923427813854, tol) # PassengerServiceMass assert_near_equal(prob[Aircraft.CrewPayload.PASSENGER_SERVICE_MASS], 7029.593528180887, tol) # ElectricalMass - assert_near_equal(prob[Aircraft.Electrical.MASS], 2654.06975307, tol) + assert_near_equal(prob[Aircraft.Electrical.MASS], 2646.52723481, tol) # AntiIcingMass - assert_near_equal(prob[Aircraft.AntiIcing.MASS], 400.99917573, tol) + assert_near_equal(prob[Aircraft.AntiIcing.MASS], 400.3921819029477, tol) # TransportAPUMass - assert_near_equal(prob[Aircraft.APU.MASS], 1581.00217211, tol) + assert_near_equal(prob[Aircraft.APU.MASS], 1578.8098560285962, tol) # NonFlightCrewMass assert_near_equal(prob[Aircraft.CrewPayload.CABIN_CREW_MASS], 1640.0, tol) # FlightCrewMass assert_near_equal(prob[Aircraft.CrewPayload.FLIGHT_CREW_MASS], 450.0, tol) # TransportInstrumentMass - assert_near_equal(prob[Aircraft.Instruments.MASS], 967.59344999, tol) + assert_near_equal(prob[Aircraft.Instruments.MASS], 961.543462363, tol) # EngineMiscMass assert_near_equal(prob[Aircraft.Propulsion.TOTAL_MISC_MASS], 0.0, tol) # NacelleMass @@ -1156,10 +1152,10 @@ def test_case_geom_mass(self): # LandingMassGroup assert_near_equal(prob[Aircraft.Design.TOUCHDOWN_MASS_MAX], 420000.0, tol) # SurfaceControlMass - assert_near_equal(prob[Aircraft.Wing.SURFACE_CONTROL_MASS], 8112.00284687, tol) - assert_near_equal(prob[Aircraft.Wing.CONTROL_SURFACE_AREA], 2536.30517032, tol) + assert_near_equal(prob[Aircraft.Wing.SURFACE_CONTROL_MASS], 8093.1997108029764, tol) + assert_near_equal(prob[Aircraft.Wing.CONTROL_SURFACE_AREA], 2526.5144041515805, tol) # BWBFuselageMass - assert_near_equal(prob[Aircraft.Fuselage.MASS], 81157.44843467, tol) + assert_near_equal(prob[Aircraft.Fuselage.MASS], 80216.313556241628, tol) # HorizontalTailMass assert_near_equal(prob[Aircraft.HorizontalTail.MASS], 6444.9988831532046, tol) # VerticalTailMass @@ -1170,30 +1166,30 @@ def test_case_geom_mass(self): assert_near_equal(prob[Aircraft.Fins.MASS], 2822.1415450307886, tol) # WingMassGroup # BWBDetailedWingBendingFact, In FLOPS run, 6.7996347825592336 - assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_FACTOR], 6.75079525, tol) + assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_FACTOR], 6.79961928, tol) assert_near_equal(prob[Aircraft.Wing.ENG_POD_INERTIA_FACTOR], 1.0, tol) # BWBWingMiscMass - assert_near_equal(prob[Aircraft.Wing.MISC_MASS], 6938.99205472, tol) + assert_near_equal(prob[Aircraft.Wing.MISC_MASS], 6975.77622754, tol) # WingShearControlMass - assert_near_equal(prob[Aircraft.Wing.SHEAR_CONTROL_MASS], 24493.35004333, tol) + assert_near_equal(prob[Aircraft.Wing.SHEAR_CONTROL_MASS], 24461.161868706797, tol) # WingBendingMass - assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_MASS], 17876.82972382, tol) + assert_near_equal(prob[Aircraft.Wing.BENDING_MATERIAL_MASS], 18001.88182061, tol) # BWBAftBodyMass - assert_near_equal(prob[Aircraft.Fuselage.AFTBODY_MASS], 10478.08779866, tol) - assert_near_equal(prob[Aircraft.Wing.BWB_AFTBODY_MASS], 8964.00411176, tol) + assert_near_equal(prob[Aircraft.Fuselage.AFTBODY_MASS], 10384.964957095559, tol) + assert_near_equal(prob[Aircraft.Wing.BWB_AFTBODY_MASS], 8884.3375208, tol) # MassSummation # StructureMass 158921.83401643133 - assert_near_equal(prob[Aircraft.Design.STRUCTURE_MASS], 167990.52160543, tol) + assert_near_equal(prob[Aircraft.Design.STRUCTURE_MASS], 167099.36823103, tol) # PropulsionMass - assert_near_equal(prob[Aircraft.Propulsion.MASS], 48215.02693733, tol) + assert_near_equal(prob[Aircraft.Propulsion.MASS], 48198.583985444384, tol) # SystemsEquipMass - assert_near_equal(prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 76221.39957552, tol) + assert_near_equal(prob[Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS], 75801.466406974854, tol) # EmptyMass - assert_near_equal(prob[Aircraft.Design.EMPTY_MASS], 292426.94811828, tol) + assert_near_equal(prob[Aircraft.Design.EMPTY_MASS], 291099.46121048, tol) # OperatingMass - assert_near_equal(prob[Mission.OPERATING_MASS], 326632.14480333, tol) + assert_near_equal(prob[Mission.OPERATING_MASS], 325301.28625612, tol) # ZeroFuelMass - assert_near_equal(prob[Mission.ZERO_FUEL_MASS], 389332.14480333, tol) + assert_near_equal(prob[Mission.ZERO_FUEL_MASS], 388001.28625612, tol) # FinMass assert_near_equal(prob[Aircraft.Fins.MASS], 2822.14154503, tol) @@ -1227,9 +1223,12 @@ def test_case_all_subsystems(self): # Only aero parameters are checked because geometry and mass are checked in test_case_geom() already. tol = 1e-4 # Design - assert_near_equal(prob[Aircraft.Design.MACH], 0.8995951, tol) - assert_near_equal(prob[Aircraft.Design.LIFT_COEFFICIENT], 0.40724438, tol) + assert_near_equal(prob[Aircraft.Design.MACH], 0.89939238, tol) + assert_near_equal(prob[Aircraft.Design.LIFT_COEFFICIENT], 0.40810915, tol) if __name__ == '__main__': unittest.main() + test = BWBPreMissionGroupTest() + test.setUp() + # test.test_case_all_subsystems() diff --git a/aviary/validation_cases/benchmark_tests/test_bwb_FwFm.py b/aviary/validation_cases/benchmark_tests/test_bwb_FwFm.py index 6ee911dc8..a0ede1e4b 100644 --- a/aviary/validation_cases/benchmark_tests/test_bwb_FwFm.py +++ b/aviary/validation_cases/benchmark_tests/test_bwb_FwFm.py @@ -198,19 +198,19 @@ def test_bench_bwb300_FwFm_SNOPT(self): # There are no truth values for these. assert_near_equal( prob.get_val(Mission.GROSS_MASS, units='lbm'), - 618370.76963151, + 615233.67861433, tolerance=rtol, ) assert_near_equal( prob.get_val(Mission.OPERATING_MASS, units='lbm'), - 328794.4056369, + 327094.09117139, tolerance=rtol, ) assert_near_equal( prob.get_val(Mission.TOTAL_FUEL, units='lbm'), - 226876.36399461, + 225439.58744294, tolerance=rtol, ) diff --git a/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py b/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py index fb7e056a5..bf1332f14 100644 --- a/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py +++ b/aviary/validation_cases/validation_data/test_data/bwb_detailed_FLOPS_data.py @@ -297,17 +297,17 @@ # --------------------------- # In FLOPS, DOWE = 411552.31557733245 because DOWE = WOWE -outputs.set_val(Aircraft.Design.EMPTY_MASS, 387978.09236156, 'lbm') # DOWE +outputs.set_val(Aircraft.Design.EMPTY_MASS, 390555.9072055, 'lbm') # DOWE outputs.set_val(Aircraft.Design.EMPTY_MASS_MARGIN, 0.0, 'lbm') # WMARG -outputs.set_val(Aircraft.Design.STRUCTURE_MASS, 238976.54475555, 'lbm') # WSTRCT 240989.14132753 -outputs.set_val(Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, 90114.25264997, 'lbm') # WSYS -outputs.set_val(Aircraft.Design.TOTAL_WETTED_AREA, 26036.62112878, 'ft**2') # TWET +outputs.set_val(Aircraft.Design.STRUCTURE_MASS, 240989.11337145, 'lbm') # WSTRCT 240989.14132753 +outputs.set_val(Aircraft.Design.SYSTEMS_AND_EQUIPMENT_MASS, 90644.95111232, 'lbm') # WSYS +outputs.set_val(Aircraft.Design.TOTAL_WETTED_AREA, 26208.46595187, 'ft**2') # TWET outputs.set_val(Aircraft.Design.TOUCHDOWN_MASS_MAX, 699279.2, 'lbm') # WLDG = GW*WRATIO -outputs.set_val(Aircraft.AirConditioning.MASS, 3871.27698278, 'lbm') # WAC -outputs.set_val(Aircraft.AntiIcing.MASS, 560.04037229, 'lbm') # WAI -outputs.set_val(Aircraft.APU.MASS, 2122.95946345, 'lbm') # WAPU -outputs.set_val(Aircraft.Avionics.MASS, 2763.47804131, 'lbm') # WAVONC +outputs.set_val(Aircraft.AirConditioning.MASS, 3897.6527857555625, 'lbm') # WAC +outputs.set_val(Aircraft.AntiIcing.MASS, 562.09100951165135, 'lbm') # WAI +outputs.set_val(Aircraft.APU.MASS, 2125.8280135763703, 'lbm') # WAPU +outputs.set_val(Aircraft.Avionics.MASS, 2778.5110590964073, 'lbm') # WAVONC outputs.set_val(Aircraft.BWB.NUM_BAYS, 7.0, 'unitless') # NBAY outputs.set_val(Aircraft.Canard.CHARACTERISTIC_LENGTH, 0.0, 'ft') # EL[-1] @@ -325,31 +325,31 @@ outputs.set_val(Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS, 97812.0, 'lbm') # WPASS+WPBAG+WCARGO outputs.set_val(Aircraft.CrewPayload.PASSENGER_PAYLOAD_MASS, 97812.0, 'lbm') # WPASS+WPBAG -outputs.set_val(Aircraft.Electrical.MASS, 4277.63057018, 'lbm') # WELEC +outputs.set_val(Aircraft.Electrical.MASS, 4291.4778106479534, 'lbm') # WELEC -outputs.set_val(Aircraft.Fuel.TOTAL_CAPACITY, 1184642.3647993, 'lbm') # FMXTOT -outputs.set_val(Aircraft.Fuel.FUEL_SYSTEM_MASS, 5410.39486929, 'lbm') # WFSYS -outputs.set_val(Aircraft.Fuel.UNUSABLE_FUEL_MASS, 1725.1605645, 'lbm') # WUF -outputs.set_val(Aircraft.Fuel.WING_FUEL_CAPACITY, 1184642.3647993, 'lbm') # FULWMX +outputs.set_val(Aircraft.Fuel.TOTAL_CAPACITY, 1197720.2419621395, 'lbm') # FMXTOT +outputs.set_val(Aircraft.Fuel.FUEL_SYSTEM_MASS, 5444.9572934402777, 'lbm') # WFSYS +outputs.set_val(Aircraft.Fuel.UNUSABLE_FUEL_MASS, 1732.78186198, 'lbm') # WUF +outputs.set_val(Aircraft.Fuel.WING_FUEL_CAPACITY, 1197720.2419621395, 'lbm') # FULWMX outputs.set_val(Aircraft.Fins.MASS, 3159.3781042368792, 'lbm') # WFIN -outputs.set_val(Aircraft.Furnishings.MASS, 57402.19908931, 'lbm') # WFURN +outputs.set_val(Aircraft.Furnishings.MASS, 57747.97136452, 'lbm') # WFURN -outputs.set_val(Aircraft.Fuselage.CABIN_AREA, 4638.43963915, 'ft**2') # ACABIN -ref_diameter = 45.88190626 +outputs.set_val(Aircraft.Fuselage.CABIN_AREA, 4697.33181006, 'ft**2') # ACABIN +ref_diameter = 46.2868886894979 outputs.set_val(Aircraft.Fuselage.REF_DIAMETER, ref_diameter, 'ft') # XD -outputs.set_val(Aircraft.Fuselage.CHARACTERISTIC_LENGTH, 111.76379613, 'ft') # EL(4) +outputs.set_val(Aircraft.Fuselage.CHARACTERISTIC_LENGTH, 112.3001936860821, 'ft') # EL(4) outputs.set_val(Aircraft.Fuselage.CROSS_SECTION, np.pi * (ref_diameter / 2.0) ** 2.0, 'ft**2') -outputs.set_val(Aircraft.Fuselage.DIAMETER_TO_WING_SPAN, 0.18137306) # DB -outputs.set_val(Aircraft.Fuselage.FINENESS, 2.43590132) # FR(4) -outputs.set_val(Aircraft.Fuselage.LENGTH_TO_DIAMETER, 2.43590132) # BODYLD -outputs.set_val(Aircraft.Fuselage.MASS, 136102.89191481, 'lbm') # WFUSE -outputs.set_val(Aircraft.Fuselage.MAX_HEIGHT, 12.29401757, 'ft') # DF -outputs.set_val(Aircraft.Fuselage.PLANFORM_AREA, 6626.34234164, 'ft**2') # FPAREA -outputs.set_val(Aircraft.Fuselage.AFTBODY_MASS, 18545.58195235, 'lbm') # WAFTB -outputs.set_val(Aircraft.Fuselage.LENGTH, 111.76379613, 'ft') # XL -outputs.set_val(Aircraft.Fuselage.MAX_WIDTH, 79.46979495, 'ft') # WF -outputs.set_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH, 78.23465729, 'ft') # XLP +outputs.set_val(Aircraft.Fuselage.DIAMETER_TO_WING_SPAN, 0.18243240878599712) # DB +outputs.set_val(Aircraft.Fuselage.FINENESS, 2.4261771932742167) # FR(4) +outputs.set_val(Aircraft.Fuselage.LENGTH_TO_DIAMETER, 2.4261771932742167) # BODYLD +outputs.set_val(Aircraft.Fuselage.MASS, 137935.30594648936, 'lbm') # WFUSE +outputs.set_val(Aircraft.Fuselage.MAX_HEIGHT, 12.35302131, 'ft') # DF +outputs.set_val(Aircraft.Fuselage.PLANFORM_AREA, 6710.4740143724875, 'ft**2') # FPAREA +outputs.set_val(Aircraft.Fuselage.AFTBODY_MASS, 18736.55008878, 'lbm') # WAFTB +outputs.set_val(Aircraft.Fuselage.LENGTH, 112.3001936860821, 'ft') # XL +outputs.set_val(Aircraft.Fuselage.MAX_WIDTH, 80.220756073526772, 'ft') # WF +outputs.set_val(Aircraft.Fuselage.PASSENGER_COMPARTMENT_LENGTH, 78.61013558, 'ft') # XLP outputs.set_val(Aircraft.HorizontalTail.CHARACTERISTIC_LENGTH, 0.0, 'ft') # EL(2) outputs.set_val(Aircraft.HorizontalTail.FINENESS, 0.11) # FR(2) @@ -358,9 +358,9 @@ outputs.set_val(Aircraft.Design.EMPENNAGE_MASS, 3159.3781042368792, 'lbm') -outputs.set_val(Aircraft.Hydraulics.MASS, 6133.98944949, 'lbm') # WHYD +outputs.set_val(Aircraft.Hydraulics.MASS, 6200.37391189, 'lbm') # WHYD -outputs.set_val(Aircraft.Instruments.MASS, 1300.50317605, 'lbm') # WIN +outputs.set_val(Aircraft.Instruments.MASS, 1309.88942193, 'lbm') # WIN outputs.set_val(Aircraft.LandingGear.MAIN_GEAR_MASS, 28200.322805698346, 'lbm') # WLGM outputs.set_val(Aircraft.LandingGear.NOSE_GEAR_MASS, 2698.6740002098945, 'lbm') # WLGN @@ -375,7 +375,7 @@ outputs.set_val(Aircraft.Paint.MASS, 0.0, 'lbm') # WPAINT, WTPNT -outputs.set_val(Aircraft.Propulsion.MASS, 58887.29495605, 'lbm') # WPRO +outputs.set_val(Aircraft.Propulsion.MASS, 58921.857380417721, 'lbm') # WPRO outputs.set_val(Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, 70000.0 * 3, 'lbf') outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 3) outputs.set_val(Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS, 346.93557352, 'lbm') # WOIL @@ -404,27 +404,27 @@ outputs.set_val(Aircraft.VerticalTail.MASS, 0.0, 'lbm') # WVT outputs.set_val(Aircraft.VerticalTail.WETTED_AREA, 0.0, 'ft**2') -outputs.set_val(Aircraft.Wing.BWB_AFTBODY_MASS, 15392.83302045, 'lbm') # W4 -outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR, 3.98518394) # FLOPS BT = 3.9724796254619563 -outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS, 8916.98295485, 'lbm') # W1 -outputs.set_val(Aircraft.Wing.CHARACTERISTIC_LENGTH, 47.53827645, 'ft') # EL(1) -outputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA, 4004.57409956, 'ft**2') # SFLAP +outputs.set_val(Aircraft.Wing.BWB_AFTBODY_MASS, 15551.33657368, 'lbm') # W4 +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR, 3.9705868) # FLOPS BT = 3.9724796254619563 +outputs.set_val(Aircraft.Wing.BENDING_MATERIAL_MASS, 8856.083631, 'lbm') # W1 +outputs.set_val(Aircraft.Wing.CHARACTERISTIC_LENGTH, 47.72916456, 'ft') # EL(1) +outputs.set_val(Aircraft.Wing.CONTROL_SURFACE_AREA, 4032.5967, 'ft**2') # SFLAP outputs.set_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR, 1.0) # CAYE outputs.set_val(Aircraft.Wing.FINENESS, 0.11) # FR(1) outputs.set_val(Aircraft.Wing.MISC_MASS, 9720.4199027685518, 'lbm') # W3 -outputs.set_val(Aircraft.Wing.SHEAR_CONTROL_MASS, 34785.04205251, 'lbm') # W2 -outputs.set_val(Aircraft.Wing.SURFACE_CONTROL_MASS, 11682.1755051, 'lbm') # WSC -outputs.set_val(Aircraft.Wing.ASPECT_RATIO, 5.37550108) # AR -outputs.set_val(Aircraft.Wing.ASPECT_RATIO_REFERENCE, 5.37550108) # ARREF -outputs.set_val(Aircraft.Wing.MASS, 68815.27793059, 'lbm') # WWING 68995.460470895763 +outputs.set_val(Aircraft.Wing.SHEAR_CONTROL_MASS, 34867.592407371565, 'lbm') # W2 +outputs.set_val(Aircraft.Wing.SURFACE_CONTROL_MASS, 11731.15573539, 'lbm') # WSC +outputs.set_val(Aircraft.Wing.ASPECT_RATIO, 5.36951675) # AR +outputs.set_val(Aircraft.Wing.ASPECT_RATIO_REFERENCE, 5.36951675) # ARREF +outputs.set_val(Aircraft.Wing.MASS, 68995.43251482, 'lbm') # WWING 68995.460470895763 outputs.set_val(Aircraft.Wing.ROOT_CHORD, 38.5, 'ft') # XLW -outputs.set_val(Aircraft.Wing.AREA, 12025.74804674, 'ft**2') # SW -outputs.set_val(Aircraft.Wing.LOAD_FRACTION, 0.47039383) # PCTL -outputs.set_val(Aircraft.Wing.WETTED_AREA, 24541.8164668, 'ft**2') # SWET(1) -outputs.set_val(Aircraft.Wing.SPAN, 252.96979495033787, 'ft') # SPAN = WF+OSSPAN*2 +outputs.set_val(Aircraft.Wing.AREA, 12109.879719468739, 'ft**2') # SW +outputs.set_val(Aircraft.Wing.LOAD_FRACTION, 0.46761341784858923) # PCTL +outputs.set_val(Aircraft.Wing.WETTED_AREA, 24713.661297561481, 'ft**2') # SWET(1) +outputs.set_val(Aircraft.Wing.SPAN, 253.720756, 'ft') # SPAN = WF+OSSPAN*2 -outputs.set_val(Mission.USEFUL_LOAD, 20988.77208872, 'lbm') +outputs.set_val(Mission.USEFUL_LOAD, 20996.3933862, 'lbm') outputs.set_val(Aircraft.Design.MACH, 0.800) -outputs.set_val(Mission.OPERATING_MASS, 408966.86445029, 'lbm') # WOWE -outputs.set_val(Mission.ZERO_FUEL_MASS, 506778.86445029, 'lbm') # WZF +outputs.set_val(Mission.OPERATING_MASS, 411552.29917206, 'lbm') # WOWE +outputs.set_val(Mission.ZERO_FUEL_MASS, 509364.29917206, 'lbm') # WZF From 53db7c73543e186bb15a9ea044005d3fea4c1efe Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 1 May 2026 12:08:33 -0400 Subject: [PATCH 16/21] a bug fix --- aviary/subsystems/mass/flops_based/wing_detailed.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/subsystems/mass/flops_based/wing_detailed.py b/aviary/subsystems/mass/flops_based/wing_detailed.py index e22f16f37..dae7bd4e6 100644 --- a/aviary/subsystems/mass/flops_based/wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/wing_detailed.py @@ -29,7 +29,7 @@ def load_intensity_by_factor(load_dist_factor, intn_stations): elif load_dist_factor == 2: load_intensity = np.sqrt(1.0 - intn_stations**2) elif load_dist_factor == 3: - load_intensity = np.ones(intn_stations + 1) + load_intensity = np.ones(len(intn_stations)) elif 1 < load_dist_factor < 2: load_intensity = (load_intensity - 1.0) * np.sqrt(1.0 - intn_stations**2) + ( 2.0 - load_intensity @@ -37,7 +37,7 @@ def load_intensity_by_factor(load_dist_factor, intn_stations): elif 2 < load_dist_factor < 3: load_intensity = (3.0 - load_intensity) * np.sqrt(1.0 - intn_stations**2) + ( load_intensity - 2.0 - ) * np.ones(intn_stations + 1) + ) * np.ones(len(intn_stations)) else: raise om.AnalysisError( f'{load_dist_factor} is not a valid value for ' From a27c3caa1355a908cfd8b35d22354c3fc922c2f7 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 1 May 2026 14:14:12 -0400 Subject: [PATCH 17/21] added a unit test for Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL = 3 --- .../flops_based/test/test_wing_detailed.py | 69 ++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) 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 e07f29d83..2bcc1c2c0 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py @@ -6,6 +6,7 @@ from openmdao.utils.testing_utils import use_tempdirs from parameterized import parameterized + from aviary.subsystems.mass.flops_based.wing_detailed import ( BWBDetailedWingBendingFact, DetailedWingBendingFact, @@ -21,6 +22,7 @@ print_case, ) from aviary.variable_info.functions import setup_model_options +from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Mission, Settings omit_cases = ['LargeSingleAisle2FLOPS'] @@ -420,6 +422,68 @@ def test_extreme_engine_loc(self): pod_inertia_factor = prob.get_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR) assert_near_equal(pod_inertia_factor, 1.0, tolerance=1e-10) + def test_intensity_factor(self): + """ + data taken from high_wing_single_aisle.csv + Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL = 3 + """ + options = get_option_defaults() + options.set_val(Aircraft.Engine.NUM_ENGINES, val=[2], units='unitless') + options.set_val(Aircraft.Engine.NUM_WING_ENGINES, val=[2], units='unitless') + options.set_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, val=2, units='unitless') + options.set_val( + Aircraft.Wing.INPUT_STATION_DISTRIBUTION, val=[0.0, 0.5, 1.0], units='unitless' + ) + options.set_val(Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL, val=3, units='unitless') + options.set_val(Aircraft.Wing.NUM_INTEGRATION_STATIONS, val=46, units='unitless') + + prob = self.prob + self.prob.model.add_subsystem( + 'wing', + DetailedWingBendingFact(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) + + prob.model.set_input_defaults( + Aircraft.Wing.LOAD_PATH_SWEEP_DISTRIBUTION, val=[23, 22.0], units='deg' + ) + prob.model.set_input_defaults( + Aircraft.Wing.THICKNESS_TO_CHORD_DISTRIBUTION, val=[0.1, 0.1, 0.1], units='unitless' + ) + prob.model.set_input_defaults( + Aircraft.Wing.CHORD_PER_SEMISPAN_DISTRIBUTION, val=[0.13, 0.115, 0.06], units='unitless' + ) + prob.model.set_input_defaults(Aircraft.Design.GROSS_MASS, val=150000.0, units='lbm') + prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO, val=9.40817168, units='unitless') + prob.model.set_input_defaults( + Aircraft.Wing.ASPECT_RATIO_REFERENCE, val=0.01, units='unitless' + ) + prob.model.set_input_defaults( + Aircraft.Wing.STRUT_BRACING_FACTOR, val=1.01, units='unitless' + ) + prob.model.set_input_defaults( + Aircraft.Wing.AEROELASTIC_TAILORING_FACTOR, val=0.01, units='unitless' + ) + prob.model.set_input_defaults(Aircraft.Wing.THICKNESS_TO_CHORD, val=0.1, units='unitless') + prob.model.set_input_defaults( + Aircraft.Wing.THICKNESS_TO_CHORD_REFERENCE, val=0.01, units='unitless' + ) + + setup_model_options(prob, options) + prob.setup(check=False, force_alloc_complex=True) + + prob.set_val(Aircraft.Engine.POD_MASS, np.array([5587.40886136]), units='lbm') + prob.set_val(Aircraft.Engine.WING_LOCATIONS, [0.22]) + + prob.run_model() + + bending_mat_factor = prob.get_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR) + assert_near_equal(bending_mat_factor, 2762.96028422, tolerance=1e-9) + + pod_inertia_factor = prob.get_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR) + assert_near_equal(pod_inertia_factor, 0.97729985, tolerance=1e-9) + def test_IO(self): assert_match_varnames(self.prob.model) @@ -698,4 +762,7 @@ def test_case2(self): if __name__ == '__main__': - unittest.main() + # unittest.main() + test = DetailedWingBendingTest() + test.setUp() + test.test_intensity_factor() From 11c13c3b8dc5643a727429be0f7ab2e6af718fc9 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 1 May 2026 14:51:03 -0400 Subject: [PATCH 18/21] changed the value of Aircraft.Wing.ASPECT_RATIO_REFERENCE to match Aircraft.Wing.ASPECT_RATIO. Then the bending material factor is more reasonable. --- .../mass/flops_based/test/test_wing_detailed.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 2bcc1c2c0..44f84410d 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py @@ -457,8 +457,8 @@ def test_intensity_factor(self): prob.model.set_input_defaults(Aircraft.Design.GROSS_MASS, val=150000.0, units='lbm') prob.model.set_input_defaults(Aircraft.Wing.ASPECT_RATIO, val=9.40817168, units='unitless') prob.model.set_input_defaults( - Aircraft.Wing.ASPECT_RATIO_REFERENCE, val=0.01, units='unitless' - ) + Aircraft.Wing.ASPECT_RATIO_REFERENCE, val=9.40817168, units='unitless' + ) # it was 0.01 in high_wing_single_aisle.csv prob.model.set_input_defaults( Aircraft.Wing.STRUT_BRACING_FACTOR, val=1.01, units='unitless' ) @@ -479,10 +479,10 @@ def test_intensity_factor(self): prob.run_model() bending_mat_factor = prob.get_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR) - assert_near_equal(bending_mat_factor, 2762.96028422, tolerance=1e-9) + assert_near_equal(bending_mat_factor, 2.9367664396, tolerance=1e-9) pod_inertia_factor = prob.get_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR) - assert_near_equal(pod_inertia_factor, 0.97729985, tolerance=1e-9) + assert_near_equal(pod_inertia_factor, 0.9772998541, tolerance=1e-9) def test_IO(self): assert_match_varnames(self.prob.model) From 276683691edbf8755d42a046c6eebc46f6e648fe Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 1 May 2026 15:28:55 -0400 Subject: [PATCH 19/21] test load intensity for more factors --- .../flops_based/test/test_wing_detailed.py | 35 ++++++++++++++++++- .../mass/flops_based/wing_detailed.py | 8 ++--- 2 files changed, 38 insertions(+), 5 deletions(-) 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 44f84410d..15135e3bf 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py @@ -425,7 +425,7 @@ def test_extreme_engine_loc(self): def test_intensity_factor(self): """ data taken from high_wing_single_aisle.csv - Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL = 3 + Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL = 3, 1, 1.5, 2.5 """ options = get_option_defaults() options.set_val(Aircraft.Engine.NUM_ENGINES, val=[2], units='unitless') @@ -484,6 +484,39 @@ def test_intensity_factor(self): pod_inertia_factor = prob.get_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR) assert_near_equal(pod_inertia_factor, 0.9772998541, tolerance=1e-9) + options.set_val(Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL, val=1, units='unitless') + setup_model_options(prob, options) + prob.setup(check=False, force_alloc_complex=True) + prob.run_model() + + bending_mat_factor = prob.get_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR) + assert_near_equal(bending_mat_factor, 1.51247369, tolerance=1e-9) + + pod_inertia_factor = prob.get_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR) + assert_near_equal(pod_inertia_factor, 1.0, tolerance=1e-9) + + options.set_val(Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL, val=1.5, units='unitless') + setup_model_options(prob, options) + prob.setup(check=False, force_alloc_complex=True) + prob.run_model() + + bending_mat_factor = prob.get_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR) + assert_near_equal(bending_mat_factor, 1.94203494, tolerance=1e-9) + + pod_inertia_factor = prob.get_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR) + assert_near_equal(pod_inertia_factor, 1.0, tolerance=1e-9) + + options.set_val(Aircraft.Wing.LOAD_DISTRIBUTION_CONTROL, val=2.5, units='unitless') + setup_model_options(prob, options) + prob.setup(check=False, force_alloc_complex=True) + prob.run_model() + + bending_mat_factor = prob.get_val(Aircraft.Wing.BENDING_MATERIAL_FACTOR) + assert_near_equal(bending_mat_factor, 2.61652282, tolerance=1e-9) + + pod_inertia_factor = prob.get_val(Aircraft.Wing.ENG_POD_INERTIA_FACTOR) + assert_near_equal(pod_inertia_factor, 1.0, tolerance=1e-9) + def test_IO(self): assert_match_varnames(self.prob.model) diff --git a/aviary/subsystems/mass/flops_based/wing_detailed.py b/aviary/subsystems/mass/flops_based/wing_detailed.py index dae7bd4e6..2f4187ae6 100644 --- a/aviary/subsystems/mass/flops_based/wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/wing_detailed.py @@ -31,12 +31,12 @@ def load_intensity_by_factor(load_dist_factor, intn_stations): elif load_dist_factor == 3: load_intensity = np.ones(len(intn_stations)) elif 1 < load_dist_factor < 2: - load_intensity = (load_intensity - 1.0) * np.sqrt(1.0 - intn_stations**2) + ( - 2.0 - load_intensity + load_intensity = (load_dist_factor - 1.0) * np.sqrt(1.0 - intn_stations**2) + ( + 2.0 - load_dist_factor ) * (1.0 - intn_stations) elif 2 < load_dist_factor < 3: - load_intensity = (3.0 - load_intensity) * np.sqrt(1.0 - intn_stations**2) + ( - load_intensity - 2.0 + load_intensity = (3.0 - load_dist_factor) * np.sqrt(1.0 - intn_stations**2) + ( + load_dist_factor - 2.0 ) * np.ones(len(intn_stations)) else: raise om.AnalysisError( From eeba67ec44ef9fc7758e1bf5bdf8781155380e95 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Fri, 1 May 2026 15:37:45 -0400 Subject: [PATCH 20/21] minor update --- .../mass/flops_based/test/test_wing_detailed.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 15135e3bf..7bbd2b959 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py @@ -795,7 +795,7 @@ def test_case2(self): if __name__ == '__main__': - # unittest.main() - test = DetailedWingBendingTest() - test.setUp() - test.test_intensity_factor() + unittest.main() + # test = DetailedWingBendingTest() + # test.setUp() + # test.test_intensity_factor() From 1de6e91f8b4a1bbb63b5c18a57b047bf630162d5 Mon Sep 17 00:00:00 2001 From: Xun Jiang Date: Mon, 4 May 2026 14:18:42 -0400 Subject: [PATCH 21/21] added comments --- .../subsystems/mass/flops_based/test/test_wing_detailed.py | 6 +++--- aviary/subsystems/mass/flops_based/wing_detailed.py | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) 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 7bbd2b959..dfd750fe4 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py @@ -36,7 +36,7 @@ class DetailedWingBendingTest(unittest.TestCase): def setUp(self): self.prob = om.Problem() - # Skip model that doesn't use detailed wing and BWB cases. + # Skip models that don't use detailed wing and skip BWB cases. @parameterized.expand(get_flops_case_names(omit=omit_cases), name_func=print_case) def test_case(self, case_name): prob = self.prob @@ -704,7 +704,8 @@ def test_case1(self): 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 + # For BWB with non wing engines, inertia_factor_prod = 1 always. + # Need a different dataset with wing engines to check this one assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) def test_case2(self): @@ -790,7 +791,6 @@ def test_case2(self): 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'), 4151.88659141, tolerance=1e-9) - # current BWB data set does not check the following assert_near_equal(pod_inertia, pod_inertia_expected, tolerance=1e-9) diff --git a/aviary/subsystems/mass/flops_based/wing_detailed.py b/aviary/subsystems/mass/flops_based/wing_detailed.py index 2f4187ae6..6611d0c0c 100644 --- a/aviary/subsystems/mass/flops_based/wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/wing_detailed.py @@ -529,7 +529,6 @@ def compute(self, inputs, outputs): # wing mounted pods here pod_mass = inputs[Aircraft.Engine.POD_MASS] 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)