def test_aircraft_name():
    """Test the function aircraft_name."""

    # Get name form the CPACS file path
    cpacs_in = str(
        Path(
            Path(__file__).parents[4],
            "test_files/CPACSfiles/D150_simple.xml"))
    assert aircraft_name(cpacs_in) == "D150"

    # Get name form TIXI handle
    tixi = open_tixi(cpacs_in)
    assert aircraft_name(tixi) == "D150"
예제 #2
0
def get_weight_unc_estimations(cpacs_path, cpacs_out_path):
    """Function to estimate the all weights for a unconventional aircraft.

    Function 'get_weight_unc_estimations' ...

    Source:
        * Reference paper or book, with author and date, see ...

    Args:
        cpacs_path (str): Path to CPACS file
        cpacs_out_path (str):Path to CPACS output file

    """

    # Removing and recreating the ToolOutput folder.
    if os.path.exists("ToolOutput"):
        shutil.rmtree("ToolOutput")
    os.makedirs("ToolOutput")

    if not os.path.exists(cpacs_path):
        raise ValueError('No "ToolInput.xml" file in the ToolInput folder.')

    name = aircraft_name(cpacs_path)

    shutil.copyfile(cpacs_path, cpacs_out_path)  # TODO: shoud not be like that
    newpath = "ToolOutput/" + name
    if not os.path.exists(newpath):
        os.makedirs(newpath)

    # USER INPUTS
    # All the input data must be defined into the unc_weight_user_input.py
    # file inside the ceasiompy.InputClasses/Unconventioanl folder.

    adui = AdvancedInputs()
    ui = UserInputs()
    mw = MassesWeights()
    out = WeightOutput()
    ed = EngineData()
    (ed, ui, adui) = getinput.get_user_inputs(ed, ui, adui, cpacs_out_path)
    if ui.USER_ENGINES:
        (ed) = getinput.get_engine_inputs(ui, ed, cpacs_out_path)

    # GEOMETRY ANALYSIS

    (fus_nb, wing_nb) = uncgeomanalysis.get_number_of_parts(cpacs_path)
    h_min = ui.FLOORS_NB * ui.H_LIM_CABIN

    if not wing_nb:
        log.warning("Aircraft does not have wings")
        raise Exception("Aircraft does not have wings")
    elif not fus_nb:
        (awg, wing_nodes) = uncgeomanalysis.no_fuse_geom_analysis(
            cpacs_out_path, ui.FLOORS_NB, wing_nb, h_min, ui.FUEL_ON_CABIN,
            name, ed.TURBOPROP)
    else:
        log.info("Fuselage detected")
        log.info("Number of fuselage: " + str(int(fus_nb)))
        # Minimum fuselage segment height to be a cabin segment.
        (afg, awg) = uncgeomanalysis.with_fuse_geom_analysis(
            cpacs_out_path, fus_nb, wing_nb, h_min, adui, ed.TURBOPROP,
            ui.F_FUEL, name)

    ui = getinput.get_user_fuel(fus_nb, ui, cpacs_out_path)

    # WEIGHT ANALYSIS
    #  Engine evaluation
    if ui.USER_ENGINES:
        check_ed(ed)
        mw.mass_engines = ed.en_mass * ed.NE

    if fus_nb:
        # Passengers mass
        (out.pass_nb, out.toilet_nb, mw.mass_pass) = estimate_fuse_passengers(
            fus_nb,
            ui.FLOORS_NB,
            adui.PASS_PER_TOILET,
            afg.cabin_area,
            adui.MASS_PASS,
            ui.PASS_BASE_DENSITY,
        )
        cabin_area = np.sum(afg.cabin_area)
        # Structure mass
        mw.mass_structure = (adui.VRT_STR_DENSITY * adui.VRT_THICK *
                             (np.sum(afg.fuse_surface) +
                              np.sum(awg.total_wings_surface))**adui.VRT_EXP)
    else:
        # Passengers mass
        (out.pass_nb, out.toilet_nb, mw.mass_pass) = estimate_wing_passengers(
            ui.FLOORS_NB,
            adui.PASS_PER_TOILET,
            awg.cabin_area,
            adui.MASS_PASS,
            ui.PASS_BASE_DENSITY,
        )
        cabin_area = awg.cabin_area
        # Structure mass
        mw.mass_structure = (adui.VRT_STR_DENSITY * adui.VRT_THICK *
                             np.sum(awg.total_wings_surface)**adui.VRT_EXP)

    pass_limit = False
    if ui.MAX_PASS > 0 and out.pass_nb > ui.MAX_PASS:
        out.pass_nb = ui.MAX_PASS
        pass_limit = True
        pass_density = round(out.pass_nb / cabin_area, 2)
        mw.mass_pass = adui.MASS_PASS * out.pass_nb
        log.warning("With the defined maximum number of passengers,")
        log.warning("the number of passengers is reduced to : " +
                    str(out.pass_nb))
        log.warning("and the passenger density is: " + str(pass_density))

    # Payload masses
    mw.mass_payload = round(ui.MASS_CARGO + mw.mass_pass, 0)

    if ui.MAX_PAYLOAD > 0 and mw.mass_payload > ui.MAX_PAYLOAD:
        mw.mass_payload = ui.MAX_PAYLOAD
        if ui.MASS_CARGO > ui.MAX_PAYLOAD:
            log.warning("Mass cargo defined exceeds the chosen" +
                        " maximum payload, the code do not consider the" +
                        " user cargo mass")
            ui.MASS_CARGO = 0.0
        if pass_limit and mw.mass_pass < ui.MAX_PAYLOAD:
            ui.MASS_CARGO = round(ui.MAX_PAYLOAD - mw.mass_pass, 0)
        elif pass_limit and mw.mass_pass > ui.MAX_PAYLOAD:
            log.warning("Pass number defined exceeds the chosen" +
                        " maximum payload, the code do not consider the" +
                        " user passenger number.")
            mw.mass_pass = ui.MAX_PAYLOAD - ui.MASS_CARGO
            out.pass_nb = int(round(mw.mass_pass / adui.MASS_PASS, 0))
        else:
            mw.mass_pass = ui.MAX_PAYLOAD - ui.MASS_CARGO
            out.pass_nb = int(round(mw.mass_pass / adui.MASS_PASS, 0))
        pass_density = round(out.pass_nb / cabin_area, 2)
        log.warning("With the defined maximum payload and cargo masses,")
        log.warning("the number of passengers is: " + str(out.pass_nb))
        log.warning("and the passenger density is: " + str(pass_density))

    #  Fuel mass
    if fus_nb:
        mw.mass_fuse_fuel = estimate_fuse_fuel_mass(afg.fuse_fuel_vol,
                                                    adui.FUEL_DENSITY)
        mw.mass_wing_fuel = estimate_wing_fuel_mass(awg.wing_fuel_vol,
                                                    adui.FUEL_DENSITY)
        mw.mass_fuel_max = mw.mass_wing_fuel + mw.mass_fuse_fuel
    else:
        mw.mass_fuel_max = estimate_wing_fuel_mass(awg.fuel_vol_tot,
                                                   adui.FUEL_DENSITY)

    if ui.MAX_FUEL_VOL > 0 and (mw.mass_fuel_max /
                                adui.FUEL_DENSITY) * 1000.0 > ui.MAX_FUEL_VOL:
        mw.mass_fuel_max = (ui.MAX_FUEL_VOL * adui.FUEL_DENSITY) / 1000.0

    # Mass Reserve and Unusable Fuel
    mw.mass_fuel_unusable = mw.mass_fuel_max * (adui.RES_FUEL_PERC)

    # Mass Fuel Maxpass
    if not out.pass_nb:
        mw.mass_fuel_maxpass = mw.mass_fuel_max
    elif ed.TURBOPROP:
        mw.mass_fuel_maxpass = mw.mass_fuel_max * (adui.FPM_TP / 100.0)
    else:
        mw.mass_fuel_maxpass = mw.mass_fuel_max * (adui.FPM / 100.0)

    wing_area = np.sum(awg.wing_plt_area)
    mw.maximum_take_off_mass = wing_area * ui.wing_loading
    new_mtom = mw.maximum_take_off_mass
    old_mtom = 0
    it = 0
    mw.zero_fuel_mass = mw.maximum_take_off_mass - mw.mass_fuel_maxpass
    if mw.zero_fuel_mass < 0:
        mw.maximum_take_off_mass = mw.mass_fuel_maxpass * 2
        mw.zero_fuel_mass = mw.maximum_take_off_mass - mw.mass_fuel_maxpass
        ui.wing_loading = mw.maximum_take_off_mass / wing_area
        log.warning("Wing loading defined too low," +
                    " starting value modified to [kg/m^2]: " +
                    str(ui.wing_loading))

    while (abs(old_mtom - new_mtom) / max(old_mtom, new_mtom)) > 0.001:
        old_mtom = new_mtom
        mw.maximum_take_off_mass = new_mtom

        if not ui.USER_ENGINES:
            (mw.mass_engines, ed) = engine_definition(mw, ui, ed)

        # Crew mass
        (out.crew_nb, out.cabin_crew_nb, mw.mass_crew) = estimate_crew(
            out.pass_nb,
            adui.MASS_PILOT,
            adui.MASS_CABIN_CREW,
            mw.maximum_take_off_mass,
            adui.PILOT_NB,
        )

        # Total people and payload mass on the aircraft
        mw.mass_people = round(mw.mass_crew + mw.mass_pass, 0)

        #  System mass
        mw.mass_systems = round(
            estimate_system_mass(
                out.pass_nb,
                awg.main_wing_surface,
                awg.tail_wings_surface,
                adui.SINGLE_HYDRAULICS,
                mw,
                ed,
            ),
            0,
        )

        #  MTOM, OEM, ZFM re-evaluation
        mw.operating_empty_mass = round(
            mw.mass_systems + mw.mass_crew + mw.mass_engines +
            mw.mass_structure + mw.mass_fuel_unusable,
            0,
        )

        new_mtom = round(mw.operating_empty_mass + mw.mass_payload +
                         mw.mass_fuel_maxpass)
        mw.zero_fuel_mass = mw.operating_empty_mass + mw.mass_payload

        it += 1
    # End of the iterative process.

    mw.maximum_take_off_mass = new_mtom
    out.wing_loading = new_mtom / wing_area

    # Log writting  (TODO: maybe create a separate function)
    log.info("--------- Masses evaluated: -----------")
    log.info("System mass [kg]: " + str(int(round(mw.mass_systems))))
    log.info("People mass [kg]: " + str(int(round(mw.mass_people))))
    log.info("Payload mass [kg]: " + str(int(round(mw.mass_payload))))
    log.info("Structure mass [kg]: " + str(int(round(mw.mass_structure))))
    log.info("Total fuel mass [kg]: " + str(int(round(mw.mass_fuel_max))))
    log.info("Total fuel volume [l]: " +
             str(int(round(mw.mass_fuel_max / adui.FUEL_DENSITY * 1000.0))))
    log.info("Mass of fuel with max passengers [kg]: " +
             str(int(round(mw.mass_fuel_maxpass))))
    log.info("Volume of fuel with maximum passengers [l]: " +
             str(int(round(mw.mass_fuel_maxpass / adui.FUEL_DENSITY *
                           1000.0))))
    log.info("Engines mass [kg]: " + str(int(round(mw.mass_engines))))
    log.info("---------------------------------------")
    log.info("Maximum Take Off Mass [kg]: " +
             str(int(round(mw.maximum_take_off_mass))))
    log.info("Operating Empty Mass [kg]: " +
             str(int(round(mw.operating_empty_mass))))
    log.info("Zero Fuel Mass [kg]: " + str(int(round(mw.zero_fuel_mass))))
    log.info("Wing loading [kg/m^2]: " + str(int(round(out.wing_loading))))
    log.info("--------- Passegers evaluated: ---------")
    log.info("Passengers: " + str(out.pass_nb))
    log.info("Toilet: " + str(int(out.toilet_nb)))
    log.info("------- Crew members evaluated: --------")
    log.info("Pilots: " + str(adui.PILOT_NB))
    log.info("Cabin crew members: " + str(out.cabin_crew_nb))
    log.info("---------------------------------------")
    log.info("Number of iterations: " + str(it))
    log.info("---------------------------------------")
    log.info("### Uconventional Weight analysis succesfuly completed ###")

    # Outptu writting
    log.info("----- Generating output text file -----")
    cpacsweightupdate.cpacs_weight_update(out, mw, ui, cpacs_out_path)
    cpacsweightupdate.toolspecific_update(fus_nb, awg, mw, out, cpacs_out_path)
    cpacsweightupdate.cpacs_engine_update(ui, ed, mw, cpacs_out_path)

    if not fus_nb:
        outputweightgen.output_bwb_txt(ui.FLOORS_NB, ed, out, mw, adui, awg,
                                       name)
    else:
        outputweightgen.output_fuse_txt(fus_nb, ui.FLOORS_NB, ed, out, mw,
                                        adui, awg, afg, name)
