Ejemplo n.º 1
0
def generate_configuration_file(configuration_file_path: str,
                                overwrite: bool = False):
    """
    Generates a sample configuration file.

    :param configuration_file_path: the path of file to be written
    :param overwrite: if True, the file will be written, even if it already exists
    :raise FastFileExistsError: if overwrite==False and configuration_file_path already exists
    """
    if not overwrite and pth.exists(configuration_file_path):
        raise FastFileExistsError(
            "Configuration file %s not written because it already exists. "
            "Use overwrite=True to bypass." % configuration_file_path,
            configuration_file_path,
        )

    make_parent_dir(configuration_file_path)

    copy_resource(resources, SAMPLE_FILENAME, configuration_file_path)
    _LOGGER.info("Sample configuration written in %s", configuration_file_path)
Ejemplo n.º 2
0
    def compute(self, inputs, outputs):

        # Results Folder creation if needed --------------------------------------------------------
        result_folder_path = self.options[OPTION_RESULT_FOLDER_PATH]
        if result_folder_path != "":
            os.makedirs(result_folder_path, exist_ok=True)

        # Creation of the temporary directory ------------------------------------------------------
        tmp_dir = TemporaryDirectory()
        if self.options[OPTION_AVL_EXE_PATH] != "":
            copy_resource(xfoil_resources, _PROFILE_FILE_NAME, tmp_dir.name)
            self.options["command"] = [self.options[OPTION_AVL_EXE_PATH]]
        else:
            copy_resource(avl336, _AVL_EXE_NAME, tmp_dir.name)
            copy_resource(xfoil_resources, _PROFILE_FILE_NAME, tmp_dir.name)
            self.options["command"] = [pth.join(tmp_dir.name, _AVL_EXE_NAME)]

        self.stdin = pth.join(tmp_dir.name, _STDIN_FILE_NANE)
        self.stdout = pth.join(tmp_dir.name, _STDOUT_FILE_NAME)
        self.stderr = pth.join(tmp_dir.name, _STDERR_FILE_NAME)

        # AVL geometry file (.avl) creation --------------------------------------------------------
        input_geom_file = pth.join(tmp_dir.name, _AVL_GEOM_NAME)
        profile_file = pth.join(tmp_dir.name, _PROFILE_FILE_NAME)
        self._get_avl_geom_file(inputs, input_geom_file, _PROFILE_FILE_NAME)

        # AVL session file creation ----------------------------------------------------------------

        s_ref = inputs["data:geometry:wing:area"]
        b_ref = inputs["data:geometry:wing:span"]
        c_ref = inputs["data:geometry:wing:MAC:length"]
        mach = inputs["data:aerostructural:load_case:mach"]
        alt = inputs["data:aerostructural:load_case:altitude"]
        rho = Atm(alt).density
        vtas = Atm(alt).speed_of_sound * mach
        q = 0.5 * rho * vtas ** 2

        m_lc = inputs["data:aerostructural:load_case:weight"]
        nz = inputs["data:aerostructural:load_case:load_factor"]
        cl = nz * m_lc * g / (q * s_ref)

        tmp_result_file = pth.join(tmp_dir.name, self.options[OPTION_RESULT_AVL_FILENAME])
        parser = InputFileGenerator()
        with path(ressources, _STDIN_FILE_NANE) as stdin_template:
            parser.set_template_file(stdin_template)
            parser.set_generated_file(self.stdin)

            # Update session file with target values:
            parser.mark_anchor("LOAD")
            parser.transfer_var(input_geom_file, 1, 1)
            parser.mark_anchor("OPER")
            parser.transfer_var(float(cl), 1, 3)
            parser.mark_anchor("M")
            parser.transfer_var(float(mach), 1, 2)
            parser.transfer_var(float(vtas), 2, 2)
            parser.transfer_var(float(rho), 3, 2)
            parser.mark_anchor("W")
            parser.transfer_var(tmp_result_file, 1, 1)

            parser.generate()

        # Check for input and output file presence -------------------------------------------------
        self.options["external_input_files"] = [
            self.stdin,
            input_geom_file,
            profile_file,
        ]
        self.options["external_output_files"] = [tmp_result_file]

        # Launch AVL -------------------------------------------------------------------------------
        super().compute(inputs, outputs)

        # Gather results ---------------------------------------------------------------------------
        parser_out = FileParser()
        parser_out.set_file(tmp_result_file)
        parser_out.mark_anchor("Alpha =")
        aoa = parser_out.transfer_var(0, 3)
        parser_out.mark_anchor("CLtot =")
        outputs["data:aerostructural:aerodynamic:CL"] = parser_out.transfer_var(0, 3)
        parser_out.mark_anchor("CDind =")
        outputs["data:aerostructural:aerodynamic:CDi"] = parser_out.transfer_var(0, 6)
        outputs["data:aerostructural:aerodynamic:Oswald_Coeff"] = parser_out.transfer_var(2, 6)
        for (comp, sect) in zip(self.options["components"], self.options["components_sections"]):
            size = sect  # default number of section for non symmetric components
            if comp in ("wing", "horizontal_tail", "strut"):
                size = sect * 2  # number of sections doubled for symmetric components
            elif comp == "fuselage":
                size = 4  # particular case for fuselage due to specific VLM modelling
            avl_comp = AVL_COMPONENT_NAMES[comp]
            parser_out.mark_anchor(avl_comp)
            comp_coef = parser_out.transfer_2Darray(0, 3, size - 1, 8)
            #  Reorganise result array to have coefficient in direct axis order
            comp_coef[:, :] = comp_coef[:, [1, 3, 0, 5, 2, 4]]
            #  Comvert coefficients into forces and moments
            comp_coef[:, :3] *= q * s_ref
            comp_coef[:, [3, 5]] *= q * s_ref * b_ref
            comp_coef[:, 4] *= q * s_ref * c_ref
            #  Change forces and moment from aerodynamic to body axis
            r_mat = self._get_rotation_matrix(aoa * degree, axis="y")
            comp_coef[:, :3] = np.dot(comp_coef[:, :3], r_mat)
            comp_coef[:, 3:] = np.dot(comp_coef[:, 3:], r_mat)  # Moments in std axis ie X fwd
            outputs["data:aerostructural:aerodynamic:" + comp + ":forces"] = comp_coef
        # outputs["data:aerostructural:aerodynamic:forces"] = q * s_ref * surface_coef

        # Store input and result files if necessary ------------------------------------------------
        if self.options[OPTION_RESULT_FOLDER_PATH]:
            if pth.exists(tmp_result_file):
                forces_file = pth.join(result_folder_path, self.options[OPTION_RESULT_AVL_FILENAME])
                shutil.move(tmp_result_file, forces_file)
            if pth.exists(input_geom_file):
                geometry_file = pth.join(result_folder_path, _AVL_GEOM_NAME)
                shutil.move(input_geom_file, geometry_file)
            if pth.exists(self.stdin):
                stdin_path = pth.join(result_folder_path, _STDIN_FILE_NANE)
                shutil.move(self.stdin, stdin_path)
            if pth.exists(self.stdout):
                stdout_path = pth.join(result_folder_path, _STDOUT_FILE_NAME)
                shutil.move(self.stdout, stdout_path)
            if pth.exists(self.stderr):
                stderr_path = pth.join(result_folder_path, _STDERR_FILE_NAME)
                shutil.move(self.stderr, stderr_path)
        tmp_dir.cleanup()
