Example #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_basic_xml_read_and_write_from_vars(cleanup):
    """
    Tests the creation of an XML file from a VariableList instance
    """
    result_folder = pth.join(RESULTS_FOLDER_PATH, "basic_xml")

    # Check write hand-made component
    vars = VariableList()
    vars["geometry/total_surface"] = {"value": [780.3], "units": "m**2"}
    vars["geometry/wing/span"] = {"value": 42.0, "units": "m", "description": "span of the wing"}
    vars["geometry/wing/aspect_ratio"] = {"value": [9.8]}
    vars["geometry/fuselage/length"] = {"value": 40.0, "units": "m"}
    vars["constants"] = {"value": [-42.0], "description": "the answer"}
    vars["constants/k1"] = {"value": [1.0, 2.0, 3.0], "units": "kg"}
    vars["constants/k2"] = {"value": [10.0, 20.0], "description": "Geronimo!"}
    vars["constants/k3"] = {"value": np.array([100.0, 200.0, 300.0, 400.0]), "units": "m/s"}
    vars["constants/k4"] = {"value": [-1.0, -2.0, -3.0]}
    vars["constants/k5"] = {"value": [100.0, 200.0, 400.0, 500.0, 600.0]}
    vars["constants/k8"] = {"value": [[1e2, 3.4e5], [5.4e3, 2.1]]}

    # Try writing with non-existing folder
    assert not pth.exists(result_folder)
    filename = pth.join(result_folder, "handmade.xml")
    xml_write = VariableIO(filename, formatter=VariableXmlStandardFormatter())
    xml_write.path_separator = "/"
    xml_write.write(vars)

    # check (read another IndepVarComp instance from  xml)
    xml_check = VariableIO(filename, formatter=VariableXmlStandardFormatter())
    xml_check.path_separator = ":"
    new_vars = xml_check.read()
    _check_basic_vars(new_vars)

    # Check reading hand-made XML (with some format twists)
    filename = pth.join(DATA_FOLDER_PATH, "basic.xml")
    xml_read = VariableIO(filename, formatter=VariableXmlStandardFormatter())
    xml_read.path_separator = ":"
    vars = xml_read.read()
    _check_basic_vars(vars)

    # write it (with existing destination folder)
    new_filename = pth.join(result_folder, "basic.xml")
    xml_write = VariableIO(new_filename, formatter=VariableXmlStandardFormatter())
    xml_write.path_separator = ":"
    xml_write.write(vars)

    # check (read another IndepVarComp instance from new xml)
    xml_check = VariableIO(new_filename, formatter=VariableXmlStandardFormatter())
    xml_check.path_separator = ":"
    new_vars = xml_check.read()
    _check_basic_vars(new_vars)

    # try to write with bad separator
    xml_write.formatter.path_separator = "/"
    with pytest.raises(FastXPathEvalError):
        xml_write.write(vars)
def test_high_speed_connection():
    """ Tests high speed components connection """

    # load all inputs
    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()
    register_wrappers()

    # Run problem with VLM and check obtained value(s) is/(are) correct
    # noinspection PyTypeChecker
    problem = run_system(AerodynamicsHighSpeed(propulsion_id=ENGINE_WRAPPER), input_vars, check=True)
    cd0 = problem["data:aerodynamics:aircraft:cruise:CD0"]
    assert cd0 == pytest.approx(0.0198, abs=1e-4)
    coef_k = problem["data:aerodynamics:aircraft:cruise:induced_drag_coefficient"]
    assert coef_k == pytest.approx(0.0528, abs=1e-4)
    cl_alpha_wing = problem.get_val("data:aerodynamics:aircraft:cruise:CL_alpha", units="rad**-1")
    assert cl_alpha_wing == pytest.approx(4.820, abs=1e-3)
    cl_alpha_htp = problem.get_val("data:aerodynamics:horizontal_tail:cruise:CL_alpha", units="rad**-1")
    assert cl_alpha_htp == pytest.approx(0.6260, abs=1e-4)
    cl_alpha_vtp = problem.get_val("data:aerodynamics:vertical_tail:cruise:CL_alpha", units="rad**-1")
    assert cl_alpha_vtp == pytest.approx(2.8553, abs=1e-4)

    # Run problem with OPENVSP and check change(s) is/(are) correct
    # noinspection PyTypeChecker
    problem = run_system(AerodynamicsHighSpeed(propulsion_id=ENGINE_WRAPPER, use_openvsp=True), input_vars, check=True)
    coef_k = problem["data:aerodynamics:aircraft:cruise:induced_drag_coefficient"]
    assert coef_k == pytest.approx(0.0487, abs=1e-4)
    cl_alpha_wing = problem.get_val("data:aerodynamics:aircraft:cruise:CL_alpha", units="rad**-1")
    assert cl_alpha_wing == pytest.approx(4.536, abs=1e-3)
    cl_alpha_htp = problem.get_val("data:aerodynamics:horizontal_tail:cruise:CL_alpha", units="rad**-1")
    assert cl_alpha_htp == pytest.approx(0.7030, abs=1e-4)
    cl_alpha_vtp = problem.get_val("data:aerodynamics:vertical_tail:cruise:CL_alpha", units="rad**-1")
    assert cl_alpha_vtp == pytest.approx(2.8553, abs=1e-4)