예제 #3
0
def generate_config_deformed_mesh(cpacs_path, cpacs_out_path, skip_config=False, skip_su2=False):
    """Function to generate all deform meshes with SU2 from CPACS data

    Function 'generate_config_deformed_mesh' reads data in the CPACS file
    and generate all the corresponding directory and config file which allow to
    generate deformed meshes.

    Args:
        cpacs_path (str): Path to CPACS file
        cpacs_out_path (str):Path to CPACS output file
        skip_config (bool):
        skip_su2 (bool):

    """

    tixi = open_tixi(cpacs_path)

    wkdir = get_results_directory("SU2Run")

    # Get SU2 mesh path
    su2_mesh_xpath = "/cpacs/toolspecific/CEASIOMpy/filesPath/su2Mesh"
    su2_mesh_path = get_value(tixi, su2_mesh_xpath)

    if wkdir in su2_mesh_path:
        log.info("The Baseline SU2 mesh is already in the working directory.")
    else:
        mesh_dir = os.path.join(wkdir, "MESH")
        if not os.path.isdir(mesh_dir):
            os.mkdir(mesh_dir)
        ac_name = aircraft_name(tixi)
        su2_mesh_new_path = os.path.join(mesh_dir, ac_name + "_baseline.su2")
        shutil.copyfile(su2_mesh_path, su2_mesh_new_path)
        tixi.updateTextElement(su2_mesh_xpath, su2_mesh_new_path)

    if not skip_config:

        # Control surfaces deflections
        control_surf_xpath = SU2_XPATH + "/options/clalculateCotrolSurfacesDeflections"
        control_surf = get_value_or_default(tixi, control_surf_xpath, False)

        if not control_surf:
            log.warning(
                "The CPACS file indicate that Control surface deflection should not be calculated!"
            )
            # active_ted_list = []
        else:

            ted_df = get_ted_list(tixi)

            # TODO: option to calculate only TED selected in cpacs
            # if ...
            #     active_ted_xpath = SU2_XPATH + '/options/....'
            #     # check element
            #     active_ted_list = get_string_vector(tixi,active_ted_xpath)
            # else: calculate all TED adn all deflections from CPACS
            #     active_ted_list = ted_list

            for i, row in ted_df.iterrows():

                # Unwrap TED data from the dataframe
                ted_uid = row["ted_uid"]
                wing_uid = row["wing_uid"]
                sym_dir = row["sym_dir"]
                defl_list = row["defl_list"]

                generate_mesh_def_config(tixi, wkdir, ted_uid, wing_uid, sym_dir, defl_list)

    if not skip_su2:

        run_mesh_deformation(tixi, wkdir)

    tixi.save(cpacs_out_path)
