Exemple #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
Exemple #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
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)
Exemple #7
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
Exemple #8
0
    def read_inputs(self):
        """
        Reads inputs from the configured input file.
        """
        if self.input_file_path:
            # Reads input file
            reader = VariableIO(self.input_file_path)
            variables = reader.read()

            ivc = variables.to_ivc()

            # ivc will be added through add_subsystem, but we must use set_order() to
            # put it first.
            # So we need order of existing subsystem to provide the full order list to
            # set_order() to get order of systems, we use system_iter() that can be used
            # only after setup().
            # But we will not be allowed to use add_subsystem() after setup().
            # So we use setup() on a copy of current instance, and get order from this copy
            tmp_prob = deepcopy(self)
            tmp_prob.setup()
            previous_order = [
                system.name
                for system in tmp_prob.model.system_iter(recurse=False)
                if system.name != "_auto_ivc"
                # OpenMDAO 3.2+ specific : _auto_ivc is an output of system_iter() but is not
                # accepted as input of set_order()
            ]

            self.model.add_subsystem(INPUT_SYSTEM_NAME, ivc, promotes=["*"])
            self.model.set_order([INPUT_SYSTEM_NAME] + previous_order)
Exemple #9
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)
Exemple #10
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)
Exemple #11
0
def convert_xml(file_path: str, translator: VarXpathTranslator):
    """
    Modifies given XML file by translating XPaths according to provided
    translator

    :param file_path:
    :param translator:
    """
    reader = VariableIO(file_path, formatter=VariableXmlBaseFormatter(translator))
    vars = reader.read()
    VariableIO(file_path).write(vars)
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)
Exemple #15
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)
Exemple #18
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²
Exemple #19
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)
Exemple #20
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)
Exemple #21
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 """

    # 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)
    def get_problem(self,
                    read_inputs: bool = False,
                    auto_scaling: bool = False) -> FASTOADProblem:
        """
        Builds the OpenMDAO problem from current configuration.

        :param read_inputs: if True, the created problem will already be fed
                            with variables from the input file
        :param auto_scaling: if True, automatic scaling is performed for design
                             variables and constraints
        :return: the problem instance
        """
        if not self._conf_dict:
            raise RuntimeError("read configuration file first")

        if read_inputs:
            reader = VariableIO(self.input_file_path)
            variables = reader.read()
            input_ivc = variables.to_ivc()
        else:
            input_ivc = None

        problem = FASTOADProblem(self._build_model(input_ivc))

        problem.input_file_path = self.input_file_path
        problem.output_file_path = self.output_file_path

        driver = self._conf_dict.get(KEY_DRIVER, "")
        if driver:
            problem.driver = _om_eval(driver)

        if self.get_optimization_definition():
            self._add_constraints(problem.model, auto_scaling)
            self._add_objectives(problem.model)

        if read_inputs:
            self._add_design_vars(problem.model, auto_scaling)

        if self._configuration_modifier:
            self._configuration_modifier.modify(problem)

        return problem
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)
def test_basic_xml_partial_read_and_write_from_vars(cleanup):
    """
    Tests the creation of an XML file from an IndepVarComp instance with only and ignore options
    """
    result_folder = pth.join(RESULTS_FOLDER_PATH, "basic_partial_xml")

    # Read full IndepVarComp
    filename = pth.join(DATA_FOLDER_PATH, "basic.xml")
    xml_read = VariableIO(filename, formatter=VariableXmlStandardFormatter())
    vars = xml_read.read(ignore=["does_not_exist"])
    _check_basic_vars(vars)

    # Add something to ignore and write it
    vars["should_be_ignored:pointless"] = {"value": 0.0}
    vars["should_also_be_ignored"] = {"value": -10.0}

    badvar_filename = pth.join(result_folder, "with_bad_var.xml")
    xml_write = VariableIO(badvar_filename, formatter=VariableXmlStandardFormatter())
    xml_write.write(vars, ignore=["does_not_exist"])  # Check with non-existent var in ignore list

    tree = etree.parse(badvar_filename)
    assert float(tree.xpath("should_be_ignored/pointless")[0].text.strip()) == 0.0
    assert float(tree.xpath("should_also_be_ignored")[0].text.strip()) == -10.0

    # Check partial reading with 'ignore'
    xml_read = VariableIO(badvar_filename, formatter=VariableXmlStandardFormatter())
    new_vars = xml_read.read(ignore=["should_be_ignored:pointless", "should_also_be_ignored"])
    _check_basic_vars(new_vars)

    # Check partial reading with 'only'
    ok_vars = [
        "geometry:total_surface",
        "geometry:wing:span",
        "geometry:wing:aspect_ratio",
        "geometry:fuselage:length",
        "constants",
        "constants:k1",
        "constants:k2",
        "constants:k3",
        "constants:k4",
        "constants:k5",
        "constants:k8",
    ]
    new_vars2 = xml_read.read(only=ok_vars)
    _check_basic_vars(new_vars2)

    # Check partial writing with 'ignore'
    varok_filename = pth.join(result_folder, "with_bad_var.xml")
    xml_write = VariableIO(varok_filename, formatter=VariableXmlStandardFormatter())
    xml_write.write(vars, ignore=["should_be_ignored:pointless", "should_also_be_ignored"])

    xml_read = VariableIO(varok_filename, formatter=VariableXmlStandardFormatter())
    new_vars = xml_read.read()
    _check_basic_vars(new_vars)

    # Check partial writing with 'only'
    varok2_filename = pth.join(result_folder, "with_bad_var.xml")
    xml_write = VariableIO(varok2_filename, formatter=VariableXmlStandardFormatter())
    xml_write.write(vars, only=ok_vars)

    xml_read = VariableIO(varok2_filename, formatter=VariableXmlStandardFormatter())
    new_vars = xml_read.read()
    _check_basic_vars(new_vars)
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