def test_v_n_diagram_openvsp():
    # load all inputs
    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()
    input_vars.add_output("data:aerodynamics:aircraft:landing:CL_max", 1.9)
    input_vars.add_output("data:aerodynamics:wing:low_speed:CL_max_clean", 1.5)
    input_vars.add_output("data:aerodynamics:wing:low_speed:CL_min_clean", -1.5)
    input_vars.add_output("data:aerodynamics:aircraft:mach_interpolation:CL_alpha_vector",
                          [5.51, 5.51, 5.56, 5.63, 5.71, 5.80])
    input_vars.add_output("data:aerodynamics:aircraft:mach_interpolation:mach_vector",
                          [0., 0.15, 0.21, 0.27, 0.33, 0.39])
    input_vars.add_output("data:weight:aircraft:MTOW", 1633.0, units="kg")
    input_vars.add_output("data:aerodynamics:cruise:mach", 0.2488)
    input_vars.add_output("data:aerodynamics:wing:cruise:induced_drag_coefficient", 0.048)
    input_vars.add_output("data:aerodynamics:aircraft:cruise:CD0", 0.02733)

    register_wrappers()

    # Run problem with VLM and check obtained value(s) is/(are) correct
    # noinspection PyTypeChecker
    problem = run_system(ComputeVNopenvspNoVH(propulsion_id=ENGINE_WRAPPER, compute_cl_alpha=True), input_vars)
    velocity_vect = np.array(
        [35.986, 35.986, 70.15, 44.367, 0., 0., 83.942,
         83.942, 83.942, 117.265, 117.265, 117.265, 117.265, 105.538,
         83.942, 0., 31.974, 45.219, 57.554]
    )
    load_factor_vect = np.array(
        [1., -1., 3.8, -1.52, 0., 0., -1.52, 3.874, -1.874, 3.8, 0., 3.05, -1.05, 0., 0., 0., 1., 2., 2.]
    )
    velocity_array = problem.get_val("data:flight_domain:velocity", units="m/s")
    load_factor_array = problem["data:flight_domain:load_factor"]
    assert np.max(np.abs(velocity_vect - velocity_array)) <= 1e-3
    assert np.max(np.abs(load_factor_vect - load_factor_array)) <= 1e-3
Example #5
0
def get_indep_var_comp(var_names):
    """ Reads required input data and returns an IndepVarcomp() instance"""
    reader = VariableIO(
        pth.join(pth.dirname(__file__), "data", "mass_breakdown_inputs.xml"))
    reader.path_separator = ":"
    ivc = reader.read(only=var_names).to_ivc()
    return ivc
Example #6
0
def get_indep_var_comp(var_names: List[str], test_file: str, xml_file_name: str) -> om.IndepVarComp:
    """ Reads required input data from xml file and returns an IndepVarcomp() instance"""
    reader = VariableIO(pth.join(pth.dirname(test_file), "data", xml_file_name))
    reader.path_separator = ":"
    ivc = reader.read(only=var_names).to_ivc()

    return ivc