예제 #4
0
def generate_mesh_def_config(tixi, wkdir, ted_uid, wing_uid, sym_dir, defl_list):
    """Function to create config file for a TED.

    Function 'generate_mesh_def_config' will create SU2 configuration files to
    create SU2 deformed mesh for a specific Trailing Edge Device (TED) at several
    deflection angle (from defl_list)

    Args:
        tixi (handle): TIXI handle
        wkdir (str): Path to the working directory
        ted_uid (str): uID of the TED
        wing_uid (str): uID of the coresponding wing
        sym_dir (str): Direction of the axis of symmetry ('x','y','z' or '')
        defl_list (str): List of deflection angles to generate

    """

    tigl = open_tigl(tixi)
    ac_name = aircraft_name(tixi)
    DEFAULT_CONFIG_PATH = MODULE_DIR + "/files/DefaultConfig_v7.cfg"
    cfg = ConfigFile(DEFAULT_CONFIG_PATH)
    config_dir_name = ac_name + "_TED_" + ted_uid
    # TODO: add check or remove if already exist?
    os.mkdir(os.path.join(wkdir, "MESH", config_dir_name))

    # Get TED and hinge line definition
    ted_corner = get_ted_corner(tixi, tigl, ted_uid)
    ted_corner_list, ted_corner_sym_list = get_ffd_box(ted_corner, sym_dir)
    ted_hinge = get_ted_hinge(tixi, tigl, ted_uid)
    hinge_list, hinge_sym_list = get_hinge_lists(ted_hinge, sym_dir)

    # General parmeters
    ref_len = get_value(tixi, REF_XPATH + "/length")
    ref_area = get_value(tixi, REF_XPATH + "/area")
    ref_ori_moment_x = get_value_or_default(tixi, REF_XPATH + "/point/x", 0.0)
    ref_ori_moment_y = get_value_or_default(tixi, REF_XPATH + "/point/y", 0.0)
    ref_ori_moment_z = get_value_or_default(tixi, REF_XPATH + "/point/z", 0.0)

    cfg["REF_LENGTH"] = ref_len
    cfg["REF_AREA"] = ref_area
    cfg["REF_ORIGIN_MOMENT_X"] = ref_ori_moment_x
    cfg["REF_ORIGIN_MOMENT_Y"] = ref_ori_moment_y
    cfg["REF_ORIGIN_MOMENT_Z"] = ref_ori_moment_z
    cfg["GRID_MOVEMENT"] = "NONE"
    cfg["ROTATION_RATE"] = "0.0 0.0 0.0"

    # TODO: is it the best way or should be pass as arg?
    mesh_dir = os.path.join(wkdir, "MESH")
    su2_mesh_path = os.path.join(mesh_dir, ac_name + "_baseline.su2")
    cfg["MESH_FILENAME"] = "../" + ac_name + "_baseline.su2"

    # Mesh Marker
    bc_wall_list, engine_bc_list = get_mesh_marker(su2_mesh_path)

    bc_wall_str = "(" + ",".join(bc_wall_list) + ")"
    cfg["MARKER_EULER"] = bc_wall_str
    cfg["MARKER_FAR"] = " (Farfield)"
    cfg["MARKER_SYM"] = " (0)"
    cfg["MARKER_PLOTTING"] = bc_wall_str
    cfg["MARKER_MONITORING"] = bc_wall_str
    cfg["MARKER_MOVING"] = "( NONE )"
    cfg["DV_MARKER"] = bc_wall_str

    # FFD BOX definition
    cfg["DV_KIND"] = "FFD_SETTING"
    cfg["DV_MARKER"] = "( " + wing_uid + ")"
    cfg["FFD_CONTINUITY"] = "2ND_DERIVATIVE"
    cfg["FFD_DEFINITION"] = "( " + ted_uid + ", " + ",".join(ted_corner_list) + ")"
    cfg["FFD_DEGREE"] = "( 6, 10, 3 )"  # TODO: how to chose/calculate these value?
    if sym_dir:
        cfg["FFD_DEFINITION"] += "; (" + ted_uid + "_sym, " + ",".join(ted_corner_sym_list) + ")"
        cfg["FFD_DEGREE"] += ";( 6, 10, 3 )"  # TODO: how to chose/calculate these value?
    cfg["MESH_OUT_FILENAME"] = "_mesh_ffd_box.su2"

    # Write Config definition for FFD box
    config_file_name = "ConfigDEF.cfg"
    config_path = os.path.join(wkdir, "MESH", config_dir_name, config_file_name)
    cfg.write_file(config_path, overwrite=True)
    log.info(config_path + " have has been written.")

    # FFD BOX rotation
    for defl in defl_list:

        cfg["DV_KIND"] = "FFD_ROTATION"
        cfg["DV_MARKER"] = "( " + wing_uid + ")"
        cfg["DV_PARAM"] = "( " + ted_uid + ", " + ",".join(hinge_list) + ")"
        cfg["DV_VALUE"] = str(defl / 1000)  # SU2 use 1/1000 degree...

        cfg["MESH_FILENAME"] = "_mesh_ffd_box.su2"
        defl_mesh_name = ac_name + "_TED_" + ted_uid + "_defl" + str(defl) + ".su2"
        if sym_dir:
            defl_mesh_name = "_" + defl_mesh_name
        cfg["MESH_OUT_FILENAME"] = defl_mesh_name

        # Write Config rotation for FFD box
        config_file_name = "ConfigROT_defl" + str(defl) + ".cfg"
        config_path = os.path.join(wkdir, "MESH", config_dir_name, config_file_name)
        cfg.write_file(config_path, overwrite=True)
        log.info(config_path + " have has been written.")

        if sym_dir:
            # TODO: add a condition for anti symmetric deflection (e.g. ailerons)
            cfg["DV_MARKER"] = "( " + wing_uid + ")"
            cfg["DV_PARAM"] = "( " + ted_uid + "_sym, " + ",".join(hinge_sym_list) + ")"
            cfg["DV_VALUE"] = str(defl / 1000)  # SU2 use 1/1000 degree...

            cfg["MESH_FILENAME"] = defl_mesh_name
            defl_mesh_sym_name = ac_name + "_TED_" + ted_uid + "_defl" + str(defl) + "_sym.su2"
            cfg["MESH_OUT_FILENAME"] = defl_mesh_sym_name

            config_file_name = "ConfigROT_sym_defl" + str(defl) + ".cfg"
            config_path = os.path.join(wkdir, "MESH", config_dir_name, config_file_name)
            cfg.write_file(config_path, overwrite=True)
            log.info(config_path + " have has been written.")
