Esempio n. 1
0
    def test_templated_input_2Darrays(self):
        template = '\n'.join([
            "Anchor",
            "0 0 0 0 0",
            "0 0 0 0 0"
        ])

        outfile = open(self.templatename, 'w')
        outfile.write(template)
        outfile.close()

        gen = InputFileGenerator()
        gen.set_template_file(self.templatename)
        gen.set_generated_file(self.filename)

        gen.mark_anchor('Anchor')
        var = array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
        gen.transfer_2Darray(var, 1, 2, 1, 5)

        gen.generate()

        infile = open(self.filename, 'r')
        result = infile.read()
        infile.close()

        answer = '\n'.join([
            "Anchor",
            "1 2 3 4 5",
            "6 7 8 9 10"
        ])

        self.assertEqual(answer, result)
Esempio n. 2
0
    def test_templated_input_same_anchors(self):
        template = '\n'.join(
            ["CQUAD4 1 3.456", "CQUAD4 2 4.123", "CQUAD4 3 7.222", "CQUAD4 4"])

        outfile = open(self.templatename, 'w')
        outfile.write(template)
        outfile.close()

        gen = InputFileGenerator()
        gen.set_template_file(self.templatename)
        gen.set_generated_file(self.filename)
        gen.set_delimiters(', ')

        gen.mark_anchor('CQUAD4')
        gen.transfer_var('x', 0, 2)
        gen.mark_anchor('CQUAD4')
        gen.transfer_var('y', 0, 3)
        gen.mark_anchor('CQUAD4', 2)
        gen.transfer_var('z', 0, 2)

        gen.generate()

        infile = open(self.filename, 'r')
        result = infile.read()
        infile.close()

        answer = '\n'.join(
            ["CQUAD4 x 3.456", "CQUAD4 2 y", "CQUAD4 3 7.222", "CQUAD4 z"])

        self.assertEqual(answer, result)
Esempio n. 3
0
    def test_templated_input_arrays(self):
        template = '\n'.join([
            "Anchor",
            "0 0 0 0 0"
        ])

        outfile = open(self.templatename, 'w')
        outfile.write(template)
        outfile.close()

        gen = InputFileGenerator()
        gen.set_template_file(self.templatename)
        gen.set_generated_file(self.filename)

        gen.mark_anchor('Anchor')
        gen.transfer_array(array([1, 2, 3, 4.75, 5.0]), 1, 3, 5, sep=' ')

        gen.generate()

        infile = open(self.filename, 'r')
        result = infile.read()
        infile.close()

        answer = '\n'.join([
            "Anchor",
            "0 0 1.0 2.0 3.0 4.75 5.0"
        ])

        self.assertEqual(answer, result)
Esempio n. 4
0
    def test_templated_input_2Darrays(self):
        template = '\n'.join([
            "Anchor",
            "0 0 0 0 0",
            "0 0 0 0 0"
        ])

        outfile = open(self.templatename, 'w')
        outfile.write(template)
        outfile.close()

        gen = InputFileGenerator()
        gen.set_template_file(self.templatename)
        gen.set_generated_file(self.filename)

        gen.mark_anchor('Anchor')
        var = array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
        gen.transfer_2Darray(var, 1, 2, 1, 5)

        gen.generate()

        infile = open(self.filename, 'r')
        result = infile.read()
        infile.close()

        answer = '\n'.join([
            "Anchor",
            "1 2 3 4 5",
            "6 7 8 9 10"
        ])

        self.assertEqual(answer, result)
Esempio n. 5
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,
        )

    if not pth.exists(pth.split(configuration_file_path)[0]):
        os.mkdir(pth.split(configuration_file_path)[0])
    parser = InputFileGenerator()
    root_folder = resources.__path__[0]
    for i in range(2):
        root_folder = pth.split(root_folder)[0]
    package_path = "[\"" + root_folder.replace('\\','\\\\') + "\"]"
    with path(resources, SAMPLE_FILENAME) as input_template_path:
        parser.set_template_file(str(input_template_path))
        # noinspection PyTypeChecker
        parser.set_generated_file(configuration_file_path)
        parser.reset_anchor()
        parser.mark_anchor("module_folders")
        parser.transfer_var(package_path, 0, 3)
        parser.generate()

    _LOGGER.info("Sample configuration written in %s", configuration_file_path)