def test_complete_cg():
    """ Run computation of all models """

    # with data from file
    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()
    input_vars.add_output("data:weight:propulsion:unusable_fuel:mass",
                          20.0,
                          units="kg")

    # Run problem and check obtained value(s) is/(are) correct
    # noinspection PyTypeChecker
    problem = run_system(CG(propulsion_id=ENGINE_WRAPPER),
                         input_vars,
                         check=True)
    cg_global = problem.get_val("data:weight:aircraft:CG:aft:x", units="m")
    assert cg_global == pytest.approx(2.5800, abs=1e-3)
    cg_ratio = problem.get_val("data:weight:aircraft:CG:aft:MAC_position")
    assert cg_ratio == pytest.approx(0.1917, abs=1e-3)
    z_cg_empty_ac = problem.get_val("data:weight:aircraft_empty:CG:z",
                                    units="m")
    assert z_cg_empty_ac == pytest.approx(1.266, abs=1e-3)
    z_cg_b1 = problem.get_val("data:weight:propulsion:engine:CG:z", units="m")
    assert z_cg_b1 == pytest.approx(1.255, abs=1e-2)
Example #8
0
def test_takeoff_phase_connections():
    """ Tests complete take-off phase connection with speeds """

    # load all inputs
    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    ivc = reader.read().to_ivc()
    register_wrappers()
    # noinspection PyTypeChecker
    problem = run_system(TakeOffPhase(propulsion_id=ENGINE_WRAPPER), ivc)
    vr = problem.get_val("data:mission:sizing:takeoff:VR", units='m/s')
    assert vr == pytest.approx(36.28, abs=1e-2)
    vloff = problem.get_val("data:mission:sizing:takeoff:VLOF", units='m/s')
    assert vloff == pytest.approx(42.52, abs=1e-2)
    v2 = problem.get_val("data:mission:sizing:takeoff:V2", units='m/s')
    assert v2 == pytest.approx(47.84, abs=1e-2)
    tofl = problem.get_val("data:mission:sizing:takeoff:TOFL", units='m')
    assert tofl == pytest.approx(341.49, abs=1)
    duration = problem.get_val("data:mission:sizing:takeoff:duration",
                               units='s')
    assert duration == pytest.approx(20.5, abs=1e-1)
    fuel1 = problem.get_val("data:mission:sizing:takeoff:fuel", units='kg')
    assert fuel1 == pytest.approx(0.246, abs=1e-2)
    fuel2 = problem.get_val("data:mission:sizing:initial_climb:fuel",
                            units='kg')
    assert fuel2 == pytest.approx(0.075, abs=1e-2)
Example #9
0
def test_compute_static_margin():
    """ Tests computation of static margin """

    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()
    input_vars.add_output("data:weight:aircraft:CG:aft:MAC_position", 0.20)

    problem = run_system(ComputeStaticMargin(), input_vars)
    static_margin = problem["data:handling_qualities:static_margin"]
    assert static_margin == pytest.approx(0.55, rel=1e-2)
def test_evaluate_owe():
    """ Tests a simple evaluation of Operating Weight Empty from sample XML data. """

    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()

    # noinspection PyTypeChecker
    mass_computation = run_system(
        ComputeOperatingWeightEmpty(propulsion_id=ENGINE_WRAPPER), input_vars)

    oew = mass_computation.get_val("data:weight:aircraft:OWE", units="kg")
    assert oew == pytest.approx(1031.500, abs=1)
def test_compute_to_rotation_limit():
    """ Tests the computation of the forward most possible CG location for the TO rotation in case HTP area is fixed"""

    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()
    input_vars.add_output("data:geometry:horizontal_tail:area", 3.78)

    problem = run_system(ComputeTORotationLimitGroup(propulsion_id=ENGINE_WRAPPER), input_vars)
    to_rotation_limit = problem["data:handling_qualities:to_rotation_limit:x"]
    assert to_rotation_limit == pytest.approx(2.99, rel=1e-2)
    to_rotation_limit_ratio = problem["data:handling_qualities:to_rotation_limit:MAC_position"]
    assert to_rotation_limit_ratio == pytest.approx(-0.0419, rel=1e-2)
