def test_add_skin_friction():
    """Test function 'add_skin_friction'"""

    # User the function to add skin frictions
    add_skin_friction(CPACS_IN_PATH, CPACS_OUT_PATH)

    # Read the aeromap with the skin friction added in the output cpacs file
    cpacs = CPACS(CPACS_OUT_PATH)
    apm_sf = cpacs.get_aeromap_by_uid("test_apm_SkinFriction")

    # Expected values
    cl_list_expected = [0.1, 0.102944, 0.1, 0.102944]
    cd_list_expected = [0.0269518, 0.0266942, 0.0266942, 0.0264406]
    cs_list_expected = [0.001, 0.001, 0.00394364, 0.00394364]

    assert all([
        a == approx(b, rel=1e-4)
        for a, b in zip(apm_sf.get("cl"), cl_list_expected)
    ])
    assert all([
        a == approx(b, rel=1e-4)
        for a, b in zip(apm_sf.get("cd"), cd_list_expected)
    ])
    assert all([
        a == approx(b, rel=1e-4)
        for a, b in zip(apm_sf.get("cs"), cs_list_expected)
    ])

    # Remove the output cpacs file if exist
    if os.path.exists(CPACS_OUT_PATH):
        os.remove(CPACS_OUT_PATH)
Esempio n. 2
0
def main(cpacs_path, cpacs_out_path):

    log.info("----- Start of " + os.path.basename(__file__) + " -----")

    # Load the model
    cpacs = CPACS(cpacs_path)
    Model = load_surrogate(cpacs.tixi)

    check_aeromap(cpacs.tixi)

    if get_value_or_default(cpacs.tixi, SMUSE_XPATH + "/AeroMapOnly", False):
        aeromap_calculation(Model.sm, cpacs)
    else:
        predict_output(Model, cpacs)

    cpacs.save_cpacs(cpacs_out_path, overwrite=True)

    log.info("----- End of " + os.path.basename(__file__) + " -----")