예제 #5
0
def get_weight_estimations(cpacs_path, cpacs_out_path):
    """Function to estimate the all weights for a conventional aircraft.

    Function 'get_weight_estimations' ...

    Source:
        * Reference paper or book, with author and date, see ...

    Args:
        cpacs_path (str): Path to CPACS file
        cpacs_out_path (str):Path to CPACS output file

    """

    # Removing and recreating the ToolOutput folder.
    if os.path.exists("ToolOutput"):
        shutil.rmtree("ToolOutput")
    os.makedirs("ToolOutput")

    # Classes
    # TODO: Use only one class or subclasses
    ui = weightconvclass.UserInputs()
    mw = weightconvclass.MassesWeights()
    out = weightconvclass.WeightOutput()

    if not os.path.exists(cpacs_path):
        raise ValueError('No "ToolInput.xml" file in the ToolInput folder.')

    name = aircraft_name(cpacs_path)

    shutil.copyfile(cpacs_path, cpacs_out_path)  # TODO: shoud not be like that
    newpath = "ToolOutput/" + name
    if not os.path.exists(newpath):
        os.makedirs(newpath)

    ag = geometry.geometry_eval(cpacs_path, name)
    fuse_length = round(ag.fuse_length[0], 3)
    fuse_width = round(np.amax(ag.fuse_sec_width[:, 0]), 3)
    ind = weightconvclass.InsideDimensions(fuse_length, fuse_width)
    ind.nose_length = round(ag.fuse_nose_length[0], 3)
    ind.tail_length = round(ag.fuse_tail_length[0], 3)
    ind.cabin_length = round(ag.fuse_cabin_length[0], 3)
    wing_area = round(ag.wing_plt_area_main, 3)
    wing_span = round(ag.wing_span[ag.main_wing_index - 1], 3)
    wing_area_tot = np.sum(ag.wing_plt_area)

    # Has been replace by classes function
    # (ind, ui) = getinput.get_user_inputs(ind, ui, ag, cpacs_out_path)
    ui.get_user_inputs(cpacs_out_path)
    ind.get_inside_dim(cpacs_out_path)

    if ui.MAX_FUEL_VOL > 0 and ui.MAX_FUEL_VOL < ag.wing_fuel_vol:
        max_fuel_vol = ui.MAX_FUEL_VOL
    else:
        max_fuel_vol = ag.wing_fuel_vol

    out.PILOT_NB = ui.PILOT_NB  # Number of pilot [-].

    # Massimum payload allowed, set 0 if equal to max passenger mass.
    mw.MAX_PAYLOAD = ui.MAX_PAYLOAD

    # Adding extra length in case of aircraft with second floor [m].
    if ui.IS_DOUBLE_FLOOR == 1:
        cabin_length2 = ind.cabin_length * 1.91
    elif ui.IS_DOUBLE_FLOOR == 2:
        cabin_length2 = ind.cabin_length * 1.20
    elif ui.IS_DOUBLE_FLOOR == 0:
        cabin_length2 = ind.cabin_length
    else:
        log.warning("Warning, double floor index can be only 0 (1 floor),\
                    2 (B747-2nd floor type) or 3 (A380-2nd floor type).\
                    Set Default value (0)")
        cabin_length2 = ind.cabin_length

    # Maximum Take Off Mass Evaluation
    mw.maximum_take_off_mass = estimate_mtom(fuse_length, fuse_width,
                                             wing_area, wing_span, name)

    # Wing loading
    out.wing_loading = mw.maximum_take_off_mass / wing_area_tot

    # Operating Empty Mass evaluation
    mw.operating_empty_mass = estimate_operating_empty_mass(
        mw.maximum_take_off_mass, fuse_length, fuse_width, wing_area,
        wing_span, ui.TURBOPROP)

    # Passengers and Crew mass evaluation
    if (fuse_width /
        (1 + (ind.fuse_thick / 100))) > (ind.seat_width + ind.aisle_width):
        (
            out.pass_nb,
            out.row_nb,
            out.abreast_nb,
            out.aisle_nb,
            out.toilet_nb,
            ind,
        ) = estimate_passengers(ui.PASS_PER_TOILET, cabin_length2, fuse_width,
                                ind)

        get_seat_config(
            out.pass_nb,
            out.row_nb,
            out.abreast_nb,
            out.aisle_nb,
            ui.IS_DOUBLE_FLOOR,
            out.toilet_nb,
            ui.PASS_PER_TOILET,
            fuse_length,
            ind,
            name,
        )
    else:
        out.pass_nb = 0
        raise Exception("The aircraft can not transport passengers, increase" +
                        " fuselage width." + "\nCabin Width [m] = " +
                        str((fuse_width / (1 + ind.fuse_thick))) +
                        " is less than seat width [m]" +
                        " + aisle width [m] = " +
                        str(ind.seat_width + ind.aisle_width))

    (out.crew_nb, out.cabin_crew_nb,
     mw.mass_crew) = estimate_crew(out.pass_nb, ui.MASS_PILOT,
                                   ui.MASS_CABIN_CREW,
                                   mw.maximum_take_off_mass, out.PILOT_NB)

    mw.mass_payload = out.pass_nb * ui.MASS_PASS + ui.MASS_CARGO

    mw.mass_people = mw.mass_crew + out.pass_nb * ui.MASS_PASS

    maxp = False
    if mw.MAX_PAYLOAD > 0 and mw.mass_payload > mw.MAX_PAYLOAD:
        mw.mass_payload = mw.MAX_PAYLOAD
        maxp = True
        log.info("With the fixed payload, passenger nb reduced to: " +
                 str(round(mw.MAX_PAYLOAD / (ui.MASS_PASS), 0)))

    # Fuel Mass evaluation
    # Maximum fuel that can be stored with maximum number of passengers.

    if not ui.MAX_FUEL_VOL:  # TODO while retesting, redo fitting
        if ui.TURBOPROP:
            if wing_area > 55.00:
                mw.mass_fuel_max = round(mw.maximum_take_off_mass / 4.6, 3)
            else:
                mw.mass_fuel_max = round(mw.maximum_take_off_mass / 3.6, 3)
        elif wing_area < 90.00:
            if fuse_length < 60.00:
                mw.mass_fuel_max = round(mw.maximum_take_off_mass / 4.3, 3)
            else:
                mw.mass_fuel_max = round(mw.maximum_take_off_mass / 4.0, 3)
        elif wing_area < 300.00:
            if fuse_length < 35.00:
                mw.mass_fuel_max = round(mw.maximum_take_off_mass / 3.6, 3)
            else:
                mw.mass_fuel_max = round(mw.maximum_take_off_mass / 3.8, 3)
        elif wing_area < 400.00:
            mw.mass_fuel_max = round(mw.maximum_take_off_mass / 2.2, 3)
        elif wing_area < 600.00:
            mw.mass_fuel_max = round(mw.maximum_take_off_mass / 2.35, 3)
        else:
            mw.mass_fuel_max = round(mw.maximum_take_off_mass / 2.8, 3)
    else:
        mw.mass_fuel_max = round(max_fuel_vol * ui.FUEL_DENSITY, 3)

    mw.mass_fuel_maxpass = round(
        mw.maximum_take_off_mass - mw.operating_empty_mass - mw.mass_payload,
        3)

    if mw.MAX_FUEL_MASS > 0 and mw.mass_fuel_maxpass > mw.MAX_FUEL_MASS:
        mw.mass_fuel_maxpass = mw.MAX_FUEL_MASS
        log.info("Maximum fuel ammount allowed reached [kg]: " +
                 str(mw.mass_fuel_maxpass))
        if mw.maximum_take_off_mass > (mw.mass_fuel_maxpass +
                                       mw.operating_empty_mass +
                                       mw.mass_payload):
            mw.mass_cargo = mw.maximum_take_off_mass - (
                mw.mass_fuel_maxpass + mw.operating_empty_mass +
                mw.mass_payload)
            if not maxp:
                log.info("Adding extra payload mass [kg]: " +
                         str(mw.mass_cargo))
                mw.mass_payload = mw.mass_payload + mw.mass_cargo
            else:
                mw.maximum_take_off_mass = mw.maximum_take_off_mass - mw.mass_cargo
                log.info("With all the constrains on the fuel and payload, " +
                         "the maximum take off mass is not reached." +
                         "\n Maximum take off mass [kg]: " +
                         str(mw.maximum_take_off_mass))
    else:
        log.info("Fuel mass with maximum passengers [kg]: " +
                 str(mw.mass_fuel_maxpass))

    if mw.MAX_FUEL_MASS > 0 and mw.mass_fuel_max > mw.MAX_FUEL_MASS:
        mw.mass_fuel_max = mw.MAX_FUEL_MASS

    # Zero Fuel Mass evaluation
    mw.zero_fuel_mass = (mw.maximum_take_off_mass - mw.mass_fuel_maxpass +
                         (ui.RES_FUEL_PERC) * mw.mass_fuel_max)

    # Log writting  (TODO: maybe create a separate function)
    log.info("---- Geometry evaluation from CPACS file ----")
    log.info("Fuselage length [m]: " + str(round(fuse_length, 3)))
    log.info("Fuselage width [m]: " + str(round(fuse_width, 3)))
    log.info("Fuselage mean width [m]: " + str(round(ag.fuse_mean_width, 3)))
    log.info("Wing Span [m]: " + str(round(wing_span, 3)))

    log.info("--------- Masses evaluated: -----------")
    log.info("Maximum Take Off Mass [kg]: " +
             str(int(round(mw.maximum_take_off_mass))))
    log.info("Operating Empty Mass [kg]: " +
             str(int(round(mw.operating_empty_mass))))
    log.info("Zero Fuel Mass [kg]: " + str(int(round(mw.zero_fuel_mass))))
    log.info("Wing loading [kg/m^2]: " + str(int(round(out.wing_loading))))
    log.info("Maximum ammount of fuel allowed with no passengers [kg]: " +
             str(int(round(mw.mass_fuel_max))))
    log.info("Maximum ammount of fuel allowed with no passengers [l]: " +
             str(int(round(mw.mass_fuel_max / ui.FUEL_DENSITY))))
    log.info("--------- Passegers evaluated: ---------")
    log.info("Passengers: " + str(out.pass_nb))
    log.info("Lavatory: " + str(out.toilet_nb))
    log.info("Payload mass [kg]: " + str(mw.mass_payload))
    log.info("------- Crew members evaluated: --------")
    log.info("Pilots: " + str(out.PILOT_NB))
    log.info("Cabin crew members: " + str(out.cabin_crew_nb))
    log.info("############### Weight estimation completed ###############")

    # Outptu writting
    log.info("-------- Generating output text file --------")
    outputweightgen.output_txt(out, mw, ind, ui, name)

    # CPACS writting
    cpacsweightupdate.cpacs_update(mw, out, cpacs_path, cpacs_out_path)