Ejemplo n.º 3
0
    def compute(self, inputs, outputs):

        # Create result folder first (if it must fail, let it fail as soon as possible)
        result_folder_path = self.options[OPTION_RESULT_FOLDER_PATH]
        if result_folder_path != "":
            os.makedirs(result_folder_path, exist_ok=True)

        # Get inputs
        reynolds = inputs["xfoil:reynolds"]
        mach = inputs["xfoil:mach"]
        thickness_ratio = inputs["data:geometry:wing:thickness_ratio"]

        # Pre-processing (populating temp directory) -----------------------------------------------
        # XFoil exe
        tmp_directory = self._create_tmp_directory()
        if self.options[OPTION_XFOIL_EXE_PATH]:
            # if a path for Xfoil has been provided, simply use it
            self.options["command"] = [self.options[OPTION_XFOIL_EXE_PATH]]
        else:
            # otherwise, copy the embedded resource in tmp dir
            copy_resource(xfoil699, XFOIL_EXE_NAME, tmp_directory.name)
            self.options["command"] = [
                pth.join(tmp_directory.name, XFOIL_EXE_NAME)
            ]

        # I/O files
        self.stdin = pth.join(tmp_directory.name, _INPUT_FILE_NAME)
        self.stdout = pth.join(tmp_directory.name, _STDOUT_FILE_NAME)
        self.stderr = pth.join(tmp_directory.name, _STDERR_FILE_NAME)

        # profile file
        tmp_profile_file_path = pth.join(tmp_directory.name,
                                         _TMP_PROFILE_FILE_NAME)
        profile = get_profile(file_name=self.options[OPTION_PROFILE_NAME],
                              thickness_ratio=thickness_ratio).get_sides()
        np.savetxt(
            tmp_profile_file_path,
            profile.to_numpy(),
            fmt="%.15f",
            delimiter=" ",
            header="Wing",
            comments="",
        )

        # standard input file
        tmp_result_file_path = pth.join(tmp_directory.name,
                                        _TMP_RESULT_FILE_NAME)
        parser = InputFileGenerator()
        with path(resources, _INPUT_FILE_NAME) as input_template_path:
            parser.set_template_file(input_template_path)
            parser.set_generated_file(self.stdin)

            # Fills numeric values
            parser.mark_anchor("RE")
            parser.transfer_var(float(reynolds), 1, 1)
            parser.mark_anchor("M")
            parser.transfer_var(float(mach), 1, 1)
            parser.mark_anchor("ITER")
            parser.transfer_var(self.options[OPTION_ITER_LIMIT], 1, 1)
            parser.mark_anchor("ASEQ")
            parser.transfer_var(self.options[OPTION_ALPHA_START], 1, 1)
            parser.transfer_var(self.options[OPTION_ALPHA_END], 2, 1)

            # Fills string values
            # If a provide path contains the string that is used as next anchor, the process
            # will fail. Doing these replacements at the end prevent this to happen.
            parser.reset_anchor()
            parser.mark_anchor("LOAD")
            parser.transfer_var(tmp_profile_file_path, 1, 1)
            parser.mark_anchor("PACC", -2)
            parser.transfer_var(tmp_result_file_path, 1, 1)

            parser.generate()

        # Run XFOIL --------------------------------------------------------------------------------
        self.options["external_input_files"] = [
            self.stdin, tmp_profile_file_path
        ]
        self.options["external_output_files"] = [tmp_result_file_path]
        super().compute(inputs, outputs)

        # Post-processing --------------------------------------------------------------------------
        result_array = self._read_polar(tmp_result_file_path)
        outputs["xfoil:CL_max_2D"] = self._get_max_cl(result_array["alpha"],
                                                      result_array["CL"])

        # Getting output files if needed
        if self.options[OPTION_RESULT_FOLDER_PATH]:
            if pth.exists(tmp_result_file_path):
                polar_file_path = pth.join(
                    result_folder_path,
                    self.options[OPTION_RESULT_POLAR_FILENAME])
                shutil.move(tmp_result_file_path, polar_file_path)

            if pth.exists(self.stdin):
                stdin_file_path = pth.join(result_folder_path,
                                           _INPUT_FILE_NAME)
                shutil.move(self.stdin, stdin_file_path)

            if pth.exists(self.stdout):
                stdout_file_path = pth.join(result_folder_path,
                                            _STDOUT_FILE_NAME)
                shutil.move(self.stdout, stdout_file_path)

            if pth.exists(self.stderr):
                stderr_file_path = pth.join(result_folder_path,
                                            _STDERR_FILE_NAME)
                shutil.move(self.stderr, stderr_file_path)

        tmp_directory.cleanup()