def test_balked_landing_limit():
    """ Tests the computation of the forward most possible CG location for a balked landing in case HTP area is fixed"""

    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()
    input_vars.add_output("data:geometry:horizontal_tail:area", 3.78)

    problem = run_system(ComputeBalkedLandingLimit(propulsion_id=ENGINE_WRAPPER), input_vars)
    balked_landing_limit = problem["data:handling_qualities:balked_landing_limit:x"]
    assert balked_landing_limit == pytest.approx(3.43, rel=1e-2)
    balked_landing_limit_ratio = problem["data:handling_qualities:balked_landing_limit:MAC_position"]
    assert balked_landing_limit_ratio == pytest.approx(0.24, rel=1e-2)
Example #13
0
def test_evaluate_oew():
    """
    Tests a simple evaluation of Operating Empty Weight from sample XML data.
    """
    reader = VariableIO(
        pth.join(pth.dirname(__file__), "data", "mass_breakdown_inputs.xml"))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()

    mass_computation = run_system(OperatingWeightEmpty(), input_vars)

    oew = mass_computation["data:weight:aircraft:OWE"]
    assert oew == pytest.approx(41591, abs=1)
def test_loop_compute_owe():
    """ Tests a weight computation loop matching the max payload criterion. """

    # with payload computed from NPAX
    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read(ignore=[
        "data:weight:aircraft:max_payload",
        "data:weight:aircraft:MTOW",
    ]).to_ivc()
    input_vars.add_output("data:mission:sizing:fuel", 0.0, units="kg")

    # noinspection PyTypeChecker
    mass_computation_1 = run_system(
        MassBreakdown(propulsion_id=ENGINE_WRAPPER, payload_from_npax=True),
        input_vars,
        check=True,
    )
    oew = mass_computation_1.get_val("data:weight:aircraft:OWE", units="kg")
    assert oew == pytest.approx(1026.20,
                                abs=1e-2)  # 1098.66 (without MTOW local loop)

    # with payload as input
    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read(ignore=[
        "data:weight:aircraft:MTOW",
    ]).to_ivc()
    input_vars.add_output("data:mission:sizing:fuel", 0.0, units="kg")
    # noinspection PyTypeChecker
    mass_computation_2 = run_system(
        MassBreakdown(propulsion_id=ENGINE_WRAPPER, payload_from_npax=False),
        input_vars,
        check=False,
    )
    oew = mass_computation_2.get_val("data:weight:aircraft:OWE", units="kg")
    assert oew == pytest.approx(1009.19,
                                abs=1e-2)  # 1098.66 (without MTOW local loop)
def test_complete_cg():
    """ Run computation of all models """

    # with data from file
    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()

    # Run problem and check obtained value(s) is/(are) correct
    problem = run_system(CG(), input_vars, check=True)
    cg_global = problem.get_val("data:weight:aircraft:CG:aft:x", units="m")
    assert cg_global == pytest.approx(3.46, abs=1e-1)
    cg_ratio = problem.get_val("data:weight:aircraft:CG:aft:MAC_position")
    assert cg_ratio == pytest.approx(0.20, abs=1e-2)
Example #16
0
def test_update_vt_area():
    """ Tests computation of the vertical tail area """

    # Research independent input value in .xml file
    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()
    input_vars.add_output("data:aerodynamics:fuselage:cruise:CnBeta", -0.0599)

    # Run problem and check obtained value(s) is/(are) correct
    register_wrappers()
    problem = run_system(UpdateVTArea(propulsion_id=ENGINE_WRAPPER),
                         input_vars)
    vt_area = problem.get_val("data:geometry:vertical_tail:area", units="m**2")
    assert vt_area == pytest.approx(
        1.751, abs=1e-2)  # old-version obtained value 2.4m²
Example #17
0
def test_compute_balked_landing():
    """ Tests computation of static margin """

    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()

    problem = run_system(
        ComputeBalkedLandingLimit(propulsion_id=ENGINE_WRAPPER), input_vars)

    x_cg_balked_landing_limit = problem[
        "data:handling_qualities:balked_landing_limit:x"]
    assert x_cg_balked_landing_limit == pytest.approx(2.0738, rel=1e-2)

    x_cg_ratio_balked_landing_limit = problem[
        "data:handling_qualities:balked_landing_limit:MAC_position"]
    assert x_cg_ratio_balked_landing_limit == pytest.approx(-0.23, rel=1e-2)
