示例#1
0
def create_routine_folder():
    """Create the working dicrectory of the routine.

    Create a folder in which all CEASIOMpy runs and routine parameters will be
    saved. This architecture may change in the future. For now the architecture
    of the folder is as such :

    > CEASIOMpy_Run_XX-XX-XX
        -> Optim
            --> Geometry
            --> Runs
                ---> Run_XX-XX-XX
        -> Optim2
            |
        -> OptimX
        -> DoE

    Args:
        None.

    """

    global optim_dir_path, Rt

    # Create the main working directory
    tixi = cpsf.open_tixi(opf.CPACS_OPTIM_PATH)
    wkdir = ceaf.get_wkdir_or_create_new(tixi)
    optim_dir_path = os.path.join(wkdir, Rt.type)
    Rt.date = wkdir[-19:]

    # Save the path to the directory in the CPACS
    if tixi.checkElement(opf.OPTWKDIR_XPATH):
        tixi.removeElement(opf.OPTWKDIR_XPATH)
    cpsf.create_branch(tixi, opf.OPTWKDIR_XPATH)
    tixi.updateTextElement(opf.OPTWKDIR_XPATH, optim_dir_path)

    # Add subdirectories
    if not os.path.isdir(optim_dir_path):
        os.mkdir(optim_dir_path)
        os.mkdir(optim_dir_path + '/Geometry')
        os.mkdir(optim_dir_path + '/Runs')
    else:
        index = 2
        optim_dir_path = optim_dir_path + str(index)
        while os.path.isdir(optim_dir_path):
            index += 1
            optim_dir_path = optim_dir_path.split(
                Rt.type)[0] + Rt.type + str(index)
        os.mkdir(optim_dir_path)
        os.mkdir(optim_dir_path + '/Geometry')
        os.mkdir(optim_dir_path + '/Runs')
    tixi.updateTextElement(opf.OPTWKDIR_XPATH, optim_dir_path)
    tixi.updateTextElement(opf.WKDIR_XPATH, optim_dir_path)

    cpsf.close_tixi(tixi, opf.CPACS_OPTIM_PATH)
示例#2
0
def routine_setup(modules, routine_type, modules_pre=[]):
    """
    Set up optimisation.

    Retrieve the list of modules to use in the optimization
    loop and launches the optimization process.

    """
    log.info('----- Start of Optimisation module -----')
    global Rt, design_var_dict, res_var_dict, optim_dir_path

    # Setup parameters of the routine
    Rt.type = routine_type
    Rt.modules = modules
    Rt.driver = 'COBYLA'
    Rt.objective = 'cl/cd'
    # Rt.design_vars =
    Rt.constraints = ['cms']
    Rt.date = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
    Rt.doetype = 'uniform'
    Rt.samplesnb = 3

    cpacs_path = mi.get_toolinput_file_path('Optimisation')

    # Create Optim folder for results
    tixi = cpsf.open_tixi(cpacs_path)
    wkdir = ceaf.get_wkdir_or_create_new(tixi)
    optim_dir_path = os.path.join(wkdir, Rt.type)
    if not os.path.isdir(optim_dir_path):
        os.mkdir(optim_dir_path)
        os.mkdir(optim_dir_path + '/Geometry')

    # Initiates dictionnaries
    res_var_dict, design_var_dict = init_dict(cpacs_path, modules, modules_pre)

    # Copy to CPACSUpdater to pass to next modules
    wkf.copy_module_to_module('Optimisation', 'in', 'CPACSUpdater', 'in')

    # Display routine info
    log.info('------ Problem description ------')
    log.info('Routine type : {}'.format(routine_type))
    log.info('Objective function : {}'.format(Rt.objective))
    [
        log.info('Design variables : {}'.format(k))
        for k in design_var_dict.keys()
    ]
    [log.info('constraints : {}'.format(k)) for k in res_var_dict.keys()]

    run_routine()

    log.info('----- End of Optimisation module -----')
示例#3
0
    def get_user_inputs(self):
        """Take user inputs from the GUI."""
        cpacs_path = mif.get_toolinput_file_path('SMTrain')
        tixi = cpsf.open_tixi(cpacs_path)

        # Search working directory
        self.wkdir = cpsf.get_value_or_default(tixi, OPTWKDIR_XPATH, '')
        if self.wkdir == '':
            self.wkdir = ceaf.get_wkdir_or_create_new(tixi) + '/SM'
        if not os.path.isdir(self.wkdir):
            os.mkdir(self.wkdir)

        self.type = cpsf.get_value_or_default(tixi,
                                              SMTRAIN_XPATH + 'modelType',
                                              'KRG')

        obj = cpsf.get_value_or_default(tixi, SMTRAIN_XPATH + 'objective',
                                        'cl')
        self.objectives = re.split(';|,', obj)
        self.user_file = cpsf.get_value_or_default(tixi,
                                                   SMTRAIN_XPATH + 'trainFile',
                                                   '')
        if self.user_file == '':
            path = cpsf.get_value_or_default(tixi, OPTWKDIR_XPATH, '')
            if path != '':
                self.user_file = path + '/Variable_history.csv'
        self.data_repartition = cpsf.get_value_or_default(
            tixi, SMTRAIN_XPATH + 'trainingPercentage', 0.9)
        self.show_plots = cpsf.get_value_or_default(
            tixi, SMTRAIN_XPATH + 'showPlots', False)

        self.aeromap_case = cpsf.get_value_or_default(
            tixi, SMTRAIN_XPATH + 'useAeromap', False)
        self.aeromap_uid = cpsf.get_value_or_default(
            tixi, SMTRAIN_XPATH + 'aeroMapUID', '')

        cpsf.close_tixi(tixi, cpacs_path)