예제 #6
0
def get_range_estimation(cpacs_path, cpacs_out_path):

    if os.path.exists("ToolOutput"):
        shutil.rmtree("ToolOutput")
    os.makedirs("ToolOutput")

    if not os.path.exists(cpacs_path):
        raise ValueError('No "ToolInput.xml" file in the ToolInput folder.')

    name = aircraft_name(cpacs_path)

    shutil.copyfile(cpacs_path, cpacs_out_path)  # TODO: shoud not be like that
    newpath = "ToolOutput/" + name
    if not os.path.exists(newpath):
        os.makedirs(newpath)

    # RANGE ANALYSIS IMPUTS

    ri = rangeclass.RangeInputs()
    out = rangeclass.RangeOutput()
    mw = rangeclass.MassesWeights()

    (mw, ri) = getdatafromcpacs.get_data(mw, ri, cpacs_out_path)

    if ri.TURBOPROP:
        LDcru = ri.LD
        LDloi = ri.LD * 0.866
    else:
        LDcru = ri.LD * 0.866
        LDloi = ri.LD

    if ri.WINGLET >= 0:
        ri.TSFC_CRUISE = ri.TSFC_CRUISE - 0.05 * ri.WINGLET
    elif ri.WINGLET > 2:
        log.warning("Warning, winglet type index is 1 (medium efficiency)," +
                    " 2 (high efficiency). Set no winglet (0)")

    # RANGE ANALYSIS

    log.info("-------- Starting the range analysis --------")
    log.info("---------- Aircraft: " + name + " -----------")

    # RANGE AND FUEL CONSUMPTION
    mw = fuel_consumption(LDloi, mw, ri, ri.RES_FUEL_PERC)

    (out.ranges, out.ranges_cru,
     mw.m_pass_middle) = breguet_cruise_range(LDcru, ri, mw, ri.RES_FUEL_PERC)

    if mw.m_pass_middle:
        out.payloads = [
            round(mw.mass_payload, 0),
            round(mw.mass_payload, 0),
            round(mw.m_pass_middle, 0),
            0,
        ]
    else:
        out.payloads = [
            round(mw.mass_payload, 0),
            round(mw.mass_payload, 0),
            round(mw.mass_payload, 0),
            0,
        ]

    # CREW MEMBERS CHECK
    if ri.cabin_crew_nb:
        (
            out.pilot_nb,
            out.cabin_crew_nb,
            out.crew_nb,
            out.mass_crew,
            out.flight_time,
        ) = crew_check(out.ranges[1], ri)

    # OUTPUT WRITING

    log.info("-------- Generating output text file --------")
    outputrangegen.output_txt(LDloi, LDcru, mw, ri, out, name)

    # CPACS WRITING

    cpacsrangeupdate.cpacs_update(ri.MASS_PASS, out, mw, cpacs_out_path)

    if os.path.exists("ToolInput/conv.temp"):
        B = "BalanceConventional/ToolInput"
    elif os.path.exists("ToolInput/unconv.temp"):
        B = "BalanceUnconventional/ToolInput"
    elif os.path.exists("ToolInput/nocpacs.temp"):
        log.warning("No Balance analysis without cpacs geometry file")
        B = False
    else:
        raise Exception("Error no conv.temp, unconv.temp " +
                        "or nocpacs.temp inside ToolInput folder")

    if os.path.exists("ToolOutput/ToolOutput.xml") and B:
        if os.path.exists("../" + B):
            shutil.rmtree("../" + B)
            os.makedirs("../" + B)
        # PATH_BALANCE_OUT = "../" + B + "/ToolInput.xml"
        # shutil.copyfile('ToolOutput/ToolOutput.xml', PATH_BALANCE_OUT)

    # PLOTS
    # Payload vs Range ---------------------------------------------------------
    log.info("---- Generating payload versus range plot ---")
    outputrangegen.payload_range_plot(out.ranges, out.ranges_cru, out.payloads,
                                      mw, name)

    # Show plots
    # plt.show()

    # LOG WRITING
    log.info("------ Mass evaluation completed ------")
    log.info("-------------- Masses -----------------")
    log.info("Payload mass [kg]: " + str(int(round(mw.mass_payload))))
    log.info("Total fuel mass [kg]: " + str(int(round(mw.mass_fuel_max))))
    log.info("Mass of fuel with maximum passengers [kg]:" +
             str(int(round(mw.mass_fuel_maxpass))))
    log.info("Maximum Take Off Mass [kg]: " +
             str(int(round(mw.maximum_take_off_mass))))

    if ri.cabin_crew_nb:
        log.info("------- Suggested crew members --------")
        log.info("Pilots: " + str(out.pilot_nb))
        log.info("Cabin crew members: " + str(out.cabin_crew_nb))
        log.info("Flight time [min]: " + str(int(round(out.flight_time * 60))))

    log.info("--------------- Ranges ----------------")
    log.info("Range with maximum payload [km]: " +
             str(int(round(out.ranges[1]))))
    log.info("Range with maximum fuel and some payload [km]: " +
             str(int(round(out.ranges[2]))))
    log.info("Maximum range [km]: " + str(int(round(out.ranges[-1]))))

    log.info("------------- Cruise Ranges --------------")
    log.info("Cruise range with maximum payload [km]: " +
             str(int(round(out.ranges_cru[1]))))
    log.info("Cruise range with maximum fuel and some payload [km]: " +
             str(int(round(out.ranges_cru[2]))))
    log.info("Maximum cruise range [km]: " +
             str(int(round(out.ranges_cru[-1]))))
    log.info("--- Fuel Consumption  (max passengers) ---")
    log.info("Fuel for take off [kg]: " + str(int(round(mw.mf_for_to))))
    log.info("Fuel for climb [kg]: " + str(int(round(mw.mf_for_climb))))
    log.info("Fuel for cruise [kg]: " + str(int(round(mw.mf_for_cruise))))
    log.info("Fuel for a 30 min loiter [kg]: " +
             str(int(round(mw.mf_for_loiter))))
    log.info("Fuel for landing [kg]: " + str(int(round(mw.mf_for_landing))))
    log.info("Total fuel remaining after landing [kg]: " +
             str(int(round(mw.mf_after_land))))

    log.info("------ Weigth loss (max passengers) ------")
    log.info("Weight after take off [N]: " + str(int(round(mw.w_after_to))))
    log.info("Weight after climb [N]: " + str(int(round(mw.w_after_climb))))
    log.info("Weight after cruise [N]: " + str(int(round(mw.w_after_cruise))))
    log.info("Weight after a 30 min loiter [N]: " +
             str(int(round(mw.w_after_loiter))))
    log.info("Weight after landing [N]: " + str(int(round(mw.w_after_land))))

    log.info("############### Range estimation completed ###############")
