Beispiel #1
0
def run_SU2_fsi(config_path, wkdir):
    """Function to run a SU2 claculation for FSI .

    Function 'run_SU2_fsi' deforms an element of the mesh (e.g. wing) from
    point file 'disp.dat' given by a sctructural model and then runs a SU2
    calculation (SU2_CFD then SU2_SOL) with the given config_path. Finally a
    load file is saved, to be send to the sctructural model.

    Args:
        config_path (str): Path to the configuration file
        wkdir (str): Path to the working directory

    """

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

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

    # Modify config file for SU2_DEF
    config_def_path = os.path.join(wkdir, 'ConfigDEF.cfg')
    cfg_def = su2f.read_config(config_path)

    cfg_def['DV_KIND'] = 'SURFACE_FILE'
    cfg_def['DV_MARKER'] = 'Wing'
    cfg_def[
        'DV_FILENAME'] = 'disp.dat'  # TODO: Should be a constant or find in CPACS ?
    # TODO: Do we need that? if yes, find 'WING' in CPACS
    cfg_def['DV_PARAM'] = ['WING', '0', '0', '1', '0.0', '0.0', '1.0']
    cfg_def['DV_VALUE'] = 0.01
    su2f.write_config(config_def_path, cfg_def)

    # Modify config file for SU2_CFD
    config_cfd_path = os.path.join(wkdir, 'ConfigCFD.cfg')
    cfg_cfd = su2f.read_config(config_path)
    cfg_cfd['MESH_FILENAME'] = 'mesh_out.su2'
    su2f.write_config(config_cfd_path, cfg_cfd)

    su2f.run_soft('SU2_DEF', config_def_path, wkdir)
    su2f.run_soft('SU2_CFD', config_cfd_path, wkdir)
    su2f.run_soft('SU2_SOL', config_cfd_path, wkdir)

    extract_loads(wkdir)

    os.chdir(original_dir)
Beispiel #2
0
    def from_config_file(self, workflow_config_path):

        cfg = su2f.read_config(workflow_config_path)

        self.cpacs_path = str(cfg['CPACS_TOOLINPUT'])
        self.module_pre = cfg['MODULE_PRE']
        self.module_optim = cfg['MODULE_OPTIM']
        self.module_post = cfg['MODULE_POST']
        self.optim_method = cfg['OPTIM_METHOD']
Beispiel #3
0
def extract_loads(results_files_dir):
    """ Function to extract loads from a SU2 resuts file.

    Function 'extract_loads'

    Args:
        results_files_dir (str): Path to the directory where results from SU2
                                 are saved.

    """

    # Path definitons
    config_file_path = results_files_dir + '/ConfigCFD.cfg'
    surface_flow_file_path = results_files_dir + '/surface_flow.vtk'
    surface_flow_force_file_path = results_files_dir + '/surface_flow_forces.vtk'
    force_file_path = results_files_dir + '/force.csv'

    cfg = read_config(config_file_path)
    updated_mesh = compute_forces(surface_flow_file_path, force_file_path, cfg)
    write_updated_mesh(updated_mesh, surface_flow_force_file_path)