示例#4
0
def create_routine_folder():
    """Create the working dicrectory of the routine.

    Create a folder in which all CEASIOMpy runs and routine parameters will be
    saved. This architecture may change in the future.

    Args:
        None.

    Returns:
        None.

    """
    global optim_dir_path, Rt

    # Create the main working directory
    tixi = cpsf.open_tixi(opf.CPACS_OPTIM_PATH)
    if tixi.checkElement(opf.WKDIR_XPATH):
        tixi.removeElement(opf.WKDIR_XPATH)
    wkdir = ceaf.get_wkdir_or_create_new(tixi)
    optim_dir_path = os.path.join(wkdir, Rt.type)
    Rt.date = wkdir[-19:]

    # Save the path to the directory in the CPACS
    if tixi.checkElement(opf.OPTWKDIR_XPATH):
        tixi.removeElement(opf.OPTWKDIR_XPATH)
    cpsf.create_branch(tixi, opf.OPTWKDIR_XPATH)
    tixi.updateTextElement(opf.OPTWKDIR_XPATH, optim_dir_path)

    # Add subdirectories
    if not os.path.isdir(optim_dir_path):
        os.mkdir(optim_dir_path)
    os.mkdir(optim_dir_path + '/Geometry')
    os.mkdir(optim_dir_path + '/Runs')

    cpsf.close_tixi(tixi, opf.CPACS_OPTIM_PATH)
示例#5
0
        # Opt.cpacs_path = '../../test/CPACSfiles/simpletest_cpacs.xml'
        Opt.module_pre = []
        Opt.module_optim = ['WeightConventional', 'PyTornado']

        Opt.optim_method = 'DoE'  # DoE, Optim, None
        Opt.module_post = []

    # Copy ToolInput.xml in ToolInput dir if not already there
    cpacs_path = mi.get_toolinput_file_path(MODULE_NAME)
    if not Opt.cpacs_path == cpacs_path:
        shutil.copy(Opt.cpacs_path, cpacs_path)
        Opt.cpacs_path = cpacs_path

    # Create a new wkdir
    tixi = cpsf.open_tixi(Opt.cpacs_path)
    wkdir = ceaf.get_wkdir_or_create_new(tixi)
    cpsf.close_tixi(tixi, Opt.cpacs_path)

    # Run Pre-otimisation workflow
    if Opt.module_pre:
        wkf.run_subworkflow(Opt.module_pre, Opt.cpacs_path)

        if not Opt.module_optim and not Opt.module_post:
            shutil.copy(mi.get_tooloutput_file_path(Opt.module_pre[-1]),
                        cpacs_path_out)

    # Run Optimisation workflow
    if Opt.module_optim:
        if Opt.module_pre:
            wkf.copy_module_to_module(Opt.module_pre[-1], 'out',
                                      'Optimisation', 'in')
示例#6
0
def create_SU2_mesh(cpacs_path, cpacs_out_path):
    """ Function to create a simple SU2 mesh form an SUMO file (.smx)

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

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

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

    """

    tixi = cpsf.open_tixi(cpacs_path)

    wkdir = ceaf.get_wkdir_or_create_new(tixi)
    sumo_dir = os.path.join(wkdir, 'SUMO')
    if not os.path.isdir(sumo_dir):
        os.mkdir(sumo_dir)
    su2_mesh_path = os.path.join(sumo_dir, 'ToolOutput.su2')

    meshdir = os.path.join(wkdir, 'MESH')
    if not os.path.isdir(meshdir):
        os.mkdir(meshdir)

    original_dir = os.getcwd()
    os.chdir(sumo_dir)

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

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

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

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

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

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

        # Check if SUMO is installed
        soft_dict = ceaf.get_install_path(['sumo'])

        # Run SUMO in batch
        output = '-output=su2'
        options = '-tetgen-options=pq1.16VY'  # See Tetgen help for more options, maybe transform that as an input
        # Command line to run: sumo -batch -output=su2 -tetgen-options=pq1.16VY ToolOutput.smx
        command = [
            soft_dict['sumo'], '-batch', output, options, sumo_file_path
        ]
        os.system(' '.join(command))

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

        log.warning('OS not supported yet by SUMOAutoMesh!')
        raise OSError('OS not supported yet!')

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

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

    if os.path.isfile(su2_mesh_new_path):
        log.info('An SU2 Mesh has been correctly generated.')
        su2_mesh_xpath = '/cpacs/toolspecific/CEASIOMpy/filesPath/su2Mesh'
        cpsf.create_branch(tixi, su2_mesh_xpath)
        tixi.updateTextElement(su2_mesh_xpath, su2_mesh_new_path)
        os.remove(su2_mesh_path)

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

    cpsf.close_tixi(tixi, cpacs_out_path)
    os.chdir(original_dir)
示例#7
0
def main():

    log.info("Running PyTornado...")

    # ===== CPACS inout and output paths =====
    MODULE_DIR = os.path.dirname(os.path.abspath(__file__))
    cpacs_in_path = mi.get_toolinput_file_path(MODULE_NAME)
    cpacs_out_path = mi.get_tooloutput_file_path(MODULE_NAME)

    # ===== Delete old working directories =====
    settings_from_CPACS = get_pytornado_settings_from_CPACS(cpacs_in_path)
    if settings_from_CPACS is not None:
        if settings_from_CPACS.get('deleteOldWKDIRs', False):
            wkdirs = glob(os.path.join(DIR_MODULE, 'wkdir_*'))
            for wkdir in wkdirs:
                shutil.rmtree(wkdir, ignore_errors=True)

    # ===== Paths =====
    dir_pyt_wkdir = os.path.join(DIR_MODULE, 'wkdir_temp')

    dir_pyt_aircraft = os.path.join(dir_pyt_wkdir, 'aircraft')
    dir_pyt_settings = os.path.join(dir_pyt_wkdir, 'settings')
    dir_pyt_results = os.path.join(dir_pyt_wkdir, '_results')
    file_pyt_aircraft = os.path.join(dir_pyt_aircraft, 'ToolInput.xml')
    file_pyt_settings = os.path.join(dir_pyt_settings, 'cpacs_run.json')

    # ===== Make directories =====
    Path(dir_pyt_wkdir).mkdir(parents=True, exist_ok=True)
    Path(dir_pyt_aircraft).mkdir(parents=True, exist_ok=True)
    Path(dir_pyt_settings).mkdir(parents=True, exist_ok=True)
    Path(dir_pyt_results).mkdir(parents=True, exist_ok=True)

    # ===== Setup =====
    shutil.copy(src=cpacs_in_path, dst=file_pyt_aircraft)
    mi.check_cpacs_input_requirements(cpacs_in_path)

    # ===== Get PyTornado settings =====
    cpacs_settings = get_pytornado_settings(cpacs_in_path)
    with open(file_pyt_settings, "w") as fp:
        dump_pretty_json(cpacs_settings, fp)

    # ===== PyTornado analysis =====
    pytornado = import_pytornado('pytornado.stdfun.run')
    #pytornado.standard_run(args=pytornado.StdRunArgs(run=file_pyt_settings, verbose=True))
    results = pytornado.standard_run(
        args=pytornado.StdRunArgs(run=file_pyt_settings, verbose=True))

    # ===== Extract load =====
    tixi = cpsf.open_tixi(cpacs_in_path)
    extract_loads_xpath = '/cpacs/toolspecific/pytornado/save_results/extractLoads'
    extract_loads = cpsf.get_value_or_default(tixi, extract_loads_xpath, False)

    if extract_loads:
        _get_load_fields(results, dir_pyt_results)

    # ===== Clean up =====
    shutil.copy(src=file_pyt_aircraft, dst=cpacs_out_path)

    wkdir = ceaf.get_wkdir_or_create_new(tixi)
    dst_pyt_wkdir = os.path.join(
        wkdir, 'CFD', 'PyTornado',
        f"wkdir_{datetime.strftime(datetime.now(), '%F_%H%M%S')}")
    shutil.copytree(src=dir_pyt_wkdir, dst=dst_pyt_wkdir)
    shutil.rmtree(dir_pyt_wkdir, ignore_errors=True)

    log.info("PyTornado analysis completed")