Esempio n. 6
0
    def test_templated_input_arrays(self):
        template = '\n'.join([
            "Anchor",
            "0 0 0 0 0"
        ])

        outfile = open(self.templatename, 'w')
        outfile.write(template)
        outfile.close()

        gen = InputFileGenerator()
        gen.set_template_file(self.templatename)
        gen.set_generated_file(self.filename)

        gen.mark_anchor('Anchor')
        gen.transfer_array(array([1, 2, 3, 4.75, 5.0]), 1, 3, 5, sep=' ')

        gen.generate()

        infile = open(self.filename, 'r')
        result = infile.read()
        infile.close()

        answer = '\n'.join([
            "Anchor",
            "0 0 1.0 2.0 3.0 4.75 5.0"
        ])

        self.assertEqual(answer, result)
Esempio n. 7
0
    def compute(self, inputs, outputs):
        x = inputs['RadLen']
        var = '{0};'.format(float(x)) 

        # generate the input file for esatan thermal analysis
        generator = InputFileGenerator()
        generator.set_template_file('radiator_templ.txt')
        generator.set_generated_file('radiator.d')
        generator.mark_anchor("$CONSTANTS")
        generator.transfer_var(var, 4, 3)
        generator.generate()

        # the parent compute function actually runs the external code
        super(Radiator, self).compute(inputs, outputs)

        # parse the output file from the external code and set the value of T_max
        parser = FileParser()
        parser.set_file('radiator.out')
        parser.mark_anchor("+RADIATOR ")
        T_max = parser.transfer_var(5, 6)

        outputs['T_max'] = T_max
