def test_mission_group_without_loop(cleanup): input_file_path = pth.join(DATA_FOLDER_PATH, "test_mission.xml") vars = VariableIO(input_file_path).read() ivc = vars.to_ivc() with pytest.raises(FastMissionFileMissingMissionNameError): run_system( Mission( propulsion_id="test.wrapper.propulsion.dummy_engine", out_file=pth.join(RESULTS_FOLDER_PATH, "test_unlooped_mission_group.csv"), use_initializer_iteration=False, mission_file_path=pth.join(DATA_FOLDER_PATH, "test_mission.yml"), adjust_fuel=False, ), ivc, ) problem = run_system( Mission( propulsion_id="test.wrapper.propulsion.dummy_engine", out_file=pth.join(RESULTS_FOLDER_PATH, "test_unlooped_mission_group.csv"), use_initializer_iteration=False, mission_file_path=pth.join(DATA_FOLDER_PATH, "test_mission.yml"), mission_name="operational", adjust_fuel=False, ), ivc, ) assert_allclose(problem["data:mission:operational:needed_block_fuel"], 6589.0, atol=1.0) assert_allclose(problem["data:mission:operational:block_fuel"], 15000.0, atol=1.0)
def test_loop_compute_oew(): """ Tests a weight computation loop matching the max payload criterion. """ # With payload from npax reader = VariableIO( pth.join(pth.dirname(__file__), "data", "mass_breakdown_inputs.xml")) reader.path_separator = ":" input_vars = reader.read(ignore=[ "data:weight:aircraft:MLW", "data:weight:aircraft:MZFW", "data:weight:aircraft:max_payload", ]).to_ivc() mass_computation = run_system(MassBreakdown(), input_vars) oew = mass_computation["data:weight:aircraft:OWE"] assert oew == pytest.approx(41591, abs=1) # with payload as input reader = VariableIO( pth.join(pth.dirname(__file__), "data", "mass_breakdown_inputs.xml")) reader.path_separator = ":" input_vars = reader.read(ignore=[ "data:weight:aircraft:MLW", "data:weight:aircraft:MZFW", ]).to_ivc() mass_computation = run_system(MassBreakdown(payload_from_npax=False), input_vars) oew = mass_computation["data:weight:aircraft:OWE"] assert oew == pytest.approx(42060, abs=1)
def test_breguet_with_rubber_engine(): ivc = om.IndepVarComp() ivc.add_output("data:mission:sizing:main_route:cruise:altitude", 35000, units="ft") ivc.add_output("data:TLAR:cruise_mach", 0.78) ivc.add_output("data:TLAR:range", 500, units="NM") ivc.add_output("data:TLAR:NPAX", 150) ivc.add_output("data:aerodynamics:aircraft:cruise:L_D_max", 16.0) ivc.add_output("data:weight:aircraft:MTOW", 74000, units="kg") ivc.add_output("data:propulsion:rubber_engine:bypass_ratio", 5) ivc.add_output("data:propulsion:rubber_engine:maximum_mach", 0.95) ivc.add_output("data:propulsion:rubber_engine:design_altitude", 35000, units="ft") ivc.add_output("data:propulsion:MTO_thrust", 100000, units="N") ivc.add_output("data:propulsion:rubber_engine:overall_pressure_ratio", 30) ivc.add_output("data:propulsion:rubber_engine:turbine_inlet_temperature", 1500, units="K") # With rubber engine OM component group = om.Group() group.add_subsystem("breguet", OMBreguet(), promotes=["*"]) group.add_subsystem("engine", OMRubberEngineComponent(), promotes=["*"]) group.nonlinear_solver = om.NonlinearBlockGS() problem = run_system(group, ivc) assert_allclose(problem["data:mission:sizing:ZFW"], 65076.0, atol=1) assert_allclose(problem["data:mission:sizing:fuel"], 8924.0, atol=1) assert_allclose(problem["data:mission:sizing:fuel:unitary"], 0.0642, rtol=1e-3) # With direct call to rubber engine problem2 = run_system( OMBreguet(propulsion_id="fastoad.wrapper.propulsion.rubber_engine"), ivc) assert_allclose(problem2["data:mission:sizing:ZFW"], 65076.0, atol=1) assert_allclose(problem2["data:mission:sizing:fuel"], 8924.0, atol=1) assert_allclose(problem2["data:mission:sizing:fuel:unitary"], 0.0642, rtol=1e-3) engine = RubberEngine(5, 30, 1500, 100000, 0.95, 35000 * foot, -50) directly_computed_flight_point = FlightPoint( mach=0.78, altitude=35000 * foot, engine_setting=EngineSetting.CRUISE, thrust=problem["data:propulsion:required_thrust"], ) engine.compute_flight_points(directly_computed_flight_point) assert_allclose( directly_computed_flight_point.sfc, problem["data:propulsion:SFC"], )
def test_breguet(): # test 1 ivc = om.IndepVarComp() ivc.add_output("data:mission:sizing:main_route:cruise:altitude", 35000, units="ft") ivc.add_output("data:TLAR:cruise_mach", 0.78) ivc.add_output("data:TLAR:range", 500, units="NM") ivc.add_output("data:TLAR:NPAX", 150) ivc.add_output("data:aerodynamics:aircraft:cruise:L_D_max", 16.0) ivc.add_output("data:propulsion:SFC", 1e-5, units="kg/N/s") ivc.add_output("data:weight:aircraft:MTOW", 74000, units="kg") problem = run_system(OMBreguet(), ivc) assert_allclose(problem["data:mission:sizing:ZFW"], 65617.0, rtol=1e-3) assert_allclose(problem["data:mission:sizing:fuel"], 8382.0, rtol=1e-3) assert_allclose(problem["data:mission:sizing:fuel:unitary"], 0.0604, rtol=1e-3) assert_allclose(problem["data:mission:sizing:fuel:unitary"], 0.0604, rtol=1e-3) assert_allclose( problem.get_val("data:mission:sizing:main_route:climb:distance", units="km"), 250.0 ) assert_allclose( problem.get_val("data:mission:sizing:main_route:descent:distance", units="km"), 250.0 ) assert_allclose( problem.get_val("data:mission:sizing:main_route:cruise:distance", units="km"), 426.0 ) # test 2 ivc = om.IndepVarComp() ivc.add_output("data:mission:sizing:main_route:cruise:altitude", 35000, units="ft") ivc.add_output("data:TLAR:cruise_mach", 0.78) ivc.add_output("data:TLAR:range", 1500, units="NM") ivc.add_output("data:TLAR:NPAX", 120) ivc.add_output("data:aerodynamics:aircraft:cruise:L_D_max", 16.0) ivc.add_output("data:propulsion:SFC", 1e-5, units="kg/N/s") ivc.add_output("data:weight:aircraft:MTOW", 74000, units="kg") problem = run_system(OMBreguet(), ivc) assert_allclose(problem["data:mission:sizing:ZFW"], 62473.0, rtol=1e-3) assert_allclose(problem["data:mission:sizing:fuel"], 11526.0, rtol=1e-3) assert_allclose(problem["data:mission:sizing:fuel:unitary"], 0.0346, rtol=1e-3) # Check consistency of other outputs assert_allclose( problem["data:mission:sizing:fuel"], problem["data:mission:sizing:main_route:fuel"] + problem["data:mission:sizing:fuel_reserve"], rtol=1e-3, ) assert_allclose( problem["data:mission:sizing:main_route:fuel"], problem["data:mission:sizing:main_route:climb:fuel"] + problem["data:mission:sizing:main_route:cruise:fuel"] + problem["data:mission:sizing:main_route:descent:fuel"], rtol=1e-3, )
def test_avl_sizing(): """ Test simple AVL computation with sizing option (nz=2.5) and simplified rectangular swept wing """ if pth.exists(AVL_RESULTS): shutil.rmtree(AVL_RESULTS) input_list = [ "data:geometry:wing:span", "data:geometry:wing:area", "data:geometry:wing:sweep_0", "data:geometry:wing:MAC:length", "data:geometry:wing:MAC:at25percent:x", "tuning:aerostructural:aerodynamic:chordwise_spacing:k", ] # Test with only wing and fuselage ------------------------------------------------------------- load_case = { "weight": 78000, "altitude": 30000, "mach": 0.84, "load_factor": 2.5 } components = ["wing"] sections = [12] ivc = get_ivc_for_components(components, sections, input_list, load_case) avl_comp = AVL(components=components, components_sections=sections) problem = run_system(avl_comp, ivc) forces_test = np.loadtxt(pth.join(pth.dirname(__file__), "data", "forces_results_wing_2p5g"), skiprows=1) np.testing.assert_allclose( problem["data:aerostructural:aerodynamic:wing:forces"], forces_test, rtol=1e-3) # Test for complete aircraft (wing, fuselage, tails) ------------------------------------------- components = ["wing", "horizontal_tail", "vertical_tail"] sections = [12, 11, 5] ivc = get_ivc_for_components(components, sections, input_list, load_case) avl_comp = AVL(components=components, components_sections=sections) problem = run_system(avl_comp, ivc) forces_test = np.loadtxt(pth.join(pth.dirname(__file__), "data", "forces_results_full_2p5g"), skiprows=1) forces_fast = np.vstack(( problem["data:aerostructural:aerodynamic:wing:forces"], problem["data:aerostructural:aerodynamic:horizontal_tail:forces"], problem["data:aerostructural:aerodynamic:vertical_tail:forces"], )) np.testing.assert_allclose(forces_fast, forces_test)
def test_compute_wing_area(): # Driven by fuel ivc = om.IndepVarComp() ivc.add_output("data:geometry:wing:aspect_ratio", 9.48) ivc.add_output("data:geometry:wing:root:thickness_ratio", 0.15) ivc.add_output("data:geometry:wing:tip:thickness_ratio", 0.11) ivc.add_output("data:weight:aircraft:sizing_block_fuel", val=20500, units="kg") ivc.add_output("data:TLAR:approach_speed", val=132, units="kn") ivc.add_output("data:weight:aircraft:MLW", val=66300, units="kg") ivc.add_output("data:weight:aircraft:MFW", val=21000, units="kg") ivc.add_output("data:aerodynamics:aircraft:landing:CL_max", val=2.80) problem = run_system(ComputeWingArea(), ivc) assert_allclose(problem["data:geometry:wing:area"], 133.97, atol=1e-2) assert_allclose( problem["data:aerodynamics:aircraft:landing:additional_CL_capacity"], 0.199, atol=1e-2) assert_allclose(problem["data:weight:aircraft:additional_fuel_capacity"], 500.0, atol=1.0) # Driven by CL max ivc = om.IndepVarComp() ivc.add_output("data:geometry:wing:aspect_ratio", 9.48) ivc.add_output("data:geometry:wing:root:thickness_ratio", 0.15) ivc.add_output("data:geometry:wing:tip:thickness_ratio", 0.11) ivc.add_output("data:weight:aircraft:sizing_block_fuel", val=15000, units="kg") ivc.add_output("data:TLAR:approach_speed", val=132, units="kn") ivc.add_output("data:weight:aircraft:MLW", val=66300, units="kg") ivc.add_output("data:weight:aircraft:MFW", val=21000, units="kg") ivc.add_output("data:aerodynamics:aircraft:landing:CL_max", val=2.80) problem = run_system(ComputeWingArea(), ivc) assert_allclose(problem["data:geometry:wing:area"], 124.38, atol=1e-2) assert_allclose( problem["data:aerodynamics:aircraft:landing:additional_CL_capacity"], 0.0, atol=1e-2) assert_allclose(problem["data:weight:aircraft:additional_fuel_capacity"], 6000.0, atol=1.0)
def test_vtp_props(): input_list = [ "data:geometry:vertical_tail:root:chord", "data:geometry:vertical_tail:tip:chord", "data:geometry:vertical_tail:thickness_ratio", "data:geometry:vertical_tail:span", "data:geometry:fuselage:maximum_height", ] ivc = get_indep_var_comp(input_list) nodes = np.zeros((6, 3)) z = np.linspace(2.02994, 8.93118, 3) nodes[:, 2] = np.tile(z, 2) ivc.add_output("data:aerostructural:structure:vertical_tail:nodes", nodes) problem = run_system(VtailBeamProps(number_of_sections=2), ivc) a = problem[ "data:aerostructural:structure:vertical_tail:beam_properties"][:, 0] i1 = problem[ "data:aerostructural:structure:vertical_tail:beam_properties"][:, 1] i2 = problem[ "data:aerostructural:structure:vertical_tail:beam_properties"][:, 2] j = problem[ "data:aerostructural:structure:vertical_tail:beam_properties"][:, 3] assert a[:2] == approx(np.array([3.6514e-2, 2.3734e-2]), abs=1e-5) assert i1[:2] == approx(np.array([3.0052e-3, 8.253e-4]), abs=1e-6) assert i2[:2] == approx(np.array([3.7565e-2, 1.0316e-2]), abs=1e-6) assert j[:2] == approx(np.array([9.3913e-3, 2.5791e-3]), abs=1e-6)
def test_htp_props(): input_list = [ "data:geometry:horizontal_tail:span", "data:geometry:horizontal_tail:root:chord", "data:geometry:horizontal_tail:tip:chord", "data:geometry:horizontal_tail:thickness_ratio", ] ivc = get_indep_var_comp(input_list) nodes = np.zeros((6, 3)) y = np.linspace(0.0, 6.13961, 3) nodes[:, 1] = np.tile(y, 2) ivc.add_output("data:aerostructural:structure:horizontal_tail:nodes", nodes) problem = run_system(HtailBeamProps(number_of_sections=2), ivc) a = problem[ "data:aerostructural:structure:horizontal_tail:beam_properties"][:, 0] i1 = problem[ "data:aerostructural:structure:horizontal_tail:beam_properties"][:, 1] i2 = problem[ "data:aerostructural:structure:horizontal_tail:beam_properties"][:, 2] j = problem[ "data:aerostructural:structure:horizontal_tail:beam_properties"][:, 3] assert a[:2] == approx(np.array([2.6435e-2, 1.7183e-2]), abs=1e-5) assert i1[:2] == approx(np.array([1.1403e-3, 3.1315e-4]), abs=1e-6) assert i2[:2] == approx(np.array([1.4254e-2, 3.9144e-3]), abs=1e-6) assert j[:2] == approx(np.array([3.5634e-3, 9.7860e-4]), abs=1e-6)
def test_geometry_wing_l2_l3(input_xml): """ Tests computation of the wing chords (l2 and l3) """ input_list = [ "data:geometry:wing:span", "data:geometry:fuselage:maximum_width", "data:geometry:wing:taper_ratio", "data:geometry:wing:sweep_25", "data:geometry:wing:root:virtual_chord", "data:geometry:wing:tip:chord", "data:geometry:wing:root:y", "data:geometry:wing:kink:y", "data:geometry:wing:tip:y", ] input_vars = input_xml.read(only=input_list).to_ivc() component = ComputeL2AndL3Wing() problem = run_system(component, input_vars) wing_l2 = problem["data:geometry:wing:root:chord"] assert wing_l2 == pytest.approx(6.26, abs=1e-2) wing_l3 = problem["data:geometry:wing:kink:chord"] assert wing_l3 == pytest.approx(3.985, abs=1e-3)
def test_compute_fuselage_basic(input_xml): """ Tests computation of the fuselage with no cabin sizing """ input_list = [ "data:geometry:cabin:NPAX1", "data:geometry:fuselage:length", "data:geometry:fuselage:maximum_width", "data:geometry:fuselage:maximum_height", "data:geometry:fuselage:front_length", "data:geometry:fuselage:rear_length", "data:geometry:fuselage:PAX_length", ] input_vars = input_xml.read(only=input_list).to_ivc() problem = run_system(ComputeFuselageGeometryBasic(), input_vars) cg_systems_c6 = problem["data:weight:systems:flight_kit:CG:x"] assert cg_systems_c6 == pytest.approx(9.19, abs=1e-2) cg_furniture_d2 = problem["data:weight:furniture:passenger_seats:CG:x"] assert cg_furniture_d2 == pytest.approx(14.91, abs=1e-2) fuselage_lcabin = problem["data:geometry:cabin:length"] assert fuselage_lcabin == pytest.approx(30.38, abs=1e-2) fuselage_wet_area = problem["data:geometry:fuselage:wetted_area"] assert fuselage_wet_area == pytest.approx(401.962, abs=1e-3) pnc = problem["data:geometry:cabin:crew_count:commercial"] assert pnc == pytest.approx(4, abs=1)
def test_htail_chords(): input_list = [ "data:geometry:wing:MAC:at25percent:x", "data:geometry:horizontal_tail:MAC:length", "data:geometry:horizontal_tail:MAC:at25percent:x:local", "data:geometry:horizontal_tail:MAC:at25percent:x:from_wingMAC25", "data:geometry:horizontal_tail:span", "data:geometry:horizontal_tail:sweep_0", "data:geometry:horizontal_tail:span", "data:geometry:horizontal_tail:root:chord", "data:geometry:horizontal_tail:tip:chord", ] ivc = get_indep_var_comp(input_list) group = om.Group() group.add_subsystem("HtailNodes", AerodynamicNodesHtail(number_of_sections=12), promotes=["*"]) group.add_subsystem("HtailChords", AerodynamicChordsHtail(number_of_sections=12), promotes=["*"]) problem = run_system(group, ivc) chord = problem["data:aerostructural:aerodynamic:horizontal_tail:chords"] assert chord[0] == approx(4.40580, abs=1e-5) # Check root chord assert chord[6] == approx(2.86377, abs=1e-5) # Check intermediate chord assert chord[12] == approx(1.32174, abs=1e-5) # Check tip chord assert chord[19] == approx(2.86377, abs=1e-5) # Check symmetry intermediate chord
def test_vtail_chords(): input_list = [ "data:geometry:wing:MAC:at25percent:x", "data:geometry:vertical_tail:MAC:at25percent:x:local", "data:geometry:vertical_tail:MAC:at25percent:x:from_wingMAC25", "data:geometry:vertical_tail:MAC:length", "data:geometry:vertical_tail:span", "data:geometry:vertical_tail:sweep_0", "data:geometry:fuselage:maximum_height", "data:geometry:vertical_tail:root:chord", "data:geometry:vertical_tail:tip:chord", ] ivc = get_indep_var_comp(input_list) group = om.Group() group.add_subsystem("VtailNodes", AerodynamicNodesVtail(number_of_sections=12), promotes=["*"]) group.add_subsystem("VtailChords", AerodynamicChordsVtail(number_of_sections=12), promotes=["*"]) problem = run_system(group, ivc) chord = problem["data:aerostructural:aerodynamic:vertical_tail:chords"] assert chord[0] == approx(6.08571, abs=1e-5) # Check root chord assert chord[6] == approx(3.95571, abs=1e-5) # Check intermediate chord assert chord[12] == approx(1.82571, abs=1e-5) # Check tip chord
def get_cl_cd(slat_angle, flap_angle, mach, landing_flag): ivc = get_indep_var_comp(input_list) if landing_flag: ivc.add_output("data:mission:sizing:landing:slat_angle", slat_angle, units="deg") ivc.add_output("data:mission:sizing:landing:flap_angle", flap_angle, units="deg") ivc.add_output("data:aerodynamics:aircraft:landing:mach", mach) else: ivc.add_output("data:mission:sizing:takeoff:slat_angle", slat_angle, units="deg") ivc.add_output("data:mission:sizing:takeoff:flap_angle", flap_angle, units="deg") ivc.add_output("data:aerodynamics:aircraft:takeoff:mach", mach) component = ComputeDeltaHighLift() component.options["landing_flag"] = landing_flag problem = run_system(component, ivc) if landing_flag: return ( problem["data:aerodynamics:high_lift_devices:landing:CL"], problem["data:aerodynamics:high_lift_devices:landing:CD"], ) return ( problem["data:aerodynamics:high_lift_devices:takeoff:CL"], problem["data:aerodynamics:high_lift_devices:takeoff:CD"], )
def test_transfer_matrices(): comps = ["wing", "horizontal_tail", "vertical_tail", "fuselage"] sects = [5, 5, 5, 4] interp = ["linear", "linear", "linear", "rigid"] # Rectangular wing and surfaces geometry from inputs file input_list = [ "data:aerostructural:structure:wing:nodes", "data:aerostructural:structure:horizontal_tail:nodes", "data:aerostructural:structure:vertical_tail:nodes", "data:aerostructural:structure:fuselage:nodes", "data:aerostructural:aerodynamic:wing:nodes", "data:aerostructural:aerodynamic:horizontal_tail:nodes", "data:aerostructural:aerodynamic:vertical_tail:nodes", "data:aerostructural:aerodynamic:fuselage:nodes", ] ivc = get_indep_var_comp(input_list) problem = run_system( TransferMatrices(components=comps, components_sections=sects, components_interp=interp), ivc) t_mat_wing = problem["data:aerostructural:transfer:wing:matrix"] t_mat_htp = problem["data:aerostructural:transfer:horizontal_tail:matrix"] t_mat_vtp = problem["data:aerostructural:transfer:vertical_tail:matrix"] t_mat_fuse = problem["data:aerostructural:transfer:fuselage:matrix"] assert t_mat_wing == approx(_test_matrix(12, 2.0), abs=1e-5) assert t_mat_htp == approx(_test_matrix(12, 1.0), abs=1e-5) assert t_mat_vtp == approx(_test_matrix(6, 1.0), abs=1e-5) assert t_mat_fuse == approx(np.zeros((36, 30)), abs=1e-5)
def test_aerodynamics_landing_with_xfoil(): """ Tests AerodynamicsHighSpeed """ input_list = [ "data:TLAR:approach_speed", "data:mission:sizing:landing:flap_angle", "data:mission:sizing:landing:slat_angle", "data:geometry:wing:MAC:length", "data:geometry:wing:thickness_ratio", "data:geometry:wing:sweep_25", "data:geometry:wing:sweep_0", "data:geometry:wing:sweep_100_outer", "data:geometry:flap:chord_ratio", "data:geometry:flap:span_ratio", "data:geometry:slat:chord_ratio", "data:geometry:slat:span_ratio", "xfoil:mach", "tuning:aerodynamics:aircraft:landing:CL_max:landing_gear_effect:k", ] ivc = get_indep_var_comp(input_list) problem = run_system(AerodynamicsLanding(xfoil_exe_path=xfoil_path), ivc) # Reference values are for Windows XFOIL version, but as results can be slightly different on other # platforms, tolerance is extended to 1e-2 assert problem["data:aerodynamics:aircraft:landing:CL_max_clean"] == approx(1.59359, abs=1e-2) assert problem["data:aerodynamics:aircraft:landing:CL_max"] == approx(2.82178, abs=1e-2)
def test_aerodynamics_landing_without_xfoil(): """ Tests AerodynamicsHighSpeed """ input_list = [ "data:TLAR:approach_speed", "data:mission:sizing:landing:flap_angle", "data:mission:sizing:landing:slat_angle", "data:geometry:wing:MAC:length", "data:geometry:wing:thickness_ratio", "data:geometry:wing:sweep_25", "data:geometry:wing:sweep_0", "data:geometry:wing:sweep_100_outer", "data:geometry:flap:chord_ratio", "data:geometry:flap:span_ratio", "data:geometry:slat:chord_ratio", "data:geometry:slat:span_ratio", "xfoil:mach", "tuning:aerodynamics:aircraft:landing:CL_max:landing_gear_effect:k", "data:aerodynamics:aircraft:landing:CL_max_clean_2D", ] ivc = get_indep_var_comp(input_list) problem = run_system(AerodynamicsLanding(use_xfoil=False), ivc) assert problem[ "data:aerodynamics:aircraft:landing:CL_max_clean"] == approx(1.54978, abs=1e-5) assert problem["data:aerodynamics:aircraft:landing:CL_max"] == approx( 2.77798, abs=1e-5)
def test_mission_group_breguet_with_loop(cleanup): input_file_path = pth.join(DATA_FOLDER_PATH, "test_mission.xml") vars = VariableIO(input_file_path).read() del vars["data:mission:operational:TOW"] ivc = vars.to_ivc() problem = run_system( Mission( propulsion_id="test.wrapper.propulsion.dummy_engine", out_file=pth.join(RESULTS_FOLDER_PATH, "test_looped_mission_group.csv"), use_initializer_iteration=True, mission_file_path=pth.join(DATA_FOLDER_PATH, "test_breguet.yml"), add_solver=True, ), ivc, ) # check loop assert_allclose( problem["data:mission:operational:TOW"], problem["data:mission:operational:OWE"] + problem["data:mission:operational:payload"] + problem["data:mission:operational:block_fuel"], atol=1.0, ) assert_allclose( problem["data:mission:operational:needed_block_fuel"], problem["data:mission:operational:block_fuel"], atol=1.0, ) assert_allclose( problem["data:mission:operational:needed_block_fuel"], 5640.0, atol=1.0, )
def get_cd_trim(cl): ivc = IndepVarComp() ivc.add_output( "data:aerodynamics:aircraft:cruise:CL", 150 * [cl] ) # needed because size of input array is fixed problem = run_system(CdTrim(), ivc) return problem["data:aerodynamics:aircraft:cruise:CD:trim"][0]
def test_compute_vt_cg(input_xml): """Tests computation of the vertical tail center of gravity""" input_list = [ "data:geometry:vertical_tail:root:chord", "data:geometry:vertical_tail:tip:chord", "data:geometry:vertical_tail:MAC:at25percent:x:from_wingMAC25", "data:geometry:vertical_tail:span", "data:geometry:wing:MAC:at25percent:x", "data:geometry:vertical_tail:sweep_25", "data:geometry:vertical_tail:MAC:length", ] input_vars = input_xml.read(only=input_list).to_ivc() input_vars.add_output( "data:geometry:vertical_tail:MAC:at25percent:x:local", 2.321, units="m") component = ComputeVTcg() problem = run_system(component, input_vars) cg_a32 = problem["data:weight:airframe:vertical_tail:CG:x"] assert cg_a32 == pytest.approx(34.265, abs=1e-3)
def test_geometry_wing_mac(input_xml): """ Tests computation of the wing mean aerodynamic chord """ input_list = [ "data:geometry:wing:area", "data:geometry:wing:kink:leading_edge:x:local", "data:geometry:wing:tip:leading_edge:x:local", "data:geometry:wing:root:y", "data:geometry:wing:kink:y", "data:geometry:wing:tip:y", "data:geometry:wing:root:chord", "data:geometry:wing:kink:chord", "data:geometry:wing:tip:chord", ] input_vars = input_xml.read(only=input_list).to_ivc() component = ComputeMACWing() problem = run_system(component, input_vars) wing_l0 = problem["data:geometry:wing:MAC:length"] assert wing_l0 == pytest.approx(4.457, abs=1e-3) wing_x0 = problem["data:geometry:wing:MAC:leading_edge:x:local"] assert wing_x0 == pytest.approx(2.361, abs=1e-3) wing_y0 = problem["data:geometry:wing:MAC:y"] assert wing_y0 == pytest.approx(6.293, abs=1e-3)
def test_geometry_wing_sweep(input_xml): """ Tests computation of the wing sweeps """ input_list = [ "data:geometry:wing:kink:leading_edge:x:local", "data:geometry:wing:tip:leading_edge:x:local", "data:geometry:wing:root:y", "data:geometry:wing:kink:y", "data:geometry:wing:tip:y", "data:geometry:wing:root:chord", "data:geometry:wing:kink:chord", "data:geometry:wing:tip:chord", ] input_vars = input_xml.read(only=input_list).to_ivc() component = ComputeSweepWing() problem = run_system(component, input_vars) sweep_0 = problem["data:geometry:wing:sweep_0"] assert sweep_0 == pytest.approx(27.55, abs=1e-2) sweep_100_inner = problem["data:geometry:wing:sweep_100_inner"] assert sweep_100_inner == pytest.approx(0.0, abs=1e-1) sweep_100_outer = problem["data:geometry:wing:sweep_100_outer"] assert sweep_100_outer == pytest.approx(16.7, abs=1e-1)
def test_compute_cg_wing(input_xml): """ Tests computation of wing center of gravity """ input_list = [ "data:geometry:wing:kink:span_ratio", "data:geometry:wing:spar_ratio:front:root", "data:geometry:wing:spar_ratio:front:kink", "data:geometry:wing:spar_ratio:front:tip", "data:geometry:wing:spar_ratio:rear:root", "data:geometry:wing:spar_ratio:rear:kink", "data:geometry:wing:spar_ratio:rear:tip", "data:geometry:wing:span", "data:geometry:wing:MAC:length", "data:geometry:wing:MAC:leading_edge:x:local", "data:geometry:wing:root:chord", "data:geometry:wing:kink:chord", "data:geometry:wing:tip:chord", "data:geometry:wing:root:y", "data:geometry:wing:kink:leading_edge:x:local", "data:geometry:wing:kink:y", "data:geometry:wing:tip:y", "data:geometry:wing:tip:leading_edge:x:local", "data:geometry:wing:MAC:at25percent:x", ] input_vars = input_xml.read(only=input_list).to_ivc() problem = run_system(ComputeWingCG(), input_vars) x_cg_wing = problem["data:weight:airframe:wing:CG:x"] assert x_cg_wing == pytest.approx(16.67, abs=1e-2)
def test_compute_power_systems_weight(): """ Tests power systems weight computation from sample XML data """ input_list = [ "data:weight:aircraft:MTOW", "tuning:weight:systems:power:auxiliary_power_unit:mass:k", "tuning:weight:systems:power:auxiliary_power_unit:mass:offset", "tuning:weight:systems:power:electric_systems:mass:k", "tuning:weight:systems:power:electric_systems:mass:offset", "tuning:weight:systems:power:hydraulic_systems:mass:k", "tuning:weight:systems:power:hydraulic_systems:mass:offset", "settings:weight:systems:power:mass:k_elec", ] ivc = get_indep_var_comp(input_list) ivc.add_output("data:geometry:cabin:NPAX1", 150) ivc.add_output("data:weight:airframe:flight_controls:mass", 700, units="kg") problem = run_system(PowerSystemsWeight(), ivc) val1 = problem["data:weight:systems:power:auxiliary_power_unit:mass"] val2 = problem["data:weight:systems:power:electric_systems:mass"] val3 = problem["data:weight:systems:power:hydraulic_systems:mass"] assert val1 == pytest.approx(279, abs=1) assert val2 == pytest.approx(1297, abs=1) assert val3 == pytest.approx(747, abs=1)
def test_compute_vt_area(input_xml): """Tests computation of the vertical tail area""" input_list = [ "data:TLAR:cruise_mach", "data:geometry:wing:MAC:length", "data:geometry:wing:MAC:length", "data:geometry:wing:area", "data:geometry:wing:span", "data:geometry:vertical_tail:MAC:at25percent:x:from_wingMAC25", "data:aerodynamics:vertical_tail:cruise:CL_alpha", ] input_vars = input_xml.read(only=input_list).to_ivc() input_vars.add_output("data:weight:aircraft:CG:aft:MAC_position", 0.364924) input_vars.add_output("data:aerodynamics:fuselage:cruise:CnBeta", -0.117901) component = ComputeVTArea() problem = run_system(component, input_vars) cn_beta_vt = problem["data:aerodynamics:vertical_tail:cruise:CnBeta"] assert cn_beta_vt == pytest.approx(0.258348, abs=1e-6) wet_area = problem["data:geometry:vertical_tail:wetted_area"] assert wet_area == pytest.approx(52.34, abs=1e-2) vt_area = problem["data:geometry:vertical_tail:area"] assert vt_area == pytest.approx(24.92, abs=1e-2)
def test_compute_cg_tanks(input_xml): """ Tests computation of tanks center of gravity """ input_list = [ "data:geometry:wing:spar_ratio:front:root", "data:geometry:wing:spar_ratio:front:kink", "data:geometry:wing:spar_ratio:front:tip", "data:geometry:wing:spar_ratio:rear:root", "data:geometry:wing:spar_ratio:rear:kink", "data:geometry:wing:spar_ratio:rear:tip", "data:geometry:wing:MAC:length", "data:geometry:wing:MAC:leading_edge:x:local", "data:geometry:wing:root:chord", "data:geometry:wing:kink:chord", "data:geometry:wing:tip:chord", "data:geometry:wing:root:y", "data:geometry:wing:kink:leading_edge:x:local", "data:geometry:wing:kink:y", "data:geometry:wing:tip:y", "data:geometry:wing:tip:leading_edge:x:local", "data:geometry:wing:MAC:at25percent:x", "data:geometry:fuselage:maximum_width", ] input_vars = input_xml.read(only=input_list).to_ivc() problem = run_system(ComputeTanksCG(), input_vars) x_cg_tank = problem["data:weight:fuel_tank:CG:x"] assert x_cg_tank == pytest.approx(16.12, abs=1e-2)
def test_compute_ht_area(input_xml): """Tests computation of the horizontal tail area""" input_list = [ "data:geometry:has_T_tail", "data:geometry:fuselage:length", "data:geometry:wing:MAC:at25percent:x", "data:geometry:wing:MAC:length", "data:geometry:wing:area", "data:weight:airframe:landing_gear:main:CG:x", "data:weight:airframe:landing_gear:front:CG:x", "data:weight:aircraft:MTOW", "settings:weight:aircraft:CG:range", ] input_vars = input_xml.read(only=input_list).to_ivc() problem = run_system(ComputeHTArea(), input_vars) ht_lp = problem[ "data:geometry:horizontal_tail:MAC:at25percent:x:from_wingMAC25"] assert ht_lp == pytest.approx(17.68, abs=1e-2) wet_area = problem["data:geometry:horizontal_tail:wetted_area"] assert wet_area == pytest.approx(70.31, abs=1e-2) ht_area = problem["data:geometry:horizontal_tail:area"] assert ht_area == pytest.approx(35.15, abs=1e-2)
def test_wing_nodes(): """ Test Aerodynamic wing nodes mesh generation """ input_list = [ "data:geometry:wing:MAC:length", "data:geometry:wing:MAC:leading_edge:x:local", "data:geometry:wing:MAC:at25percent:x", "data:geometry:wing:root:y", "data:geometry:wing:root:z", "data:geometry:wing:kink:leading_edge:x:local", "data:geometry:wing:kink:y", "data:geometry:wing:kink:z", "data:geometry:wing:tip:leading_edge:x:local", "data:geometry:wing:tip:y", "data:geometry:wing:tip:z", ] ivc = get_indep_var_comp(input_list) component = AerodynamicNodesWing(number_of_sections=12) problem = run_system(component, ivc) nodes = problem["data:aerostructural:aerodynamic:wing:nodes"] assert nodes[0, 0] == approx(12.83803, abs=1e-5) assert nodes[12, 0] == approx(20.81736, abs=1e-5) assert (nodes[1, 1] - nodes[0, 1]) == approx(1.95994, abs=1e-5) assert (nodes[5, 1] - nodes[4, 1]) == approx(1.31764, abs=1e-5)
def test_structure_htail_nodes(): input_list = [ "data:geometry:wing:MAC:at25percent:x", "data:geometry:horizontal_tail:MAC:at25percent:x:local", "data:geometry:horizontal_tail:MAC:at25percent:x:from_wingMAC25", "data:geometry:horizontal_tail:MAC:length", "data:geometry:horizontal_tail:span", "data:geometry:horizontal_tail:sweep_0", "data:geometry:horizontal_tail:root:z", "data:geometry:horizontal_tail:tip:z", "data:geometry:horizontal_tail:root:chord", "data:geometry:horizontal_tail:tip:chord", ] ivc = get_indep_var_comp(input_list) problem = run_system(StructureNodesHtail(number_of_sections=4), ivc) assert problem[ "data:aerostructural:structure:horizontal_tail:nodes"][:5, 1] == approx( np.array([ 0.0, 1.5349, 3.06980, 4.6047, 6.1396 ]), abs=1e-5) assert problem["data:aerostructural:structure:horizontal_tail:nodes"][ 5:, 1] == approx(np.array([-0.0, -1.5349, -3.06980, -4.6047, -6.1396]), abs=1e-5) assert problem[ "data:aerostructural:structure:horizontal_tail:nodes"][:5, 0] == approx( np.array([34.59222, 35.21558, 35.83895, 36.46232, 37.08568]), abs=1e-5)
def test_compute_cg_loadcases(input_xml): """Tests computation of center of gravity for load case 2""" input_list = [ "data:geometry:wing:MAC:length", "data:geometry:wing:MAC:at25percent:x", "data:weight:payload:PAX:CG:x", "data:weight:payload:rear_fret:CG:x", "data:weight:payload:front_fret:CG:x", "data:TLAR:NPAX", "data:weight:aircraft:MFW", "data:weight:fuel_tank:CG:x", ] input_vars = input_xml.read(only=input_list).to_ivc() input_vars.add_output("data:weight:aircraft_empty:CG:x", 699570.01 / 40979.11) input_vars.add_output("data:weight:aircraft_empty:mass", 40979.11) # Testing each load case independently ------------- classes = [ ComputeCGLoadCase1, ComputeCGLoadCase2, ComputeCGLoadCase3, ComputeCGLoadCase4 ] cg_ratio_lc = [ 0.0 ] # dummy first item to ensure cg_ratio_lc[i] is for load case i for i, cg_class in enumerate(classes): problem = run_system(cg_class(), input_vars) cg_ratio_lc.append( problem[f"data:weight:aircraft:load_case_{i+1}:CG:MAC_position"]) assert cg_ratio_lc[1] == pytest.approx(0.364907, abs=1e-6) assert cg_ratio_lc[2] == pytest.approx(0.285139, abs=1e-6) assert cg_ratio_lc[3] == pytest.approx(0.386260, abs=1e-6) assert cg_ratio_lc[4] == pytest.approx(0.388971, abs=1e-6) # Testing the aggregated load cases ------------- problem = run_system(CGRatiosForLoadCases(), input_vars) cg_ratios = problem["data:weight:aircraft:load_cases:CG:MAC_position"] max_cg_ratios = problem[ "data:weight:aircraft:load_cases:CG:MAC_position:maximum"] assert cg_ratios == pytest.approx([0.364907, 0.285139, 0.386260, 0.388971], abs=1e-6) assert max_cg_ratios == pytest.approx(0.388971, abs=1e-6)
def test_polar_low_speed(): """Tests ComputePolar""" # Need to plug Cd modules, Reynolds and Oswald input_list = [ "data:aerodynamics:aircraft:takeoff:mach", "data:geometry:wing:area", "data:geometry:wing:span", "data:geometry:fuselage:maximum_height", "data:geometry:fuselage:maximum_width", "data:geometry:wing:root:chord", "data:geometry:wing:tip:chord", "data:geometry:wing:sweep_25", "data:geometry:wing:thickness_ratio", "data:geometry:wing:wetted_area", "data:geometry:wing:MAC:length", "data:geometry:fuselage:length", "data:geometry:fuselage:wetted_area", "data:geometry:horizontal_tail:MAC:length", "data:geometry:horizontal_tail:thickness_ratio", "data:geometry:horizontal_tail:sweep_25", "data:geometry:horizontal_tail:wetted_area", "data:geometry:vertical_tail:MAC:length", "data:geometry:vertical_tail:thickness_ratio", "data:geometry:vertical_tail:sweep_25", "data:geometry:vertical_tail:wetted_area", "data:geometry:propulsion:pylon:length", "data:geometry:propulsion:nacelle:length", "data:geometry:propulsion:pylon:wetted_area", "data:geometry:propulsion:nacelle:wetted_area", "data:geometry:propulsion:engine:count", "data:geometry:propulsion:fan:length", "data:geometry:aircraft:wetted_area", "tuning:aerodynamics:aircraft:cruise:CD:k", "tuning:aerodynamics:aircraft:cruise:CD:offset", "tuning:aerodynamics:aircraft:cruise:CD:winglet_effect:k", "tuning:aerodynamics:aircraft:cruise:CD:winglet_effect:offset", ] group = Group() group.add_subsystem("reynolds", ComputeReynolds(low_speed_aero=True), promotes=["*"]) group.add_subsystem("oswald", OswaldCoefficient(low_speed_aero=True), promotes=["*"]) group.add_subsystem( "induced_drag_coeff", InducedDragCoefficient(low_speed_aero=True), promotes=["*"] ) group.add_subsystem("cd0", CD0(low_speed_aero=True), promotes=["*"]) group.add_subsystem("cd_trim", CdTrim(low_speed_aero=True), promotes=["*"]) group.add_subsystem("polar", ComputePolar(polar_type=PolarType.LOW_SPEED), promotes=["*"]) ivc = get_indep_var_comp(input_list) ivc.add_output("data:aerodynamics:aircraft:low_speed:CL", np.arange(0.0, 1.5, 0.01)) problem = run_system(group, ivc) cd = problem["data:aerodynamics:aircraft:low_speed:CD"] cl = problem["data:aerodynamics:aircraft:low_speed:CL"] assert cd[cl == 0.5] == approx(0.033441, abs=1e-5) assert cd[cl == 1.0] == approx(0.077523, abs=1e-5)