示例#8
0
def generate_config_deformed_mesh(cpacs_path,
                                  cpacs_out_path,
                                  skip_config=False,
                                  skip_su2=False):
    """Function to generate all deform meshes with SU2 from CPACS data

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

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

    """

    tixi = cpsf.open_tixi(cpacs_path)
    wkdir = ceaf.get_wkdir_or_create_new(tixi)

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

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

    if not skip_config:

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

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

            ted_df = get_ted_list(tixi)

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

            for i, row in ted_df.iterrows():

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

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

    if not skip_su2:

        run_mesh_deformation(tixi, wkdir)

    cpsf.close_tixi(tixi, cpacs_out_path)
def run_workflow(Otp):
    """ Run the complete Worflow

    Args:
        Opt (class): Cl
        cpacs_out_path (str): Path to the output CPACS file
        module_list (list): List of module to inclue in the GUI

    """

    # Copy ToolInput.xml in ToolInput dir if not already there
    cpacs_path = mi.get_toolinput_file_path(MODULE_NAME)
    if not os.path.abspath(Opt.cpacs_path) == os.path.abspath(cpacs_path):
        shutil.copy(Opt.cpacs_path, cpacs_path)
        Opt.cpacs_path = os.path.abspath(cpacs_path)

    # Create a new wkdir
    tixi = cpsf.open_tixi(Opt.cpacs_path)
    wkdir = ceaf.get_wkdir_or_create_new(tixi)
    cpsf.close_tixi(tixi, Opt.cpacs_path)

    # Run Pre-otimisation workflow
    if Opt.module_pre:
        wkf.run_subworkflow(Opt.module_pre, Opt.cpacs_path)

        if not Opt.module_optim and not Opt.module_post:
            shutil.copy(mi.get_tooloutput_file_path(Opt.module_pre[-1]),
                        cpacs_path_out)

    # Run Optimisation workflow
    if Opt.module_optim:
        if Opt.module_pre:
            wkf.copy_module_to_module(Opt.module_pre[-1], 'out',
                                      'Optimisation', 'in')
        else:
            wkf.copy_module_to_module('WorkflowCreator', 'in', 'Optimisation',
                                      'in')

        if Opt.optim_method != 'None':
            routine_launcher(Opt)
        else:
            log.warning('No optimization method has been selected!')
            log.warning('The modules will be run as a simple workflow')
            wkf.run_subworkflow(Opt.module_optim)

        if not Opt.module_post:
            shutil.copy(mi.get_tooloutput_file_path(Opt.module_optim[-1]),
                        cpacs_path_out)

    # Run Post-optimisation workflow
    if Opt.module_post:

        if Opt.module_optim:
            wkf.copy_module_to_module(Opt.module_optim[-1], 'out',
                                      Opt.module_post[0], 'in')
        elif Opt.module_pre:
            wkf.copy_module_to_module(Opt.module_pre[-1], 'out',
                                      Opt.module_post[0], 'in')
        else:
            wkf.copy_module_to_module('WorkflowCreator', 'in',
                                      Opt.module_post[0], 'in')

        # wkf.copy_module_to_module('CPACSUpdater','out',Opt.module_post[0],'in')  usefuel?
        wkf.run_subworkflow(Opt.module_post)
        shutil.copy(mi.get_tooloutput_file_path(Opt.module_post[-1]),
                    cpacs_path_out)