예제 #7
0
def get_balance_estimations(cpacs_path, cpacs_out_path):
    """Function to estimate inertia value and CoF of an conventional aircraft.

    Function 'get_balance_unc_estimations' ...

    Source:
        * Reference paper or book, with author and date, see ...

    Args:
        cpacs_path (str): Path to CPACS file
        cpacs_out_path (str):Path to CPACS output file

    """

    # Removing and recreating the ToolOutput folder.
    if os.path.exists("ToolOutput"):
        shutil.rmtree("ToolOutput")
    os.makedirs("ToolOutput")

    if not os.path.exists(cpacs_path):
        raise ValueError('No "ToolInput.xml" file in the ToolInput folder.')

    name = aircraft_name(cpacs_path)

    shutil.copyfile(cpacs_path, cpacs_out_path)  # TODO: shoud not be like that
    newpath = "ToolOutput/" + name
    if not os.path.exists(newpath):
        os.makedirs(newpath)

    # BALANCE ANALSIS INPUTS
    bi = balanceconvclass.BalanceInputs()
    out = balanceconvclass.BalanceOutputs()
    mw = balanceconvclass.MassesWeights()
    (mw, bi) = getdatafromcpacs.get_data(mw, bi, cpacs_out_path)

    # BALANCE ANALYSIS

    log.info("------- Starting the balance analysis -------")
    log.info("---------- Aircraft: " + name + " -----------")
    F_PERC_MAXPASS = (mw.mass_fuel_maxpass / mw.mass_fuel_max) * 100

    # CENTER OF GRAVITY---------------------------------------------------------
    ag = geometry.geometry_eval(cpacs_out_path, name)

    log.info("------- Center of Gravity coordinates -------")
    log.info("--------- Max Payload configuration ---------")
    (out.center_of_gravity, mass_seg_i,
     airplane_centers_segs) = center_of_gravity_evaluation(
         F_PERC_MAXPASS, 100, ag.cabin_seg, ag, mw, bi.WING_MOUNTED)
    log.info("[x, y, z] = " + str(out.center_of_gravity))
    log.info("---------- Zero Fuel configuration ----------")
    (out.cg_zfm, ms_zfm, airplane_centers_segs) = center_of_gravity_evaluation(
        0, 100, ag.cabin_seg, ag, mw, bi.WING_MOUNTED)
    log.info("[x, y, z] = " + str(out.cg_zfm))
    log.info("-------- Zero Payload configuration ---------")
    (out.cg_zpm, ms_zpm, airplane_centers_segs) = center_of_gravity_evaluation(
        100, 0, ag.cabin_seg, ag, mw, bi.WING_MOUNTED)
    log.info("[x, y, z] = " + str(out.cg_zpm))
    log.info("------------- OEM configuration -------------")
    (out.cg_oem, ms_oem, airplane_centers_segs) = center_of_gravity_evaluation(
        0, 0, ag.cabin_seg, ag, mw, bi.WING_MOUNTED)
    log.info("[x, y, z] = " + str(out.cg_oem))
    if bi.USER_CASE == True:
        if bi.P_PERC < 0 or bi.F_PERC < 0:
            raise Exception("Error, F_PERC and P_PERC can" +
                            " not be zero or negative.")
        if (mw.mass_fuel_maxpass * (bi.F_PERC / 100.0) + mw.mass_payload *
            (bi.P_PERC / 100.0)) > mw.mass_fuel_maxpass + mw.mass_payload:
            log.warning("Exceeding maximum fuel amount with the" +
                        "chosen payload mass," +
                        "fuel mass automatically reduced")
            bi.F_PERC = 1 + ((mw.mass_payload / mw.mass_fuel_maxpass) *
                             (1 - (bi.P_PERC / 100.0)))
            log.warning("FUEL percentage: " + str(bi.F_PERC))
        log.info("------------- User configuration ------------")
        (out.cg_user, ms_user,
         airplane_centers_segs) = center_of_gravity_evaluation(
             bi.F_PERC * 100, bi.P_PERC, ag.cabin_seg, ag, mw, bi.WING_MOUNTED)

    # MOMENT OF INERTIA
    log.info("------------- Inertia Evaluation ------------")
    log.info("------------ Lumped mass Inertia ------------")
    log.info("--------- Max Payload configuration ---------")
    (_, _, _, Ixxf, Iyyf, Izzf, Ixyf, Iyzf,
     Ixzf) = lumpedmassesinertia.fuselage_inertia(bi.SPACING_FUSE,
                                                  out.center_of_gravity,
                                                  mass_seg_i, ag,
                                                  cpacs_out_path)
    (_, _, _, Ixxw, Iyyw, Izzw, Ixyw, Iyzw,
     Ixzw) = lumpedmassesinertia.wing_inertia(bi.WPP, bi.SPACING_WING,
                                              out.center_of_gravity,
                                              mass_seg_i, ag, cpacs_out_path)

    rd = check_rounding(Ixxf + Ixxw, Iyzf + Iyzw)
    out.Ixx_lump = round(Ixxf + Ixxw, rd)
    out.Iyy_lump = round(Iyyf + Iyyw, rd)
    out.Izz_lump = round(Izzf + Izzw, rd)
    out.Ixy_lump = round(Ixyf + Ixyw, rd)
    out.Iyz_lump = round(Iyzf + Iyzw, rd)
    out.Ixz_lump = round(Ixzf + Ixzw, rd)

    log.info("---------- Zero Fuel configuration ----------")
    (_, _, _, Ixxf2, Iyyf2, Izzf2, Ixyf2, Iyzf2,
     Ixzf2) = lumpedmassesinertia.fuselage_inertia(bi.SPACING_FUSE, out.cg_zfm,
                                                   ms_zfm, ag, cpacs_out_path)
    (_, _, _, Ixxw2, Iyyw2, Izzw2, Ixyw2, Iyzw2,
     Ixzw2) = lumpedmassesinertia.wing_inertia(bi.WPP, bi.SPACING_WING,
                                               out.cg_zfm, ms_zfm, ag,
                                               cpacs_out_path)

    out.Ixx_lump_zfm = round(Ixxf2 + Ixxw2, rd)
    out.Iyy_lump_zfm = round(Iyyf2 + Iyyw2, rd)
    out.Izz_lump_zfm = round(Izzf2 + Izzw2, rd)
    out.Ixy_lump_zfm = round(Ixyf2 + Ixyw2, rd)
    out.Iyz_lump_zfm = round(Iyzf2 + Iyzw2, rd)
    out.Ixz_lump_zfm = round(Ixzf2 + Ixzw2, rd)

    log.info("--------- Zero Payload configuration --------")
    (_, _, _, Ixxf3, Iyyf3, Izzf3, Ixyf3, Iyzf3,
     Ixzf3) = lumpedmassesinertia.fuselage_inertia(bi.SPACING_FUSE, out.cg_zpm,
                                                   ms_zpm, ag, cpacs_out_path)
    (_, _, _, Ixxw3, Iyyw3, Izzw3, Ixyw3, Iyzw3,
     Ixzw3) = lumpedmassesinertia.wing_inertia(bi.WPP, bi.SPACING_WING,
                                               out.cg_zpm, ms_zpm, ag,
                                               cpacs_out_path)

    out.Ixx_lump_zpm = round(Ixxf3 + Ixxw3, rd)
    out.Iyy_lump_zpm = round(Iyyf3 + Iyyw3, rd)
    out.Izz_lump_zpm = round(Izzf3 + Izzw3, rd)
    out.Ixy_lump_zpm = round(Ixyf3 + Ixyw3, rd)
    out.Iyz_lump_zpm = round(Iyzf3 + Iyzw3, rd)
    out.Ixz_lump_zpm = round(Ixzf3 + Ixzw3, rd)

    log.info("------------- OEM configuration -------------")
    (fx, fy, fz, Ixxf4, Iyyf4, Izzf4, Ixyf4, Iyzf4,
     Ixzf4) = lumpedmassesinertia.fuselage_inertia(bi.SPACING_FUSE, out.cg_oem,
                                                   ms_oem, ag, cpacs_out_path)
    (wx, wy, wz, Ixxw4, Iyyw4, Izzw4, Ixyw4, Iyzw4,
     Ixzw4) = lumpedmassesinertia.wing_inertia(bi.WPP, bi.SPACING_WING,
                                               out.cg_oem, ms_oem, ag,
                                               cpacs_out_path)

    out.Ixx_lump_oem = round(Ixxf4 + Ixxw4, rd)
    out.Iyy_lump_oem = round(Iyyf4 + Iyyw4, rd)
    out.Izz_lump_oem = round(Izzf4 + Izzw4, rd)
    out.Ixy_lump_oem = round(Ixyf4 + Ixyw4, rd)
    out.Iyz_lump_oem = round(Iyzf4 + Iyzw4, rd)
    out.Ixz_lump_oem = round(Ixzf4 + Ixzw4, rd)

    if bi.USER_CASE:
        log.info("------------- User configuration ------------")
        (
            fx,
            fy,
            fz,
            Ixxfu,
            Iyyfu,
            Izzfu,
            Ixyfu,
            Iyzfu,
            Ixzfu,
        ) = lumpedmassesinertia.fuselage_inertia(bi.SPACING_FUSE, out.cg_user,
                                                 ms_user, ag, cpacs_out_path)
        (wx, wy, wz, Ixxwu, Iyywu, Izzwu, Ixywu, Iyzwu,
         Ixzwu) = lumpedmassesinertia.wing_inertia(bi.WPP, bi.SPACING_WING,
                                                   out.cg_user, ms_user, ag,
                                                   cpacs_out_path)

        out.Ixx_lump_user = round(Ixxfu + Ixxwu, rd)
        out.Iyy_lump_user = round(Iyyfu + Iyywu, rd)
        out.Izz_lump_user = round(Izzfu + Izzwu, rd)
        out.Ixy_lump_user = round(Ixyfu + Ixywu, rd)
        out.Iyz_lump_user = round(Iyzfu + Iyzwu, rd)
        out.Ixz_lump_user = round(Ixzfu + Ixzwu, rd)

    # OUTPUT WRITING

    log.info("-------- Generating output text file --------")
    outputbalancegen.output_txt(out, mw, bi, name)

    # CPACS WRITING
    cpacsbalanceupdate.cpacs_mbd_update(out, mw, bi, np.sum(ms_zpm),
                                        cpacs_out_path)

    # PLOTS
    # Aircraft Cog Plot
    log.info("--- Generating aircraft center of gravity plot (.png) ---")
    outputbalancegen.aircraft_cog_plot(out.center_of_gravity, ag, name)

    # Aircraft Nodes
    # Uncomment to plot aircraft nodes.
    # log.info('--- Generating aircraft nodes plot (.png) ---')
    # outputbalancegen.aircraft_nodes_plot(fx, fy, fz, wx, wy, wz, name)

    # Show plots
    plt.show()

    # LOG WRITING
    log.info("---- Center of Gravity coordinates ----")
    log.info("------ Max Payload configuration ------")
    log.info("[x, y, z]: " + str(out.center_of_gravity))
    log.info("---------------------------------------")
    log.info("------- Zero Fuel configuration -------")
    log.info("[x, y, z]: " + str(out.cg_zfm))
    log.info("---------------------------------------")
    log.info("----- Zero Payload configuration ------")
    log.info("[x, y, z]: " + str(out.cg_zpm))
    log.info("---------------------------------------")
    log.info("---------- OEM configuration ----------")
    log.info("[x, y, z]: " + str(out.cg_oem))
    log.info("---------------------------------------")
    if bi.USER_CASE:
        log.info("---------- User configuration ---------")
        log.info("Chosen Fuel Percentage: " + str(bi.F_PERC))
        log.info("Chosen Payload Percentage: " + str(bi.P_PERC))
        log.info("[x, y, z]: " + str(out.cg_user))
    log.info("---------------------------------------")
    log.info("---------- Inertia Evaluation ---------")
    log.info("--------- Lumped mass Inertia ---------")
    log.info("------ Max Payload configuration ------")
    log.info("Roll moment, Ixx [kgm^2]: " + str(out.Ixx_lump))
    log.info("Pitch moment, Iyy [kgm^2]: " + str(out.Iyy_lump))
    log.info("Yaw moment, Izz [kgm^2]: " + str(out.Izz_lump))
    log.info("Ixy moment [kgm^2]: " + str(out.Ixy_lump))
    log.info("Iyz moment [kgm^2]: " + str(out.Iyz_lump))
    log.info("Ixz moment [kgm^2]: " + str(out.Ixz_lump))
    log.info("---------------------------------------")
    log.info("------- Zero Fuel configuration -------")
    log.info("Roll moment, Ixx [kgm^2]: " + str(out.Ixx_lump_zfm))
    log.info("Pitch moment, Iyy [kgm^2]: " + str(out.Iyy_lump_zfm))
    log.info("Yaw moment, Izz [kgm^2]: " + str(out.Izz_lump_zfm))
    log.info("Ixy moment [kgm^2]: " + str(out.Ixy_lump_zfm))
    log.info("Iyz moment [kgm^2]: " + str(out.Iyz_lump_zfm))
    log.info("Ixz moment [kgm^2]: " + str(out.Ixz_lump_zfm))
    log.info("---------------------------------------")
    log.info("------ Zero Payload configuration -----")
    log.info("Roll moment, Ixx [kgm^2]: " + str(out.Ixx_lump_zpm))
    log.info("Pitch moment, Iyy [kgm^2]: " + str(out.Iyy_lump_zpm))
    log.info("Yaw moment, Izz [kgm^2]: " + str(out.Izz_lump_zpm))
    log.info("Ixy moment [kgm^2]: " + str(out.Ixy_lump_zpm))
    log.info("Iyz moment [kgm^2]: " + str(out.Iyz_lump_zpm))
    log.info("Ixz moment [kgm^2]: " + str(out.Ixz_lump_zpm))
    log.info("---------------------------------------")
    log.info("---------- OEM configuration ----------")
    log.info("Roll moment, Ixx [kgm^2]: " + str(out.Ixx_lump_oem))
    log.info("Pitch moment, Iyy [kgm^2]: " + str(out.Iyy_lump_oem))
    log.info("Yaw moment, Izz [kgm^2]: " + str(out.Izz_lump_oem))
    log.info("Ixy moment [kgm^2]: " + str(out.Ixy_lump_oem))
    log.info("Iyz moment [kgm^2]: " + str(out.Iyz_lump_oem))
    log.info("Ixz moment [kgm^2]: " + str(out.Ixz_lump_oem))
    log.info("---------------------------------------")
    if bi.USER_CASE:
        log.info("---------- User configuration ---------")
        log.info("Roll moment, Ixx [kgm^2]: " + str(out.Ixx_lump_user))
        log.info("Pitch moment, Iyy [kgm^2]: " + str(out.Iyy_lump_user))
        log.info("Yaw moment, Izz [kgm^2]: " + str(out.Izz_lump_user))
        log.info("Ixy moment [kgm^2]: " + str(out.Ixy_lump_user))
        log.info("Iyz moment [kgm^2]: " + str(out.Iyz_lump_user))
        log.info("Ixz moment [kgm^2]: " + str(out.Ixz_lump_user))
        log.info("---------------------------------------")

    log.info("############## Balance estimation completed ##############")