Ejemplo n.º 4
0
    def compute(self, inputs, outputs):

        # Get inputs and initialise outputs
        mach = round(float(inputs["xfoil:mach"]) * 1e4) / 1e4
        reynolds = round(float(inputs["xfoil:reynolds"]))

        # Search if data already stored for this profile and mach with reynolds values bounding current value.
        # If so, use linear interpolation with the nearest upper/lower reynolds
        no_file = True
        data_saved = None
        interpolated_result = None
        if self.options['symmetrical']:
            result_file = pth.join(pth.split(os.path.realpath(__file__))[0], "resources",
                                   self.options["airfoil_file"].replace('.af', '_sym') + '.csv')
        else:
            result_file = pth.join(pth.split(os.path.realpath(__file__))[0], "resources",
                                   self.options["airfoil_file"].replace('.af', '') + '.csv')
        if pth.exists(result_file):
            no_file = False
            data_saved = pd.read_csv(result_file)
            values = data_saved.to_numpy()[:, 1:len(data_saved.to_numpy()[0])]
            labels = data_saved.to_numpy()[:, 0].tolist()
            data_saved = pd.DataFrame(values, index=labels)
            index_mach = np.where(data_saved.loc["mach", :].to_numpy() == str(mach))[0]
            data_reduced = data_saved.loc[labels, index_mach]
            # Search if this exact reynolds has been computed and save results
            reynolds_vect = np.array([float(x) for x in list(data_reduced.loc["reynolds", :].to_numpy())])
            index_reynolds = index_mach[np.where(reynolds_vect == reynolds)[0]]
            if len(index_reynolds) == 1:
                interpolated_result = data_reduced.loc[labels, index_reynolds]
            # Else search for lower/upper Reynolds
            else:
                lower_reynolds = reynolds_vect[np.where(reynolds_vect < reynolds)[0]]
                upper_reynolds = reynolds_vect[np.where(reynolds_vect > reynolds)[0]]
                if not (len(lower_reynolds) == 0 or len(upper_reynolds) == 0):
                    index_lower_reynolds = index_mach[np.where(reynolds_vect == max(lower_reynolds))[0]]
                    index_upper_reynolds = index_mach[np.where(reynolds_vect == min(upper_reynolds))[0]]
                    lower_values = data_reduced.loc[labels, index_lower_reynolds]
                    upper_values = data_reduced.loc[labels, index_upper_reynolds]
                    interpolated_result = lower_values
                    # Calculate reynolds interval ratio
                    x_ratio = (min(upper_reynolds) - reynolds) / (min(upper_reynolds) - max(lower_reynolds))
                    # Search for common alpha range
                    alpha_lower = eval(lower_values.loc['alpha', index_lower_reynolds].to_numpy()[0])
                    alpha_upper = eval(upper_values.loc['alpha', index_upper_reynolds].to_numpy()[0])
                    alpha_shared = np.array(list(set(alpha_upper).intersection(alpha_lower)))
                    interpolated_result.loc['alpha', index_lower_reynolds] = str(alpha_shared.tolist())
                    labels.remove('alpha')
                    # Calculate average values (cd, cl...) with linear interpolation
                    for label in labels:
                        lower_value = np.array(eval(lower_values.loc[label, index_lower_reynolds].to_numpy()[0]))
                        upper_value = np.array(eval(upper_values.loc[label, index_upper_reynolds].to_numpy()[0]))
                        # If values relative to alpha vector, performs interpolation with shared vector
                        if np.size(lower_value) == len(alpha_lower):
                            lower_value = np.interp(alpha_shared, np.array(alpha_lower), lower_value)
                            upper_value = np.interp(alpha_shared, np.array(alpha_upper), upper_value)
                        value = (lower_value * x_ratio + upper_value * (1 - x_ratio)).tolist()
                        interpolated_result.loc[label, index_lower_reynolds] = str(value)

        if interpolated_result is None:
            # Create result folder first (if it must fail, let it fail as soon as possible)
            result_folder_path = self.options[OPTION_RESULT_FOLDER_PATH]
            if result_folder_path != "":
                os.makedirs(result_folder_path, exist_ok=True)

            # Pre-processing (populating temp directory) -----------------------------------------------
            # XFoil exe
            tmp_directory = self._create_tmp_directory()
            if self.options[OPTION_XFOIL_EXE_PATH]:
                # if a path for Xfoil has been provided, simply use it
                self.options["command"] = [self.options[OPTION_XFOIL_EXE_PATH]]
            else:
                # otherwise, copy the embedded resource in tmp dir
                # noinspection PyTypeChecker
                copy_resource(xfoil699, XFOIL_EXE_NAME, tmp_directory.name)
                self.options["command"] = [pth.join(tmp_directory.name, XFOIL_EXE_NAME)]

            # I/O files
            self.stdin = pth.join(tmp_directory.name, _INPUT_FILE_NAME)
            self.stdout = pth.join(tmp_directory.name, _STDOUT_FILE_NAME)
            self.stderr = pth.join(tmp_directory.name, _STDERR_FILE_NAME)

            # profile file
            tmp_profile_file_path = pth.join(tmp_directory.name, _TMP_PROFILE_FILE_NAME)
            profile = get_profile(
                file_name=self.options["airfoil_file"],
            ).get_sides()
            # noinspection PyTypeChecker
            np.savetxt(
                tmp_profile_file_path,
                profile.to_numpy(),
                fmt="%.15f",
                delimiter=" ",
                header="Wing",
                comments="",
            )

            # standard input file
            tmp_result_file_path = pth.join(tmp_directory.name, _TMP_RESULT_FILE_NAME)
            self._write_script_file(
                reynolds, mach, tmp_profile_file_path, tmp_result_file_path, self.options[OPTION_ALPHA_START],
                self.options[OPTION_ALPHA_END], ALPHA_STEP)

            # Run XFOIL --------------------------------------------------------------------------------
            self.options["external_input_files"] = [self.stdin, tmp_profile_file_path]
            self.options["external_output_files"] = [tmp_result_file_path]
            super().compute(inputs, outputs)

            if self.options['symmetrical']:
                result_array_p = self._read_polar(tmp_result_file_path)
                os.remove(self.stdin)
                os.remove(self.stdout)
                os.remove(self.stderr)
                os.remove(tmp_result_file_path)
                self._write_script_file(
                    reynolds, mach, tmp_profile_file_path, tmp_result_file_path, -1 * self.options[OPTION_ALPHA_START],
                                                                                 -1 * self.options[OPTION_ALPHA_END],
                    -ALPHA_STEP)
                super().compute(inputs, outputs)
                result_array_n = self._read_polar(tmp_result_file_path)
            else:
                result_array_p = self._read_polar(tmp_result_file_path)
                result_array_n = result_array_p

            # Post-processing --------------------------------------------------------------------------
            cl_max_2d, error = self._get_max_cl(result_array_p["alpha"], result_array_p["CL"])
            cl_min_2d, error = self._get_min_cl(result_array_n["alpha"], result_array_n["CL"])
            if POLAR_POINT_COUNT < len(result_array_p["alpha"]):
                alpha = np.linspace(result_array_p["alpha"][0], result_array_p["alpha"][-1], POLAR_POINT_COUNT)
                cl = np.interp(alpha, result_array_p["alpha"], result_array_p["CL"])
                cd = np.interp(alpha, result_array_p["alpha"], result_array_p["CD"])
                cdp = np.interp(alpha, result_array_p["alpha"], result_array_p["CDp"])
                cm = np.interp(alpha, result_array_p["alpha"], result_array_p["CM"])
                warnings.warn("Defined polar point in fast aerodynamics\\constants.py exceeded!")
            else:
                additional_zeros = list(np.zeros(POLAR_POINT_COUNT - len(result_array_p["alpha"])))
                alpha = result_array_p["alpha"].tolist()
                alpha.extend(additional_zeros)
                alpha = np.asarray(alpha)
                cl = result_array_p["CL"].tolist()
                cl.extend(additional_zeros)
                cl = np.asarray(cl)
                cd = result_array_p["CD"].tolist()
                cd.extend(additional_zeros)
                cd = np.asarray(cd)
                cdp = result_array_p["CDp"].tolist()
                cdp.extend(additional_zeros)
                cdp = np.asarray(cdp)
                cm = result_array_p["CM"].tolist()
                cm.extend(additional_zeros)
                cm = np.asarray(cm)

            # Save results to defined path -------------------------------------------------------------
            if not error:
                results = [np.array(mach), np.array(reynolds), np.array(cl_max_2d), np.array(cl_min_2d),
                           str(self._reshape(alpha, alpha).tolist()), str(self._reshape(alpha, cl).tolist()),
                           str(self._reshape(alpha, cd).tolist()), str(self._reshape(alpha, cdp).tolist()),
                           str(self._reshape(alpha, cm).tolist())]
                labels = ["mach", "reynolds", "cl_max_2d", "cl_min_2d", "alpha", "cl", "cd", "cdp", "cm"]
                if no_file or (data_saved is None):
                    data = pd.DataFrame(results, index=labels)
                    data.to_csv(result_file)
                else:
                    data = pd.DataFrame(np.c_[data_saved, results], index=labels)
                    data.to_csv(result_file)

            # Getting output files if needed ---------------------------------------------------------
            if self.options[OPTION_RESULT_FOLDER_PATH] != "":
                if pth.exists(tmp_result_file_path):
                    polar_file_path = pth.join(
                        result_folder_path, self.options[OPTION_RESULT_POLAR_FILENAME]
                    )
                    shutil.move(tmp_result_file_path, polar_file_path)

                if pth.exists(self.stdout):
                    stdout_file_path = pth.join(result_folder_path, _STDOUT_FILE_NAME)
                    shutil.move(self.stdout, stdout_file_path)

                if pth.exists(self.stderr):
                    stderr_file_path = pth.join(result_folder_path, _STDERR_FILE_NAME)
                    shutil.move(self.stderr, stderr_file_path)

            tmp_directory.cleanup()

        else:
            # Extract results
            cl_max_2d = np.array(eval(interpolated_result.loc["cl_max_2d", :].to_numpy()[0]))
            cl_min_2d = np.array(eval(interpolated_result.loc["cl_min_2d", :].to_numpy()[0]))
            ALPHA = np.array(eval(interpolated_result.loc["alpha", :].to_numpy()[0]))
            CL = np.array(eval(interpolated_result.loc["cl", :].to_numpy()[0]))
            CD = np.array(eval(interpolated_result.loc["cd", :].to_numpy()[0]))
            CDP = np.array(eval(interpolated_result.loc["cdp", :].to_numpy()[0]))
            CM = np.array(eval(interpolated_result.loc["cm", :].to_numpy()[0]))

            # Modify vector length if necessary
            if POLAR_POINT_COUNT < len(ALPHA):
                alpha = np.linspace(ALPHA[0], ALPHA[-1], POLAR_POINT_COUNT)
                cl = np.interp(alpha, ALPHA, CL)
                cd = np.interp(alpha, ALPHA, CD)
                cdp = np.interp(alpha, ALPHA, CDP)
                cm = np.interp(alpha, ALPHA, CM)
            else:
                additional_zeros = list(np.zeros(POLAR_POINT_COUNT - len(ALPHA)))
                alpha = ALPHA.tolist()
                alpha.extend(additional_zeros)
                # noinspection PyTypeChecker
                alpha = np.asarray(alpha)
                cl = CL.tolist()
                cl.extend(additional_zeros)
                # noinspection PyTypeChecker
                cl = np.asarray(cl)
                cd = CD.tolist()
                cd.extend(additional_zeros)
                # noinspection PyTypeChecker
                cd = np.asarray(cd)
                cdp = CDP.tolist()
                cdp.extend(additional_zeros)
                # noinspection PyTypeChecker
                cdp = np.asarray(cdp)
                cm = CM.tolist()
                cm.extend(additional_zeros)
                # noinspection PyTypeChecker
                cm = np.asarray(cm)

        # Defining outputs -------------------------------------------------------------------------
        outputs["xfoil:alpha"] = alpha
        outputs["xfoil:CL"] = cl
        outputs["xfoil:CD"] = cd
        outputs["xfoil:CDp"] = cdp
        outputs["xfoil:CM"] = cm
        outputs["xfoil:CL_max_2D"] = cl_max_2d
        outputs["xfoil:CL_min_2D"] = cl_min_2d