Beispiel #4
0
def generate_su2_config(cpacs_path, cpacs_out_path, wkdir):
    """Function to create SU2 confif file.

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

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

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

    """

    # Get value from CPACS
    tixi = cpsf.open_tixi(cpacs_path)
    tigl = cpsf.open_tigl(tixi)

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

    # Get reference values
    ref_xpath = '/cpacs/vehicles/aircraft/model/reference'
    ref_len = cpsf.get_value(tixi,ref_xpath + '/length')
    ref_area = cpsf.get_value(tixi,ref_xpath + '/area')
    ref_ori_moment_x = cpsf.get_value_or_default(tixi,ref_xpath+'/point/x',0.0)
    ref_ori_moment_y = cpsf.get_value_or_default(tixi,ref_xpath+'/point/y',0.0)
    ref_ori_moment_z = cpsf.get_value_or_default(tixi,ref_xpath+'/point/z',0.0)

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

    # Mesh Marker
    bc_wall_xpath = SU2_XPATH + '/boundaryConditions/wall'
    bc_wall_list = su2f.get_mesh_marker(su2_mesh_path)
    cpsf.create_branch(tixi, bc_wall_xpath)
    bc_wall_str = ';'.join(bc_wall_list)
    tixi.updateTextElement(bc_wall_xpath,bc_wall_str)

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

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

        log.info('Configuration file for ""' + aeromap_uid + '"" calculation will be created.')

        # Get parameters of the aeroMap (alt,ma,aoa,aos)
        Param = apmf.get_aeromap(tixi,aeromap_uid)
        param_count = Param.get_count()

        if param_count >= 1:
            alt_list = Param.alt
            mach_list =  Param.mach
            aoa_list = Param.aoa
            aos_list = Param.aos
        else:
            raise ValueError('No parametre have been found in the aeroMap!')

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

        range_xpath = '/cpacs/toolspecific/CEASIOMpy/ranges'

        # Parameters fixed CL calulation
        param_count = 1

        # These parameters will not be used
        aoa_list = [0.0]
        aos_list = [0.0]

        cruise_mach_xpath= range_xpath + '/cruiseMach'
        mach = cpsf.get_value_or_default(tixi,cruise_mach_xpath,0.78)
        mach_list = [mach]
        cruise_alt_xpath= range_xpath + '/cruiseAltitude'
        alt = cpsf.get_value_or_default(tixi,cruise_alt_xpath,12000)
        alt_list = [alt]

        aeromap_uid = 'aeroMap_fixedCL_SU2'
        description = 'AeroMap created for SU2 fixed CL value of: ' + str(target_cl)
        apmf.create_empty_aeromap(tixi, aeromap_uid, description)
        Parameters = apmf.AeroCoefficient()
        Parameters.alt = alt_list
        Parameters.mach = mach_list
        Parameters.aoa = aoa_list
        Parameters.aos = aos_list
        apmf.save_parameters(tixi,aeromap_uid,Parameters)
        tixi.updateTextElement(SU2_XPATH+ '/aeroMapUID',aeromap_uid)


    # Get and modify the default configuration file
    cfg = su2f.read_config(DEFAULT_CONFIG_PATH)

    # General parmeters
    cfg['REF_LENGTH'] = ref_len
    cfg['REF_AREA'] = ref_area

    cfg['REF_ORIGIN_MOMENT_X'] = ref_ori_moment_x
    cfg['REF_ORIGIN_MOMENT_Y'] = ref_ori_moment_y
    cfg['REF_ORIGIN_MOMENT_Z'] = ref_ori_moment_z


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

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

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

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

        cfg['MESH_FILENAME'] = su2_mesh_path

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

        Atm = get_atmosphere(alt)
        pressure = Atm.pres
        temp = Atm.temp

        cfg['MACH_NUMBER'] = mach
        cfg['AOA'] = aoa
        cfg['SIDESLIP_ANGLE'] = aos
        cfg['FREESTREAM_PRESSURE'] = pressure
        cfg['FREESTREAM_TEMPERATURE'] = temp

        cfg['ROTATION_RATE'] = '0.0 0.0 0.0'

        config_file_name = 'ConfigCFD.cfg'


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

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

        config_output_path = os.path.join(wkdir,case_dir_name,config_file_name)

        su2f.write_config(config_output_path,cfg)


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

        if damping_der:

            rotation_rate_xpath = SU2_XPATH + '/options/rotationRate'
            rotation_rate = cpsf.get_value_or_default(tixi,rotation_rate_xpath,1.0)

            cfg['GRID_MOVEMENT'] = 'ROTATING_FRAME'

            cfg['ROTATION_RATE'] = str(rotation_rate) + ' 0.0 0.0'
            os.mkdir(os.path.join(wkdir,case_dir_name+'_dp'))
            config_output_path = os.path.join(wkdir,case_dir_name+'_dp',config_file_name)
            su2f.write_config(config_output_path,cfg)

            cfg['ROTATION_RATE'] = '0.0 ' + str(rotation_rate) + ' 0.0'
            os.mkdir(os.path.join(wkdir,case_dir_name+'_dq'))
            config_output_path = os.path.join(wkdir,case_dir_name+'_dq',config_file_name)
            su2f.write_config(config_output_path,cfg)

            cfg['ROTATION_RATE'] = '0.0 0.0 ' + str(rotation_rate)
            os.mkdir(os.path.join(wkdir,case_dir_name+'_dr'))
            config_output_path = os.path.join(wkdir,case_dir_name+'_dr',config_file_name)
            su2f.write_config(config_output_path,cfg)

            log.info('Damping derivatives cases directory has been created.')



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

        if control_surf:

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

            for su2_def_mesh in su2_def_mesh_list:

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

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

                config_file_name = 'ConfigCFD.cfg'
                config_output_path = os.path.join(wkdir,config_dir_path,config_file_name)
                su2f.write_config(config_output_path,cfg)


    # TODO: change that, but if it is save in tooloutput it will be erease by results...
    cpsf.close_tixi(tixi,cpacs_path)
Beispiel #5
0
def generate_mesh_def_config(tixi, wkdir, ted_uid, wing_uid, sym_dir,
                             defl_list):
    """Function to create config file for a TED.

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

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

    """

    tigl = cpsf.open_tigl(tixi)
    aircraft_name = cpsf.aircraft_name(tixi)
    DEFAULT_CONFIG_PATH = MODULE_DIR + '/files/DefaultConfig_v7.cfg'
    cfg = su2f.read_config(DEFAULT_CONFIG_PATH)
    config_dir_name = aircraft_name + '_TED_' + ted_uid
    # TODO: add check or remove if alread exist?
    os.mkdir(os.path.join(wkdir, 'MESH', config_dir_name))

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

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

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

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

    # Mesh Marker
    bc_wall_list = su2f.get_mesh_marker(su2_mesh_path)
    bc_wall_str = '(' + ','.join(bc_wall_list) + ')'
    cfg['MARKER_EULER'] = bc_wall_str
    cfg['MARKER_FAR'] = ' (Farfield)'
    cfg['MARKER_SYM'] = ' (0)'
    cfg['MARKER_PLOTTING'] = bc_wall_str
    cfg['MARKER_MONITORING'] = bc_wall_str
    cfg['MARKER_MOVING'] = '( NONE )'
    cfg['DV_MARKER'] = bc_wall_str

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

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

    # FFD BOX rotation
    for defl in defl_list:

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

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

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

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

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

            config_file_name = 'ConfigROT_sym_defl' + str(defl) + '.cfg'
            config_path = os.path.join(wkdir, 'MESH', config_dir_name,
                                       config_file_name)
            su2f.write_config(config_path, cfg)
            log.info(config_path + ' have has been written.')