예제 #8
0
def get_balance_unc_estimations(cpacs_path, cpacs_out_path):
    """Function to estimate inertia value and CoF of an unconventional aircraft.

    Function 'get_balance_unc_estimations' ...

    Source:
        * Reference paper or book, with author and date, see ...

    Args:
        cpacs_path (str): Path to CPACS file
        cpacs_out_path (str):Path to CPACS output file

    """

    # Removing and recreating the ToolOutput folder.
    if os.path.exists("ToolOutput"):
        shutil.rmtree("ToolOutput")
    os.makedirs("ToolOutput")

    if not os.path.exists(cpacs_path):
        raise ValueError('No "ToolInput.xml" file in the ToolInput folder.')

    name = aircraft_name(cpacs_path)

    shutil.copyfile(cpacs_path, cpacs_out_path)  # TODO: shoud not be like that
    newpath = "ToolOutput/" + name
    if not os.path.exists(newpath):
        os.makedirs(newpath)

    bout = balanceuncclass.BalanceOutputs()

    # BALANCE ANALSIS INPUTS

    bi = balanceuncclass.BalanceInputs()
    mw = balanceuncclass.MassesWeights()
    ui = weightuncclass.UserInputs()
    ed = engineclass.EngineData()

    adui = weightuncclass.AdvancedInputs()

    (mw, ed) = getdatafromcpacs.get_data(ui, bi, mw, ed, cpacs_out_path)

    # GEOMETRY ANALYSIS

    (fus_nb, w_nb) = uncgeomanalysis.get_number_of_parts(cpacs_path)
    if not w_nb:
        log.warning("Aircraft does not have wings")
        raise Exception("Aircraft does not have wings")
    elif not fus_nb:
        (awg, wing_nodes) = uncgeomanalysis.no_fuse_geom_analysis(
            cpacs_path, ui.FLOORS_NB, w_nb, ui.H_LIM_CABIN, ui.FUEL_ON_CABIN,
            name, ed.TURBOPROP)
    else:
        log.info("Fuselage detected")
        log.info("Number of fuselage: " + str(int(fus_nb)))
        # Minimum fuselage segment height to be a cabin segment.
        h_min = ui.FLOORS_NB * ui.H_LIM_CABIN
        (afg, awg) = uncgeomanalysis.with_fuse_geom_analysis(
            cpacs_path, fus_nb, w_nb, h_min, adui, ed.TURBOPROP, ui.F_FUEL,
            name)

    ui = getdatafromcpacs.get_user_fuel(fus_nb, ui, cpacs_out_path)

    # BALANCE ANALYSIS

    log.info("----- Generating output text file -----")
    log.info("---- Starting the balance analysis ----")
    log.info("---- Aircraft: " + name)

    # CENTER OF GRAVITY

    if not fus_nb:
        (bout, airplane_centers_segs) = bwb_center_of_gravity(
            awg, bout, ui, bi, mw, ed)
    else:
        (bout, airplane_centers_segs) = unc_center_of_gravity(
            awg, afg, bout, ui, bi, mw, ed)

    # MOMENT OF INERTIA

    if not fus_nb:
        (bout, wx, wy,
         wz) = uncinertia.bwb_inertia_eval(awg, bout, bi, mw, ed,
                                           cpacs_out_path)
    else:
        (bout, fx, fy, fz, wx, wy,
         wz) = uncinertia.unc_inertia_eval(awg, afg, bout, bi, mw, ed,
                                           cpacs_out_path)

    # OUTPUT WRITING

    log.info("----- Generating output text file -----")
    outputbalancegen.output_txt(bout, mw, bi, ed, name)

    # CPACS WRITING
    cpacsbalanceupdate.cpacs_mbd_update(bout, mw, bi, np.sum(mw.ms_zpm),
                                        cpacs_out_path)

    # PLOTS

    log.info("--- Generating aircraft center of gravity plot (.png) ---")
    if not fus_nb:
        outputbalancegen.aircraft_cog_bwb_plot(bout.center_of_gravity, bi, ed,
                                               awg, name)
    else:
        outputbalancegen.aircraft_cog_unc_plot(bout.center_of_gravity, bi, ed,
                                               afg, awg, name)

    # Aircraft Nodes
    # log.info('--- Generating aircraft nodes plot (.png) ---')
    # if not fus_nb:
    # outputbalancegen.aircraft_nodes_bwb_plot(wx, wy, wz, name)
    # else:
    # outputbalancegen.aircraft_nodes_unc_plot(fx, fy, fz, wx, wy, wz, name)

    # Show plots
    plt.show()

    # LOG WRITING

    log.info("---- Center of Gravity coordinates ----")
    log.info("------ Max Payload configuration ------")
    log.info("[x, y, z]: " + str(bout.center_of_gravity))
    log.info("---------------------------------------")
    log.info("------- Zero Fuel configuration -------")
    log.info("[x, y, z]: " + str(bout.cg_zfm))
    log.info("---------------------------------------")
    log.info("----- Zero Payload configuration ------")
    log.info("[x, y, z]: " + str(bout.cg_zpm))
    log.info("---------------------------------------")
    log.info("---------- OEM configuration ----------")
    log.info("[x, y, z]: " + str(bout.cg_oem))
    log.info("---------------------------------------")

    if bi.USER_CASE:
        log.info("---------- User configuration ---------")
        log.info("Chosen Fuel Percentage: " + str(bi.F_PERC))
        log.info("Chosen Payload Percentage: " + str(bi.P_PERC))
        log.info("[x, y, z]: " + str(bout.cg_user))

    log.info("---------------------------------------")
    log.info("---------- Inertia Evaluation ---------")

    if bi.USER_EN_PLACEMENT:
        log.info("------------ Engine Inertia -----------")
        log.info("Roll moment, Ixx [kgm^2]: " + str(int(round(bout.Ixxen))))
        log.info("Pitch moment, Iyy [kgm^2]: " + str(int(round(bout.Iyyen))))
        log.info("Yaw moment, Izz [kgm^2]: " + str(int(round(bout.Izzen))))
        log.info("Ixy moment [kgm^2]: " + str(int(round(bout.Ixyen))))
        log.info("Iyz moment [kgm^2]: " + str(int(round(bout.Iyzen))))
        log.info("Ixz moment [kgm^2]: " + str(int(round(bout.Ixzen))))
        log.info("---------------------------------------")

    log.info("--------- Lumped mass Inertia ---------")
    log.info("------ Max Payload configuration ------")
    log.info("Roll moment, Ixx [kgm^2]: " + str(bout.Ixx_lump))
    log.info("Pitch moment, Iyy [kgm^2]: " + str(bout.Iyy_lump))
    log.info("Yaw moment, Izz [kgm^2]: " + str(bout.Izz_lump))
    log.info("Ixy moment [kgm^2]: " + str(bout.Ixy_lump))
    log.info("Iyz moment [kgm^2]: " + str(bout.Iyz_lump))
    log.info("Ixz moment [kgm^2]: " + str(bout.Ixz_lump))

    log.info("---------------------------------------")
    log.info("------- Zero Fuel configuration -------")
    log.info("Roll moment, Ixx [kgm^2]: " + str(bout.Ixx_lump_zfm))
    log.info("Pitch moment, Iyy [kgm^2]: " + str(bout.Iyy_lump_zfm))
    log.info("Yaw moment, Izz [kgm^2]: " + str(bout.Izz_lump_zfm))
    log.info("Ixy moment [kgm^2]: " + str(bout.Ixy_lump_zfm))
    log.info("Iyz moment [kgm^2]: " + str(bout.Iyz_lump_zfm))
    log.info("Ixz moment [kgm^2]: " + str(bout.Ixz_lump_zfm))

    log.info("---------------------------------------")
    log.info("------ Zero Payload configuration -----")
    log.info("Roll moment, Ixx [kgm^2]: " + str(bout.Ixx_lump_zpm))
    log.info("Pitch moment, Iyy [kgm^2]: " + str(bout.Iyy_lump_zpm))
    log.info("Yaw moment, Izz [kgm^2]: " + str(bout.Izz_lump_zpm))
    log.info("Ixy moment [kgm^2]: " + str(bout.Ixy_lump_zpm))
    log.info("Iyz moment [kgm^2]: " + str(bout.Iyz_lump_zpm))
    log.info("Ixz moment [kgm^2]: " + str(bout.Ixz_lump_zpm))

    log.info("---------------------------------------")
    log.info("---------- OEM configuration ----------")
    log.info("Roll moment, Ixx [kgm^2]: " + str(bout.Ixx_lump_oem))
    log.info("Pitch moment, Iyy [kgm^2]: " + str(bout.Iyy_lump_oem))
    log.info("Yaw moment, Izz [kgm^2]: " + str(bout.Izz_lump_oem))
    log.info("Ixy moment [kgm^2]: " + str(bout.Ixy_lump_oem))
    log.info("Iyz moment [kgm^2]: " + str(bout.Iyz_lump_oem))
    log.info("Ixz moment [kgm^2]: " + str(bout.Ixz_lump_oem))
    log.info("---------------------------------------")

    if bi.USER_CASE:
        log.info("---------- User configuration ---------")
        log.info("Roll moment, Ixx [kgm^2]: " + str(bout.Ixx_lump_user))
        log.info("Pitch moment, Iyy [kgm^2]: " + str(bout.Iyy_lump_user))
        log.info("Yaw moment, Izz [kgm^2]: " + str(bout.Izz_lump_user))
        log.info("Ixy moment [kgm^2]: " + str(bout.Ixy_lump_user))
        log.info("Iyz moment [kgm^2]: " + str(bout.Iyz_lump_user))
        log.info("Ixz moment [kgm^2]: " + str(bout.Ixz_lump_user))
        log.info("---------------------------------------")

    log.info("##  Uconventional Balance analysis succesfuly completed ##")