Ejemplo n.º 5
0
    def compute(self, inputs, outputs):

        # Create result folder first (if it must fail, let it fail as soon as possible)
        result_folder_path = self.options[OPTION_RESULT_FOLDER_PATH]
        if result_folder_path != "":
            os.makedirs(pth.join(result_folder_path, 'OSWALD'), exist_ok=True)

        # Get inputs (and calculate missing ones)
        x0_wing = inputs["data:geometry:wing:MAC:leading_edge:x:local"]
        l0_wing = inputs["data:geometry:wing:MAC:length"]
        width_max = inputs["data:geometry:fuselage:maximum_width"]
        y1_wing = width_max / 2.0
        y2_wing = inputs["data:geometry:wing:root:y"]
        l2_wing = inputs["data:geometry:wing:root:chord"]
        y4_wing = inputs["data:geometry:wing:tip:y"]
        l4_wing = inputs["data:geometry:wing:tip:chord"]
        sweep_0_wing = inputs["data:geometry:wing:sweep_0"]
        fa_length = inputs["data:geometry:wing:MAC:at25percent:x"]
        sref_wing = inputs['data:geometry:wing:area']
        span_wing = inputs['data:geometry:wing:span']
        height_max = inputs["data:geometry:fuselage:maximum_height"]
        if self.options["low_speed_aero"]:
            altitude = 0.0
            atm = Atmosphere(altitude)
            mach = inputs["data:aerodynamics:low_speed:mach"]
        else:
            altitude = inputs["data:mission:sizing:main_route:cruise:altitude"]
            atm = Atmosphere(altitude)
            mach = inputs["data:aerodynamics:cruise:mach"]

            # Initial parameters calculation
        x_wing = fa_length - x0_wing - 0.25 * l0_wing
        z_wing = -(height_max - 0.12 * l2_wing) * 0.5
        span2_wing = y4_wing - y2_wing
        viscosity = atm.kinematic_viscosity
        rho = atm.density
        v_inf = max(atm.speed_of_sound * mach, 0.1)  # avoid V=0 m/s crashes
        reynolds = v_inf * l0_wing / viscosity

        # OPENVSP-SCRIPT: Geometry generation ######################################################

        # I/O files --------------------------------------------------------------------------------
        tmp_directory = self._create_tmp_directory()
        # avoid to dump void xternal_code_comp_error.out error file
        self.stderr = pth.join(tmp_directory.name, _STDERR_FILE_NAME)
        if self.options[OPTION_OPENVSP_EXE_PATH]:
            target_directory = pth.abspath(self.options[OPTION_OPENVSP_EXE_PATH])
        else:
            target_directory = tmp_directory.name
        input_file_list = [pth.join(target_directory, _INPUT_SCRIPT_FILE_NAME),
                           pth.join(target_directory, self.options['wing_airfoil_file'])]
        tmp_result_file_path = pth.join(target_directory, _INPUT_AERO_FILE_NAME + '0.csv')
        output_file_list = [tmp_result_file_path]
        self.options["external_input_files"] = input_file_list
        self.options["external_output_files"] = output_file_list

        # Pre-processing (populating temp directory and generate batch file) -----------------------
        # Copy resource in temp directory if needed
        if not (self.options[OPTION_OPENVSP_EXE_PATH]):
            # noinspection PyTypeChecker
            copy_resource_folder(openvsp3201, target_directory)
            # noinspection PyTypeChecker
            copy_resource(resources, self.options['wing_airfoil_file'], target_directory)
        # Create corresponding .bat file
        self.options["command"] = [pth.join(target_directory, 'vspscript.bat')]
        command = pth.join(target_directory, VSPSCRIPT_EXE_NAME) + ' -script ' \
                  + pth.join(target_directory, _INPUT_SCRIPT_FILE_NAME) + ' >nul 2>nul\n'
        batch_file = open(self.options["command"][0], "w+")
        batch_file.write("@echo off\n")
        batch_file.write(command)
        batch_file.close()

        # standard SCRIPT input file ---------------------------------------------------------------
        parser = InputFileGenerator()
        with path(local_resources, _INPUT_SCRIPT_FILE_NAME) as input_template_path:
            parser.set_template_file(str(input_template_path))
            parser.set_generated_file(input_file_list[0])
            parser.mark_anchor("x_wing")
            parser.transfer_var(float(x_wing), 0, 5)
            parser.mark_anchor("z_wing")
            parser.transfer_var(float(z_wing), 0, 5)
            parser.mark_anchor("y1_wing")
            parser.transfer_var(float(y1_wing), 0, 5)
            for i in range(3):
                parser.mark_anchor("l2_wing")
                parser.transfer_var(float(l2_wing), 0, 5)
            parser.reset_anchor()
            parser.mark_anchor("span2_wing")
            parser.transfer_var(float(span2_wing), 0, 5)
            parser.mark_anchor("l4_wing")
            parser.transfer_var(float(l4_wing), 0, 5)
            parser.mark_anchor("sweep_0_wing")
            parser.transfer_var(float(sweep_0_wing), 0, 5)
            parser.mark_anchor("airfoil_0_file")
            parser.transfer_var(self._rewrite_path(input_file_list[1]), 0, 3)
            parser.mark_anchor("airfoil_1_file")
            parser.transfer_var(self._rewrite_path(input_file_list[1]), 0, 3)
            parser.mark_anchor("airfoil_2_file")
            parser.transfer_var(self._rewrite_path(input_file_list[1]), 0, 3)
            parser.mark_anchor("csv_file")
            parser.transfer_var(self._rewrite_path(tmp_result_file_path), 0, 3)
            parser.generate()

        # Run SCRIPT --------------------------------------------------------------------------------
        super().compute(inputs, outputs)

        # Getting input/output files if needed
        if self.options[OPTION_RESULT_FOLDER_PATH] != "":
            for file_path in input_file_list:
                new_path = pth.join(result_folder_path, 'OSWALD', pth.split(file_path)[1])
                if pth.exists(file_path):
                    shutil.copyfile(file_path, new_path)
            for file_path in output_file_list:
                new_path = pth.join(result_folder_path, 'OSWALD', pth.split(file_path)[1])
                if pth.exists(file_path):
                    shutil.copyfile(file_path, new_path)

        # OPENVSP-AERO: aero calculation ############################################################

        # I/O files --------------------------------------------------------------------------------
        # Duplicate .csv file for multiple run
        input_file_list = [tmp_result_file_path]
        for idx in range(len(_INPUT_AOAList) - 1):
            shutil.copy(tmp_result_file_path, pth.join(target_directory, _INPUT_AERO_FILE_NAME + str(idx + 1) + '.csv'))
            input_file_list.append(pth.join(target_directory, _INPUT_AERO_FILE_NAME + str(idx + 1) + '.csv'))
        output_file_list = []
        for idx in range(len(_INPUT_AOAList)):
            input_file_list.append(pth.join(target_directory, _INPUT_AERO_FILE_NAME) + str(idx) + '.vspaero')
            output_file_list.append(pth.join(target_directory, _INPUT_AERO_FILE_NAME) + str(idx) + '.polar')
        self.options["external_input_files"] = input_file_list
        self.options["external_output_files"] = output_file_list

        # Pre-processing (create batch file) -------------------------------------------------------
        self.options["command"] = [pth.join(target_directory, 'vspaero.bat')]
        batch_file = open(self.options["command"][0], "w+")
        batch_file.write("@echo off\n")
        for idx in range(len(_INPUT_AOAList)):
            command = pth.join(target_directory, VSPAERO_EXE_NAME) + ' ' \
                      + pth.join(target_directory, _INPUT_AERO_FILE_NAME + str(idx) + ' >nul 2>nul\n')
            batch_file.write(command)
        batch_file.close()

        # standard AERO input file -----------------------------------------------------------------
        parser = InputFileGenerator()
        for idx in range(len(_INPUT_AOAList)):
            with path(local_resources, _INPUT_AERO_FILE_NAME + '.vspaero') as input_template_path:
                parser.set_template_file(str(input_template_path))
                parser.set_generated_file(input_file_list[len(_INPUT_AOAList) + idx])
                parser.reset_anchor()
                parser.mark_anchor("Sref")
                parser.transfer_var(float(sref_wing), 0, 3)
                parser.mark_anchor("Cref")
                parser.transfer_var(float(l0_wing), 0, 3)
                parser.mark_anchor("Bref")
                parser.transfer_var(float(span_wing), 0, 3)
                parser.mark_anchor("X_cg")
                parser.transfer_var(float(fa_length), 0, 3)
                parser.mark_anchor("Mach")
                parser.transfer_var(float(mach), 0, 3)
                parser.mark_anchor("AOA")
                parser.transfer_var(float(_INPUT_AOAList[idx]), 0, 3)
                parser.mark_anchor("Vinf")
                parser.transfer_var(float(v_inf), 0, 3)
                parser.mark_anchor("Rho")
                parser.transfer_var(float(rho), 0, 3)
                parser.mark_anchor("ReCref")
                parser.transfer_var(float(reynolds), 0, 3)
                parser.generate()

        # Run AERO --------------------------------------------------------------------------------
        super().compute(inputs, outputs)

        # Post-processing --------------------------------------------------------------------------
        result_oswald = []
        for idx in range(len(_INPUT_AOAList)):
            _, _, oswald, _ = self._read_polar_file(output_file_list[idx])
            result_oswald.append(oswald)
        # Fuselage correction
        k_fus = 1 - 2 * (width_max / span_wing) ** 2
        # Full aircraft correction: Wing lift is 105% of total lift.
        # This means CDind = (CL*1.05)^2/(piAe) -> e' = e/1.05^2
        coef_e = float(result_oswald[0] * k_fus / 1.05 ** 2)
        coef_k = 1. / (math.pi * span_wing ** 2 / sref_wing * coef_e)

        if self.options["low_speed_aero"]:
            outputs["data:aerodynamics:aircraft:low_speed:induced_drag_coefficient"] = coef_k
        else:
            outputs["data:aerodynamics:aircraft:cruise:induced_drag_coefficient"] = coef_k

        # Getting input/output files if needed
        if self.options[OPTION_RESULT_FOLDER_PATH] != "":
            for file_path in input_file_list:
                new_path = pth.join(result_folder_path, 'OSWALD', pth.split(file_path)[1])
                if pth.exists(file_path):
                    shutil.copyfile(file_path, new_path)
            for file_path in output_file_list:
                new_path = pth.join(result_folder_path, 'OSWALD', pth.split(file_path)[1])
                if pth.exists(file_path):
                    shutil.copyfile(file_path, new_path)

        # Delete temporary directory    
        tmp_directory.cleanup()