Example #18
0
def test_compute_to_rotation_limit():
    """ Tests computation of static margin """

    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()

    problem = run_system(
        ComputeTORotationLimitGroup(propulsion_id=ENGINE_WRAPPER), input_vars)

    x_cg_rotation_limit = problem[
        "data:handling_qualities:to_rotation_limit:x"]
    assert x_cg_rotation_limit == pytest.approx(1.9355, rel=1e-2)

    x_cg_ratio_rotation_limit = problem[
        "data:handling_qualities:to_rotation_limit:MAC_position"]
    assert x_cg_ratio_rotation_limit == pytest.approx(-0.3451, rel=1e-2)
def test_low_speed_connection():
    """ Tests low speed components connection """

    # Clear saved polar results (for wing and htp airfoils)
    clear_polar_results()

    # load all inputs
    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()
    register_wrappers()

    # Run problem with VLM
    # noinspection PyTypeChecker
    run_system(AerodynamicsLowSpeed(propulsion_id=ENGINE_WRAPPER, use_openvsp=False), input_vars)

    # Run problem with OPENVSP
    # noinspection PyTypeChecker
    run_system(AerodynamicsLowSpeed(propulsion_id=ENGINE_WRAPPER, use_openvsp=True), input_vars)
Example #20
0
def test_compute_static_margin():
    """ Tests computation of static margin """

    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()

    problem = run_system(ComputeStaticMargin(), input_vars)
    stick_fixed_static_margin = problem[
        "data:handling_qualities:stick_fixed_static_margin"]
    assert stick_fixed_static_margin == pytest.approx(0.0479, rel=1e-2)

    free_elevator_factor = problem[
        "data:aerodynamics:cruise:neutral_point:free_elevator_factor"]
    assert free_elevator_factor == pytest.approx(0.7217, rel=1e-2)

    stick_free_static_margin = problem[
        "data:handling_qualities:stick_free_static_margin"]
    assert stick_free_static_margin == pytest.approx(-0.0253, rel=1e-2)
def test_low_speed_connection():
    """ Tests low speed components connection """

    # load all inputs
    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()
    register_wrappers()

    # Run problem with VLM and check obtained value(s) is/(are) correct
    # noinspection PyTypeChecker
    problem = run_system(AerodynamicsLowSpeed(propulsion_id=ENGINE_WRAPPER), input_vars, check=True)
    cd0 = problem["data:aerodynamics:aircraft:low_speed:CD0"]
    assert cd0 == pytest.approx(0.0452, abs=1e-4)
    coef_k = problem["data:aerodynamics:aircraft:low_speed:induced_drag_coefficient"]
    assert coef_k == pytest.approx(0.0530, abs=1e-4)
    cl_alpha_wing = problem.get_val("data:aerodynamics:aircraft:low_speed:CL_alpha", units="rad**-1")
    assert cl_alpha_wing == pytest.approx(4.705, abs=1e-3)
    cl_max_clean = problem["data:aerodynamics:wing:low_speed:CL_max_clean"]
    assert cl_max_clean == pytest.approx(1.4456, abs=1e-4)
    cl_max_takeoff = problem["data:aerodynamics:aircraft:takeoff:CL_max"]
    assert cl_max_takeoff == pytest.approx(1.5675, abs=1e-4)
    cl_max_landing = problem["data:aerodynamics:aircraft:landing:CL_max"]
    assert cl_max_landing == pytest.approx(2.0245, abs=1e-4)
    cl_alpha_htp = problem.get_val("data:aerodynamics:horizontal_tail:low_speed:CL_alpha", units="rad**-1")
    assert cl_alpha_htp == pytest.approx(0.6202, abs=1e-4)

    # Run problem with OPENVSP and check change(s) is/(are) correct
    # noinspection PyTypeChecker
    problem = run_system(AerodynamicsLowSpeed(propulsion_id=ENGINE_WRAPPER, use_openvsp=True), input_vars, check=True)
    coef_k = problem["data:aerodynamics:aircraft:low_speed:induced_drag_coefficient"]
    assert coef_k == pytest.approx(0.0487, abs=1e-4)
    cl_alpha_wing = problem.get_val("data:aerodynamics:aircraft:low_speed:CL_alpha", units="rad**-1")
    assert cl_alpha_wing == pytest.approx(4.459, abs=1e-3)
    cl_max_clean = problem["data:aerodynamics:wing:low_speed:CL_max_clean"]
    assert cl_max_clean == pytest.approx(1.5352, abs=1e-4)
    cl_max_takeoff = problem["data:aerodynamics:aircraft:takeoff:CL_max"]
    assert cl_max_takeoff == pytest.approx(1.6571, abs=1e-4)
    cl_max_landing = problem["data:aerodynamics:aircraft:landing:CL_max"]
    assert cl_max_landing == pytest.approx(2.1141, abs=1e-4)
    cl_alpha_htp = problem.get_val("data:aerodynamics:horizontal_tail:low_speed:CL_alpha", units="rad**-1")
    assert cl_alpha_htp == pytest.approx(0.6967, abs=1e-4)