예제 #9
0
def create_SU2_mesh(cpacs_path, cpacs_out_path):
    """Function to create a simple SU2 mesh form an SUMO file (.smx)

    Function 'create_mesh' is used to generate an unstructured mesh with  SUMO
    (which integrage Tetgen for the volume mesh) using a SUMO (.smx) geometry
    file as input.
    Meshing option could be change manually (only in the script for now)

    Source :
        * sumo help, tetgen help (in the folder /doc)

    Args:
        cpacs_path (str): Path to the CPACS file
        cpacs_out_path (str): Path to the output CPACS file

    """

    tixi = open_tixi(cpacs_path)

    sumo_dir = get_results_directory("SUMOAutoMesh")
    su2_mesh_path = os.path.join(sumo_dir, "ToolOutput.su2")

    sumo_file_xpath = "/cpacs/toolspecific/CEASIOMpy/filesPath/sumoFilePath"
    sumo_file_path = get_value_or_default(tixi, sumo_file_xpath, "")
    if sumo_file_path == "":
        raise ValueError("No SUMO file to use to create a mesh")

    # Set mesh parameters
    log.info("Mesh parameter will be set")
    refine_level_xpath = "/cpacs/toolspecific/CEASIOMpy/mesh/sumoOptions/refinementLevel"
    refine_level = get_value_or_default(tixi, refine_level_xpath, 0.0)
    log.info("Refinement level is {}".format(refine_level))
    add_mesh_parameters(sumo_file_path, refine_level)

    # Check current Operating System
    current_os = platform.system()

    if current_os == "Darwin":
        log.info("Your OS is Mac\n\n")
        log.info(
            "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
        log.info("On MacOS the mesh has to be generated manually.")
        log.info("To create a SU2Mesh you have to :")
        log.info("Open the .smx geometry that you will find there:")
        log.info(sumo_file_path)
        log.info('Click on the button "Mesh"')
        log.info('Click on "Create Mesh"')
        log.info('Click on "Volume Mesh"')
        log.info('Click on "Run"')
        log.info('When the mesh generation is completed, click on "Close"')
        log.info('Go to the Menu "Mesh" -> "Save volume mesh..."')
        log.info('Chose "SU2 (*.su2)" as File Type"')
        log.info("Copy/Paste the following line as File Name")
        log.info(su2_mesh_path)
        log.info('Click on "Save"')
        log.info("You can now close SUMO, your workflow will continue.")
        log.info(
            "More information:"
            "https://ceasiompy.readthedocs.io/en/latest/user_guide/modules/SUMOAutoMesh/index.html"
        )
        log.info(
            "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n"
        )

        # For now, I did not find a way to run "sumo -batch" on Mac...
        # The command just open SUMO GUI, the mesh has to be generate and save manually
        with change_working_dir(sumo_dir):
            command = ["open", "/Applications/SUMO/dwfsumo.app/"]

        # /Applications/SUMO/dwfsumo.app/Contents/MacOS/dwfsumo
        # -batch output=su2 -tetgen-options=pq1.16VY ToolOutput.smx
        os.system(" ".join(command))
        input("Press ENTER to continue...")

    elif current_os == "Linux":
        log.info("Your OS is Linux")

        # Check if SUMO is installed
        soft_dict = get_install_path(["sumo"])

        # Run SUMO in batch
        output = "-output=su2"
        options = "-tetgen-options=pq1.16VY"  # See Tetgen help for more options
        # Command line to run: sumo -batch -output=su2 -tetgen-options=pq1.16VY ToolOutput.smx
        command = [
            soft_dict["sumo"], "-batch", output, options, sumo_file_path
        ]

        with change_working_dir(sumo_dir):
            os.system(" ".join(command))

    elif current_os == "Windows":
        log.info("Your OS is Windows")
        # TODO: develop this part

        log.warning("OS not supported yet by SUMOAutoMesh!")
        raise NotImplementedError("OS not supported yet!")

    else:
        raise OSError("OS not recognize!")

    # Copy the mesh in the MESH directory
    su2_mesh_name = aircraft_name(tixi) + "_baseline.su2"
    su2_mesh_new_path = os.path.join(sumo_dir, su2_mesh_name)
    shutil.copyfile(su2_mesh_path, su2_mesh_new_path)

    if os.path.isfile(su2_mesh_new_path):
        log.info("An SU2 Mesh has been correctly generated.")
        create_branch(tixi, SU2MESH_XPATH)
        tixi.updateTextElement(SU2MESH_XPATH, su2_mesh_new_path)
        os.remove(su2_mesh_path)

    else:
        raise ValueError("No SU2 Mesh file has been generated!")

    tixi.save(cpacs_out_path)