Ejemplo n.º 6
0
    def compute(self, inputs, outputs):

        # Create result folder first (if it must fail, let it fail as soon as possible)
        result_folder_path = self.options[OPTION_RESULT_FOLDER_PATH]
        if result_folder_path != "":
            os.makedirs(pth.join(result_folder_path, 'ClCmHT'), exist_ok=True)

        # Get inputs (and calculate missing ones)
        x0_wing = inputs["data:geometry:wing:MAC:leading_edge:x:local"]
        l0_wing = inputs["data:geometry:wing:MAC:length"]
        width_max = inputs["data:geometry:fuselage:maximum_width"]
        y1_wing = width_max / 2.0
        y2_wing = inputs["data:geometry:wing:root:y"]
        l2_wing = inputs["data:geometry:wing:root:chord"]
        y4_wing = inputs["data:geometry:wing:tip:y"]
        l4_wing = inputs["data:geometry:wing:tip:chord"]
        sweep_0_wing = inputs["data:geometry:wing:sweep_0"]
        fa_length = inputs["data:geometry:wing:MAC:at25percent:x"]
        sref_wing = inputs['data:geometry:wing:area']
        span_wing = inputs['data:geometry:wing:span']
        height_max = inputs["data:geometry:fuselage:maximum_height"]
        sweep_25_htp = inputs["data:geometry:horizontal_tail:sweep_25"]
        span_htp = inputs["data:geometry:horizontal_tail:span"] / 2.0
        root_chord_htp = inputs["data:geometry:horizontal_tail:root:chord"]
        tip_chord_htp = inputs["data:geometry:horizontal_tail:tip:chord"]
        lp_htp = inputs[
            "data:geometry:horizontal_tail:MAC:at25percent:x:from_wingMAC25"]
        l0_htp = inputs["data:geometry:horizontal_tail:MAC:length"]
        x0_htp = inputs[
            "data:geometry:horizontal_tail:MAC:at25percent:x:local"]
        height_htp = inputs["data:geometry:horizontal_tail:z:from_wingMAC25"]
        mach = inputs["data:aerodynamics:low_speed:mach"]
        altitude = 0.0

        # Compute remaining inputs
        x_wing = fa_length - x0_wing - 0.25 * l0_wing
        z_wing = -(height_max - 0.12 * l2_wing) * 0.5
        span2_wing = y4_wing - y2_wing
        distance_htp = fa_length + lp_htp - 0.25 * l0_htp - x0_htp
        atm = Atmosphere(altitude)
        viscosity = atm.kinematic_viscosity
        rho = atm.density
        v_inf = max(atm.speed_of_sound * mach, 0.01)  # avoid V=0 m/s crashes
        reynolds = v_inf * l0_wing / viscosity

        # OPENVSP-SCRIPT: Geometry generation ######################################################

        # I/O files --------------------------------------------------------------------------------
        tmp_directory = self._create_tmp_directory()
        # avoid to dump void xternal_code_comp_error.out error file
        self.stderr = pth.join(tmp_directory.name, _STDERR_FILE_NAME)
        if self.options[OPTION_OPENVSP_EXE_PATH]:
            target_directory = pth.abspath(
                self.options[OPTION_OPENVSP_EXE_PATH])
        else:
            target_directory = tmp_directory.name
        input_file_list = [
            pth.join(target_directory, _INPUT_SCRIPT_FILE_NAME),
            pth.join(target_directory, self.options['wing_airfoil_file']),
            pth.join(target_directory, self.options['htp_airfoil_file'])
        ]
        tmp_result_file_path = pth.join(target_directory,
                                        _INPUT_AERO_FILE_NAME + '0.csv')
        output_file_list = [tmp_result_file_path]
        self.options["external_input_files"] = input_file_list
        self.options["external_output_files"] = output_file_list

        # Pre-processing (populating temp directory) -----------------------------------------------
        # Copy resource in temp directory if needed
        if not (self.options[OPTION_OPENVSP_EXE_PATH]):
            # noinspection PyTypeChecker
            copy_resource_folder(openvsp3201, target_directory)
            # noinspection PyTypeChecker
            copy_resource(resources, self.options['wing_airfoil_file'],
                          target_directory)
            # noinspection PyTypeChecker
            copy_resource(resources, self.options['htp_airfoil_file'],
                          target_directory)
        # Create corresponding .bat file
        self.options["command"] = [pth.join(target_directory, 'vspscript.bat')]
        command = pth.join(target_directory, VSPSCRIPT_EXE_NAME) + ' -script ' \
                  + pth.join(target_directory, _INPUT_SCRIPT_FILE_NAME) + ' >nul 2>nul\n'
        batch_file = open(self.options["command"][0], "w+")
        batch_file.write("@echo off\n")
        batch_file.write(command)
        batch_file.close()

        # standard SCRIPT input file ----------------------------------------------------------------
        parser = InputFileGenerator()
        with path(local_resources,
                  _INPUT_SCRIPT_FILE_NAME) as input_template_path:
            parser.set_template_file(str(input_template_path))
            parser.set_generated_file(input_file_list[0])
            parser.mark_anchor("x_wing")
            parser.transfer_var(float(x_wing), 0, 5)
            parser.mark_anchor("z_wing")
            parser.transfer_var(float(z_wing), 0, 5)
            parser.mark_anchor("y1_wing")
            parser.transfer_var(float(y1_wing), 0, 5)
            for i in range(3):
                parser.mark_anchor("l2_wing")
                parser.transfer_var(float(l2_wing), 0, 5)
            parser.reset_anchor()
            parser.mark_anchor("span2_wing")
            parser.transfer_var(float(span2_wing), 0, 5)
            parser.mark_anchor("l4_wing")
            parser.transfer_var(float(l4_wing), 0, 5)
            parser.mark_anchor("sweep_0_wing")
            parser.transfer_var(float(sweep_0_wing), 0, 5)
            parser.mark_anchor("airfoil_0_file")
            parser.transfer_var(self._rewrite_path(input_file_list[1]), 0, 3)
            parser.mark_anchor("airfoil_1_file")
            parser.transfer_var(self._rewrite_path(input_file_list[1]), 0, 3)
            parser.mark_anchor("airfoil_2_file")
            parser.transfer_var(self._rewrite_path(input_file_list[1]), 0, 3)
            parser.mark_anchor("distance_htp")
            parser.transfer_var(float(distance_htp), 0, 5)
            parser.mark_anchor("height_htp")
            parser.transfer_var(float(height_htp), 0, 5)
            parser.mark_anchor("span_htp")
            parser.transfer_var(float(span_htp), 0, 5)
            parser.mark_anchor("root_chord_htp")
            parser.transfer_var(float(root_chord_htp), 0, 5)
            parser.mark_anchor("tip_chord_htp")
            parser.transfer_var(float(tip_chord_htp), 0, 5)
            parser.mark_anchor("sweep_25_htp")
            parser.transfer_var(float(sweep_25_htp), 0, 5)
            parser.mark_anchor("airfoil_3_file")
            parser.transfer_var(self._rewrite_path(input_file_list[2]), 0, 3)
            parser.mark_anchor("airfoil_4_file")
            parser.transfer_var(self._rewrite_path(input_file_list[2]), 0, 3)
            parser.mark_anchor("csv_file")
            parser.transfer_var(self._rewrite_path(tmp_result_file_path), 0, 3)
            parser.generate()

        # Run SCRIPT --------------------------------------------------------------------------------
        super().compute(inputs, outputs)

        # Getting input/output files if needed
        if self.options[OPTION_RESULT_FOLDER_PATH] != "":
            for file_path in input_file_list:
                new_path = pth.join(result_folder_path, 'ClCmHT',
                                    pth.split(file_path)[1])
                if pth.exists(file_path):
                    shutil.copyfile(file_path, new_path)
            for file_path in output_file_list:
                new_path = pth.join(result_folder_path, 'ClCmHT',
                                    pth.split(file_path)[1])
                if pth.exists(file_path):
                    shutil.copyfile(file_path, new_path)

        # OPENVSP-AERO: aero calculation ############################################################

        # I/O files --------------------------------------------------------------------------------
        # Duplicate .csv file for multiple run
        input_file_list = [tmp_result_file_path]
        for idx in range(len(_INPUT_AOAList) - 1):
            shutil.copy(
                tmp_result_file_path,
                pth.join(target_directory,
                         _INPUT_AERO_FILE_NAME + str(idx + 1) + '.csv'))
            input_file_list.append(
                pth.join(target_directory,
                         _INPUT_AERO_FILE_NAME + str(idx + 1) + '.csv'))
        output_file_list = []
        for idx in range(len(_INPUT_AOAList)):
            input_file_list.append(
                pth.join(target_directory, _INPUT_AERO_FILE_NAME) + str(idx) +
                '.vspaero')
            output_file_list.append(
                pth.join(target_directory, _INPUT_AERO_FILE_NAME) + str(idx) +
                '.lod')
        self.options["external_input_files"] = input_file_list
        self.options["external_output_files"] = output_file_list

        # Pre-processing (create batch file) -------------------------------------------------------
        self.options["command"] = [pth.join(target_directory, 'vspaero.bat')]
        batch_file = open(self.options["command"][0], "w+")
        batch_file.write("@echo off\n")
        for idx in range(len(_INPUT_AOAList)):
            command = pth.join(target_directory, VSPAERO_EXE_NAME) + ' ' \
                      + pth.join(target_directory, _INPUT_AERO_FILE_NAME + str(idx) + ' >nul 2>nul\n')
            batch_file.write(command)
        batch_file.close()

        # standard AERO input file -----------------------------------------------------------------
        parser = InputFileGenerator()
        for idx in range(len(_INPUT_AOAList)):
            with path(local_resources, _INPUT_AERO_FILE_NAME +
                      '.vspaero') as input_template_path:
                parser.set_template_file(str(input_template_path))
                parser.set_generated_file(input_file_list[len(_INPUT_AOAList) +
                                                          idx])
                parser.reset_anchor()
                parser.mark_anchor("Sref")
                parser.transfer_var(float(sref_wing), 0, 3)
                parser.mark_anchor("Cref")
                parser.transfer_var(float(l0_wing), 0, 3)
                parser.mark_anchor("Bref")
                parser.transfer_var(float(span_wing), 0, 3)
                parser.mark_anchor("X_cg")
                parser.transfer_var(float(fa_length), 0, 3)
                parser.mark_anchor("Mach")
                parser.transfer_var(float(mach), 0, 3)
                parser.mark_anchor("AOA")
                parser.transfer_var(float(_INPUT_AOAList[idx]), 0, 3)
                parser.mark_anchor("Vinf")
                parser.transfer_var(float(v_inf), 0, 3)
                parser.mark_anchor("Rho")
                parser.transfer_var(float(rho), 0, 3)
                parser.mark_anchor("ReCref")
                parser.transfer_var(float(reynolds), 0, 3)
                parser.generate()

        # Run AERO --------------------------------------------------------------------------------
        super().compute(inputs, outputs)

        # Post-processing --------------------------------------------------------------------------
        result_cl = []
        result_cm1 = []
        result_cm2 = []
        for idx in range(len(_INPUT_AOAList)):
            cl_htp, cm_htp, cm_wing = self._read_lod_file(
                output_file_list[idx])
            result_cl.append(cl_htp)
            result_cm1.append(cm_htp)
            result_cm2.append(cm_wing)

        outputs[
            'data:aerodynamics:horizontal_tail:low_speed:alpha'] = np.array(
                _INPUT_AOAList)
        outputs['data:aerodynamics:horizontal_tail:low_speed:CL'] = np.array(
            result_cl)
        outputs['data:aerodynamics:horizontal_tail:low_speed:CM'] = np.array(
            result_cm1)
        outputs['data:aerodynamics:wing:low_speed:alpha'] = np.array(
            _INPUT_AOAList)
        outputs['data:aerodynamics:wing:low_speed:CM'] = np.array(result_cm2)

        # Getting input/output files if needed
        if self.options[OPTION_RESULT_FOLDER_PATH] != "":
            for file_path in input_file_list:
                new_path = pth.join(result_folder_path, 'ClCmHT',
                                    pth.split(file_path)[1])
                if pth.exists(file_path):
                    shutil.copyfile(file_path, new_path)
            for file_path in output_file_list:
                new_path = pth.join(result_folder_path, 'ClCmHT',
                                    pth.split(file_path)[1])
                if pth.exists(file_path):
                    shutil.copyfile(file_path, new_path)

        # Delete temporary directory
        tmp_directory.cleanup()