Esempio n. 3
0
    def __init__(self, master, cpacs_path, cpacs_out_path, submodule_list, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        self.pack(fill=tk.BOTH)

        self.submodule_list = submodule_list
        self.cpacs_out_path = cpacs_out_path

        # Notebook for tabs
        self.tabs = ttk.Notebook(self)
        self.tabs.grid(row=0, column=0, columnspan=3)  # pack()#expand=1, side=tk.LEFT)

        # Open the cpacs file
        self.cpacs = CPACS(cpacs_path)

        aeromap_uid_list = self.cpacs.get_aeromap_uid_list()
        if not aeromap_uid_list:
            csv_path = os.path.join(
                MODULE_DIR, "..", "..", "test_files", "AeroMaps", "Aeromap_1point.csv"
            )
            new_aeromap = self.cpacs.create_aeromap_from_csv(csv_path, "AeroMap_1point")
            new_aeromap.save()
            aeromap_uid_list = self.cpacs.get_aeromap_uid_list()

        # Generate AeroMaps Edition tab
        AeroMapTab(self.tabs, self.cpacs, aeromap_uid_list)

        # Generate Auto Tab =============
        self.tab_list = []
        self._update_all()

        # Check windows size to change position of button if too small
        row = 1
        col = 1
        if self.winfo_screenheight() < 1000:
            row = 0
            col = 3

        # General button
        self.update_button = tk.Button(self, text="Update", command=self._update_all)
        self.update_button.grid(row=row, column=col, sticky="E")
        self.close_button = tk.Button(self, text="Save & Quit", command=self._save_quit)
        self.close_button.grid(row=row, column=col + 1, sticky="W")
Esempio n. 4
0
def export_aeromaps(cpacs_path, cpacs_out_path):

    cpacs = CPACS(cpacs_path)

    aeromap_to_export_xpath = CEASIOMPY_XPATH + "/export/aeroMapToExport"

    aeromap_uid_list = []
    aeromap_uid_list = get_string_vector(cpacs.tixi, aeromap_to_export_xpath)

    results_dir = get_results_directory("ExportCSV")

    for aeromap_uid in aeromap_uid_list:
        aeromap = cpacs.get_aeromap_by_uid(aeromap_uid)

        csv_path = Path(results_dir, f"{aeromap_uid}.csv")
        aeromap.export_csv(csv_path)

        log.info(f"Aeromap(s) has been saved to {csv_path}")

    cpacs.save_cpacs(cpacs_out_path, overwrite=True)
Esempio n. 5
0
def test_Point():
    """Test the class 'Point'"""

    cpacs = CPACS(CPACS_PATH)
    tixi = cpacs.tixi

    point1 = Point()

    assert point1.x == 0.0
    assert point1.y == 0.0
    assert point1.z == 0.0

    xpath = "/cpacs/vehicles/aircraft/model/fuselages/fuselage/transformation/scaling"
    point1.get_cpacs_points(tixi, xpath)

    assert point1.x == 1.0
    assert point1.y == 0.5
    assert point1.z == 0.5
Esempio n. 6
0
def routine_launcher(optim_method, module_optim, wkflow_dir):
    """Run an optimisation routine or DoE using the OpenMDAO library.

    This function launches the setup for the routine by setting up the problem
    with the OpenMDAO component, creating of reading a file containing all the
    problem parameters and launching the driver. It also specifies where to
    save the case recordings and launches the results plotting at the end of
    the routine.

    Args:
        optim_method (str): Optimisation method to be used
        module_optim (list): list of modules (ModuleToRun object) in the optimisation loop

    """

    Rt.type = optim_method
    Rt.modules = module_optim
    Rt.wkflow_dir = wkflow_dir

    # Cpacs from the ouput of the last module
    cpacs_path = str(Rt.modules[0].cpacs_in)

    cpacs = CPACS(cpacs_path)

    Rt.get_user_inputs(cpacs.tixi)

    Rt.optim_dir = Path(wkflow_dir, "Results", optim_method)
    Rt.optim_dir.mkdir(parents=True, exist_ok=True)

    Rt.optim_var_dict = create_variable_library(Rt, cpacs.tixi, Rt.optim_dir)
    Rt.am_dict = create_aeromap_dict(cpacs, Rt.aeromap_uid, Rt.objective)

    # Instantiate components and subsystems ##
    prob = om.Problem()
    create_om_problem(prob)

    # Run the model ##
    prob.run_driver()

    generate_results(prob)
Esempio n. 7
0
    def compute(self, inputs, outputs):
        """Compute the objective expression"""

        # Add new variables to dictionnary
        cpacs = CPACS(str(Rt.modules[-1].cpacs_out))

        update_dict(cpacs.tixi, Rt.optim_var_dict)

        # Save the whole aeromap if needed
        if Rt.use_aeromap:
            update_am_dict(cpacs, Rt.aeromap_uid, Rt.am_dict)

        for obj in Rt.objective:
            var_list = split("[+*/-]", obj)
            for v in var_list:
                if not v.isdigit() and v != "":
                    exec('{} = inputs["{}"]'.format(v, v))
            result = eval(obj)

            if Rt.minmax == "min":
                outputs["Objective function " + obj] = result
            else:
                outputs["Objective function " + obj] = -result
Esempio n. 8
0
def test_Transfomation():
    """Test the class 'Point'"""

    cpacs = CPACS(CPACS_PATH)
    tixi = cpacs.tixi

    trans1 = Transformation()

    assert trans1.scaling.x == 1.0
    assert trans1.scaling.y == 1.0
    assert trans1.scaling.z == 1.0

    assert trans1.rotation.x == 0.0
    assert trans1.translation.y == 0.0

    xpath = "/cpacs/vehicles/aircraft/model/fuselages/fuselage"
    trans1.get_cpacs_transf(tixi, xpath)

    assert trans1.scaling.x == 1.0
    assert trans1.scaling.y == 0.5
    assert trans1.scaling.z == 0.5
    assert trans1.rotation.x == 0.1
    assert trans1.rotation.y == 0.2
    assert trans1.rotation.z == 0.3
    assert trans1.translation.x == 0.4
    assert trans1.translation.y == 0.5
    assert trans1.translation.z == 0.6

    trans_wing = Transformation()
    xpath = "/cpacs/vehicles/aircraft/model/wings/wing"
    trans_wing.get_cpacs_transf(tixi, xpath)
    trans_wing.get_parent_transformation()

    assert trans_wing.translation.x == 0.4
    assert trans_wing.translation.y == 0.5
    assert trans_wing.translation.z == 0.6
Esempio n. 9
0
def plot_aero_coef(cpacs_path, cpacs_out_path):
    """Plot Aero coefficients from the chosen aeroMap in the CPACS file

    Function 'plot_aero_coef' can plot one or several aeromap from the CPACS
    file according to some user option, these option will be shown in the the
    SettingGUI or default values will be used.

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

    # Open TIXI handle
    cpacs = CPACS(cpacs_path)

    # Get aeroMap list to plot
    aeromap_to_plot_xpath = PLOT_XPATH + "/aeroMapToPlot"
    aeromap_uid_list = []

    # Option to select aeromap manualy
    manual_selct = get_value_or_default(cpacs.tixi, PLOT_XPATH + "/manualSelection", False)
    if manual_selct:
        aeromap_uid_list = open_select_aeromap_gui(cpacs)
        create_branch(cpacs.tixi, aeromap_to_plot_xpath)
        add_string_vector(cpacs.tixi, aeromap_to_plot_xpath, aeromap_uid_list)

    else:
        try:
            aeromap_uid_list = get_string_vector(cpacs.tixi, aeromap_to_plot_xpath)
        except ValueError:
            # If aeroMapToPlot is not define, select manualy anyway
            aeromap_uid_list = open_select_aeromap_gui(cpacs)
            create_branch(cpacs.tixi, aeromap_to_plot_xpath)
            add_string_vector(cpacs.tixi, aeromap_to_plot_xpath, aeromap_uid_list)

    # Create DataFrame from aeromap(s)
    aeromap_df_list = []
    for aeromap_uid in aeromap_uid_list:
        aeromap_df = cpacs.get_aeromap_by_uid(aeromap_uid).df
        aeromap_df["uid"] = aeromap_uid
        aeromap_df_list.append(aeromap_df)

    aeromap = pd.concat(aeromap_df_list, ignore_index=True)

    if len(aeromap_uid_list) > 1:
        uid_crit = None
    else:
        uid_crit = aeromap_uid_list[0]

    # Default options
    title = cpacs.ac_name
    criterion = pd.Series([True] * len(aeromap.index))
    groupby_list = ["uid", "machNumber", "altitude", "angleOfSideslip"]

    # Get criterion from CPACS
    crit_xpath = PLOT_XPATH + "/criterion"
    alt_crit = get_value_or_default(cpacs.tixi, crit_xpath + "/alt", "None")
    mach_crit = get_value_or_default(cpacs.tixi, crit_xpath + "/mach", "None")
    aos_crit = get_value_or_default(cpacs.tixi, crit_xpath + "/aos", "None")

    cpacs.save_cpacs(cpacs_out_path, overwrite=True)

    # Modify criterion and title according to user option
    if len(aeromap["altitude"].unique()) == 1:
        title += " - Alt = " + str(aeromap["altitude"].loc[0])
        groupby_list.remove("altitude")
    elif alt_crit not in NONE_LIST:
        criterion = criterion & (aeromap.altitude == alt_crit)
        title += " - Alt = " + str(alt_crit)
        groupby_list.remove("altitude")

    if len(aeromap["machNumber"].unique()) == 1:
        title += " - Mach = " + str(aeromap["machNumber"].loc[0])
        groupby_list.remove("machNumber")
    elif mach_crit not in NONE_LIST:
        criterion = criterion & (aeromap.machNumber == mach_crit)
        title += " - Mach = " + str(mach_crit)
        groupby_list.remove("machNumber")

    if len(aeromap["angleOfSideslip"].unique()) == 1:
        title += " - AoS = " + str(aeromap["angleOfSideslip"].loc[0])
        groupby_list.remove("angleOfSideslip")
    elif aos_crit not in NONE_LIST:
        criterion = criterion & (aeromap.angleOfSideslip == aos_crit)
        title += " - AoS = " + str(aos_crit)
        groupby_list.remove("angleOfSideslip")

    if uid_crit is not None and len(groupby_list) > 1:
        criterion = criterion & (aeromap.uid == uid_crit)
        title += " - " + uid_crit
        groupby_list.remove("uid")

    # Plot settings
    fig, axs = plt.subplots(2, 3)
    fig.suptitle(title, fontsize=14)
    fig.set_figheight(8)
    fig.set_figwidth(15)
    fig.subplots_adjust(left=0.06)
    axs[0, 1].axhline(y=0.0, color="k", linestyle="-")  # Line at Cm=0

    # Plot aerodynamic coerfficients
    for value, grp in aeromap.loc[criterion].groupby(groupby_list):

        legend = write_legend(groupby_list, value)

        axs[0, 0].plot(grp["angleOfAttack"], grp["cl"], "x-", label=legend)
        axs[1, 0].plot(grp["angleOfAttack"], grp["cd"], "x-")
        axs[0, 1].plot(grp["angleOfAttack"], grp["cms"], "x-")
        axs[1, 1].plot(grp["angleOfAttack"], grp["cl"] / grp["cd"], "x-")
        axs[0, 2].plot(grp["cd"], grp["cl"], "x-")
        axs[1, 2].plot(grp["cl"], grp["cl"] / grp["cd"], "x-")

    # Set subplot options
    subplot_options(axs[0, 0], "CL", "AoA")
    subplot_options(axs[1, 0], "CD", "AoA")
    subplot_options(axs[0, 1], "Cm", "AoA")
    subplot_options(axs[1, 1], "CL/CD", "AoA")
    subplot_options(axs[0, 2], "CL", "CD")
    subplot_options(axs[1, 2], "CL/CD", "CL")

    fig.legend(loc="upper right")
    plt.show()
Esempio n. 10
0
class SettingGUI(tk.Frame):
    """Main window. All the other widgets are stored in this window."""

    def __init__(self, master, cpacs_path, cpacs_out_path, submodule_list, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        self.pack(fill=tk.BOTH)

        self.submodule_list = submodule_list
        self.cpacs_out_path = cpacs_out_path

        # Notebook for tabs
        self.tabs = ttk.Notebook(self)
        self.tabs.grid(row=0, column=0, columnspan=3)  # pack()#expand=1, side=tk.LEFT)

        # Open the cpacs file
        self.cpacs = CPACS(cpacs_path)

        aeromap_uid_list = self.cpacs.get_aeromap_uid_list()
        if not aeromap_uid_list:
            csv_path = os.path.join(
                MODULE_DIR, "..", "..", "test_files", "AeroMaps", "Aeromap_1point.csv"
            )
            new_aeromap = self.cpacs.create_aeromap_from_csv(csv_path, "AeroMap_1point")
            new_aeromap.save()
            aeromap_uid_list = self.cpacs.get_aeromap_uid_list()

        # Generate AeroMaps Edition tab
        AeroMapTab(self.tabs, self.cpacs, aeromap_uid_list)

        # Generate Auto Tab =============
        self.tab_list = []
        self._update_all()

        # Check windows size to change position of button if too small
        row = 1
        col = 1
        if self.winfo_screenheight() < 1000:
            row = 0
            col = 3

        # General button
        self.update_button = tk.Button(self, text="Update", command=self._update_all)
        self.update_button.grid(row=row, column=col, sticky="E")
        self.close_button = tk.Button(self, text="Save & Quit", command=self._save_quit)
        self.close_button.grid(row=row, column=col + 1, sticky="W")

    def _update_all(self):

        # Remove existing AutoTab
        if len(self.tab_list) > 0:
            for i in range(len(self.tab_list)):
                self.tabs.forget(1)
            self.tab_list = []

        # Generate new Auto Tab
        for module_name in self.submodule_list:

            specs = mi.get_specs_for_module(module_name)
            if specs is None:  # Specs does not exist
                continue
            self.gui_dict = specs.cpacs_inout.get_gui_dict()
            if not self.gui_dict:  # Empty dict --> nothing to do
                continue

            tab = AutoTab(self.tabs, self.cpacs, module_name)
            self.tab_list.append(tab)

    def _save_quit(self):

        # Iterate over all existing tabs
        for tab in self.tab_list:
            # Iterate in Variable dictionary of each tab
            for key, var in tab.var_dict.items():
                # Get the XPath from the GUI setting dictionary and crate a branch
                name = tab.gui_dict[key][0]
                xpath = tab.gui_dict[key][4]
                create_branch(self.cpacs.tixi, xpath)
                if name == "__AEROMAP_CHECHBOX":
                    aeromap_uid_list_str = ""
                    for aeromap_uid, aeromap_bool in tab.aeromap_var_dict.items():
                        if aeromap_bool.get():
                            aeromap_uid_list_str += aeromap_uid + ";"
                    if aeromap_uid_list_str == "":
                        messagebox.showerror(
                            "ValueError",
                            'In the Tab "'
                            + tab.module_name
                            + '", no value has been selected for "'
                            + name
                            + '" ',
                        )
                        raise TypeError("No value has been selected for " + name + " !")
                    self.cpacs.tixi.updateTextElement(xpath, aeromap_uid_list_str)

                # '__AEROMAP_SELECTION' and list Type value will be saved as any other variable
                else:
                    if str(var.get()) == "":
                        # Not working when it expect an 'int' or a 'float'
                        messagebox.showerror(
                            "ValueError",
                            'In the Tab "'
                            + tab.module_name
                            + '", no value has been entered for "'
                            + name
                            + '" ',
                        )
                        raise TypeError("No value has been entered for " + name + " !")

                    try:
                        self.cpacs.tixi.updateTextElement(xpath, str(var.get()))
                    except:

                        messagebox.showerror(
                            "TypeError",
                            'In the Tab "'
                            + tab.module_name
                            + '", the value "'
                            + name
                            + '" has not the correct type!',
                        )
                        raise TypeError(name + " has not the correct type!")

        self.cpacs.save_cpacs(self.cpacs_out_path, overwrite=True)

        self.quit()
Esempio n. 11
0
def add_skin_friction(cpacs_path, cpacs_out_path):
    """Function to add the skin frictions drag coefficient to aerodynamic coefficients

    Function 'add_skin_friction' add the skin friction drag 'cd0' to  the
    SU2 and pyTornado aeroMap, if their UID is not given, it will add skin
    friction to all aeroMap. For each aeroMap it creates a new aeroMap where
    the skin friction drag coefficient is added with the correct projections.

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

    # Load a CPACS file
    cpacs = CPACS(cpacs_path)

    analyses_xpath = "/cpacs/toolspecific/CEASIOMpy/geometry/analysis"

    # Required input data from CPACS
    wetted_area = get_value(cpacs.tixi, analyses_xpath + "/wettedArea")

    # Wing area/span, default values will be calculated if no value found in the CPACS file
    wing_area_xpath = analyses_xpath + "/wingArea"
    wing_area = get_value_or_default(cpacs.tixi, wing_area_xpath,
                                     cpacs.aircraft.wing_area)
    wing_span_xpath = analyses_xpath + "/wingSpan"
    wing_span = get_value_or_default(cpacs.tixi, wing_span_xpath,
                                     cpacs.aircraft.wing_span)

    # Get aeroMapToCalculate
    aeroMap_to_calculate_xpath = SF_XPATH + "/aeroMapToCalculate"
    if cpacs.tixi.checkElement(aeroMap_to_calculate_xpath):
        aeromap_uid_list = get_string_vector(cpacs.tixi,
                                             aeroMap_to_calculate_xpath)
    else:
        aeromap_uid_list = []

    # If no aeroMap in aeroMapToCalculate, get all existing aeroMap
    if len(aeromap_uid_list) == 0:
        aeromap_uid_list = cpacs.get_aeromap_uid_list()

        if not aeromap_uid_list:
            raise ValueError(
                "No aeroMap has been found in this CPACS file, skin friction cannot be added!"
            )

    # Get unique aeroMap list
    aeromap_uid_list = list(set(aeromap_uid_list))
    new_aeromap_uid_list = []

    # Add skin friction to all listed aeroMap
    for aeromap_uid in aeromap_uid_list:

        log.info("adding skin friction coefficients to: " + aeromap_uid)

        aeromap = cpacs.get_aeromap_by_uid(aeromap_uid)

        # Create new aeromap object to store coef with added skin friction
        aeromap_sf = cpacs.duplicate_aeromap(aeromap_uid,
                                             aeromap_uid + "_SkinFriction")
        aeromap_sf.description = (
            aeromap_sf.description +
            " Skin friction has been add to this AeroMap.")

        # Add skin friction to all force coefficient (with projections)
        aeromap_sf.df["cd"] = aeromap.df.apply(
            lambda row: row["cd"] + estimate_skin_friction_coef(
                wetted_area, wing_area, wing_span, row["machNumber"], row[
                    "altitude"]) * math.cos(math.radians(row["angleOfAttack"]))
            * math.cos(math.radians(row["angleOfSideslip"])),
            axis=1,
        )

        aeromap_sf.df["cl"] = aeromap.df.apply(
            lambda row: row["cl"] + estimate_skin_friction_coef(
                wetted_area, wing_area, wing_span, row[
                    "machNumber"], row["altitude"]) * math.sin(
                        math.radians(row["angleOfAttack"])),
            axis=1,
        )

        aeromap_sf.df["cs"] = aeromap.df.apply(
            lambda row: row["cs"] + estimate_skin_friction_coef(
                wetted_area, wing_area, wing_span, row["machNumber"], row[
                    "altitude"]) * math.sin(
                        math.radians(row["angleOfSideslip"])),
            axis=1,
        )

        # TODO: Should we change something in moment coef?
        # e.i. if a force is not apply at aero center...?

        aeromap_sf.save()

    # Get aeroMap list to plot
    plot_xpath = "/cpacs/toolspecific/CEASIOMpy/aerodynamics/plotAeroCoefficient"
    aeromap_to_plot_xpath = plot_xpath + "/aeroMapToPlot"

    if cpacs.tixi.checkElement(aeromap_to_plot_xpath):
        aeromap_uid_list = get_string_vector(cpacs.tixi, aeromap_to_plot_xpath)
        new_aeromap_to_plot = aeromap_uid_list + new_aeromap_uid_list
        new_aeromap_to_plot = list(set(new_aeromap_to_plot))
        add_string_vector(cpacs.tixi, aeromap_to_plot_xpath,
                          new_aeromap_to_plot)
    else:
        create_branch(cpacs.tixi, aeromap_to_plot_xpath)
        add_string_vector(cpacs.tixi, aeromap_to_plot_xpath,
                          new_aeromap_uid_list)

    log.info('AeroMap "' + aeromap_uid + '" has been added to the CPACS file')

    cpacs.save_cpacs(cpacs_out_path, overwrite=True)
Esempio n. 12
0
def get_cl(cpacs_path, cpacs_out_path):
    """Function to calculate CL required as a function of the parameter found
    in the CPACS file.

    Function 'get_cl' find input value in the CPACS file, calculate the
    required CL (with function calculate_cl) and  save the CL value in the
    CPACS file.

    Args:
        cpacs_path (str):  Path to CPACS file
        cpacs_out_path (str): Path to CPACS output file
    """
    cpacs = CPACS(cpacs_path)
    tixi = cpacs.tixi

    # XPath definition
    model_xpath = "/cpacs/vehicles/aircraft/model"
    ref_area_xpath = model_xpath + "/reference/area"

    mass_type_xpath = "/cpacs/toolspecific/CEASIOMpy/aerodynamics/clCalculation/massType"
    custom_mass_xpath = "/cpacs/toolspecific/CEASIOMpy/aerodynamics/clCalculation/customMass"
    percent_fuel_mass_xpath = (
        "/cpacs/toolspecific/CEASIOMpy/aerodynamics/clCalculation/percentFuelMass"
    )

    cruise_alt_xpath = CLCALC_XPATH + "/cruiseAltitude"
    cruise_mach_xpath = CLCALC_XPATH + "/cruiseMach"
    load_fact_xpath = CLCALC_XPATH + "/loadFactor"

    # Required input data from CPACS
    ref_area = get_value(tixi, ref_area_xpath)
    log.info(f"Aircraft reference area is {ref_area} [m^2]")

    # Mass
    mass = None
    mass_type = get_value_or_default(tixi, mass_type_xpath, "mTOM")

    if mass_type == "Custom":
        mass = get_value(tixi, custom_mass_xpath)

    elif mass_type == "% fuel mass":
        percent_fuel_mass = get_value(tixi, percent_fuel_mass_xpath)
        mtom = get_value(
            tixi,
            model_xpath + "/analyses/massBreakdown/designMasses/mTOM/mass")
        mzfm = get_value(
            tixi,
            model_xpath + "/analyses/massBreakdown/designMasses/mZFM/mass")
        if mzfm > mtom:
            raise ValueError("mZFM is bigger than mTOM!")
        mass = (mtom - mzfm) * percent_fuel_mass / 100 + mzfm

    else:
        mass_xpath = model_xpath + f"/analyses/massBreakdown/designMasses/{mass_type}/mass"
        mass = get_value(tixi, mass_xpath)

    # mtom = get_value(tixi,mtom_xpath)
    if mass:
        log.info(f"Aircraft mass use for this analysis is {mass} [kg]")
    else:
        raise ValueError("The chosen aircraft mass has not been found!")

    # Required input data that could be replace by a default value if missing
    cruise_alt = get_value_or_default(tixi, cruise_alt_xpath, 12000.0)
    cruise_mach = get_value_or_default(tixi, cruise_mach_xpath, 0.78)
    load_fact = get_value_or_default(tixi, load_fact_xpath, 1.05)

    # CL calculation
    target_cl = calculate_cl(ref_area, cruise_alt, cruise_mach, mass,
                             load_fact)

    # Save TargetCL and fixedCL option
    create_branch(tixi, SU2_XPATH)
    create_branch(tixi, SU2_XPATH + "/targetCL")
    create_branch(tixi, SU2_XPATH + "/fixedCL")
    tixi.updateDoubleElement(SU2_XPATH + "/targetCL", target_cl, "%g")
    tixi.updateTextElement(SU2_XPATH + "/fixedCL", "YES")
    log.info("Target CL has been saved in the CPACS file")

    cpacs.save_cpacs(cpacs_out_path, overwrite=True)
Esempio n. 13
0
def generate_su2_cfd_config(cpacs_path, cpacs_out_path, wkdir):
    """Function to create SU2 confif file.

    Function 'generate_su2_cfd_config' reads data in the CPACS file and generate
    configuration files for one or multible flight conditions (alt,mach,aoa,aos)

    Source:
        * SU2 config template: https://github.com/su2code/SU2/blob/master/config_template.cfg

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

    """

    # Get value from CPACS
    cpacs = CPACS(cpacs_path)

    # Get SU2 mesh path
    su2_mesh_path = get_value(cpacs.tixi, SU2MESH_XPATH)

    # Get SU2 settings
    max_iter_xpath = SU2_XPATH + "/settings/maxIter"
    max_iter = get_value_or_default(cpacs.tixi, max_iter_xpath, 200)
    cfl_nb_xpath = SU2_XPATH + "/settings/cflNumber"
    cfl_nb = get_value_or_default(cpacs.tixi, cfl_nb_xpath, 1.0)
    mg_level_xpath = SU2_XPATH + "/settings/multigridLevel"
    mg_level = get_value_or_default(cpacs.tixi, mg_level_xpath, 3)

    # Mesh Marker
    bc_wall_xpath = SU2_XPATH + "/boundaryConditions/wall"
    bc_farfield_xpath = SU2_XPATH + "/boundaryConditions/farfield"
    bc_wall_list, engine_bc_list = get_mesh_marker(su2_mesh_path)

    create_branch(cpacs.tixi, bc_wall_xpath)
    bc_wall_str = ";".join(bc_wall_list)
    cpacs.tixi.updateTextElement(bc_wall_xpath, bc_wall_str)

    create_branch(cpacs.tixi, bc_farfield_xpath)
    bc_farfiled_str = ";".join(engine_bc_list)
    cpacs.tixi.updateTextElement(bc_farfield_xpath, bc_farfiled_str)

    # Fixed CL parameters
    fixed_cl_xpath = SU2_XPATH + "/fixedCL"
    fixed_cl = get_value_or_default(cpacs.tixi, fixed_cl_xpath, "NO")
    target_cl_xpath = SU2_XPATH + "/targetCL"
    target_cl = get_value_or_default(cpacs.tixi, target_cl_xpath, 1.0)

    if fixed_cl == "NO":
        active_aeroMap_xpath = SU2_XPATH + "/aeroMapUID"
        aeromap_uid = get_value(cpacs.tixi, active_aeroMap_xpath)

        log.info(
            f'Configuration file for "{aeromap_uid}" calculation will be created.'
        )

        active_aeromap = cpacs.get_aeromap_by_uid(aeromap_uid)

        # Get parameters of the aeroMap (altitude, machNumber, angleOfAttack, angleOfSideslip)
        alt_list = active_aeromap.get("altitude").tolist()
        mach_list = active_aeromap.get("machNumber").tolist()
        aoa_list = active_aeromap.get("angleOfAttack").tolist()
        aos_list = active_aeromap.get("angleOfSideslip").tolist()

        param_count = len(alt_list)

    else:  # if fixed_cl == 'YES':
        log.info(
            "Configuration file for fixed CL calculation will be created.")

        # Parameters fixed CL calulation
        param_count = 1

        # Create a new aeroMap
        fix_cl_aeromap = cpacs.create_aeromap("aeroMap_fixedCL_SU2")
        fix_cl_aeromap.description = "AeroMap created for SU2 fixed CL value of: " + str(
            target_cl)

        # Get cruise mach and altitude
        cruise_mach_xpath = RANGE_XPATH + "/cruiseMach"
        mach = get_value_or_default(cpacs.tixi, cruise_mach_xpath, 0.78)
        cruise_alt_xpath = RANGE_XPATH + "/cruiseAltitude"
        alt = get_value_or_default(cpacs.tixi, cruise_alt_xpath, 12000)

        # Add new parameters to the aeroMap and save it
        fix_cl_aeromap.add_row(alt=alt, mach=mach, aos=0.0, aoa=0.0)
        fix_cl_aeromap.save()

        # Parameter lists
        alt_list = [alt]
        mach_list = [mach]
        aoa_list = [0.0]
        aos_list = [0.0]

    # Get and modify the default configuration file
    cfg = ConfigFile(DEFAULT_CONFIG_PATH)

    # General parmeters
    cfg["REF_LENGTH"] = cpacs.aircraft.ref_lenght
    cfg["REF_AREA"] = cpacs.aircraft.ref_area
    cfg["REF_ORIGIN_MOMENT_X"] = cpacs.aircraft.ref_point_x
    cfg["REF_ORIGIN_MOMENT_Y"] = cpacs.aircraft.ref_point_y
    cfg["REF_ORIGIN_MOMENT_Z"] = cpacs.aircraft.ref_point_z

    # Settings
    cfg["INNER_ITER"] = int(max_iter)
    cfg["CFL_NUMBER"] = cfl_nb
    cfg["MGLEVEL"] = int(mg_level)

    # Fixed CL mode (AOA will not be taken into account)
    cfg["FIXED_CL_MODE"] = fixed_cl
    cfg["TARGET_CL"] = target_cl
    cfg["DCL_DALPHA"] = "0.1"
    cfg["UPDATE_AOA_ITER_LIMIT"] = "50"
    cfg["ITER_DCL_DALPHA"] = "80"
    # TODO: correct value for the 3 previous parameters ??

    # Mesh Marker
    bc_wall_str = "(" + ",".join(bc_wall_list) + ")"
    cfg["MARKER_EULER"] = bc_wall_str
    cfg["MARKER_FAR"] = " (Farfield, " + ",".join(engine_bc_list) + ")"
    cfg["MARKER_SYM"] = " (0)"  # TODO: maybe make that a variable?
    cfg["MARKER_PLOTTING"] = bc_wall_str
    cfg["MARKER_MONITORING"] = bc_wall_str
    cfg["MARKER_MOVING"] = "( NONE )"  # TODO: when do we need to define MARKER_MOVING?
    cfg["DV_MARKER"] = bc_wall_str

    # Parameters which will vary for the different cases (alt,mach,aoa,aos)
    for case_nb in range(param_count):

        cfg["MESH_FILENAME"] = su2_mesh_path

        alt = alt_list[case_nb]
        mach = mach_list[case_nb]
        aoa = aoa_list[case_nb]
        aos = aos_list[case_nb]

        Atm = Atmosphere(alt)

        cfg["MACH_NUMBER"] = mach
        cfg["AOA"] = aoa
        cfg["SIDESLIP_ANGLE"] = aos
        cfg["FREESTREAM_PRESSURE"] = Atm.pressure[0]
        cfg["FREESTREAM_TEMPERATURE"] = Atm.temperature[0]
        cfg["ROTATION_RATE"] = "0.0 0.0 0.0"

        config_file_name = "ConfigCFD.cfg"

        case_dir_name = "".join([
            "Case",
            str(case_nb).zfill(2),
            "_alt",
            str(alt),
            "_mach",
            str(round(mach, 2)),
            "_aoa",
            str(round(aoa, 1)),
            "_aos",
            str(round(aos, 1)),
        ])

        case_dir_path = os.path.join(wkdir, case_dir_name)
        if not os.path.isdir(case_dir_path):
            os.mkdir(case_dir_path)

        config_output_path = os.path.join(wkdir, case_dir_name,
                                          config_file_name)
        cfg.write_file(config_output_path, overwrite=True)

        # Damping derivatives
        damping_der_xpath = SU2_XPATH + "/options/clalculateDampingDerivatives"
        damping_der = get_value_or_default(cpacs.tixi, damping_der_xpath,
                                           False)

        if damping_der:

            rotation_rate_xpath = SU2_XPATH + "/options/rotationRate"
            rotation_rate = get_value_or_default(cpacs.tixi,
                                                 rotation_rate_xpath, 1.0)

            cfg["GRID_MOVEMENT"] = "ROTATING_FRAME"

            cfg["ROTATION_RATE"] = str(rotation_rate) + " 0.0 0.0"
            os.mkdir(os.path.join(wkdir, case_dir_name + "_dp"))
            config_output_path = os.path.join(wkdir, case_dir_name + "_dp",
                                              config_file_name)
            cfg.write_file(config_output_path, overwrite=True)

            cfg["ROTATION_RATE"] = "0.0 " + str(rotation_rate) + " 0.0"
            os.mkdir(os.path.join(wkdir, case_dir_name + "_dq"))
            config_output_path = os.path.join(wkdir, case_dir_name + "_dq",
                                              config_file_name)
            cfg.write_file(config_output_path, overwrite=True)

            cfg["ROTATION_RATE"] = "0.0 0.0 " + str(rotation_rate)
            os.mkdir(os.path.join(wkdir, case_dir_name + "_dr"))
            config_output_path = os.path.join(wkdir, case_dir_name + "_dr",
                                              config_file_name)
            cfg.write_file(config_output_path, overwrite=True)
            log.info("Damping derivatives cases directory has been created.")

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

        if control_surf:

            # Get deformed mesh list
            su2_def_mesh_xpath = SU2_XPATH + "/availableDeformedMesh"
            if cpacs.tixi.checkElement(su2_def_mesh_xpath):
                su2_def_mesh_list = get_string_vector(cpacs.tixi,
                                                      su2_def_mesh_xpath)
            else:
                log.warning("No SU2 deformed mesh has been found!")
                su2_def_mesh_list = []

            for su2_def_mesh in su2_def_mesh_list:

                mesh_path = os.path.join(wkdir, "MESH", su2_def_mesh)

                config_dir_path = os.path.join(
                    wkdir, case_dir_name + "_" + su2_def_mesh.split(".")[0])
                os.mkdir(config_dir_path)
                cfg["MESH_FILENAME"] = mesh_path

                config_file_name = "ConfigCFD.cfg"
                config_output_path = os.path.join(wkdir, config_dir_path,
                                                  config_file_name)
                cfg.write_file(config_output_path, overwrite=True)

    # TODO: change that, but if it is save in tooloutput it will be erease by results...
    cpacs.save_cpacs(cpacs_out_path, overwrite=True)
Esempio n. 14
0
def get_su2_results(cpacs_path, cpacs_out_path, wkdir):
    """Function to write SU2 results in a CPACS file.

    Function 'get_su2_results' get available results from the latest SU2
    calculation and put it at the correct place in the CPACS file.

    '/cpacs/vehicles/aircraft/model/analyses/aeroPerformance/aerpMap[n]/aeroPerformanceMap'

    Args:
        cpacs_path (str): Path to input CPACS file
        cpacs_out_path (str): Path to output CPACS file
        wkdir (str): Path to the working directory

    """

    cpacs = CPACS(cpacs_path)

    if not os.path.exists(wkdir):
        raise OSError("The working directory : " + wkdir + "does not exit!")

    dir_list = os.listdir(wkdir)

    # Get and save Wetted area
    wetted_area = get_wetted_area(wkdir)
    create_branch(cpacs.tixi, WETTED_AREA_XPATH)
    cpacs.tixi.updateDoubleElement(WETTED_AREA_XPATH, wetted_area, "%g")

    # Check if loads shoud be extracted
    check_extract_loads_xpath = SU2_XPATH + "/results/extractLoads"
    check_extract_loads = get_value_or_default(cpacs.tixi,
                                               check_extract_loads_xpath,
                                               False)

    # Get fixed_cl option
    fixed_cl_xpath = SU2_XPATH + "/fixedCL"
    fixed_cl = get_value_or_default(cpacs.tixi, fixed_cl_xpath, "NO")

    # Get aeroMap uid
    if fixed_cl == "YES":
        aeromap_uid = "aeroMap_fixedCL_SU2"
    elif fixed_cl == "NO":
        su2_aeromap_xpath = SU2_XPATH + "/aeroMapUID"
        aeromap_uid = get_value(cpacs.tixi, su2_aeromap_xpath)
    else:
        raise ValueError(
            "The value for fixed_cl is not valid! Should be YES or NO")

    aeromap = cpacs.get_aeromap_by_uid(aeromap_uid)

    alt_list = aeromap.get("altitude").tolist()
    mach_list = aeromap.get("machNumber").tolist()
    aoa_list = aeromap.get("angleOfAttack").tolist()
    aos_list = aeromap.get("angleOfSideslip").tolist()

    case_dir_list = [dir for dir in dir_list if "Case" in dir]

    for config_dir in sorted(case_dir_list):

        case_nb = int(config_dir.split("_")[0].split("Case")[1])

        aoa = aoa_list[case_nb]
        aos = aos_list[case_nb]
        mach = mach_list[case_nb]
        alt = alt_list[case_nb]

        config_dir_path = os.path.join(wkdir, config_dir)

        if os.path.isdir(config_dir_path):

            force_file_path = os.path.join(config_dir_path,
                                           "forces_breakdown.dat")

            if not os.path.isfile(force_file_path):
                raise OSError("No result force file have been found!")

            if fixed_cl == "YES":
                cl_cd, aoa = get_efficiency_and_aoa(force_file_path)

                # Replace aoa with the with the value from fixed cl calculation
                aeromap.df.loc[0, ["angleOfAttack"]] = aoa

                # Save cl/cd found during the fixed CL calculation
                # TODO: maybe save cl/cd somewhere else
                lDRatio_xpath = "/cpacs/toolspecific/CEASIOMpy/ranges/lDRatio"
                create_branch(cpacs.tixi, lDRatio_xpath)
                cpacs.tixi.updateDoubleElement(lDRatio_xpath, cl_cd, "%g")

            # Read result file
            with open(force_file_path) as f:
                for line in f.readlines():
                    if "Total CL:" in line:
                        cl = float(line.split(":")[1].split("|")[0])
                    if "Total CD:" in line:
                        cd = float(line.split(":")[1].split("|")[0])
                    if "Total CSF:" in line:
                        cs = float(line.split(":")[1].split("|")[0])
                    # TODO: Check which axis name corespond to waht: cml, cmd, cms
                    if "Total CMx:" in line:
                        cmd = float(line.split(":")[1].split("|")[0])
                    if "Total CMy:" in line:
                        cms = float(line.split(":")[1].split("|")[0])
                    if "Total CMz:" in line:
                        cml = float(line.split(":")[1].split("|")[0])
                    if "Free-stream velocity" in line and "m/s" in line:
                        velocity = float(line.split(" ")[7])

            # Damping derivatives
            rotation_rate_xpath = SU2_XPATH + "/options/rotationRate"
            rotation_rate = get_value_or_default(cpacs.tixi,
                                                 rotation_rate_xpath, -1.0)
            ref_len = cpacs.aircraft.ref_lenght
            adim_rot_rate = rotation_rate * ref_len / velocity

            coefs = {
                "cl": cl,
                "cd": cd,
                "cs": cs,
                "cmd": cmd,
                "cms": cms,
                "cml": cml
            }

            if "_dp" in config_dir:
                for coef in COEFS:
                    coef_baseline = aeromap.get(coef,
                                                alt=alt,
                                                mach=mach,
                                                aoa=aoa,
                                                aos=aos)
                    dcoef = (coefs[coef] - coef_baseline) / adim_rot_rate
                    aeromap.add_damping_derivatives(
                        alt=alt,
                        mach=mach,
                        aos=aos,
                        aoa=aoa,
                        coef=coef,
                        axis="dp",
                        value=dcoef,
                        rate=rotation_rate,
                    )

            elif "_dq" in config_dir:
                for coef in COEFS:
                    coef_baseline = aeromap.get(coef,
                                                alt=alt,
                                                mach=mach,
                                                aoa=aoa,
                                                aos=aos)
                    dcoef = (coefs[coef] - coef_baseline) / adim_rot_rate
                    aeromap.add_damping_derivatives(
                        alt=alt,
                        mach=mach,
                        aos=aos,
                        aoa=aoa,
                        coef=coef,
                        axis="dq",
                        value=dcoef,
                        rate=rotation_rate,
                    )

            elif "_dr" in config_dir:
                for coef in COEFS:
                    coef_baseline = aeromap.get(coef,
                                                alt=alt,
                                                mach=mach,
                                                aoa=aoa,
                                                aos=aos)
                    dcoef = (coefs[coef] - coef_baseline) / adim_rot_rate
                    aeromap.add_damping_derivatives(
                        alt=alt,
                        mach=mach,
                        aos=aos,
                        aoa=aoa,
                        coef=coef,
                        axis="dr",
                        value=dcoef,
                        rate=rotation_rate,
                    )

            elif "_TED_" in config_dir:

                # TODO: convert when it is possible to save TED in cpacspy
                raise NotImplementedError("TED not implemented yet")

                # config_dir_split = config_dir.split('_')
                # ted_idx = config_dir_split.index('TED')
                # ted_uid = config_dir_split[ted_idx+1]
                # defl_angle = float(config_dir.split('_defl')[1])

                # try:
                #     print(Coef.IncrMap.dcl)
                # except AttributeError:
                #     Coef.IncrMap = a.p.m.f.IncrementMap(ted_uid)

                # dcl = (cl-Coef.cl[-1])
                # dcd = (cd-Coef.cd[-1])
                # dcs = (cs-Coef.cs[-1])
                # dcml = (cml-Coef.cml[-1])
                # dcmd = (cmd-Coef.cmd[-1])
                # dcms = (cms-Coef.cms[-1])

                # control_parameter = -1

                # Coef.IncrMap.add_cs_coef(dcl,dcd,dcs,dcml,dcmd,dcms,ted_uid,control_parameter)

            else:  # Baseline coefficients, (no damping derivative or control surfaces case)
                aeromap.add_coefficients(
                    alt=alt,
                    mach=mach,
                    aos=aos,
                    aoa=aoa,
                    cd=cd,
                    cl=cl,
                    cs=cs,
                    cml=cml,
                    cmd=cmd,
                    cms=cms,
                )

            if check_extract_loads:
                results_files_dir = os.path.join(wkdir, config_dir)
                extract_loads(results_files_dir)

    # Save object Coef in the CPACS file
    aeromap.save()

    # Save the CPACS file
    cpacs.save_cpacs(cpacs_out_path, overwrite=True)