def test_loop_cruise_distance():
    """ Tests a distance computation loop matching the descent value/TLAR total range. """

    # Get the parameters from .xml
    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    ivc = reader.read().to_ivc()

    # Run problem and check obtained value(s) is/(are) correct
    register_wrappers()
    # noinspection PyTypeChecker
    problem = run_system(Sizing(propulsion_id=ENGINE_WRAPPER), ivc)
    m_total = problem.get_val("data:mission:sizing:fuel", units="kg")
    assert m_total == pytest.approx(117.20, abs=1e-1)
    climb_distance = problem.get_val("data:mission:sizing:main_route:climb:distance", units="NM")
    cruise_distance = problem.get_val("data:mission:sizing:main_route:cruise:distance", units="NM")
    descent_distance = problem.get_val("data:mission:sizing:main_route:descent:distance", units="NM")
    total_distance = problem.get_val("data:TLAR:range", units="NM")
    error_distance = total_distance - (climb_distance + cruise_distance + descent_distance)
    assert error_distance == pytest.approx(0.0, abs=1e-1)
def test_loop_compute_owe():
    """ Tests a weight computation loop matching the max payload criterion. """

    # Payload is computed from NPAX_design
    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read(ignore=[
        "data:weight:aircraft:max_payload",
        "data:weight:aircraft:MLW",
    ]).to_ivc()
    input_vars.add_output("data:mission:sizing:fuel", 0.0, units="kg")

    # noinspection PyTypeChecker
    mass_computation = run_system(
        MassBreakdown(propulsion_id=ENGINE_WRAPPER, payload_from_npax=True),
        input_vars,
        check=True,
    )
    oew = mass_computation.get_val("data:weight:aircraft:OWE", units="kg")
    assert oew == pytest.approx(1031.539, abs=1)