Ejemplo n.º 7
0
    def compute(self, inputs, outputs):
        result_folder_path = self.options[OPTION_RESULT_FOLDER_PATH]
        if result_folder_path != "":
            os.makedirs(result_folder_path, exist_ok=True)

        components = self.options["components"]
        nsects = self.options["components_sections"]

        # Prepare input file ----------------------------------------------------------------------
        cg_loc = inputs["data:geometry:wing:MAC:at25percent:x"]
        nz = inputs["data:aerostructural:load_case:load_factor"]
        strg = []
        spc_strg = "SPCADD, 1, "
        for idx, comp in enumerate(components):
            mat_prop = np.zeros(3)
            nodes = inputs["data:aerostructural:structure:" + comp + ":nodes"]
            props = inputs["data:aerostructural:structure:" + comp + ":beam_properties"]
            forces = inputs["data:aerostructural:structure:" + comp + ":forces"]
            mat_prop[0] = inputs["data:aerostructural:structure:" + comp + ":material:E"]
            mat_prop[1] = inputs["data:aerostructural:structure:" + comp + ":material:mu"]
            mat_prop[2] = inputs["data:aerostructural:structure:" + comp + ":material:density"]
            strg += get_nodes_cards(comp, nodes, basis_id[comp])
            strg += get_props_cards(comp, props, basis_id[comp])
            strg += get_mat_cards(mat_prop, basis_id[comp])
            strg += get_rbe_junction_cards(comp, nodes, basis_id[comp])
            strg += get_forces_cards(comp, forces, basis_id[comp])
            # if comp != "strut":
            #     master = "fuselage"
            #     master_nodes = inputs["data:aerostructural:structure:fuselage:nodes"]
            #     strg += get_bc_cards(comp, master, master_nodes, nodes, cg_loc)
            if comp == "strut":
                master = "wing"
                master_nodes = inputs["data:aerostructural:structure:wing:nodes"]
                strg += get_rbe_cards(comp, master, master_nodes, nodes, cg_loc)
                strg += get_spc_cards(idx + 2, "123", basis_id[comp])
            else:
                strg += get_spc_cards(idx + 2, "123456", basis_id[comp])
            spc_strg += str(idx + 2) + ", "
        strg += [spc_strg + "\n"]

        tmp_dir = TemporaryDirectory()
        self.input_file = pth.join(tmp_dir.name, _TMP_INPUT_FILE_NAME)
        if self.options[OPTION_MYSTRAN_EXE_PATH]:
            # if a path for MYSTRAN has been provided, simply use it
            self.options["command"] = [self.options[OPTION_MYSTRAN_EXE_PATH], self.input_file]
        else:
            # otherwise, copy the embedded resource in tmp dir
            copy_resource(mystran112, MYSTRAN_EXE_NAME, tmp_dir.name)
            self.options["command"] = [pth.join(tmp_dir.name, MYSTRAN_EXE_NAME), self.input_file]

        # Input BDF file generation ---------------------------------------------------------------
        get_nastran_bdf(self.input_file, strg, sol="static", nz=nz)
        self.sderr = pth.join(tmp_dir.name, _STDERR_FILE_NAME)
        self.stdout = pth.join(tmp_dir.name, _STDOUT_FILE_NAME)
        # Run MYSTRAN -----------------------------------------------------------------------------
        result_file = pth.join(tmp_dir.name, _TMP_OUTPUT_FILE_NAME)
        # self.options["external_input_files"] = [input_file]
        # self.options["external_output_files"] = [result_file]

        super().compute(inputs, outputs)

        # Post-processing -------------------------------------------------------------------------
        displacements, stresses = readf06(result_file)
        # split displacements and stresses matrices for each component
        split_displacements = self._get_component_matrix(
            displacements, components, nsects, type="grid"
        )
        split_stresses = self._get_component_matrix(stresses, components, nsects, type="element")
        for i, comp in enumerate(components):
            outputs[
                "data:aerostructural:structure:" + comp + ":displacements"
            ] = split_displacements[i]
            outputs["data:aerostructural:structure:" + comp + ":stresses"] = split_stresses[i]

        # Getting output files if needed ----------------------------------------------------------
        if self.options[OPTION_RESULT_FOLDER_PATH]:
            if pth.exists(result_file):
                f06_file_path = pth.join(result_folder_path, _TMP_OUTPUT_FILE_NAME)
                shutil.move(result_file, f06_file_path)

            if pth.exists(self.input_file):
                bdf_file_path = pth.join(result_folder_path, _TMP_INPUT_FILE_NAME)
                shutil.move(self.input_file, bdf_file_path)

        tmp_dir.cleanup()