Esempio n. 8
0
 def _write_script_file(self, reynolds, mach, tmp_profile_file_path, tmp_result_file_path, alpha_start,
                        alpha_end, step):
     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(alpha_start, 1, 1)
         parser.transfer_var(alpha_end, 2, 1)
         parser.transfer_var(step, 3, 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()
Esempio n. 9
0
    def test_templated_input_same_anchors(self):
        template = '\n'.join([
            "CQUAD4 1 3.456",
            "CQUAD4 2 4.123",
            "CQUAD4 3 7.222",
            "CQUAD4 4"
        ])

        outfile = open(self.templatename, 'w')
        outfile.write(template)
        outfile.close()

        gen = InputFileGenerator()
        gen.set_template_file(self.templatename)
        gen.set_generated_file(self.filename)
        gen.set_delimiters(', ')

        gen.mark_anchor('CQUAD4')
        gen.transfer_var('x', 0, 2)
        gen.mark_anchor('CQUAD4')
        gen.transfer_var('y', 0, 3)
        gen.mark_anchor('CQUAD4', 2)
        gen.transfer_var('z', 0, 2)

        gen.generate()

        infile = open(self.filename, 'r')
        result = infile.read()
        infile.close()

        answer = '\n'.join([
            "CQUAD4 x 3.456",
            "CQUAD4 2 y",
            "CQUAD4 3 7.222",
            "CQUAD4 z"
        ])

        self.assertEqual(answer, result)
Esempio n. 10
0
    def test_templated_input(self):
        template = '\n'.join([
            "Junk",
            "Anchor",
            " A 1, 2 34, Test 1e65",
            " B 4 Stuff",
            "Anchor",
            " C 77 False Inf 333.444"
        ])

        outfile = open(self.templatename, 'w')
        outfile.write(template)
        outfile.close()

        gen = InputFileGenerator()
        gen.set_template_file(self.templatename)
        gen.set_generated_file(self.filename)
        gen.set_delimiters(', ')

        gen.mark_anchor('Anchor')
        gen.transfer_var('CC', 2, 0)
        gen.transfer_var(3.0, 1, 3)
        gen.reset_anchor()
        gen.mark_anchor('Anchor', 2)
        gen.transfer_var('NaN', 1, 4)
        gen.reset_anchor()
        gen.transfer_var('55', 3, 2)
        gen.mark_anchor('C 77')
        gen.transfer_var(1.3e-37, -3, 6)
        gen.clearline(-5)
        gen.mark_anchor('Anchor', -1)
        gen.transfer_var('8.7', 1, 5)

        gen.generate()

        infile = open(self.filename, 'r')
        result = infile.read()
        infile.close()

        answer = '\n'.join([
            "",
            "Anchor",
            " A 1, 3.0 34, Test 1.3e-37",
            " B 55 Stuff",
            "Anchor",
            " C 77 False NaN 8.7"
        ])

        self.assertEqual(answer, result)

        # Test some errors
        try:
            gen.mark_anchor('C 77', 3.14)
        except ValueError as err:
            msg = "The value for occurrence must be an integer"
            self.assertEqual(str(err), msg)
        else:
            self.fail('ValueError expected')

        try:
            gen.mark_anchor('C 77', 0)
        except ValueError as err:
            msg = "0 is not valid for an anchor occurrence."
            self.assertEqual(str(err), msg)
        else:
            self.fail('ValueError expected')

        try:
            gen.mark_anchor('ZZZ')
        except RuntimeError as err:
            msg = "Could not find pattern ZZZ in template file template.dat"
            self.assertEqual(str(err), msg)
        else:
            self.fail('RuntimeError expected')
    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()
Esempio n. 12
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()
Esempio n. 13
0
    def test_templated_input(self):
        template = '\n'.join([
            "Junk", "Anchor", " A 1, 2 34, Test 1e65", " B 4 Stuff", "Anchor",
            " C 77 False Inf 333.444"
        ])

        outfile = open(self.templatename, 'w')
        outfile.write(template)
        outfile.close()

        gen = InputFileGenerator()
        gen.set_template_file(self.templatename)
        gen.set_generated_file(self.filename)
        gen.set_delimiters(', ')

        gen.mark_anchor('Anchor')
        gen.transfer_var('CC', 2, 0)
        gen.transfer_var(3.0, 1, 3)
        gen.reset_anchor()
        gen.mark_anchor('Anchor', 2)
        gen.transfer_var('NaN', 1, 4)
        gen.reset_anchor()
        gen.transfer_var('55', 3, 2)
        gen.mark_anchor('C 77')
        gen.transfer_var(1.3e-37, -3, 6)
        gen.clearline(-5)
        gen.mark_anchor('Anchor', -1)
        gen.transfer_var('8.7', 1, 5)

        gen.generate()

        infile = open(self.filename, 'r')
        result = infile.read()
        infile.close()

        answer = '\n'.join([
            "", "Anchor", " A 1, 3.0 34, Test 1.3e-37", " B 55 Stuff",
            "Anchor", " C 77 False NaN 8.7"
        ])

        self.assertEqual(answer, result)

        # Test some errors
        try:
            gen.mark_anchor('C 77', 3.14)
        except ValueError as err:
            msg = "The value for occurrence must be an integer"
            self.assertEqual(str(err), msg)
        else:
            self.fail('ValueError expected')

        try:
            gen.mark_anchor('C 77', 0)
        except ValueError as err:
            msg = "0 is not valid for an anchor occurrence."
            self.assertEqual(str(err), msg)
        else:
            self.fail('ValueError expected')

        try:
            gen.mark_anchor('ZZZ')
        except RuntimeError as err:
            msg = "Could not find pattern ZZZ in template file template.dat"
            self.assertEqual(str(err), msg)
        else:
            self.fail('RuntimeError expected')
Esempio n. 14
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()
Esempio n. 15
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()
Esempio n. 16
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()
Esempio n. 17
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()
Esempio n. 18
0
    def compute(self, inputs, outputs):
        eff = inputs['eff']
        length = inputs['length']
        alp = inputs['alp']
        eps = inputs['eps']
        GL107_200 = 1 / inputs['R_m']
        GL111_300 = 1 / inputs['R_p']
        GL103_400 = inputs['GlTether']
        GL102_601 = 1 / inputs['R_s']
        GL107_111 = inputs['ci1']
        GL107_109 = inputs['ci2']
        GL103_109 = inputs['ci3']
        GL101_109 = inputs['ci4']
        GL109_111 = inputs['ci5']
        GL101_103 = inputs['ci6']
        GL103_111 = inputs['ci7']
        GL101_107 = inputs['ci8']
        GL103_105 = inputs['ci9']
        GL101_105 = inputs['ci10']
        GL105_111 = inputs['ci11']
        GL105_107 = inputs['ci12']
        r_bat = inputs['r_bat']
        ht_gain = inputs['ht_gain']
        q_s = inputs['q_s']

        eff = '{0};'.format(float(eff))
        length = '{0};'.format(float(length))
        ht_gain = '{0};'.format(float(ht_gain))
        r_bat = '{0};'.format(float(r_bat))
        q_s = '{0};'.format(float(q_s))
        alp = '{0},'.format(float(alp))
        eps = '{0},'.format(float(eps))
        GL107_200 = '{0};'.format(float(GL107_200))
        GL111_300 = '{0};'.format(float(GL111_300))
        GL103_400 = '{0};'.format(float(GL103_400))
        GL102_601 = '{0};'.format(float(GL102_601))
        GL107_111 = '{0};'.format(float(GL107_111))
        GL107_109 = '{0};'.format(float(GL107_109))
        GL103_109 = '{0};'.format(float(GL103_109))
        GL101_109 = '{0};'.format(float(GL101_109))
        GL109_111 = '{0};'.format(float(GL109_111))
        GL101_103 = '{0};'.format(float(GL101_103))
        GL103_111 = '{0};'.format(float(GL103_111))
        GL101_107 = '{0};'.format(float(GL101_107))
        GL103_105 = '{0};'.format(float(GL103_105))
        GL101_105 = '{0};'.format(float(GL101_105))
        GL105_111 = '{0};'.format(float(GL105_111))
        GL105_107 = '{0};'.format(float(GL105_107))

        # generate the input file for RU_tm thermal analysis
        generator = InputFileGenerator()
        generator.set_template_file('./esatan/RU_template.txt')
        generator.set_generated_file('./esatan/RU_tm.d')
        generator.mark_anchor("$LOCALS")
        generator.transfer_var(length, 21, 3)
        generator.transfer_var(eff, 23, 3)
        generator.transfer_var(r_bat, 25, 3)
        generator.transfer_var(ht_gain, 27, 3)
        generator.transfer_var(q_s, 29, 3)
        generator.mark_anchor("$NODES")
        generator.transfer_var(alp, 53, 6)
        generator.transfer_var(eps, 53, 9)
        generator.transfer_var(alp, 61, 6)
        generator.transfer_var(eps, 61, 9)
        generator.transfer_var(alp, 69, 6)
        generator.transfer_var(eps, 69, 9)
        generator.transfer_var(alp, 77, 6)
        generator.transfer_var(eps, 77, 9)
        generator.transfer_var(alp, 85, 6)
        generator.transfer_var(eps, 85, 9)
        generator.transfer_var(alp, 93, 6)
        generator.transfer_var(eps, 93, 9)
        generator.mark_anchor("Generated conductors")
        generator.transfer_var(GL107_200, 3, 3)
        generator.transfer_var(GL111_300, 4, 3)
        generator.transfer_var(GL107_111, 5, 3)
        generator.transfer_var(GL107_109, 6, 3)
        generator.transfer_var(GL103_109, 7, 3)
        generator.transfer_var(GL101_109, 8, 3)
        generator.transfer_var(GL109_111, 9, 3)
        generator.transfer_var(GL101_103, 10, 3)
        generator.transfer_var(GL103_111, 11, 3)
        generator.transfer_var(GL101_107, 12, 3)
        generator.transfer_var(GL103_105, 13, 3)
        generator.transfer_var(GL101_105, 14, 3)
        generator.transfer_var(GL105_111, 15, 3)
        generator.transfer_var(GL105_107, 16, 3)
        generator.transfer_var(GL102_601, 17, 3)
        generator.transfer_var(GL103_400, 45, 3)
        generator.generate()

        # the parent compute function actually runs the external code
        super(RUextCodeComp, self).compute(inputs, outputs)

        # parse the output file from the external code and set the value of T_max
        parser = FileParser()
        parser.set_file('./esatan/RU_TM.out')
        parser.mark_anchor("+RU_TM")
        tBat = parser.transfer_var(7, 3)
        tMain = parser.transfer_var(34, 3)
        tProp = parser.transfer_var(35, 3)
        tTether = parser.transfer_var(36, 3)
        tBPanel = parser.transfer_var(41, 3)
        tDPanel = parser.transfer_var(43, 3)

        outputs['tBat'] = tBat
        outputs['tMain'] = tMain
        outputs['tProp'] = tProp
        outputs['tTether'] = tTether
        outputs['tBPanel'] = tBPanel
        outputs['tDPanel'] = tDPanel