Example #24
0
def generate_block_analysis(
        system: Union[ExplicitComponent, ImplicitComponent, Group],
        var_inputs: List,
        xml_file_path: str,
        overwrite: bool = False,
):

    # Search what are the component/group outputs
    variables = list_variables(system)
    inputs_names = [var.name for var in variables if var.is_input]
    outputs_names = [var.name for var in variables if not var.is_input]

    # Check that variable inputs are in the group/component list
    if not(set(var_inputs) == set(inputs_names).intersection(set(var_inputs))):
        raise Exception('The input list contains name(s) out of component/group input list!')

    # Perform some tests on the .xml availability and completeness
    if not(os.path.exists(xml_file_path)) and not(set(var_inputs) == set(inputs_names)):
        # If no input file and some inputs are missing, generate it and return None
        if isinstance(system, Group):
            problem = FASTOADProblem(system)
        else:
            group = AutoUnitsDefaultGroup()
            group.add_subsystem('system', system, promotes=["*"])
            problem = FASTOADProblem(group)
        problem.input_file_path = xml_file_path
        problem.setup()
        problem.write_needed_inputs(None, VariableXmlStandardFormatter())
        raise Exception('Input .xml file not found, a default file has been created with default NaN values, '
                        'but no function is returned!\nConsider defining proper values before second execution!')

    elif os.path.exists(xml_file_path):

        reader = VariableIO(xml_file_path, VariableXmlStandardFormatter()).read(ignore=(var_inputs + outputs_names))
        xml_inputs = reader.names()
        if not(set(xml_inputs + var_inputs).intersection(set(inputs_names)) == set(inputs_names)):
            # If some inputs are missing write an error message and add them to the problem if authorized
            missing_inputs = list(
                set(inputs_names).difference(set(xml_inputs + var_inputs).intersection(set(inputs_names)))
            )
            message = 'The following inputs are missing in .xml file:'
            for item in missing_inputs:
                message += ' [' + item + '],'
            message = message[:-1] + '.\n'
            if overwrite:
                reader.path_separator = ":"
                ivc = reader.to_ivc()
                group = AutoUnitsDefaultGroup()
                group.add_subsystem('system', system, promotes=["*"])
                group.add_subsystem('ivc', ivc, promotes=["*"])
                problem = FASTOADProblem(group)
                problem.input_file_path = xml_file_path
                problem.output_file_path = xml_file_path
                problem.setup()
                problem.write_outputs()
                message += 'Default values have been added to {} file. ' \
                           'Consider modifying them for a second run!'.format(xml_file_path)
                raise Exception(message)
            else:
                raise Exception(message)
        else:
            # If all inputs addressed either by .xml or var_inputs, construct the function
            def patched_function(inputs_dict: dict) -> dict:
                """
                The patched function perform a run of an openmdao component or group applying FASTOAD formalism.

                @param inputs_dict: dictionary of input (values, units) saved with their key name,
                as an example: inputs_dict = {'in1': (3.0, "m")}.
                @return: dictionary of the component/group outputs saving names as keys and (value, units) as tuple.
                """


                # Read .xml file and construct Independent Variable Component excluding outputs
                reader.path_separator = ":"
                ivc_local = reader.to_ivc()
                for name, value in inputs_dict.items():
                    ivc_local.add_output(name, value[0], units=value[1])
                group_local = AutoUnitsDefaultGroup()
                group_local.add_subsystem('system', system, promotes=["*"])
                group_local.add_subsystem('ivc', ivc_local, promotes=["*"])
                problem_local = FASTOADProblem(group_local)
                problem_local.setup()
                problem_local.run_model()
                if overwrite:
                    problem_local.output_file_path = xml_file_path
                    problem_local.write_outputs()
                # Get output names from component/group and construct dictionary
                outputs_units = [var.units for var in variables if not var.is_input]
                outputs_dict = {}
                for idx in range(len(outputs_names)):
                    value = problem_local.get_val(outputs_names[idx], outputs_units[idx])
                    outputs_dict[outputs_names[idx]] = (value, outputs_units[idx])
                return outputs_dict
            return patched_function