示例#10
0
def convert_cpacs_to_sumo(cpacs_path, cpacs_out_path):
    """ Function to convert a CPACS file geometry into a SUMO file geometry.

    Function 'convert_cpacs_to_sumo' open an input cpacs file with TIXI handle
    and via two main loop, one for fuselage(s), one for wing(s) it convert
    every element (as much as possible) in the SUMO (.smx) format, which is
    also an xml file. Due to some differences between both format, some CPACS
    definition could lead to issues. The output sumo file is saved in the
    folder /ToolOutput

    Source:
        * CPACS documentation: https://www.cpacs.de/pages/documentation.html

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

    Returns:
        sumo_output_path (str): Path to the SUMO file

    """

    EMPTY_SMX = MODULE_DIR + '/files/sumo_empty.smx'

    tixi = cpsf.open_tixi(cpacs_path)
    sumo = cpsf.open_tixi(EMPTY_SMX)

    # Fuslage(s) -----
    FUSELAGES_XPATH = '/cpacs/vehicles/aircraft/model/fuselages'

    if tixi.checkElement(FUSELAGES_XPATH):
        fus_cnt = tixi.getNamedChildrenCount(FUSELAGES_XPATH, 'fuselage')
        log.info(str(fus_cnt) + ' fuselage has been found.')
    else:
        fus_cnt = 0
        log.warning('No fuselage has been found in this CPACS file!')

    for i_fus in range(fus_cnt):
        fus_xpath = FUSELAGES_XPATH + '/fuselage[' + str(i_fus + 1) + ']'
        fus_uid = tixi.getTextAttribute(fus_xpath, 'uID')
        fus_transf = Transformation()
        fus_transf.get_cpacs_transf(tixi, fus_xpath + '/transformation')

        # Create new body (SUMO)
        sumo.createElementAtIndex('/Assembly', 'BodySkeleton', i_fus + 1)
        body_xpath = '/Assembly/BodySkeleton[' + str(i_fus + 1) + ']'

        sumo.addTextAttribute(body_xpath, 'akimatg', 'false')
        sumo.addTextAttribute(body_xpath, 'name', fus_uid)

        body_tansf = Transformation()
        body_tansf.translation = fus_transf.translation

        # Convert angles
        body_tansf.rotation = euler2fix(fus_transf.rotation)

        # Add body rotation
        body_rot_str = str(math.radians(body_tansf.rotation.x)) + ' '   \
                       + str(math.radians(body_tansf.rotation.y)) + ' ' \
                       + str(math.radians(body_tansf.rotation.z))
        sumo.addTextAttribute(body_xpath, 'rotation', body_rot_str)

        # Add body origin
        body_ori_str = str(body_tansf.translation.x) + ' ' \
                       + str(body_tansf.translation.y) + ' ' \
                       + str(body_tansf.translation.z)
        sumo.addTextAttribute(body_xpath, 'origin', body_ori_str)

        # Positionings
        if tixi.checkElement(fus_xpath + '/positionings'):
            pos_cnt = tixi.getNamedChildrenCount(fus_xpath + '/positionings',
                                                 'positioning')

            log.info(str(fus_cnt) + ' "Positionning" has been found : ')

            pos_x_list = []
            pos_y_list = []
            pos_z_list = []
            from_sec_list = []
            to_sec_list = []

            for i_pos in range(pos_cnt):
                pos_xpath = fus_xpath + '/positionings/positioning[' \
                           + str(i_pos+1) + ']'

                length = tixi.getDoubleElement(pos_xpath + '/length')
                sweep_deg = tixi.getDoubleElement(pos_xpath + '/sweepAngle')
                sweep = math.radians(sweep_deg)
                dihedral_deg = tixi.getDoubleElement(pos_xpath +
                                                     '/dihedralAngle')
                dihedral = math.radians(dihedral_deg)

                # Get the corresponding translation of each positionning
                pos_x_list.append(length * math.sin(sweep))
                pos_y_list.append(length * math.cos(dihedral) *
                                  math.cos(sweep))
                pos_z_list.append(length * math.sin(dihedral) *
                                  math.cos(sweep))

                # Get which section are connected by the positionning
                if tixi.checkElement(pos_xpath + '/fromSectionUID'):
                    from_sec = tixi.getTextElement(pos_xpath +
                                                   '/fromSectionUID')
                else:
                    from_sec = ''
                from_sec_list.append(from_sec)

                if tixi.checkElement(pos_xpath + '/toSectionUID'):
                    to_sec = tixi.getTextElement(pos_xpath + '/toSectionUID')
                else:
                    to_sec = ''
                to_sec_list.append(to_sec)

            # Re-loop though the positionning to re-order them
            for j_pos in range(pos_cnt):
                if from_sec_list[j_pos] == '':
                    prev_pos_x = 0
                    prev_pos_y = 0
                    prev_pos_z = 0

                elif from_sec_list[j_pos] == to_sec_list[j_pos - 1]:
                    prev_pos_x = pos_x_list[j_pos - 1]
                    prev_pos_y = pos_y_list[j_pos - 1]
                    prev_pos_z = pos_z_list[j_pos - 1]

                else:
                    index_prev = to_sec_list.index(from_sec_list[j_pos])
                    prev_pos_x = pos_x_list[index_prev]
                    prev_pos_y = pos_y_list[index_prev]
                    prev_pos_z = pos_z_list[index_prev]

                pos_x_list[j_pos] += prev_pos_x
                pos_y_list[j_pos] += prev_pos_y
                pos_z_list[j_pos] += prev_pos_z

        else:
            log.warning('No "positionings" have been found!')
            pos_cnt = 0

        #Sections
        sec_cnt = tixi.getNamedChildrenCount(fus_xpath + '/sections',
                                             'section')
        log.info("    -" + str(sec_cnt) + ' fuselage sections have been found')

        if pos_cnt == 0:
            pos_x_list = [0.0] * sec_cnt
            pos_y_list = [0.0] * sec_cnt
            pos_z_list = [0.0] * sec_cnt

        for i_sec in range(sec_cnt):
            sec_xpath = fus_xpath + '/sections/section[' + str(i_sec + 1) + ']'
            sec_uid = tixi.getTextAttribute(sec_xpath, 'uID')

            sec_transf = Transformation()
            sec_transf.get_cpacs_transf(tixi, sec_xpath + '/transformation')

            if (sec_transf.rotation.x or sec_transf.rotation.y
                    or sec_transf.rotation.z):

                log.warning('Sections "' + sec_uid + '" is rotated, it is \
                            not possible to take that into acount in SUMO !')

            # Elements
            elem_cnt = tixi.getNamedChildrenCount(sec_xpath + '/elements',
                                                  'element')

            if elem_cnt > 1:
                log.warning("Sections " + sec_uid + "  contains multiple \
                             element, it could be an issue for the conversion \
                             to SUMO!")

            for i_elem in range(elem_cnt):
                elem_xpath = sec_xpath + '/elements/element[' \
                            + str(i_elem + 1) + ']'
                elem_uid = tixi.getTextAttribute(elem_xpath, 'uID')

                elem_transf = Transformation()
                elem_transf.get_cpacs_transf(tixi,
                                             elem_xpath + '/transformation')

                if (elem_transf.rotation.x or elem_transf.rotation.y
                        or elem_transf.rotation.z):
                    log.warning('Element "' + elem_uid + '" is rotated, it \
                                 is not possible to take that into acount in \
                                 SUMO !')

                # Fuselage profiles
                prof_uid = tixi.getTextElement(elem_xpath + '/profileUID')
                prof_xpath = tixi.uIDGetXPath(prof_uid)

                prof_vect_x_str = tixi.getTextElement(prof_xpath +
                                                      '/pointList/x')
                prof_vect_y_str = tixi.getTextElement(prof_xpath +
                                                      '/pointList/y')
                prof_vect_z_str = tixi.getTextElement(prof_xpath +
                                                      '/pointList/z')

                # Transform sting into list of float
                prof_vect_x = []
                for i, item in enumerate(prof_vect_x_str.split(';')):
                    if item:
                        prof_vect_x.append(float(item))
                prof_vect_y = []
                for i, item in enumerate(prof_vect_y_str.split(';')):
                    if item:
                        prof_vect_y.append(float(item))
                prof_vect_z = []
                for i, item in enumerate(prof_vect_z_str.split(';')):
                    if item:
                        prof_vect_z.append(float(item))

                prof_size_y = (max(prof_vect_y) - min(prof_vect_y)) / 2
                prof_size_z = (max(prof_vect_z) - min(prof_vect_z)) / 2

                prof_vect_y[:] = [y / prof_size_y for y in prof_vect_y]
                prof_vect_z[:] = [z / prof_size_z for z in prof_vect_z]

                prof_min_y = min(prof_vect_y)
                prof_max_y = max(prof_vect_y)
                prof_min_z = min(prof_vect_z)
                prof_max_z = max(prof_vect_z)

                prof_vect_y[:] = [y - 1 - prof_min_y for y in prof_vect_y]
                prof_vect_z[:] = [z - 1 - prof_min_z for z in prof_vect_z]

                # Could be a problem if they are less positionings than secions
                # TODO: solve that!
                pos_y_list[i_sec] += (
                    (1 + prof_min_y) * prof_size_y) * elem_transf.scale.y
                pos_z_list[i_sec] += (
                    (1 + prof_min_z) * prof_size_z) * elem_transf.scale.z

                # #To Plot a particular section
                # if i_sec==5:
                #     plt.plot(prof_vect_z, prof_vect_y,'x')
                #     plt.xlabel('y')
                #     plt.ylabel('z')
                #     plt.grid(True)
                #     plt.show

                # Put value in SUMO format
                body_frm_center_x = ( elem_transf.translation.x \
                                        + sec_transf.translation.x \
                                        + pos_x_list[i_sec]) \
                                        * fus_transf.scale.x
                body_frm_center_y = ( elem_transf.translation.y \
                                        * sec_transf.scale.y \
                                        + sec_transf.translation.y \
                                        + pos_y_list[i_sec]) \
                                        * fus_transf.scale.y
                body_frm_center_z = ( elem_transf.translation.z \
                                        * sec_transf.scale.z \
                                        + sec_transf.translation.z \
                                        + pos_z_list[i_sec]) \
                                        * fus_transf.scale.z


                body_frm_height = prof_size_z * 2 * elem_transf.scale.z \
                                  * sec_transf.scale.z * fus_transf.scale.z
                if body_frm_height < 0.01:
                    body_frm_height = 0.01
                body_frm_width = prof_size_y * 2 * elem_transf.scale.y \
                                 * sec_transf.scale.y * fus_transf.scale.y
                if body_frm_width < 0.01:
                    body_frm_width = 0.01

                # Convert the profile points in the SMX format
                prof_str = ''
                teta_list = []
                teta_half = []
                prof_vect_y_half = []
                prof_vect_z_half = []
                check_max = 0
                check_min = 0

                # Use polar angle to keep point in the correct order
                for i, item in enumerate(prof_vect_y):
                    teta_list.append(math.atan2(prof_vect_z[i],
                                                prof_vect_y[i]))

                for t, teta in enumerate(teta_list):
                    HALF_PI = math.pi / 2
                    EPSILON = 0.04

                    if abs(teta) <= HALF_PI - EPSILON:
                        teta_half.append(teta)
                        prof_vect_y_half.append(prof_vect_y[t])
                        prof_vect_z_half.append(prof_vect_z[t])
                    elif abs(teta) < HALF_PI + EPSILON:
                        # Check if not the last element of the list
                        if not t == len(teta_list) - 1:
                            next_val = prof_vect_z[t + 1]
                            # Check if it is better to keep next point
                            if not abs(next_val) > abs(prof_vect_z[t]):
                                if prof_vect_z[t] > 0 and not check_max:
                                    teta_half.append(teta)
                                    # Force y=0, to get symmetrical profile
                                    prof_vect_y_half.append(0)
                                    prof_vect_z_half.append(prof_vect_z[t])
                                    check_max = 1
                                elif prof_vect_z[t] < 0 and not check_min:
                                    teta_half.append(teta)
                                    # Force y=0, to get symmetrical profile
                                    prof_vect_y_half.append(0)
                                    prof_vect_z_half.append(prof_vect_z[t])
                                    check_min = 1

                # Sort points by teta value, to fit the SUMO profile format
                teta_half, prof_vect_z_half, prof_vect_y_half = \
                      (list(t) for t in zip(*sorted(zip(teta_half,
                                                        prof_vect_z_half,
                                                        prof_vect_y_half))))

                # Write profile as a string and add y=0 point at the begining
                # and at the end to ensure symmmetry
                if not check_min:
                    prof_str += str(0) + ' ' + str(prof_vect_z_half[0]) + ' '
                for i, item in enumerate(prof_vect_z_half):
                    prof_str += str(round(prof_vect_y_half[i], 4)) + ' ' \
                                + str(round(prof_vect_z_half[i], 4)) + ' '
                if not check_max:
                    prof_str += str(0) + ' ' + str(prof_vect_z_half[i]) + ' '

                # Write the SUMO file
                sumo.addTextElementAtIndex(body_xpath, 'BodyFrame', prof_str,
                                           i_sec + 1)
                frame_xpath = body_xpath + '/BodyFrame[' + str(i_sec + 1) + ']'

                body_center_str = str(body_frm_center_x) + ' ' + \
                                  str(body_frm_center_y) + ' ' + \
                                  str(body_frm_center_z)

                sumo.addTextAttribute(frame_xpath, 'center', body_center_str)
                sumo.addTextAttribute(frame_xpath, 'height',
                                      str(body_frm_height))
                sumo.addTextAttribute(frame_xpath, 'width',
                                      str(body_frm_width))
                sumo.addTextAttribute(frame_xpath, 'name', sec_uid)

    # To remove the default BodySkeleton
    if fus_cnt == 0:
        sumo.removeElement('/Assembly/BodySkeleton')
    else:
        sumo.removeElement('/Assembly/BodySkeleton[' + str(fus_cnt + 1) + ']')

    # Wing(s) -----
    WINGS_XPATH = '/cpacs/vehicles/aircraft/model/wings'

    if tixi.checkElement(WINGS_XPATH):
        wing_cnt = tixi.getNamedChildrenCount(WINGS_XPATH, 'wing')
        log.info(str(wing_cnt) + ' wings has been found.')
    else:
        wing_cnt = 0
        log.warning('No wings has been found in this CPACS file!')

    for i_wing in range(wing_cnt):
        wing_xpath = WINGS_XPATH + '/wing[' + str(i_wing + 1) + ']'
        wing_uid = tixi.getTextAttribute(wing_xpath, 'uID')
        wing_transf = Transformation()
        wing_transf.get_cpacs_transf(tixi, wing_xpath + '/transformation')

        # Create new wing (SUMO)
        sumo.createElementAtIndex('/Assembly', 'WingSkeleton', i_wing + 1)
        wg_sk_xpath = '/Assembly/WingSkeleton[' + str(i_wing + 1) + ']'

        sumo.addTextAttribute(wg_sk_xpath, 'akimatg', 'false')
        sumo.addTextAttribute(wg_sk_xpath, 'name', wing_uid)

        # Create a class for the transformation of the WingSkeleton
        wg_sk_tansf = Transformation()

        # Convert WingSkeleton rotation and add it to SUMO
        wg_sk_tansf.rotation = euler2fix(wing_transf.rotation)
        wg_sk_rot_str = str(math.radians(wg_sk_tansf.rotation.x)) + ' '   \
                        + str(math.radians(wg_sk_tansf.rotation.y)) + ' ' \
                        + str(math.radians(wg_sk_tansf.rotation.z))
        sumo.addTextAttribute(wg_sk_xpath, 'rotation', wg_sk_rot_str)

        # Add WingSkeleton origin
        wg_sk_tansf.translation = wing_transf.translation
        wg_sk_ori_str = str(wg_sk_tansf.translation.x) + ' ' \
                        + str(wg_sk_tansf.translation.y) + ' ' \
                        + str(wg_sk_tansf.translation.z)
        sumo.addTextAttribute(wg_sk_xpath, 'origin', wg_sk_ori_str)

        if tixi.checkAttribute(wing_xpath, 'symmetry'):
            if tixi.getTextAttribute(wing_xpath, 'symmetry') == 'x-z-plane':
                sumo.addTextAttribute(wg_sk_xpath, 'flags',
                                      'autosym,detectwinglet')
            else:
                sumo.addTextAttribute(wg_sk_xpath, 'flags', 'detectwinglet')

        # Positionings
        if tixi.checkElement(wing_xpath + '/positionings'):
            pos_cnt = tixi.getNamedChildrenCount(wing_xpath + '/positionings',
                                                 'positioning')
            log.info(str(wing_cnt) + ' "positionning" has been found : ')

            pos_x_list = []
            pos_y_list = []
            pos_z_list = []
            from_sec_list = []
            to_sec_list = []

            for i_pos in range(pos_cnt):
                pos_xpath = wing_xpath + '/positionings/positioning[' \
                           + str(i_pos+1) + ']'

                length = tixi.getDoubleElement(pos_xpath + '/length')
                sweep_deg = tixi.getDoubleElement(pos_xpath + '/sweepAngle')
                sweep = math.radians(sweep_deg)
                dihedral_deg = tixi.getDoubleElement(pos_xpath +
                                                     '/dihedralAngle')
                dihedral = math.radians(dihedral_deg)

                # Get the corresponding translation of each positionning
                pos_x_list.append(length * math.sin(sweep))
                pos_y_list.append(length * math.cos(dihedral) *
                                  math.cos(sweep))
                pos_z_list.append(length * math.sin(dihedral) *
                                  math.cos(sweep))

                # Get which section are connected by the positionning
                if tixi.checkElement(pos_xpath + '/fromSectionUID'):
                    from_sec = tixi.getTextElement(pos_xpath +
                                                   '/fromSectionUID')
                else:
                    from_sec = ''
                from_sec_list.append(from_sec)

                if tixi.checkElement(pos_xpath + '/toSectionUID'):
                    to_sec = tixi.getTextElement(pos_xpath + '/toSectionUID')
                else:
                    to_sec = ''
                to_sec_list.append(to_sec)

            # Re-loop though the positionning to re-order them
            for j_pos in range(pos_cnt):
                if from_sec_list[j_pos] == '':
                    prev_pos_x = 0
                    prev_pos_y = 0
                    prev_pos_z = 0
                elif from_sec_list[j_pos] == to_sec_list[j_pos - 1]:
                    prev_pos_x = pos_x_list[j_pos - 1]
                    prev_pos_y = pos_y_list[j_pos - 1]
                    prev_pos_z = pos_z_list[j_pos - 1]
                else:
                    index_prev = to_sec_list.index(from_sec_list[j_pos])
                    prev_pos_x = pos_x_list[index_prev]
                    prev_pos_y = pos_y_list[index_prev]
                    prev_pos_z = pos_z_list[index_prev]

                pos_x_list[j_pos] += prev_pos_x
                pos_y_list[j_pos] += prev_pos_y
                pos_z_list[j_pos] += prev_pos_z

        else:
            log.warning('No "positionings" have been found!')
            pos_cnt = 0

        #Sections
        sec_cnt = tixi.getNamedChildrenCount(wing_xpath + '/sections',
                                             'section')
        log.info("    -" + str(sec_cnt) + ' wing sections have been found')
        wing_sec_index = 1

        if pos_cnt == 0:
            pos_x_list = [0.0] * sec_cnt
            pos_y_list = [0.0] * sec_cnt
            pos_z_list = [0.0] * sec_cnt

        for i_sec in reversed(range(sec_cnt)):
            sec_xpath = wing_xpath + '/sections/section[' + str(i_sec +
                                                                1) + ']'
            sec_uid = tixi.getTextAttribute(sec_xpath, 'uID')
            sec_transf = Transformation()
            sec_transf.get_cpacs_transf(tixi, sec_xpath + '/transformation')

            # Elements
            elem_cnt = tixi.getNamedChildrenCount(sec_xpath + '/elements',
                                                  'element')

            if elem_cnt > 1:
                log.warning("Sections " + sec_uid + "  contains multiple \
                             element, it could be an issue for the conversion \
                             to SUMO!")

            for i_elem in range(elem_cnt):
                elem_xpath = sec_xpath + '/elements/element[' \
                            + str(i_elem + 1) + ']'
                elem_uid = tixi.getTextAttribute(elem_xpath, 'uID')
                elem_transf = Transformation()
                elem_transf.get_cpacs_transf(tixi,
                                             elem_xpath + '/transformation')

                # Wing profile (airfoil)
                prof_uid = tixi.getTextElement(elem_xpath + '/airfoilUID')
                prof_xpath = tixi.uIDGetXPath(prof_uid)

                try:
                    tixi.checkElement(prof_xpath)
                except:
                    log.error('No profile "' + prof_uid + '" has been found!')

                prof_vect_x_str = tixi.getTextElement(prof_xpath +
                                                      '/pointList/x')
                prof_vect_y_str = tixi.getTextElement(prof_xpath +
                                                      '/pointList/y')
                prof_vect_z_str = tixi.getTextElement(prof_xpath +
                                                      '/pointList/z')

                # Transform airfoil points (string) into list of float
                prof_vect_x = []
                for i, item in enumerate(prof_vect_x_str.split(';')):
                    if item:
                        prof_vect_x.append(float(item))
                prof_vect_y = []
                for i, item in enumerate(prof_vect_y_str.split(';')):
                    if item:
                        prof_vect_y.append(float(item))
                prof_vect_z = []
                for i, item in enumerate(prof_vect_z_str.split(';')):
                    if item:
                        prof_vect_z.append(float(item))

                if sum(prof_vect_z[0:len(prof_vect_z)//2]) \
                   < sum(prof_vect_z[len(prof_vect_z)//2:-1]):
                    log.info("Airfoil's points will be reversed.")

                    tmp_vect_x = []
                    tmp_vect_y = []
                    tmp_vect_z = []

                    for i in range(len(prof_vect_x)):
                        tmp_vect_x.append(prof_vect_x[len(prof_vect_x) - 1 -
                                                      i])
                        tmp_vect_y.append(prof_vect_y[len(prof_vect_y) - 1 -
                                                      i])
                        tmp_vect_z.append(prof_vect_z[len(prof_vect_z) - 1 -
                                                      i])

                    prof_vect_x = tmp_vect_x
                    prof_vect_y = tmp_vect_y
                    prof_vect_z = tmp_vect_z

                # Apply scaling
                for i, item in enumerate(prof_vect_x):
                    prof_vect_x[i] = item * elem_transf.scale.x \
                                     * sec_transf.scale.x * wing_transf.scale.x
                for i, item in enumerate(prof_vect_y):
                    prof_vect_y[i] = item * elem_transf.scale.y \
                                     * sec_transf.scale.y * wing_transf.scale.y
                for i, item in enumerate(prof_vect_z):
                    prof_vect_z[i] = item * elem_transf.scale.z \
                                     * sec_transf.scale.z * wing_transf.scale.z

                # if (i_sec>8 and i_sec<=10):
                #     plt.plot(prof_vect_x, prof_vect_z,'x')
                #     plt.xlabel('x')
                #     plt.ylabel('z')
                #     plt.grid(True)
                #     plt.show()

                prof_size_x = (max(prof_vect_x) - min(prof_vect_x))
                prof_size_y = (max(prof_vect_y) - min(prof_vect_y))
                prof_size_z = (max(prof_vect_z) - min(prof_vect_z))

                if prof_size_y == 0:
                    prof_vect_x[:] = [x / prof_size_x for x in prof_vect_x]
                    prof_vect_z[:] = [z / prof_size_x for z in prof_vect_z]
                    # Is it correct to divide by prof_size_x ????

                    wg_sec_chord = prof_size_x
                else:
                    log.error("An airfoil profile is not define correctly")

                # SUMO variable for WingSection
                wg_sec_center_x = ( elem_transf.translation.x \
                                  + sec_transf.translation.x \
                                  + pos_x_list[i_sec]) \
                                  * wing_transf.scale.x
                wg_sec_center_y = ( elem_transf.translation.y \
                                  * sec_transf.scale.y \
                                  + sec_transf.translation.y \
                                  + pos_y_list[i_sec]) \
                                  * wing_transf.scale.y
                wg_sec_center_z = ( elem_transf.translation.z \
                                  * sec_transf.scale.z \
                                  + sec_transf.translation.z \
                                  + pos_z_list[i_sec]) \
                                  * wing_transf.scale.z

                # Add roation from element and sections
                # Adding the two angles: Maybe not work in every case!!!
                add_rotation = SimpleNamespace()
                add_rotation.x = elem_transf.rotation.x + sec_transf.rotation.x
                add_rotation.y = elem_transf.rotation.y + sec_transf.rotation.y
                add_rotation.z = elem_transf.rotation.z + sec_transf.rotation.z

                # Get Section rotation for SUMO
                wg_sec_rot = euler2fix(add_rotation)
                wg_sec_dihed = math.radians(wg_sec_rot.x)
                wg_sec_twist = math.radians(wg_sec_rot.y)
                wg_sec_yaw = math.radians(wg_sec_rot.z)

                # Convert point list into string
                prof_str = ''

                # Airfoil points order : shoud be from TE (1 0) to LE (0 0)
                # then TE(1 0), but not reverse way.

                # to avoid double zero, not accepted by SUMO
                for i, item in (enumerate(prof_vect_x)):
                    # if not (prof_vect_x[i] == prof_vect_x[i-1] or \
                    #         round(prof_vect_z[i],4) == round(prof_vect_z[i-1],4)):
                    if round(prof_vect_z[i], 4) != round(
                            prof_vect_z[i - 1], 4):
                        prof_str += str(round(prof_vect_x[i], 4)) + ' ' \
                                    + str(round(prof_vect_z[i], 4)) + ' '

                sumo.addTextElementAtIndex(wg_sk_xpath, 'WingSection',
                                           prof_str, wing_sec_index)
                wg_sec_xpath = wg_sk_xpath + '/WingSection[' \
                              + str(wing_sec_index) + ']'
                sumo.addTextAttribute(wg_sec_xpath, 'airfoil', prof_uid)
                sumo.addTextAttribute(wg_sec_xpath, 'name', sec_uid)
                wg_sec_center_str = str(wg_sec_center_x) + ' ' + \
                                    str(wg_sec_center_y) + ' ' + \
                                    str(wg_sec_center_z)
                sumo.addTextAttribute(wg_sec_xpath, 'center',
                                      wg_sec_center_str)
                sumo.addTextAttribute(wg_sec_xpath, 'chord', str(wg_sec_chord))
                sumo.addTextAttribute(wg_sec_xpath, 'dihedral',
                                      str(wg_sec_dihed))
                sumo.addTextAttribute(wg_sec_xpath, 'twist', str(wg_sec_twist))
                sumo.addTextAttribute(wg_sec_xpath, 'yaw', str(wg_sec_yaw))
                sumo.addTextAttribute(wg_sec_xpath, 'napprox', '-1')
                sumo.addTextAttribute(wg_sec_xpath, 'reversed', 'false')
                sumo.addTextAttribute(wg_sec_xpath, 'vbreak', 'false')

                wing_sec_index += 1

        # Add Wing caps
        sumo.createElementAtIndex(wg_sk_xpath, "Cap", 1)
        sumo.addTextAttribute(wg_sk_xpath + '/Cap[1]', 'height', '0')
        sumo.addTextAttribute(wg_sk_xpath + '/Cap[1]', 'shape', 'LongCap')
        sumo.addTextAttribute(wg_sk_xpath + '/Cap[1]', 'side', 'south')

        sumo.createElementAtIndex(wg_sk_xpath, 'Cap', 2)
        sumo.addTextAttribute(wg_sk_xpath + '/Cap[2]', 'height', '0')
        sumo.addTextAttribute(wg_sk_xpath + '/Cap[2]', 'shape', 'LongCap')
        sumo.addTextAttribute(wg_sk_xpath + '/Cap[2]', 'side', 'north')

    # Save the SMX file

    wkdir = ceaf.get_wkdir_or_create_new(tixi)

    sumo_file_xpath = '/cpacs/toolspecific/CEASIOMpy/filesPath/sumoFilePath'
    sumo_dir = os.path.join(wkdir, 'SUMO')
    sumo_file_path = os.path.join(sumo_dir, 'ToolOutput.smx')
    if not os.path.isdir(sumo_dir):
        os.mkdir(sumo_dir)
    cpsf.create_branch(tixi, sumo_file_xpath)
    tixi.updateTextElement(sumo_file_xpath, sumo_file_path)

    cpsf.close_tixi(tixi, cpacs_out_path)
    cpsf.close_tixi(sumo, sumo_file_path)
示例#11
0
def create_SU2_mesh(cpacs_path, cpacs_out_path):
    """ Function to create a simple SU2 mesh form an SUMO file (.smx)

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

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

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

    """

    tixi = cpsf.open_tixi(cpacs_path)

    wkdir = ceaf.get_wkdir_or_create_new(tixi)
    sumo_dir = os.path.join(wkdir, 'SUMO')
    if not os.path.isdir(sumo_dir):
        os.mkdir(sumo_dir)

    mesh_dir = os.path.join(wkdir, 'MESH')
    if not os.path.isdir(mesh_dir):
        os.mkdir(mesh_dir)

    original_dir = os.getcwd()
    os.chdir(sumo_dir)

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

    # Check if SUMO is installed
    soft_dict = ceaf.get_install_path(['sumo'])

    # Run SUMO to create a create a mesh
    # sumo - batch -output=su2 -tetgen-options=pq1.16VY mesh.smx
    sumo_output = '-output=su2'  # For now, must be SU2
    tetgen_options = '-tetgen-options=pq1.16VY'  # See Tetgen help for more options, maybe transform that as an input
    command_line = [
        soft_dict['sumo'], '-batch', sumo_output, tetgen_options,
        sumo_file_path
    ]

    # print(' '.join(command_line))
    os.system(' '.join(command_line))

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

    if os.path.isfile(su2_mesh_new_path):
        log.info('An SU2 Mesh has been correctly generated.')
        su2_mesh_xpath = '/cpacs/toolspecific/CEASIOMpy/filesPath/su2Mesh'
        cpsf.create_branch(tixi, su2_mesh_xpath)
        tixi.updateTextElement(su2_mesh_xpath, su2_mesh_new_path)

        os.remove(su2_mesh_path)

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

    cpsf.close_tixi(tixi, cpacs_out_path)

    os.chdir(original_dir)
示例#12
0
def create_SU2_mesh(cpacs_path, cpacs_out_path):
    """ Function to create a simple SU2 mesh form an SUMO file (.smx)

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

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

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

    """

    tixi = cpsf.open_tixi(cpacs_path)

    wkdir = ceaf.get_wkdir_or_create_new(tixi)
    sumo_dir = os.path.join(wkdir, 'SUMO')
    if not os.path.isdir(sumo_dir):
        os.mkdir(sumo_dir)

    mesh_dir = os.path.join(wkdir, 'MESH')
    if not os.path.isdir(mesh_dir):
        os.mkdir(mesh_dir)

    original_dir = os.getcwd()
    os.chdir(sumo_dir)

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

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

    if current_os == 'Darwin':
        log.info('Your OS is Mac')
        # TODO: chck install path
        log.info('On Mac the mesh has to be generated manually.')
        log.info('You can find your geometry there:')
        log.info(sumo_file_path)
        # For now, I did find a way to run sumo -batch on Mac...
        # The command just open SUMO GUI
        command_line = ['open', '/Applications/SUMO/dwfsumo.app/']
        os.system(' '.join(command_line))

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

        # Check if SUMO is installed
        soft_dict = ceaf.get_install_path(['sumo'])

        # Run SUMO to create a create a mesh
        # sumo -batch -output=su2 -tetgen-options=pq1.16VY mesh.smx
        sumo_output = '-output=su2'
        tetgen_options = '-tetgen-options=pq1.16VY'  # See Tetgen help for more options, maybe transform that as an input
        command_line = [
            soft_dict['sumo'], '-batch', sumo_output, tetgen_options,
            sumo_file_path
        ]
        os.system(' '.join(command_line))

    elif current_os == 'Windwos':
        log.info('Your OS is Windows')
        log.warning('OS not supported yet by SUMOAutoMesh!')
        # TODO

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

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

    if os.path.isfile(su2_mesh_new_path):
        log.info('An SU2 Mesh has been correctly generated.')
        su2_mesh_xpath = '/cpacs/toolspecific/CEASIOMpy/filesPath/su2Mesh'
        cpsf.create_branch(tixi, su2_mesh_xpath)
        tixi.updateTextElement(su2_mesh_xpath, su2_mesh_new_path)

        os.remove(su2_mesh_path)

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

    cpsf.close_tixi(tixi, cpacs_out_path)

    os.chdir(original_dir)