Ejemplo n.º 8
0
    def compute(self, inputs, outputs):

        # Create result folder first (if it must fail, let it fail as soon as possible)
        result_folder_path = self.options[OPTION_RESULT_FOLDER_PATH]
        if result_folder_path != "":
            os.makedirs(result_folder_path, exist_ok=True)

        # Get inputs and initialise outputs
        thickness_ratio = inputs["data:geometry:wing:thickness_ratio"]
        length = inputs["xfoil:length"]
        mach = inputs["xfoil:mach"]
        reynolds = inputs["xfoil:unit_reynolds"]*length

        # Pre-processing (populating temp directory) -----------------------------------------------
        # XFoil exe
        tmp_directory = self._create_tmp_directory()
        if self.options[OPTION_XFOIL_EXE_PATH]:
            # if a path for Xfoil has been provided, simply use it
            self.options["command"] = [self.options[OPTION_XFOIL_EXE_PATH]]
        else:
            # otherwise, copy the embedded resource in tmp dir
            # noinspection PyTypeChecker
            copy_resource(xfoil699, XFOIL_EXE_NAME, tmp_directory.name)
            self.options["command"] = [pth.join(tmp_directory.name, XFOIL_EXE_NAME)]

        # I/O files
        self.stdin = pth.join(tmp_directory.name, _INPUT_FILE_NAME)
        self.stdout = pth.join(tmp_directory.name, _STDOUT_FILE_NAME)
        self.stderr = pth.join(tmp_directory.name, _STDERR_FILE_NAME)

        # profile file
        tmp_profile_file_path = pth.join(tmp_directory.name, _TMP_PROFILE_FILE_NAME)
        profile = get_profile(
            file_name=self.options["wing_airfoil_file"],
            thickness_ratio=thickness_ratio,
        ).get_sides()
        # noinspection PyTypeChecker
        np.savetxt(
            tmp_profile_file_path,
            profile.to_numpy(),
            fmt="%.15f",
            delimiter=" ",
            header="Wing",
            comments="",
        )

        # standard input file
        tmp_result_file_path = pth.join(tmp_directory.name, _TMP_RESULT_FILE_NAME)
        parser = InputFileGenerator()
        with path(local_resources, _INPUT_FILE_NAME) as input_template_path:
            parser.set_template_file(str(input_template_path))
            parser.set_generated_file(self.stdin)
            parser.mark_anchor("RE")
            parser.transfer_var(float(reynolds), 1, 1)
            parser.mark_anchor("M")
            parser.transfer_var(float(mach), 1, 1)
            parser.mark_anchor("ITER")
            parser.transfer_var(self.options[OPTION_ITER_LIMIT], 1, 1)
            parser.mark_anchor("ASEQ")
            parser.transfer_var(self.options[OPTION_ALPHA_START], 1, 1)
            parser.transfer_var(self.options[OPTION_ALPHA_END], 2, 1)
            parser.reset_anchor()
            parser.mark_anchor("/profile")
            parser.transfer_var(tmp_profile_file_path, 0, 1)
            parser.mark_anchor("/polar_result")
            parser.transfer_var(tmp_result_file_path, 0, 1)
            parser.generate()

        # Run XFOIL --------------------------------------------------------------------------------
        self.options["external_input_files"] = [self.stdin, tmp_profile_file_path]
        self.options["external_output_files"] = [tmp_result_file_path]
        super().compute(inputs, outputs)

        # Post-processing --------------------------------------------------------------------------
        result_array = self._read_polar(tmp_result_file_path)
        cl_max_2d = self._get_max_cl(result_array["alpha"], result_array["CL"])
        real_length = min(POLAR_POINT_COUNT, len(result_array["alpha"]))
        if real_length < len(result_array["alpha"]):
            warnings.warn("Defined maximum polar point count in constants.py exceeded!")
            outputs["xfoil:alpha"] = np.linspace(result_array["alpha"][0], result_array["alpha"][-1], POLAR_POINT_COUNT)
            outputs["xfoil:CL"] = np.interp(outputs["xfoil:alpha"], result_array["alpha"], result_array["CL"])
            outputs["xfoil:CD"] = np.interp(outputs["xfoil:alpha"], result_array["alpha"], result_array["CD"])
            outputs["xfoil:CDp"] = np.interp(outputs["xfoil:alpha"], result_array["alpha"], result_array["CDp"])
            outputs["xfoil:CDp"] = np.interp(outputs["xfoil:alpha"], result_array["alpha"], result_array["CM"])
        else:
            outputs["xfoil:alpha"] = np.zeros(POLAR_POINT_COUNT)
            outputs["xfoil:CL"] = np.zeros(POLAR_POINT_COUNT)
            outputs["xfoil:CD"] = np.zeros(POLAR_POINT_COUNT)
            outputs["xfoil:CDp"] = np.zeros(POLAR_POINT_COUNT)
            outputs["xfoil:CM"] = np.zeros(POLAR_POINT_COUNT)
            outputs["xfoil:alpha"][0:real_length] = result_array["alpha"]
            outputs["xfoil:CL"][0:real_length] = result_array["CL"]
            outputs["xfoil:CD"][0:real_length] = result_array["CD"]
            outputs["xfoil:CDp"][0:real_length] = result_array["CDp"]
            outputs["xfoil:CM"][0:real_length] = result_array["CM"]
        outputs["xfoil:CL_max_2D"] = cl_max_2d

        # Getting output files if needed
        if self.options[OPTION_RESULT_FOLDER_PATH] != "":
            if pth.exists(tmp_result_file_path):
                polar_file_path = pth.join(
                    result_folder_path, self.options[OPTION_RESULT_POLAR_FILENAME]
                )
                shutil.move(tmp_result_file_path, polar_file_path)

            if pth.exists(self.stdout):
                stdout_file_path = pth.join(result_folder_path, _STDOUT_FILE_NAME)
                shutil.move(self.stdout, stdout_file_path)

            if pth.exists(self.stderr):
                stderr_file_path = pth.join(result_folder_path, _STDERR_FILE_NAME)
                shutil.move(self.stderr, stderr_file_path)

        tmp_directory.cleanup()
    def compute(self, inputs, outputs):

        # Create result folder first (if it must fail, let it fail as soon as possible)
        result_folder_path = self.options[OPTION_RESULT_FOLDER_PATH]
        if result_folder_path != "":
            os.makedirs(pth.join(result_folder_path, 'ClAlphaWING'),
                        exist_ok=True)

        # Get inputs (and calculate missing ones)
        x0_wing = inputs["data:geometry:wing:MAC:leading_edge:x:local"]
        l0_wing = inputs["data:geometry:wing:MAC:length"]
        width_max = inputs["data:geometry:fuselage:maximum_width"]
        y1_wing = width_max / 2.0
        y2_wing = inputs["data:geometry:wing:root:y"]
        l2_wing = inputs["data:geometry:wing:root:chord"]
        y4_wing = inputs["data:geometry:wing:tip:y"]
        l4_wing = inputs["data:geometry:wing:tip:chord"]
        sweep_0_wing = inputs["data:geometry:wing:sweep_0"]
        fa_length = inputs["data:geometry:wing:MAC:at25percent:x"]
        sref_wing = inputs['data:geometry:wing:area']
        span_wing = inputs['data:geometry:wing:span']
        height_max = inputs["data:geometry:fuselage:maximum_height"]
        if self.options["low_speed_aero"]:
            altitude = 0.0
            atm = Atmosphere(altitude)
            mach = inputs["data:aerodynamics:low_speed:mach"]
        else:
            altitude = inputs["data:mission:sizing:main_route:cruise:altitude"]
            atm = Atmosphere(altitude)
            mach = inputs["data:aerodynamics:cruise:mach"]

        # Initial parameters calculation
        x_wing = fa_length - x0_wing - 0.25 * l0_wing
        z_wing = -(height_max - 0.12 * l2_wing) * 0.5
        span2_wing = y4_wing - y2_wing
        viscosity = atm.kinematic_viscosity
        rho = atm.density
        v_inf = max(atm.speed_of_sound * mach, 0.01)  # avoid V=0 m/s crashes
        reynolds = v_inf * l0_wing / viscosity

        # OPENVSP-SCRIPT: Geometry generation ######################################################

        # I/O files --------------------------------------------------------------------------------
        tmp_directory = self._create_tmp_directory()
        # avoid to dump void xternal_code_comp_error.out error file
        self.stderr = pth.join(tmp_directory.name, _STDERR_FILE_NAME)
        if self.options[OPTION_OPENVSP_EXE_PATH]:
            target_directory = pth.abspath(
                self.options[OPTION_OPENVSP_EXE_PATH])
        else:
            target_directory = tmp_directory.name
        input_file_list = [
            pth.join(target_directory, _INPUT_SCRIPT_FILE_NAME),
            pth.join(target_directory, self.options['wing_airfoil_file'])
        ]
        tmp_result_file_path = pth.join(target_directory,
                                        _INPUT_AERO_FILE_NAME + '0.csv')
        output_file_list = [tmp_result_file_path]
        self.options["external_input_files"] = input_file_list
        self.options["external_output_files"] = output_file_list

        # Pre-processing (populating temp directory and generate batch file) -----------------------
        # Copy resource in temp directory if needed
        if not (self.options[OPTION_OPENVSP_EXE_PATH]):
            # noinspection PyTypeChecker
            copy_resource_folder(openvsp3201, target_directory)
            # noinspection PyTypeChecker
            copy_resource(resources, self.options['wing_airfoil_file'],
                          target_directory)
        # Create corresponding .bat file
        self.options["command"] = [pth.join(target_directory, 'vspscript.bat')]
        command = pth.join(target_directory, VSPSCRIPT_EXE_NAME) + ' -script ' \
                  + pth.join(target_directory, _INPUT_SCRIPT_FILE_NAME) + ' >nul 2>nul\n'
        batch_file = open(self.options["command"][0], "w+")
        batch_file.write("@echo off\n")
        batch_file.write(command)
        batch_file.close()

        # standard SCRIPT input file ---------------------------------------------------------------
        parser = InputFileGenerator()
        with path(local_resources,
                  _INPUT_SCRIPT_FILE_NAME) as input_template_path:
            parser.set_template_file(str(input_template_path))
            parser.set_generated_file(input_file_list[0])
            parser.mark_anchor("x_wing")
            parser.transfer_var(float(x_wing), 0, 5)
            parser.mark_anchor("z_wing")
            parser.transfer_var(float(z_wing), 0, 5)
            parser.mark_anchor("y1_wing")
            parser.transfer_var(float(y1_wing), 0, 5)
            for i in range(3):
                parser.mark_anchor("l2_wing")
                parser.transfer_var(float(l2_wing), 0, 5)
            parser.reset_anchor()
            parser.mark_anchor("span2_wing")
            parser.transfer_var(float(span2_wing), 0, 5)
            parser.mark_anchor("l4_wing")
            parser.transfer_var(float(l4_wing), 0, 5)
            parser.mark_anchor("sweep_0_wing")
            parser.transfer_var(float(sweep_0_wing), 0, 5)
            parser.mark_anchor("airfoil_0_file")
            parser.transfer_var(self._rewrite_path(input_file_list[1]), 0, 3)
            parser.mark_anchor("airfoil_1_file")
            parser.transfer_var(self._rewrite_path(input_file_list[1]), 0, 3)
            parser.mark_anchor("airfoil_2_file")
            parser.transfer_var(self._rewrite_path(input_file_list[1]), 0, 3)
            parser.mark_anchor("csv_file")
            parser.transfer_var(self._rewrite_path(tmp_result_file_path), 0, 3)
            parser.generate()

        # Run SCRIPT --------------------------------------------------------------------------------
        super().compute(inputs, outputs)

        # Getting input/output files if needed
        if self.options[OPTION_RESULT_FOLDER_PATH] != "":
            for file_path in input_file_list:
                new_path = pth.join(result_folder_path, 'ClAlphaWING',
                                    pth.split(file_path)[1])
                if pth.exists(file_path):
                    shutil.copyfile(file_path, new_path)
            for file_path in output_file_list:
                new_path = pth.join(result_folder_path, 'ClAlphaWING',
                                    pth.split(file_path)[1])
                if pth.exists(file_path):
                    shutil.copyfile(file_path, new_path)

        # OPENVSP-AERO: aero calculation ############################################################

        # I/O files --------------------------------------------------------------------------------
        # Duplicate .csv file for multiple run
        input_file_list = [tmp_result_file_path]
        for idx in range(len(_INPUT_AOAList) - 1):
            shutil.copy(
                tmp_result_file_path,
                pth.join(target_directory,
                         _INPUT_AERO_FILE_NAME + str(idx + 1) + '.csv'))
            input_file_list.append(
                pth.join(target_directory,
                         _INPUT_AERO_FILE_NAME + str(idx + 1) + '.csv'))
        output_file_list = []
        for idx in range(len(_INPUT_AOAList)):
            input_file_list.append(
                pth.join(target_directory, _INPUT_AERO_FILE_NAME) + str(idx) +
                '.vspaero')
            output_file_list.append(
                pth.join(target_directory, _INPUT_AERO_FILE_NAME) + str(idx) +
                '.polar')
        output_file_list.append(
            pth.join(target_directory, _INPUT_AERO_FILE_NAME) + '0.lod')
        self.options["external_input_files"] = input_file_list
        self.options["external_output_files"] = output_file_list

        # Pre-processing (create batch file) -------------------------------------------------------
        self.options["command"] = [pth.join(target_directory, 'vspaero.bat')]
        batch_file = open(self.options["command"][0], "w+")
        batch_file.write("@echo off\n")
        for idx in range(len(_INPUT_AOAList)):
            command = pth.join(target_directory, VSPAERO_EXE_NAME) + ' ' \
                      + pth.join(target_directory, _INPUT_AERO_FILE_NAME + str(idx) + ' >nul 2>nul\n')
            batch_file.write(command)
        batch_file.close()

        # standard AERO input file -----------------------------------------------------------------
        parser = InputFileGenerator()
        for idx in range(len(_INPUT_AOAList)):
            with path(local_resources, _INPUT_AERO_FILE_NAME +
                      '.vspaero') as input_template_path:
                parser.set_template_file(str(input_template_path))
                parser.set_generated_file(input_file_list[len(_INPUT_AOAList) +
                                                          idx])
                parser.reset_anchor()
                parser.mark_anchor("Sref")
                parser.transfer_var(float(sref_wing), 0, 3)
                parser.mark_anchor("Cref")
                parser.transfer_var(float(l0_wing), 0, 3)
                parser.mark_anchor("Bref")
                parser.transfer_var(float(span_wing), 0, 3)
                parser.mark_anchor("X_cg")
                parser.transfer_var(float(fa_length), 0, 3)
                parser.mark_anchor("Mach")
                parser.transfer_var(float(mach), 0, 3)
                parser.mark_anchor("AOA")
                parser.transfer_var(float(_INPUT_AOAList[idx]), 0, 3)
                parser.mark_anchor("Vinf")
                parser.transfer_var(float(v_inf), 0, 3)
                parser.mark_anchor("Rho")
                parser.transfer_var(float(rho), 0, 3)
                parser.mark_anchor("ReCref")
                parser.transfer_var(float(reynolds), 0, 3)
                parser.generate()

        # Run AERO --------------------------------------------------------------------------------
        super().compute(inputs, outputs)

        # Post-processing --------------------------------------------------------------------------
        result_cl = []
        for idx in range(len(_INPUT_AOAList)):
            cl, _, _, _ = self._read_polar_file(output_file_list[idx])
            result_cl.append(cl)
        # Fuselage correction
        k_fus = 1 + 0.025 * width_max / span_wing - 0.025 * (width_max /
                                                             span_wing)**2
        cl_0 = float(result_cl[0] * k_fus)
        cl_1 = float(result_cl[1] * k_fus)
        # Calculate derivative
        cl_alpha = (cl_1 - cl_0) / (
            (_INPUT_AOAList[1] - _INPUT_AOAList[0]) * math.pi / 180)
        # Get lift curve
        y_vector, cl_vector = self._read_lod_file(output_file_list[-1])
        real_length = min(SPAN_MESH_POINT_OPENVSP, len(y_vector))
        if real_length < len(y_vector):
            warnings.warn(
                "Defined maximum span mesh in constants.py exceeded!")

        if self.options["low_speed_aero"]:
            outputs['data:aerodynamics:aircraft:low_speed:CL0_clean'] = cl_0
            outputs['data:aerodynamics:aircraft:low_speed:CL_alpha'] = cl_alpha
            if real_length >= len(y_vector):
                outputs[
                    'data:aerodynamics:wing:low_speed:Y_vector'] = np.zeros(
                        SPAN_MESH_POINT_OPENVSP)
                outputs[
                    'data:aerodynamics:wing:low_speed:CL_vector'] = np.zeros(
                        SPAN_MESH_POINT_OPENVSP)
                outputs['data:aerodynamics:wing:low_speed:Y_vector'][
                    0:real_length] = y_vector
                outputs['data:aerodynamics:wing:low_speed:CL_vector'][
                    0:real_length] = cl_vector
            else:
                outputs[
                    'data:aerodynamics:aircraft:wing:Y_vector'] = np.linspace(
                        y_vector[0], y_vector[1], SPAN_MESH_POINT_OPENVSP)
                outputs['data:aerodynamics:aircraft:wing:CL_vector'] = \
                    np.interp(outputs['data:aerodynamics:aircraft:low_speed:Y_vector'], y_vector, cl_vector)
        else:
            outputs['data:aerodynamics:aircraft:cruise:CL0_clean'] = cl_0
            outputs['data:aerodynamics:aircraft:cruise:CL_alpha'] = cl_alpha

        # Getting input/output files if needed
        if self.options[OPTION_RESULT_FOLDER_PATH] != "":
            for file_path in input_file_list:
                new_path = pth.join(result_folder_path, 'ClAlphaWING',
                                    pth.split(file_path)[1])
                if pth.exists(file_path):
                    shutil.copyfile(file_path, new_path)
            for file_path in output_file_list:
                new_path = pth.join(result_folder_path, 'ClAlphaWING',
                                    pth.split(file_path)[1])
                if pth.exists(file_path):
                    shutil.copyfile(file_path, new_path)

        # Delete temporary directory
        tmp_directory.cleanup()