def test_v_n_diagram_vlm():
    # load all inputs
    reader = VariableIO(pth.join(pth.dirname(__file__), "data", XML_FILE))
    reader.path_separator = ":"
    input_vars = reader.read().to_ivc()
    cl_wing_airfoil = np.zeros(POLAR_POINT_COUNT)
    cdp_wing_airfoil = np.zeros(POLAR_POINT_COUNT)
    cl_htp_airfoil = np.zeros(POLAR_POINT_COUNT)
    cdp_htp_airfoil = np.zeros(POLAR_POINT_COUNT)
    cl_wing_airfoil[0:38] = np.array(
        [0.1391, 0.1988, 0.2581, 0.3177, 0.377, 0.4903, 0.5477, 0.6062,
         0.6647, 0.7226, 0.7807, 0.838, 0.8939, 0.9473, 1.1335, 1.1968,
         1.2451, 1.296, 1.3424, 1.4014, 1.4597, 1.5118, 1.5575, 1.6006,
         1.6383, 1.664, 1.6845, 1.7023, 1.7152, 1.7196, 1.7121, 1.6871,
         1.6386, 1.563, 1.4764, 1.3993, 1.3418, 1.2981]
    )
    cdp_wing_airfoil[0:38] = np.array(
        [0.00143, 0.00147, 0.00154, 0.00163, 0.00173, 0.00196, 0.00214,
         0.00235, 0.0026, 0.00287, 0.00317, 0.00349, 0.00385, 0.00424,
         0.00572, 0.00636, 0.00701, 0.00777, 0.00908, 0.00913, 0.00923,
         0.00982, 0.01098, 0.01221, 0.01357, 0.01508, 0.01715, 0.01974,
         0.02318, 0.02804, 0.035, 0.04486, 0.05824, 0.07544, 0.09465,
         0.1133, 0.1299, 0.14507]
    )
    cl_htp_airfoil[0:41] = np.array(
        [-0., 0.0582, 0.117, 0.1751, 0.2333, 0.291, 0.3486,
         0.4064, 0.4641, 0.5216, 0.5789, 0.6356, 0.6923, 0.747,
         0.8027, 0.8632, 0.9254, 0.9935, 1.0611, 1.127, 1.1796,
         1.227, 1.2762, 1.3255, 1.3756, 1.4232, 1.4658, 1.5084,
         1.5413, 1.5655, 1.5848, 1.5975, 1.6002, 1.5894, 1.5613,
         1.5147, 1.4515, 1.3761, 1.2892, 1.1988, 1.1276]
    )
    cdp_htp_airfoil[0:41] = np.array(
        [0.00074, 0.00075, 0.00078, 0.00086, 0.00095, 0.00109, 0.00126,
         0.00145, 0.00167, 0.00191, 0.00218, 0.00249, 0.00283, 0.00324,
         0.00365, 0.00405, 0.00453, 0.00508, 0.00559, 0.00624, 0.00679,
         0.0074, 0.00813, 0.00905, 0.01, 0.01111, 0.0126, 0.01393,
         0.0155, 0.01743, 0.01993, 0.02332, 0.0282, 0.03541, 0.04577,
         0.05938, 0.07576, 0.0944, 0.11556, 0.13878, 0.16068]
    )
    input_vars.add_output("data:aerodynamics:wing:cruise:CL", cl_wing_airfoil)
    input_vars.add_output("data:aerodynamics:wing:cruise:CDp", cdp_wing_airfoil)
    input_vars.add_output("data:aerodynamics:horizontal_tail:cruise:CL", cl_htp_airfoil)
    input_vars.add_output("data:aerodynamics:horizontal_tail:cruise:CDp", cdp_htp_airfoil)
    input_vars.add_output("data:aerodynamics:aircraft:landing:CL_max", 1.949)
    input_vars.add_output("data:aerodynamics:wing:low_speed:CL_max_clean", 1.4818)
    input_vars.add_output("data:aerodynamics:wing:low_speed:CL_min_clean", -1.1614)
    input_vars.add_output("data:weight:aircraft:MTOW", 1633.0, units="kg")
    input_vars.add_output("data:aerodynamics:cruise:mach", 0.2488)
    input_vars.add_output("data:aerodynamics:wing:cruise:induced_drag_coefficient", 0.048)
    input_vars.add_output("data:aerodynamics:aircraft:cruise:CD0", 0.02733)
    input_vars.add_output("data:aerodynamics:aircraft:mach_interpolation:CL_alpha_vector",
                          [5.235, 5.235, 5.297, 5.381, 5.484, 5.606])
    input_vars.add_output("data:aerodynamics:aircraft:mach_interpolation:mach_vector",
                          [0., 0.15, 0.214, 0.275, 0.332, 0.386])
    register_wrappers()

    # Run problem with VLM and check obtained value(s) is/(are) correct
    # noinspection PyTypeChecker
    problem = run_system(ComputeVNvlmNoVH(propulsion_id=ENGINE_WRAPPER, compute_cl_alpha=True), input_vars)
    velocity_vect = np.array(
        [36.206, 40.897, 70.579, 50.421, 0., 0., 75.561,
         75.561, 75.561, 105.556, 105.556, 105.556, 105.556, 95.001,
         83.942, 0., 31.57, 44.647, 56.826]
    )
    load_factor_vect = np.array(
        [1., -1., 3.8, -1.52, 0., 0., -1.52, 3.8,
         -1.52, 3.8, 0., 2.764, -0.764, 0., 0., 0.,
         1., 2., 2.]
    )
    velocity_array = problem.get_val("data:flight_domain:velocity", units="m/s")
    load_factor_array = problem["data:flight_domain:load_factor"]
    assert np.max(np.abs(velocity_vect - velocity_array)) <= 1e-3
    assert np.max(np.abs(load_factor_vect - load_factor_array)) <= 1e-3