Ejemplo n.º 1
0
def init_specials(tixi):
    """
    Add specific design variables without the tigl handler.

    Parameters
    ----------
    tixi : tixi3_handler

    Returns
    -------
    None.

    """
    if XPATH != 'None':
        # Xpath to optimisation results
        aeromap_uid = cpsf.get_value(tixi, XPATH + '/aeroMapUID')
        xpath = tixi.uIDGetXPath(aeromap_uid) + '/aeroPerformanceMap/'

        # Xpath to initial results
        aeromap_uid_pre = cpsf.get_value(tixi, XPATH_PRE + '/aeroMapUID')
        xpath_pre = tixi.uIDGetXPath(aeromap_uid_pre) + '/aeroPerformanceMap/'

        var_name = 'angleOfAttack'
        getcmd = 'cpsf.get_value(tixi, "{}")'.format(xpath + var_name)
        setcmd = 'cpsf.add_float_vector(tixi, "{}", {})'.format(
            xpath, var_name)
        init_value = cpsf.get_value(tixi, xpath_pre + var_name)
Ejemplo n.º 2
0
def get_cl(cpacs_path, cpacs_out_path):
    """ Function to calculate CL requiered as a function of the parameter found
    in the CPACS file.

    Function 'get_cl' find input value in the CPACS file, calculate the
    requiered CL (with calculate_cl) and  save the CL value in
    /cpacs/toolspecific/CEASIOMpy/aerodynamics/su2/targetCL

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

    """

    tixi = open_tixi(cpacs_path)

    # XPath definition
    model_xpath = '/cpacs/vehicles/aircraft/model'
    ref_area_xpath = model_xpath + '/reference/area'
    mtom_xpath = model_xpath + '/analyses/massBreakdown/designMasses/mTOM/mass'
    range_xpath = '/cpacs/toolspecific/CEASIOMpy/ranges'
    cruise_alt_xpath = range_xpath + '/cruiseAltitude'
    cruise_mach_xpath = range_xpath + '/cruiseMach'
    load_fact_xpath = range_xpath + '/loadFactor'
    su2_xpath = '/cpacs/toolspecific/CEASIOMpy/aerodynamics/su2'

    # Requiered input data from CPACS
    ref_area = get_value(tixi, ref_area_xpath)
    mtom = get_value(tixi, mtom_xpath)

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

    # Get atmosphere from cruise altitude
    Atm = get_atmosphere(cruise_alt)

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

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

    close_tixi(tixi, cpacs_out_path)
Ejemplo n.º 3
0
    def compute(self, inputs, outputs):
        """Launches the module"""

        # Updating inputs in CPACS file
        cpacs_path = mif.get_toolinput_file_path(self.module_name)
        tixi = cpsf.open_tixi(cpacs_path)
        for name in inputs:
            if name in optim_var_dict:
                xpath = optim_var_dict[name][4]
                cpsf.add_float_vector(tixi, xpath, inputs[name])
        cpsf.close_tixi(tixi, cpacs_path)

        # Running the module
        wkf.run_subworkflow([self.module_name])

        # Feeding CPACS file restults to outputs
        cpacs_path = mif.get_tooloutput_file_path(self.module_name)
        tixi = cpsf.open_tixi(cpacs_path)
        for name in outputs:
            if name in optim_var_dict:
                xpath = optim_var_dict[name][4]
                outputs[name] = cpsf.get_value(tixi, xpath)

        # Copy CPACS to input folder of next module
        index = Rt.modules.index(self.module_name) + 1
        if index != len(Rt.modules):
            cpacs_path = mif.get_toolinput_file_path(Rt.modules[index])
        else:
            cpacs_path = mif.get_toolinput_file_path(Rt.modules[0])
        cpsf.close_tixi(tixi, cpacs_path)
Ejemplo n.º 4
0
def get_aero_param(tixi):
    """Add the aeromap variables to the optimisation dictionnary.

    Takes the variables of the aeromap that is used.
    It is checked if the variable has a user-specified initial value, else it
    will assign a default value or the variable will be excluded from the
    problem.

    Args:
        tixi (Tixi3 handle): Handle of the current CPACS file.

    """

    log.info('Default aeromap parameters will be set')

    am_uid = cpsf.get_value(tixi, OPTIM_XPATH+'aeroMapUID')
    am_index = apmf.get_aeromap_index(tixi, am_uid)

    log.info('Aeromap \"{}\" will be used for the variables.'.format(am_uid))

    xpath = apmf.AEROPERFORMANCE_XPATH + '/aeroMap'\
            + am_index + '/aeroPerformanceMap/'

    for name in apmf.COEF_LIST+apmf.XSTATES:
        xpath_param = xpath+name
        value = str(tixi.getDoubleElement(xpath_param))

        var['Name'].append(name)
        var['init'].append(value)
        var['xpath'].append(xpath_param)

        tls.add_type(name, apmf.COEF_LIST, objective, var)
        tls.add_bounds(value, var)
Ejemplo n.º 5
0
def test_estimate_skin_friction_coef():
    """Test function 'estimate_skin_friction_coef' """

    # Test 1
    wetted_area = 1
    wing_area = 1
    wing_span = 1
    mach = 1
    alt = 1

    cd0 = estimate_skin_friction_coef(wetted_area,wing_area,wing_span,mach,alt)

    assert cd0 == approx(0.005320707210958961)

    # Test 2, with "real values"
    tixi = open_tixi(CPACS_IN_PATH)
    tigl = open_tigl(tixi)
    analyses_xpath = '/cpacs/toolspecific/CEASIOMpy/geometry/analyses'
    wetted_area = get_value(tixi,analyses_xpath + '/wettedArea')
    wing_area, wing_span = get_largest_wing_dim(tixi,tigl)
    mach = 0.78
    alt = 12000

    cd0 = estimate_skin_friction_coef(wetted_area,wing_area,wing_span,mach,alt)

    assert cd0 == approx(0.01998328842386761)
Ejemplo n.º 6
0
def add_skin_friction(cpacs_path, cpacs_out_path):
    """ Function to add the skin frinction drag coeffienct to the CPACS file

    Function 'add_skin_friction' add the skin friction drag 'cd0' to the CPACS
    file, then it could be added to the drag coeffienct obtain with Euler
    calcualtions or other methods

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

    tixi = open_tixi(cpacs_path)
    tigl = open_tigl(tixi)

    wing_area_max, wing_span_max = get_largest_wing_dim(tixi, tigl)

    analysis_xpath = '/cpacs/toolspecific/CEASIOMpy/geometry/analysis'
    range_xpath = '/cpacs/toolspecific/CEASIOMpy/ranges'

    # Requiered input data from CPACS
    wetted_area = get_value(tixi, analysis_xpath + '/wettedArea')

    # Not requiered input data (a default value will be used if no
    # value has been found in the CPACS file)
    wing_area_xpath = analysis_xpath + '/wingArea'
    tixi, wing_area = get_value_or_default(tixi, wing_area_xpath,
                                           wing_area_max)
    if wing_area != wing_area_max:
        log.warning('Wing area found in the CPACS file /toolspecific is \
                     different from the one calculated from geometry, \
                     /toolspecific value will be used')

    wing_span_xpath = analysis_xpath + '/wingSpan'
    tixi, wing_span = get_value_or_default(tixi, wing_span_xpath,
                                           wing_span_max)
    if wing_span != wing_span_max:
        log.warning('Wing span found in the CPACS file /toolspecific is \
                    different from the one calculated from geometry, \
                    /toolspecific value will be used')

    cruise_alt_xpath = range_xpath + '/cruiseAltitude'
    tixi, cruise_alt = get_value_or_default(tixi, cruise_alt_xpath, 12000)

    cruise_mach_xpath = range_xpath + '/cruiseMach'
    tixi, cruise_mach = get_value_or_default(tixi, cruise_mach_xpath, 0.78)

    # Calculate Cd0
    cd0 = estimate_skin_friction_coef(wetted_area,wing_area,wing_span, \
                                      cruise_mach,cruise_alt)

    # Save Cd0 in the CPACS file
    cd0_xpath = '/cpacs/toolspecific/CEASIOMpy/aerodynamics/skinFriction/cd0'
    tixi = create_branch(tixi, cd0_xpath)
    tixi.updateDoubleElement(cd0_xpath, cd0, '%g')
    log.info('Skin friction drag coeffienct (cd0) has been saved in the \
              CPACS file')

    close_tixi(tixi, cpacs_out_path)
Ejemplo n.º 7
0
def get_fuselage_scaling(cpacs_path, cpacs_out_path):
    """Function to get fuselage scaling along x,y,z axis.

    Function 'get_fuselage_scaling' return the value of the scaling for the
    fuselage. (This is an example function just to show usaga of CPACS and tixi)

    Source:
        * Reference paper or book, with author and date

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

    Returns:
        Tuple with fuselage scaling

        * x (float): Scaling on x [-]
        * y (float): Scaling on y [-]
        * z (float): Scaling on z [-]
    """

    # Open TIXI handle
    tixi = open_tixi(cpacs_path)

    # Create xpaths
    FUSELAGE_XPATH = '/cpacs/vehicles/aircraft/model/fuselages/fuselage'
    SCALING_XPATH = '/transformation/scaling'

    x_fus_scaling_xpath = FUSELAGE_XPATH + SCALING_XPATH + '/x'
    y_fus_scaling_xpath = FUSELAGE_XPATH + SCALING_XPATH + '/y'
    z_fus_scaling_xpath = FUSELAGE_XPATH + SCALING_XPATH + '/z'

    # Get values
    x = get_value(tixi, x_fus_scaling_xpath)
    y = get_value(tixi, y_fus_scaling_xpath)
    z = get_value(tixi, z_fus_scaling_xpath)

    # Log
    log.info('Fuselage x scaling is : ' + str(x))
    log.info('Fuselage y scaling is : ' + str(y))
    log.info('Fuselage z scaling is : ' + str(z))

    # Close TIXI handle and save the CPACS file
    close_tixi(tixi, cpacs_out_path)

    return x, y, z
Ejemplo n.º 8
0
    def compute(self, inputs, outputs):
        """Launches the module"""

        # Updating inputs in CPACS file
        cpacs_path = mif.get_toolinput_file_path(self.module_name)
        tixi = cpsf.open_tixi(cpacs_path)
        for name in inputs:
            if name in optim_var_dict:
                xpath = optim_var_dict[name][4]
                # Change only the first vector value for aeromap param
                if name in apmf.XSTATES:
                    size = tixi.getVectorSize(xpath)
                    v = list(tixi.getFloatVector(xpath, size))
                    v.pop(0)
                    v.insert(0, inputs[name])
                    tixi.updateFloatVector(xpath, v, size, '%g')
                else:
                    cpsf.add_float_vector(tixi, xpath, inputs[name])
        cpsf.close_tixi(tixi, cpacs_path)

        # Running the module
        wkf.run_subworkflow([self.module_name])

        # Feeding CPACS file results to outputs
        cpacs_path = mif.get_tooloutput_file_path(self.module_name)
        tixi = cpsf.open_tixi(cpacs_path)
        for name in outputs:
            if name in optim_var_dict:
                xpath = optim_var_dict[name][4]
                if name in apmf.COEF_LIST:
                    val = cpsf.get_value(tixi, xpath)
                    if isinstance(val, str):
                        val = val.split(';')
                        outputs[name] = val[0]
                    else:
                        outputs[name] = val
                else:
                    outputs[name] = cpsf.get_value(tixi, xpath)

        # Copy CPACS to input folder of next module
        index = Rt.modules.index(self.module_name) + 1
        if index != len(Rt.modules):
            cpacs_path = mif.get_toolinput_file_path(Rt.modules[index])
        else:
            cpacs_path = mif.get_toolinput_file_path(Rt.modules[0])
        cpsf.close_tixi(tixi, cpacs_path)
Ejemplo n.º 9
0
def init_res_dict(tixi):
    """
    Return dictionary of the constraints.

    Parameters
    ----------
    tixi : tixi3_handler

    Returns
    -------
    res_var_dict : dictionnary

    """
    if XPATH != 'None':
        # Xpath to optimisation results
        aeromap_uid = cpsf.get_value(tixi, XPATH + '/aeroMapUID')
        xpath = tixi.uIDGetXPath(aeromap_uid) + '/aeroPerformanceMap/'

        # Xpath to initial results
        aeromap_uid_pre = cpsf.get_value(tixi, XPATH_PRE + '/aeroMapUID')
        xpath_pre = tixi.uIDGetXPath(aeromap_uid_pre) + '/aeroPerformanceMap/'

        for el in ['cl', 'cd', 'cms']:
            getcmd = 'cpsf.get_float_vector(tixi, "{}")'.format(xpath + el)
            setcmd = ''
            init_value = eval(
                'cpsf.get_float_vector(tixi, "{}")'.format(xpath_pre + el))
            create_var(el, init_value[0], getcmd, setcmd)

    # passenger = cpsf.get_value(tixi, '/cpacs/toolspecific/CEASIOMpy/weight/passengers/passNb')
    # Coef = apmf.get_aeromap(tixi, aeromap_uid)

    xpath = '/cpacs/vehicles/aircraft/model/analyses/massBreakdown/designMasses/mTOM/mass'
    getcmd = 'cpsf.get_value(tixi, "{}")'.format(xpath)
    setcmd = ''
    init_value = eval(getcmd)
    create_var('mtom', init_value, getcmd, setcmd)

    xpath = '/cpacs/toolspecific/CEASIOMpy/weight/passengers/passNb'
    getcmd = 'cpsf.get_value(tixi, "{}")'.format(xpath)
    setcmd = ''
    init_value = eval(getcmd)
    create_var('passengers', init_value, getcmd, setcmd)

    return res_var_dict
Ejemplo n.º 10
0
def one_iteration():
    """
    Compute the objective function.

    Function 'one_iteration' will exectute in order all the module contained
    in '...' and extract the ... value from the last CPACS file, this value will
    be returned to the optimizer CPACSUpdater....

    """
    global counter
    counter += 1

    # Create the parameter in CPACS with 'CPACSUpdater' module
    cpacs_path = mi.get_toolinput_file_path('CPACSUpdater')
    cpacs_out_path = mi.get_tooloutput_file_path('CPACSUpdater')

    tixi = cpsf.open_tixi(cpacs_path)
    wkdir_path = ceaf.create_new_wkdir(Rt.date)
    WKDIR_XPATH = '/cpacs/toolspecific/CEASIOMpy/filesPath/wkdirPath'
    tixi.updateTextElement(WKDIR_XPATH, wkdir_path)

    # TODO: improve this part! (maybe move somewhere else)
    # To delete coef from previous iter
    if opf.get_aeromap_path(Rt.modules) != 'None':
        xpath = opf.get_aeromap_path(Rt.modules)
        aeromap_uid = cpsf.get_value(tixi, xpath + '/aeroMapUID')
        Coef = apmf.get_aeromap(tixi, aeromap_uid)
        apmf.delete_aeromap(tixi, aeromap_uid)
        apmf.create_empty_aeromap(tixi, aeromap_uid, 'test_optim')
        apmf.save_parameters(tixi, aeromap_uid, Coef)
        cpsf.close_tixi(tixi, cpacs_path)

    # Update the CPACS file with the parameters contained in design_var_dict
    update_cpacs_file(cpacs_path, cpacs_out_path, design_var_dict)

    # Save the CPACS file
    if counter % 1 == 0:
        file_copy_from = mi.get_tooloutput_file_path('CPACSUpdater')
        shutil.copy(
            file_copy_from,
            optim_dir_path + '/Geometry/' + 'iter_{}.xml'.format(counter))

    # Run optimisation sub workflow
    wkf.copy_module_to_module('CPACSUpdater', 'out', Rt.modules[0], 'in')
    wkf.run_subworkflow(Rt.modules)
    wkf.copy_module_to_module(Rt.modules[-1], 'out', 'CPACSUpdater', 'in')

    # Extract results  TODO: improve this part
    cpacs_results_path = mi.get_tooloutput_file_path(Rt.modules[-1])
    log.info('Results will be extracted from:' + cpacs_results_path)
    tixi = cpsf.open_tixi(cpacs_results_path)

    # Update the constraints values
    update_res_var_dict(tixi)
    return compute_obj()
Ejemplo n.º 11
0
def test_get_value():
    """Test the function 'get_value'"""

    tixi = cpsf.open_tixi(CPACS_IN_PATH)

    # Check if the correct value (float) is return from an xpath
    xpath = '/cpacs/vehicles/aircraft/model/reference/area'
    value = cpsf.get_value(tixi, xpath)
    assert value == 1.0

    # Check if the correct value (text) is return from an xpath
    xpath = '/cpacs/vehicles/aircraft/model/name'
    value = cpsf.get_value(tixi, xpath)
    assert value == 'Cpacs2Test'

    # Check if boolean are returned from an xpath or default value
    xpath = '/cpacs/toolspecific/testUtils/testCPACSFunctions/testBoolTrue'
    value = cpsf.get_value(tixi, xpath)
    assert value == True

    xpath = '/cpacs/toolspecific/testUtils/testCPACSFunctions/testBoolFalse'
    value = cpsf.get_value(tixi, xpath)
    assert value == False

    # Check if a false xpath raises ValueError
    xpath = '/cpacs/vehicles/aircraft/model/reference/aarreeaa'
    with pytest.raises(ValueError):
        value_error = cpsf.get_value(tixi, xpath)

    # Check if no value in the field raises ValueError
    xpath = '/cpacs/vehicles/aircraft/model'
    with pytest.raises(ValueError):
        value_text = cpsf.get_value(tixi, xpath)
Ejemplo n.º 12
0
def test_get_value():
    """Test the function 'get_value'"""

    tixi = open_tixi(CPACS_IN_PATH)

    # Check if the correct value (float) is return from an xpath
    xpath = '/cpacs/vehicles/aircraft/model/reference/area'
    value = get_value(tixi, xpath)
    assert value == 1.0

    # Check if the correct value (text) is return from an xpath
    xpath = '/cpacs/vehicles/aircraft/model/name'
    value = get_value(tixi, xpath)
    assert value == 'Cpacs2Test'

    # Check if a false xpath raises ValueError
    xpath = '/cpacs/vehicles/aircraft/model/reference/aarreeaa'
    with pytest.raises(ValueError):
        value_error = get_value(tixi, xpath)

    # Check if no value in the field raises ValueError
    xpath = '/cpacs/vehicles/aircraft/model'
    with pytest.raises(ValueError):
        value_text = get_value(tixi, xpath)
Ejemplo n.º 13
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.')
Ejemplo n.º 14
0
def add_skin_friction(cpacs_path, cpacs_out_path):
    """ Function to add the skin frinction drag coeffienct to aerodynamic coefficients

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

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

    tixi = cpsf.open_tixi(cpacs_path)
    tigl = cpsf.open_tigl(tixi)

    wing_area_max, wing_span_max = get_largest_wing_dim(tixi, tigl)

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

    # Requiered input data from CPACS
    wetted_area = cpsf.get_value(tixi, analyses_xpath + '/wettedArea')

    # Wing area/span, default values will be calated if no value found in the CPACS file
    wing_area_xpath = analyses_xpath + '/wingArea'
    wing_area = cpsf.get_value_or_default(tixi, wing_area_xpath, wing_area_max)
    wing_span_xpath = analyses_xpath + '/wingSpan'
    wing_span = cpsf.get_value_or_default(tixi, wing_span_xpath, wing_span_max)

    aeromap_uid_list = []

    # Try to get aeroMapToCalculate
    aeroMap_to_clculate_xpath = SF_XPATH + '/aeroMapToCalculate'
    if tixi.checkElement(aeroMap_to_clculate_xpath):
        aeromap_uid_list = cpsf.get_string_vector(tixi,
                                                  aeroMap_to_clculate_xpath)
    else:
        aeromap_uid_list = []

    # If no aeroMap in aeroMapToCalculate, get all existing aeroMap
    if len(aeromap_uid_list) == 0:
        try:
            aeromap_uid_list = apmf.get_aeromap_uid_list(tixi)
        except:
            raise ValueError(
                'No aeroMap has been found in this CPACS file, skin friction cannot be added!'
            )

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

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

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

        # Get orignial aeroPerformanceMap
        AeroCoef = apmf.get_aeromap(tixi, aeromap_uid)
        AeroCoef.complete_with_zeros()

        # Create new aeroCoefficient object to store coef with added skin friction
        AeroCoefSF = apmf.AeroCoefficient()
        AeroCoefSF.alt = AeroCoef.alt
        AeroCoefSF.mach = AeroCoef.mach
        AeroCoefSF.aoa = AeroCoef.aoa
        AeroCoefSF.aos = AeroCoef.aos

        # Iterate over all cases
        case_count = AeroCoef.get_count()
        for case in range(case_count):

            # Get parameters for this case
            alt = AeroCoef.alt[case]
            mach = AeroCoef.mach[case]
            aoa = AeroCoef.aoa[case]
            aos = AeroCoef.aos[case]

            # Calculate Cd0 for this case
            cd0 = estimate_skin_friction_coef(wetted_area,wing_area,wing_span, \
                                              mach,alt)

            # Projection of cd0 on cl, cd and cs axis
            #TODO: Should Cd0 be projected or not???
            aoa_rad = math.radians(aoa)
            aos_rad = math.radians(aos)
            cd0_cl = cd0 * math.sin(aoa_rad)
            cd0_cd = cd0 * math.cos(aoa_rad) * math.cos(aos_rad)
            cd0_cs = cd0 * math.sin(aos_rad)

            # Update aerodynamic coefficients
            cl = AeroCoef.cl[case] + cd0_cl
            cd = AeroCoef.cd[case] + cd0_cd
            cs = AeroCoef.cs[case] + cd0_cs

            # Shoud we change something? e.i. if a force is not apply at aero center...?
            if len(AeroCoef.cml):
                cml = AeroCoef.cml[case]
            else:
                cml = 0.0  # Shoud be change, just to test pyTornado
            if len(AeroCoef.cmd):
                cmd = AeroCoef.cmd[case]
            else:
                cmd = 0.0
            if len(AeroCoef.cms):
                cms = AeroCoef.cms[case]
            else:
                cms = 0.0

            # Add new coefficients into the aeroCoefficient object
            AeroCoefSF.add_coefficients(cl, cd, cs, cml, cmd, cms)

        # Create new aeroMap UID
        aeromap_sf_uid = aeromap_uid + '_SkinFriction'
        new_aeromap_uid_list.append(aeromap_sf_uid)

        # Create new description
        description_xpath = tixi.uIDGetXPath(aeromap_uid) + '/description'
        sf_description = cpsf.get_value(
            tixi,
            description_xpath) + ' Skin friction has been add to this AeroMap.'
        apmf.create_empty_aeromap(tixi, aeromap_sf_uid, sf_description)

        # Save aeroCoefficient object Coef in the CPACS file
        apmf.save_parameters(tixi, aeromap_sf_uid, AeroCoefSF)
        apmf.save_coefficients(tixi, aeromap_sf_uid, AeroCoefSF)

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

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

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

    cpsf.close_tixi(tixi, cpacs_out_path)
Ejemplo n.º 15
0
def dynamic_stability_analysis(cpacs_path, cpacs_out_path):
    """Function to analyse a full Aeromap

    Function 'dynamic_stability_analysis' analyses longitudinal dynamic
    stability and directionnal dynamic.

    Args:
        cpacs_path (str): Path to CPACS file
        cpacs_out_path (str):Path to CPACS output file
        plot (boolean): Choise to plot graph or not

    Returns:  (#TODO put that in the documentation)
        *   Adrvertisements certifying if the aircraft is stable or Not
        *   In case of longitudinal dynamic UNstability or unvalid test on data:
                -	Plot cms VS aoa for constant Alt, Mach and different aos
                -	Plot cms VS aoa for const alt and aos and different mach
                -	plot cms VS aoa for constant mach, AOS and different altitudes
        *  In case of directionnal dynamic UNstability or unvalid test on data:
                -	Pcot cml VS aos for constant Alt, Mach and different aoa
                -	Plot cml VS aos for const alt and aoa and different mach
                -	plot cml VS aos for constant mach, AOA and different altitudes
        *  Plot one graph of  cruising angles of attack for different mach and altitudes

    Make the following tests:
        *   Check the CPACS path
        *   For longitudinal dynamic stability analysis:
                -   If there is more than one angle of attack for a given altitude, mach, aos
                -   If cml values are only zeros for a given altitude, mach, aos
                -   If there one aoa value which is repeated for a given altitude, mach, aos
        *   For directionnal dynamic stability analysis:
                -   If there is more than one angle of sideslip for a given altitude, mach, aoa
                -   If cms values are only zeros for a given altitude, mach, aoa
                -   If there one aos value which is repeated for a given altitude, mach, aoa
    """

    # XPATH definition
    aeromap_uid_xpath = DYNAMIC_ANALYSIS_XPATH + '/aeroMapUid'
    aircraft_class_xpath = DYNAMIC_ANALYSIS_XPATH + '/class'  # Classes 1 2 3 4 small, heavy ...
    aircraft_cathegory_xpath = DYNAMIC_ANALYSIS_XPATH + '/category'  # flight phase A B C
    selected_mass_config_xpath = DYNAMIC_ANALYSIS_XPATH + '/massConfiguration'
    longi_analysis_xpath = DYNAMIC_ANALYSIS_XPATH + '/instabilityModes/longitudinal'
    direc_analysis_xpath = DYNAMIC_ANALYSIS_XPATH + '/instabilityModes/lateralDirectional'
    show_plot_xpath = DYNAMIC_ANALYSIS_XPATH + '/showPlots'
    save_plot_xpath = DYNAMIC_ANALYSIS_XPATH + '/savePlots'

    model_xpath = '/cpacs/vehicles/aircraft/model'
    ref_area_xpath = model_xpath + '/reference/area'
    ref_length_xpath = model_xpath + '/reference/length'
    flight_qualities_case_xpath = model_xpath + '/analyses/flyingQualities/fqCase'
    masses_location_xpath = model_xpath + '/analyses/massBreakdown/designMasses'
    # aircraft_class_xpath = flight_qualities_case_xpath + '/class' # Classes 1 2 3 4 small, heavy ...
    # aircraft_cathegory_xpath = flight_qualities_case_xpath + '/cathegory' # flight phase A B C

    # Ask user flight path angles : gamma_e
    thrust_available = None  # Thrust data are not available
    flight_path_angle_deg = [
        0
    ]  # [-15,-10,-5,0,5,10,15] # The user should have the choice to select them !!!!!!!!!!!!!!!!!!!!
    flight_path_angle = [
        angle * (np.pi / 180) for angle in flight_path_angle_deg
    ]  # flight_path_angle in [rad]

    tixi = cpsf.open_tixi(cpacs_path)
    # Get aeromap uid
    aeromap_uid = cpsf.get_value(tixi, aeromap_uid_xpath)
    log.info('The following aeroMap will be analysed: ' + aeromap_uid)

    # Mass configuration: (Maximum landing mass, Maximum ramp mass (the maximum weight authorised for the ground handling), Take off mass, Zero Fuel mass)
    mass_config = cpsf.get_value(tixi, selected_mass_config_xpath)
    log.info('The aircraft mass configuration used for analysis is: ' +
             mass_config)

    # Analyses to do : longitudinal / Lateral-Directional
    longitudinal_analysis = cpsf.get_value(tixi, longi_analysis_xpath)
    lateral_directional_analysis = False
    # lateral_directional_analysis = cpsf.get_value(tixi, direc_analysis_xpath )
    # Plots configuration with Setting GUI
    show_plots = cpsf.get_value_or_default(tixi, show_plot_xpath, False)
    save_plots = cpsf.get_value_or_default(tixi, save_plot_xpath, False)

    mass_config_xpath = masses_location_xpath + '/' + mass_config
    if tixi.checkElement(mass_config_xpath):
        mass_xpath = mass_config_xpath + '/mass'
        I_xx_xpath = mass_config_xpath + '/massInertia/Jxx'
        I_yy_xpath = mass_config_xpath + '/massInertia/Jyy'
        I_zz_xpath = mass_config_xpath + '/massInertia/Jzz'
        I_xz_xpath = mass_config_xpath + '/massInertia/Jxz'
    else:
        raise ValueError(
            'The mass configuration : {} is not defined in the CPACS file !!!'.
            format(mass_config))

    s = cpsf.get_value(
        tixi, ref_area_xpath
    )  # Wing area : s  for non-dimonsionalisation of aero data.
    mac = cpsf.get_value(
        tixi, ref_length_xpath
    )  # ref length for non dimensionalisation, Mean aerodynamic chord: mac,
    # TODO: check that
    b = s / mac

    # TODO: find a way to get that
    xh = 10  # distance Aircaft cg-ac_horizontal-tail-plane.

    m = cpsf.get_value(tixi, mass_xpath)  # aircraft mass dimensional
    I_xx = cpsf.get_value(tixi, I_xx_xpath)  # X inertia dimensional
    I_yy = cpsf.get_value(tixi, I_yy_xpath)  # Y inertia dimensional
    I_zz = cpsf.get_value(tixi, I_zz_xpath)  # Z inertia dimensional
    I_xz = cpsf.get_value(tixi, I_xz_xpath)  # XZ inertia dimensional

    aircraft_class = cpsf.get_value(
        tixi, aircraft_class_xpath)  # aircraft class 1 2 3 4
    flight_phase = cpsf.get_string_vector(
        tixi, aircraft_cathegory_xpath)[0]  # Flight phase A B C

    Coeffs = apmf.get_aeromap(
        tixi, aeromap_uid
    )  # Warning: Empty uID found! This might lead to unknown errors!

    alt_list = Coeffs.alt
    mach_list = Coeffs.mach
    aoa_list = Coeffs.aoa
    aos_list = Coeffs.aos
    cl_list = Coeffs.cl
    cd_list = Coeffs.cd
    cs_list = Coeffs.cs
    cml_list = Coeffs.cml
    cms_list = Coeffs.cms
    cmd_list = Coeffs.cmd
    dcsdrstar_list = Coeffs.dcsdrstar
    dcsdpstar_list = Coeffs.dcsdpstar
    dcldqstar_list = Coeffs.dcldqstar
    dcmsdqstar_list = Coeffs.dcmsdqstar
    dcddqstar_list = Coeffs.dcddqstar
    dcmldqstar_list = Coeffs.dcmldqstar
    dcmddpstar_list = Coeffs.dcmddpstar
    dcmldpstar_list = Coeffs.dcmldpstar
    dcmldrstar_list = Coeffs.dcmldrstar
    dcmddrstar_list = Coeffs.dcmddrstar

    # All different vallues with only one occurence
    alt_unic = get_unic(alt_list)
    mach_unic = get_unic(mach_list)
    aos_unic = get_unic(aos_list)
    aoa_unic = get_unic(aoa_list)

    # TODO get from CPACS
    incrementalMap = False

    for alt in alt_unic:
        idx_alt = [i for i in range(len(alt_list)) if alt_list[i] == alt]
        Atm = get_atmosphere(alt)
        g = Atm.grav
        a = Atm.sos
        rho = Atm.dens

        for mach in mach_unic:
            print('Mach : ', mach)
            idx_mach = [
                i for i in range(len(mach_list)) if mach_list[i] == mach
            ]
            u0, m_adim, i_xx, i_yy, i_zz, i_xz = adimensionalise(
                a, mach, rho, s, b, mac, m, I_xx, I_yy, I_zz,
                I_xz)  # u0 is V0 in Cook

            # Hyp: trim condition when: ( beta = 0 and dCm/dalpha = 0)  OR  ( aos=0 and dcms/daoa = 0 )
            if 0 not in aos_unic:
                log.warning(
                    'The aircraft can not be trimmed (requiring symetric flight condition) as beta never equal to 0 for Alt = {}, mach = {}'
                    .format(alt, mach))
            else:
                idx_aos = [i for i in range(len(aos_list)) if aos_list[i] == 0]
                find_index = get_index(idx_alt, idx_mach, idx_aos)
                # If there is only one data at (alt, mach, aos) then dont make stability anlysis
                if len(find_index) <= 1:
                    log.warning(
                        'Not enough data at : Alt = {} , mach = {}, aos = 0, can not perform stability analysis'
                        .format(alt, mach))
                # If there is at leat 2 data at (alt, mach, aos) then, make stability anlysis
                else:
                    # Calculate trim conditions
                    cms = []
                    aoa = []
                    cl = []
                    for index in find_index:
                        cms.append(cms_list[index])
                        aoa.append(aoa_list[index] * np.pi / 180)
                        cl.append(cl_list[index])

                    cl_required = (m * g) / (0.5 * rho * u0**2 * s)
                    (trim_aoa, idx_trim_before, idx_trim_after,
                     ratio) = trim_condition(
                         alt,
                         mach,
                         cl_required,
                         cl,
                         aoa,
                     )

                    if trim_aoa:
                        trim_aoa_deg = trim_aoa * 180 / np.pi
                        trim_cms = interpolation(cms, idx_trim_before,
                                                 idx_trim_after, ratio)
                        pitch_moment_derivative_rad = (
                            cms[idx_trim_after] - cms[idx_trim_before]) / (
                                aoa[idx_trim_after] - aoa[idx_trim_before])
                        pitch_moment_derivative_deg = pitch_moment_derivative_rad / (
                            180 / np.pi)
                        # Find incremental cms
                        if incrementalMap:
                            for index, mach_number in enumerate(mach_unic, 0):
                                if mach_number == mach:
                                    mach_index = index
                            dcms_before = dcms_list[mach_index * len(aoa_unic)
                                                    + idx_trim_before]
                            dcms_after = dcms_list[mach_index * len(aoa_unic) +
                                                   idx_trim_after]
                            dcms = dcms_before + ratio * (dcms_after -
                                                          dcms_before)
                            trim_elevator = -trim_cms / dcms  # Trim elevator deflection in [°]
                        else:
                            dcms = None
                            trim_elevator = None

                    else:
                        trim_aoa_deg = None
                        trim_cms = None
                        pitch_moment_derivative_deg = None
                        dcms = None
                        trim_elevator = None

                    # Longitudinal dynamic stability,
                    # Stability analysis
                    if longitudinal_analysis and trim_cms:
                        cl = []
                        cd = []
                        dcldqstar = []
                        dcddqstar = []
                        dcmsdqstar = []
                        for index in find_index:
                            cl.append(cl_list[index])
                            cd.append(cd_list[index])
                            dcldqstar.append(dcldqstar_list[index])
                            dcddqstar.append(dcddqstar_list[index])
                            dcmsdqstar.append(dcmsdqstar_list[index])

                        # Trimm variables
                        cd0 = interpolation(cd, idx_trim_before,
                                            idx_trim_after,
                                            ratio)  # Dragg coeff at trim
                        cl0 = interpolation(cl, idx_trim_before,
                                            idx_trim_after,
                                            ratio)  # Lift coeff at trim
                        cl_dividedby_cd_trim = cl0 / cd0  #  cl/cd ratio at trim, at trim aoa

                        # Lift & drag coefficient derivative with respect to AOA at trimm
                        cl_alpha0 = (cl[idx_trim_after] - cl[idx_trim_before]
                                     ) / (aoa[idx_trim_after] -
                                          aoa[idx_trim_before])
                        cd_alpha0 = (cd[idx_trim_after] - cd[idx_trim_before]
                                     ) / (aoa[idx_trim_after] -
                                          aoa[idx_trim_before])
                        print(idx_trim_before, idx_trim_after, ratio)

                        dcddqstar0 = interpolation(dcddqstar, idx_trim_before,
                                                   idx_trim_after,
                                                   ratio)  # x_q
                        dcldqstar0 = interpolation(dcldqstar, idx_trim_before,
                                                   idx_trim_after,
                                                   ratio)  # z_q
                        dcmsdqstar0 = interpolation(dcmsdqstar,
                                                    idx_trim_before,
                                                    idx_trim_after,
                                                    ratio)  # m_q
                        cm_alpha0 = trim_cms

                        # Speed derivatives if there is at least 2 distinct mach values
                        if len(mach_unic) >= 2:
                            dcddm0 = speed_derivative_at_trim(
                                cd_list, mach, mach_list, mach_unic, idx_alt,
                                aoa_list, aos_list, idx_trim_before,
                                idx_trim_after, ratio)

                            if dcddm0 == None:
                                dcddm0 = 0
                                log.warning(
                                    'Not enough data to determine dcddm or (Cd_mach) at trim condition at Alt = {}, mach = {}, aoa = {}, aos = 0. Assumption: dcddm = 0'
                                    .format(alt, mach, round(trim_aoa_deg, 2)))
                            dcldm0 = speed_derivative_at_trim(
                                cl_list, mach, mach_list, mach_unic, idx_alt,
                                aoa_list, aos_list, idx_trim_before,
                                idx_trim_after, ratio)
                            if dcldm0 == None:
                                dcldm0 = 0
                                log.warning(
                                    'Not enough data to determine dcldm (Cl_mach) at trim condition at Alt = {}, mach = {}, aoa = {}, aos = 0. Assumption: dcldm = 0'
                                    .format(alt, mach, round(trim_aoa_deg, 2)))
                        else:
                            dcddm0 = 0
                            dcldm0 = 0
                            log.warning(
                                'Not enough data to determine dcddm (Cd_mach) and dcldm (Cl_mach) at trim condition at Alt = {}, mach = {}, aoa = {}, aos = 0. Assumption: dcddm = dcldm = 0'
                                .format(alt, mach, round(trim_aoa_deg, 2)))

                        # Controls Derivatives to be found in the CPACS (To be calculated)
                        dcddeta0 = 0
                        dcldeta0 = 0
                        dcmsdeta0 = 0
                        dcddtau0 = 0
                        dcldtau0 = 0
                        dcmsdtau0 = 0

                        # Traduction Ceasiom -> Theory
                        Ue = u0 * np.cos(
                            trim_aoa
                        )  # *np.cos(aos) as aos = 0 at trim, cos(aos)=1
                        We = u0 * np.sin(
                            trim_aoa
                        )  # *np.cos(aos) as aos = 0 at trim, cos(aos)=1

                        # Dimentionless State Space variables,
                        # In generalised body axes coordinates ,
                        # simplifications: Ue=V0, We=0, sin(Theta_e)=0 cos(Theta_e)=0
                        if thrust_available:  #   If power data
                            X_u = -(2 * cd0 + mach * dcddm0) + 1 / (
                                0.5 * rho * s * a ^ 2
                            ) * dtaudm0  # dtaudm dimensional Thrust derivative at trim conditions, P340 Michael V. Cook
                        else:  #   Glider Mode
                            X_u = -(2 * cd0 + mach * dcddm0)

                        Z_u = -(2 * cl0 + mach * dcldm0)
                        M_u = 0  # Negligible for subsonic conditions  or better with P289 Yechout (cm_u+2cm0)

                        X_w = (cl0 - cd_alpha0)
                        Z_w = -(cl_alpha0 + cd0)
                        M_w = cm_alpha0

                        X_q = dcddqstar0  # Normally almost = 0
                        Z_q = dcldqstar0
                        M_q = -dcmsdqstar0

                        X_dotw = 0  # Negligible
                        Z_dotw = 1 / 3 * M_q / u0 / (
                            xh / mac
                        )  # Thumb rule : M_alpha_dot = 1/3 Mq , ( not true for 747 :caughey P83,M_alpha_dot = 1/6Mq )
                        M_dotw = 1 / 3 * M_q / u0  # Thumb rule : M_alpha_dot = 1/3 Mq

                        # Controls:
                        X_eta = dcddeta0  # To be found from the cpacs file, and defined by the user!
                        Z_eta = dcldeta0  # To be found from the cpacs file, and defined by the user!
                        M_eta = dcmsdeta0  # To be found from the cpacs file, and defined by the user!

                        X_tau = dcddtau0  # To be found from the cpacs file, and defined by the user!
                        Z_tau = dcldtau0  # To be found from the cpacs file, and defined by the user!
                        M_tau = dcmsdtau0  # To be found from the cpacs file, and defined by the user!
                        # -----------------  Traduction Ceasiom -> Theory   END -----------------------------------

                        # Sign check  (Ref: Thomas Yechout Book, P304)
                        check_sign_longi(cd_alpha0, M_w, cl_alpha0, M_dotw,
                                         Z_dotw, M_q, Z_q, M_eta, Z_eta)

                    # Laterl-Directional
                    if lateral_directional_analysis:
                        cml = []  # N
                        cmd = []  # L
                        aos = []
                        aoa = []  # For Ue We
                        cs = []  # For y_v
                        dcsdpstar = []  # y_p
                        dcmddpstar = []  # l_p
                        dcmldpstar = []  # n_p
                        dcsdrstar = []  # y_r
                        dcmldrstar = []  # n_r
                        dcmddrstar = []  # l_r

                        for index in find_index:
                            cml.append(cml_list[index])  # N , N_v
                            cmd.append(cmd_list[index])  # L ,  L_v
                            aos.append(aos_list[index] * np.pi / 180)
                            aoa.append(aoa_list[index])  # For Ue We
                            cs.append(cs_list[index])
                            dcsdpstar.append(dcsdpstar_list[index])  # y_p
                            dcmddpstar.append(dcmddpstar_list[index])  # l_p
                            dcmldpstar.append(dcmldpstar_list[index])  # n_p
                            dcsdrstar.append(dcsdrstar_list[index])  # y_r
                            dcmldrstar.append(dcmldrstar_list[index])  # n_r
                            dcmddrstar.append(dcmddrstar_list[index])  # l_r

                        #Trimm condition calculation
                        # speed derivatives :  y_v / l_v / n_v  /  Must be devided by speed given that the hyp v=Beta*U
                        if len(aos_unic) >= 2:
                            print('Mach : ', mach, '   and idx_mach : ',
                                  idx_mach)
                            cs_beta0 = speed_derivative_at_trim_lat(
                                cs_list, aos_list, aos_unic, idx_alt, idx_mach,
                                aoa_list, idx_trim_before, idx_trim_after,
                                ratio)  # y_v
                            if cs_beta0 == None:
                                cs_beta0 = 0
                                log.warning(
                                    'Not enough data to determine cs_beta (Y_v) at trim condition at Alt = {}, mach = {}, aoa = {}, aos = 0. Assumption: cs_beta = 0'
                                    .format(alt, mach, round(trim_aoa_deg, 2)))
                            cmd_beta0 = speed_derivative_at_trim_lat(
                                cmd_list, aos_list, aos_unic, idx_alt,
                                idx_mach, aoa_list, idx_trim_before,
                                idx_trim_after, ratio)  # l_v
                            if cmd_beta0 == None:
                                cmd_beta0 = 0
                                log.warning(
                                    'Not enough data to determine cmd_beta (L_v) at trim condition at Alt = {}, mach = {}, aoa = {}, aos = 0. Assumption: cmd_beta = 0'
                                    .format(alt, mach, round(trim_aoa_deg, 2)))
                            cml_beta0 = speed_derivative_at_trim_lat(
                                cml_list, aos_list, aos_unic, idx_alt,
                                idx_mach, aoa_list, idx_trim_before,
                                idx_trim_after, ratio)  # n_v
                            if cml_beta0 == None:
                                cml_beta0 = 0
                                log.warning(
                                    'Not enough data to determine cml_beta (N_v) at trim condition at Alt = {}, mach = {}, aoa = {}, aos = 0. Assumption: cml_beta = 0'
                                    .format(alt, mach, round(trim_aoa_deg, 2)))
                        else:
                            cs_beta0 = 0
                            cmd_beta0 = 0
                            cml_beta0 = 0
                            log.warning(
                                'Not enough data to determine cs_beta (Y_v), cmd_beta (L_v) and cml_beta (N_v) at trim condition at Alt = {}, mach = {}, aoa = {}, aos = 0. Assumption: cs_beta = cmd_beta = cml_beta = 0'
                                .format(alt, mach, round(trim_aoa_deg, 2)))

                        dcsdpstar0 = interpolation(dcsdpstar, idx_trim_before,
                                                   idx_trim_after,
                                                   ratio)  # y_p
                        dcmddpstar0 = interpolation(dcmddpstar,
                                                    idx_trim_before,
                                                    idx_trim_after,
                                                    ratio)  # l_p
                        dcmldpstar0 = interpolation(dcmldpstar,
                                                    idx_trim_before,
                                                    idx_trim_after,
                                                    ratio)  # n_p

                        dcsdrstar0 = interpolation(dcsdrstar, idx_trim_before,
                                                   idx_trim_after,
                                                   ratio)  # y_r
                        dcmldrstar0 = interpolation(dcmldrstar,
                                                    idx_trim_before,
                                                    idx_trim_after,
                                                    ratio)  # n_r
                        dcmddrstar0 = interpolation(dcmddrstar,
                                                    idx_trim_before,
                                                    idx_trim_after,
                                                    ratio)  # l_r

                        # TODO: calculate that and find in the cpacs
                        dcsdxi0 = 0
                        dcmddxi0 = 0
                        dcmldxi0 = 0
                        dcsdzeta0 = 0
                        dcmddzeta0 = 0
                        dcmldzeta0 = 0

                        # Traduction Ceasiom -> Theory
                        Y_v = cs_beta0
                        L_v = cmd_beta0
                        N_v = cml_beta0

                        Y_p = -dcsdpstar0 * mac / b
                        L_p = -dcmddpstar0 * mac / b
                        N_p = dcmldpstar0 * mac / b

                        Y_r = dcsdrstar0 * mac / b
                        N_r = -dcmldrstar0 * mac / b  # mac/b :Because coefficients in ceasiom are nondimensionalised by the mac instead of the span
                        L_r = dcmddrstar0 * mac / b

                        # Controls:
                        # Ailerons
                        Y_xi = dcsdxi0  # To be found from the cpacs file, and defined by the user!
                        L_xi = dcmddxi0  # To be found from the cpacs file, and defined by the user!
                        N_xi = dcmldxi0  # To be found from the cpacs file, and defined by the user!
                        # Rudder
                        Y_zeta = dcsdzeta0  # To be found from the cpacs file, and defined by the user!
                        L_zeta = dcmddzeta0  # To be found from the cpacs file, and defined by the user!
                        N_zeta = dcmldzeta0  # To be found from the cpacs file, and defined by the user!

                        Ue = u0 * np.cos(
                            trim_aoa
                        )  # *np.cos(aos) as aos = 0 at trim, cos(aos)=1
                        We = u0 * np.sin(
                            trim_aoa
                        )  # *np.cos(aos) as aos = 0 at trim, cos(aos)=1

                        # Sign check  (Ref: Thomas Yechout Book, P304)
                        check_sign_lat(Y_v, L_v, N_v, Y_p, L_p, Y_r, L_r, N_r,
                                       L_xi, Y_zeta, L_zeta, N_zeta)

                    if trim_aoa:
                        for angles in flight_path_angle:
                            theta_e = angles + trim_aoa

                            if longitudinal_analysis:
                                (A_longi, B_longi, x_u,z_u,m_u,x_w,z_w,m_w, x_q,z_q,m_q,x_theta,z_theta,m_theta,x_eta,z_eta,m_eta, x_tau,z_tau,m_tau)\
                                                                    = concise_derivative_longi(X_u,Z_u,M_u,X_w,Z_w,M_w,\
                                                                    X_q,Z_q,M_q,X_dotw,Z_dotw,M_dotw,X_eta,Z_eta,M_eta,\
                                                                    X_tau,Z_tau,M_tau, g, theta_e, u0,We,Ue,mac,m_adim,i_yy)

                                C_longi = np.identity(4)
                                D_longi = np.zeros((4, 2))
                                # Identify longitudinal roots
                                if longi_root_identification(
                                        A_longi
                                )[0] == None:  # If longitudinal root not complex conjugate raise warning and plot roots
                                    eg_value_longi = longi_root_identification(
                                        A_longi)[1]
                                    log.warning(
                                        'Longi : charcateristic equation  roots are not complex conjugate : {}'
                                        .format(eg_value_longi))
                                    legend = [
                                        'Root1', 'Root2', 'Root3', 'Root4'
                                    ]
                                    plot_title = 'S-plane longitudinal characteristic equation roots at (Alt = {}, Mach= {}, trimed at aoa = {}°)'.format(
                                        alt, mach, trim_aoa)
                                    plot_splane(eg_value_longi, plot_title,
                                                legend, show_plots, save_plots)
                                else:  # Longitudinal roots are complex conjugate
                                    (sp1, sp2, ph1, ph2, eg_value_longi , eg_vector_longi, eg_vector_longi_magnitude)\
                                            = longi_root_identification(A_longi)
                                    legend = ['sp1', 'sp2', 'ph1', 'ph2']
                                    plot_title = 'S-plane longitudinal characteristic equation roots at (Alt = {}, Mach= {}, trimed at aoa = {}°)'.format(
                                        alt, mach, trim_aoa)
                                    plot_splane(eg_value_longi, plot_title,
                                                legend, show_plots, save_plots)

                                    # Modes parameters : damping ratio, frequence, CAP, time tou double amplitude
                                    Z_w_dimensional = Z_w * (
                                        0.5 * rho * s * u0**2
                                    )  # Z_w* (0.5*rho*s*u0**2)  is the dimensional form of Z_w,   Z_w = -(cl_alpha0 + cd0) P312 Yechout
                                    z_alpha = Z_w_dimensional * u0 / m  # alpha = w/u0 hence,   z_alpha =  Z_w_dimensional * u0      [Newton/rad/Kg :   m/s^2 /rad]
                                    load_factor = -z_alpha / g  #  number of g's/rad (1g/rad 2g/rad  3g/rad)
                                    (sp_freq, sp_damp, sp_cap, ph_freq, ph_damp, ph_t2)\
                                            =  longi_mode_characteristic(sp1,sp2,ph1,ph2,load_factor)

                                    # Rating
                                    sp_damp_rate = short_period_damping_rating(
                                        aircraft_class, sp_damp)
                                    sp_freq_rate = short_period_frequency_rating(
                                        flight_phase, aircraft_class, sp_freq,
                                        load_factor)
                                    # Plot SP freq vs Load factor
                                    legend = 'Alt = {}, Mach= {}, trim aoa = {}°'.format(
                                        alt, mach, trim_aoa)
                                    if flight_phase == 'A':
                                        plot_sp_level_a([load_factor],
                                                        [sp_freq], legend,
                                                        show_plots, save_plots)
                                    elif flight_phase == 'B':
                                        plot_sp_level_b(
                                            x_axis, y_axis, legend, show_plots,
                                            save_plots)
                                    else:
                                        plot_sp_level_c(
                                            x_axis, y_axis, legend, show_plots,
                                            save_plots)
                                    sp_cap_rate = cap_rating(
                                        flight_phase, sp_cap, sp_damp)
                                    ph_rate = phugoid_rating(ph_damp, ph_t2)
                                    # Raise warning if unstable mode in the log file
                                    if sp_damp_rate == None:
                                        log.warning(
                                            'ShortPeriod UNstable at Alt = {}, Mach = {} , due to DampRatio = {} '
                                            .format(alt, mach,
                                                    round(sp_damp, 4)))
                                    if sp_freq_rate == None:
                                        log.warning(
                                            'ShortPeriod UNstable at Alt = {}, Mach = {} , due to UnDampedFreq = {} rad/s '
                                            .format(alt, mach,
                                                    round(sp_freq, 4)))
                                    if sp_cap_rate == None:
                                        log.warning(
                                            'ShortPeriod UNstable at Alt = {}, Mach = {} , with CAP evaluation, DampRatio = {} , CAP = {} '
                                            .format(alt, mach,
                                                    round(sp_damp, 4),
                                                    round(sp_cap, 4)))
                                    if ph_rate == None:
                                        log.warning(
                                            'Phugoid UNstable at Alt = {}, Mach = {} , DampRatio = {} , UnDampedFreq = {} rad/s'
                                            .format(alt, mach,
                                                    round(ph_damp, 4),
                                                    round(ph_freq, 4)))

                                    # TODO
                                    # Compute numerator TF for (Alt, mach, flight_path_angle, aoa_trim, aos=0

                            if lateral_directional_analysis:
                                (A_direc, B_direc,y_v,l_v,n_v,y_p,y_phi,y_psi,l_p,l_phi,l_psi,n_p,y_r,l_r,n_r,n_phi,n_psi, y_xi,l_xi,n_xi, y_zeta,l_zeta,n_zeta)\
                                    = concise_derivative_lat(Y_v,L_v,N_v,Y_p,L_p,N_p,Y_r,L_r,N_r,\
                                                                            Y_xi,L_xi,N_xi, Y_zeta,L_zeta,N_zeta,\
                                                                            g, b, theta_e, u0,We,Ue,m_adim,i_xx,i_zz,i_xz )

                                C_direc = np.identity(5)
                                D_direc = np.zeros((5, 2))

                                if direc_root_identification(
                                        A_direc
                                )[0] == None:  # Lateral-directional roots are correctly identified
                                    eg_value_direc = direc_root_identification(
                                        A_direc)[1]
                                    print(
                                        'Lat-Dir : charcateristic equation  roots are not complex conjugate : {}'
                                        .format(eg_value_direc))
                                    legend = [
                                        'Root1', 'Root2', 'Root3', 'Root4'
                                    ]
                                    plot_title = 'S-plane lateral characteristic equation roots at (Alt = {}, Mach= {}, trimed at aoa = {}°)'.format(
                                        alt, mach, trim_aoa)
                                    plot_splane(eg_value_direc, plot_title,
                                                legend, show_plots, save_plots)
                                else:  # Lateral-directional roots are correctly identified
                                    (roll, spiral, dr1, dr2, eg_value_direc, eg_vector_direc, eg_vector_direc_magnitude)\
                                        = direc_root_identification(A_direc)
                                    legend = ['roll', 'spiral', 'dr1', 'dr2']
                                    plot_title = 'S-plane lateralcharacteristic equation roots at (Alt = {}, Mach= {}, trimed at aoa = {}°)'.format(
                                        alt, mach, trim_aoa)
                                    plot_splane(eg_value_direc, plot_title,
                                                legend, show_plots, save_plots)
                                    (roll_timecst, spiral_timecst, spiral_t2,
                                     dr_freq, dr_damp,
                                     dr_damp_freq) = direc_mode_characteristic(
                                         roll, spiral, dr1, dr2)

                                    # Rating
                                    roll_rate = roll_rating(
                                        flight_phase, aircraft_class,
                                        roll_timecst)
                                    spiral_rate = spiral_rating(
                                        flight_phase, spiral_timecst,
                                        spiral_t2)
                                    dr_rate = dutch_roll_rating(
                                        flight_phase, aircraft_class, dr_damp,
                                        dr_freq, dr_damp_freq)

                                    # Raise warning in the log file if unstable mode
                                    if roll_rate == None:
                                        log.warning(
                                            'Roll mode UNstable at Alt = {}, Mach = {} , due to roll root = {}, roll time contatant = {} s'
                                            .format(alt, mach,
                                                    round(roll_root, 4),
                                                    round(roll_timecst, 4)))
                                    if spiral_rate == None:
                                        log.warning(
                                            'Spiral mode UNstable at Alt = {}, Mach = {} , spiral root = {}, time_double_ampl = {}'
                                            .format(alt, mach,
                                                    round(spiral_root, 4),
                                                    round(spiral_t2, 4)))
                                    if dr_rate == None:
                                        log.warning(
                                            'Dutch Roll UNstable at Alt = {}, Mach = {} , Damping Ratio = {} , frequency = {} rad/s '
                                            .format(alt, mach,
                                                    round(dr_damp, 4),
                                                    round(dr_freq, 4)))
Ejemplo n.º 16
0
def test_static_stability_analysis():
    """Test function 'staticStabilityAnalysis' """

    MODULE_DIR = os.path.dirname(os.path.abspath(__file__))
    cpacs_path = os.path.join(MODULE_DIR,'ToolInput','CPACSTestStability.xml')
    cpacs_out_path = os.path.join(MODULE_DIR,'ToolOutput', 'CPACSTestStability.xml')
    csv_path = MODULE_DIR + '/ToolInput/csvtest.csv'

    tixi = cpsf.open_tixi(cpacs_path)
    # Get Aeromap UID list
    # uid_list = apmf.get_aeromap_uid_list(tixi)
    # aeromap_uid = uid_list[0]
    # # Import aeromap from the CSV to the xml
    # apmf.aeromap_from_csv(tixi, aeromap_uid, csv_path)
    # cpsf.close_tixi(tixi, cpacs_out_path)

    # Make the static stability analysis, on the modified xml file
    static_stability_analysis(cpacs_path, cpacs_out_path)

    # Assert that all error messages are present
    #log_path = os.path.join(LIB_DIR,'StabilityStatic','staticstability.log')
    # graph_cruising = False
    # errors = ''
    # #Open  log file
    # with open(log_path, "r") as f :
    #     # For each line in the log file
    #     for line in f :
    #         # if the info insureing that the graph of cruising aoa VS mach has been generated.
    #         if 'graph : cruising aoa vs mach genrated' in line :
    #             graph_cruising = True
    #         # if 'warning' or 'error ' is in line
    #         if  'ERROR' in line :
    #             # check if error type (altitude) is in line
    #             errors += line
    # TODO: remove, not good to test with the logfile
    # Assert that all error type happend only once.
    #assert graph_cruising == True

    tixi = cpsf.open_tixi(cpacs_out_path)
    static_xpath = '/cpacs/toolspecific/CEASIOMpy/stability/static'
    long_static_stable = cpsf.get_value(tixi, static_xpath+'/results/longitudinalStaticStable')
    lat_static_stable = cpsf.get_value(tixi, static_xpath+'/results/lateralStaticStable')
    dir_static_stable = cpsf.get_value(tixi, static_xpath+'/results/directionnalStaticStable')

    assert long_static_stable
    assert lat_static_stable
    assert not dir_static_stable

    trim_longi_alt = cpsf.get_value(tixi, static_xpath+'/trimConditions/longitudinal/altitude')
    trim_longi_mach = cpsf.get_value(tixi, static_xpath+'/trimConditions/longitudinal/machNumber')
    trim_longi_aoa = cpsf.get_value(tixi, static_xpath+'/trimConditions/longitudinal/angleOfAttack')
    trim_longi_aos = cpsf.get_value(tixi, static_xpath+'/trimConditions/longitudinal/angleOfSideslip')

    assert trim_longi_alt == 1400
    assert trim_longi_mach == 0.6
    assert trim_longi_aoa == 3.25803
    assert trim_longi_aos == 0

    trim_dir_alt = cpsf.get_string_vector(tixi, static_xpath+'/trimConditions/directional/altitude')
    trim_dir_mach = cpsf.get_string_vector(tixi, static_xpath+'/trimConditions/directional/machNumber')
    trim_dir_aoa = cpsf.get_string_vector(tixi, static_xpath+'/trimConditions/directional/angleOfAttack')
    trim_dir_aos = cpsf.get_string_vector(tixi, static_xpath+'/trimConditions/directional/angleOfSideslip')

    assert trim_dir_alt == ['2400','2500','2600','2700']
    assert trim_dir_mach == ['0.6','0.5','0.5','0.5']
    assert trim_dir_aoa == ['1','2','4','2.5']
    assert trim_dir_aos == ['0','0','0','0']

    cpsf.close_tixi(tixi, cpacs_out_path)
Ejemplo n.º 17
0
    create_om_problem(prob)

    ## Run the model ##
    prob.run_driver()

    generate_results(prob)


if __name__ == '__main__':

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

    log.info('Impose the aeromap of the optimisation to all other modules')

    cpacs_path = mif.get_toolinput_file_path('Optimisation')
    cpacs_out_path = mif.get_tooloutput_file_path('Optimisation')
    tixi = cpsf.open_tixi(cpacs_path)

    try:
        am_uid = cpsf.get_value(tixi, opf.OPTIM_XPATH + 'aeroMapUID')
    except:
        raise ValueError('No aeromap found in the file')

    log.info('Aeromap ' + am_uid + ' will be used')

    #opf.update_am_path(tixi, am_uid)

    cpsf.close_tixi(tixi, cpacs_out_path)

    log.info('----- End of ' + os.path.basename(__file__) + ' -----')
Ejemplo n.º 18
0
    def __init__(self, tabs, tixi, module_name):
        """Tab class

        Note:
            A tab will only be created if the module actually has
            any settings which are to be shown

        Args:
            tabs (TODO): TODO
            tixi (handle): Tixi handle
            module_name (str): String of the module name for which a tab is to be created
        """

        self.var_dict = {}
        self.group_dict = {}

        self.module_name = module_name
        self.tabs = tabs
        self.tixi = tixi
        self.tab = tk.Frame(tabs, borderwidth=1)
        tabs.add(self.tab, text=module_name)

        # Get GUI dict from specs
        specs = mif.get_specs_for_module(module_name)

        self.gui_dict = specs.cpacs_inout.get_gui_dict()

        #canvas has replaced self.tab in the following lines
        space_label = tk.Label(self.tab, text=' ')
        space_label.grid(column=0, row=0)

        row_pos = 1

        for key, (name, def_value, dtype, unit, xpath, description, group) in self.gui_dict.items():
            # Create a LabelFrame for new groupe
            if group:
                if not group in self.group_dict:
                    self.labelframe = tk.LabelFrame(self.tab, text=group)
                    self.labelframe.grid(column=0, row=row_pos, columnspan=3,sticky= tk.W, padx=5, pady=5)
                    self.group_dict[group] = self.labelframe
                parent = self.group_dict[group]
            else:  # if not a group, use tab as parent
                parent = self.tab

            # Name label for variable
            if (name is not '__AEROMAP_SELECTION' and name is not '__AEROMAP_CHECHBOX'):
                self.name_label = tk.Label(parent, text= name)
                self.name_label.grid(column=0, row=row_pos, sticky= tk.W, padx=5, pady=5)

            # Type and Value
            if dtype is bool:
                self.var_dict[key] = tk.BooleanVar()
                value = cpsf.get_value_or_default(self.tixi,xpath,def_value)
                self.var_dict[key].set(value)
                bool_entry = tk.Checkbutton(parent, text='', variable=self.var_dict[key])
                bool_entry.grid(column=1, row=row_pos, padx=5, pady=5)

            elif dtype is int:
                value = cpsf.get_value_or_default(self.tixi, xpath, def_value)
                self.var_dict[key] = tk.IntVar()
                self.var_dict[key].set(int(value))
                value_entry = tk.Entry(parent, bd=2, textvariable=self.var_dict[key])
                value_entry.grid(column=1, row=row_pos, padx=5, pady=5)

            elif dtype is float:
                value = cpsf.get_value_or_default(self.tixi, xpath, def_value)
                self.var_dict[key] = tk.DoubleVar()
                self.var_dict[key].set(value)
                value_entry = tk.Entry(parent, bd=2, textvariable=self.var_dict[key])
                value_entry.grid(column=1, row=row_pos, padx=5, pady=5)

            elif dtype is 'pathtype':

                value = cpsf.get_value_or_default(self.tixi,xpath,def_value)
                self.var_dict[key] = tk.StringVar()
                self.var_dict[key].set(value)
                value_entry = tk.Entry(parent, textvariable=self.var_dict[key])
                value_entry.grid(column=1, row=row_pos, padx=5, pady=5)

                self.key = key
                self.browse_button = tk.Button(parent, text="Browse", command=self._browse_file)
                self.browse_button.grid(column=2, row=row_pos, padx=5, pady=5)


            elif dtype is list:
                if name == '__AEROMAP_SELECTION':

                    # Get the list of all AeroMaps
                    self.aeromap_uid_list = apm.get_aeromap_uid_list(self.tixi)

                    # Try to get the pre-selected AeroMap from the xpath
                    try:
                        selected_aeromap = cpsf.get_value(self.tixi,xpath)
                        selected_aeromap_index = self.aeromap_uid_list.index(selected_aeromap)
                    except:
                        selected_aeromap = ''
                        selected_aeromap_index = 0

                    self.labelframe = tk.LabelFrame(parent, text='Choose an AeroMap')
                    self.labelframe.grid(column=0, row=row_pos, columnspan=3, sticky=tk.W, padx=5, pady=5)

                    # The Combobox is directly use as the varaible
                    self.var_dict[key] = ttk.Combobox(self.labelframe, values=self.aeromap_uid_list)
                    self.var_dict[key].current(selected_aeromap_index)
                    self.var_dict[key].grid(column=1, row=row_pos, padx=5, pady=5)


                elif name == '__AEROMAP_CHECHBOX':

                    # Just to find back the name when data are saved
                    self.var_dict[key] = None
                    # __AEROMAP_CHECHBOX is a bit different, data are saved in their own dictionary
                    self.aeromap_var_dict = {}

                    # Get the list of all AeroMaps
                    self.aeromap_uid_list = apm.get_aeromap_uid_list(self.tixi)
                    self.labelframe = tk.LabelFrame(parent, text='Selecte AeroMap(s)')
                    self.labelframe.grid(column=0, row=row_pos, columnspan=3, sticky=tk.W, padx=5, pady=5)

                    # Try to get pre-selected AeroMaps from the xpath
                    try:
                        selected_aeromap = cpsf.get_string_vector(self.tixi,xpath)
                    except:
                        selected_aeromap = ''

                    # Create one checkbox for each AeroMap
                    for aeromap in self.aeromap_uid_list:
                        self.aeromap_var_dict[aeromap] = tk.BooleanVar()

                        #if aeromap in selected_aeromap:
                        # For now, set all to True
                        self.aeromap_var_dict[aeromap].set(True)

                        aeromap_entry = tk.Checkbutton(self.labelframe,text=aeromap,variable=self.aeromap_var_dict[aeromap])
                        aeromap_entry.pack()#side=tk.TOP, anchor='w')

                else: # Other kind of list (not aeroMap)

                    # 'def_value' will be the list of possibilies in this case

                    # Try to get the pre-selected AeroMap from the xpath
                    try: # TODO Should be retested...
                        selected_value = cpsf.get_value(self.tixi,xpath)
                        selected_value_index = def_value.index(selected_value)
                    except:
                        selected_value = ''
                        selected_value_index = 0

                    # The Combobox is directly use as the varaible
                    self.var_dict[key] = ttk.Combobox(parent, values=def_value)
                    self.var_dict[key].current(selected_value_index)
                    self.var_dict[key].grid(column=1, row=row_pos, padx=5, pady=5)

            else:
                value = cpsf.get_value_or_default(self.tixi,xpath,def_value)
                self.var_dict[key] = tk.StringVar()
                self.var_dict[key].set(value)
                value_entry = tk.Entry(parent, textvariable=self.var_dict[key])
                value_entry.grid(column=1, row=row_pos, padx=5, pady=5)

            # Units
            if unit and unit != '1':
                unit_label = tk.Label(parent, text=pretty_unit(unit))
                unit_label.grid(column=2, row=row_pos, padx=5, pady=5)

            row_pos += 1
Ejemplo n.º 19
0
def aeromap_case_gen(modules):
    """
    Generate a CSV file containing a dataset generated with aeromap parameters
    only.

    Args:
        modules (lst) : list of modules to execute.

    Returns:
        file (str) : Path to CSV file.

    """
    file = MODULE_DIR + '/Aeromap_generated.csv'
    infile = mi.get_toolinput_file_path('PredictiveTool')
    outfile = mi.get_tooloutput_file_path('PredictiveTool')

    tixi = cpsf.open_tixi(infile)

    # Inputs
    alt = [0, 0]
    mach = [0.5, 0.5]
    aoa = [-10, 10]
    aos = [0, 0]
    nt = 100
    bounds = np.array([alt, mach, aoa, aos])
    # Sort criterion : ‘center’, ‘maximin’, ‘centermaximin’, ‘correlation’
    crit = 'corr'

    # Generate sample points, LHS or FullFactorial
    sampling = smp.LHS(xlimits=bounds, criterion=crit)
    xd = sampling(nt)
    xd = xd.transpose()
    # Delete the other aeromaps... maybe conserve them ?
    for uid in apmf.get_aeromap_uid_list(tixi):
        apmf.delete_aeromap(tixi, uid)

    # Create new aeromap
    aeromap_uid = 'DoE_Aeromap'
    am_xpath = tls.get_aeromap_path(modules)
    apmf.create_empty_aeromap(tixi, aeromap_uid)
    cpsf.add_string_vector(tixi, am_xpath + '/aeroMapUID', [aeromap_uid])

    # Add parameters to aeromap
    Param = apmf.AeroCoefficient()
    for i in range(0, xd.shape[1]):
        Param.add_param_point(xd[0][i], xd[1][i], xd[2][i], xd[3][i])
    apmf.save_parameters(tixi, aeromap_uid, Param)
    cpsf.close_tixi(tixi, infile)

    wkf.run_subworkflow(modules, cpacs_path_in=infile, cpacs_path_out=outfile)

    # Get Aerocoefficient
    tixi = cpsf.open_tixi(outfile)
    am_xpath = tls.get_aeromap_path(modules)
    aeromap_uid = cpsf.get_value(tixi, am_xpath + '/aeroMapUID')
    AeroCoefficient = apmf.get_aeromap(tixi, aeromap_uid)
    cpsf.close_tixi(tixi, outfile)

    dct = AeroCoefficient.to_dict()

    # Write to CSV
    df = pd.DataFrame(dct)
    df = df.transpose()
    var_type = [
        'obj' if i in objectives else
        'des' if i in ['alt', 'mach', 'aoa', 'aos'] else 'const'
        for i in df.index
    ]
    df.insert(0, 'type', var_type)
    df.to_csv(file, index=True)
    return file
Ejemplo n.º 20
0
    file = 'Aeromap_generated100_points.csv'
    # file = '_Variable_history.csv'
    aeromap = True
    modules = ['WeightConventional', 'PyTornado']

    if os.path.isfile(file):
        log.info('File found, will be used to generate the model')
    elif aeromap and not os.path.isfile(file):
        log.info('Specific aeromap case')
        modules.insert(0, 'SettingsGUI')
        file = aeromap_case_gen(modules)
    else:
        log.info('No file found, running DoE')

        wkf.copy_module_to_module('PredictiveTool', 'in', 'Optimisation', 'in')
        opt.routine_setup(modules, 'DoE')
        wkf.copy_module_to_module('Optimisation', 'out', 'PredictiveTool',
                                  'in')

        cpacs_path = mi.get_tooloutput_file_path('Optimisation')
        tixi = cpsf.open_tixi(cpacs_path)
        file = cpsf.get_value(tixi,
                              opf.OPTWKDIR_XPATH) + '/Variable_history.csv'
        objectives = cpsf.get_value(tixi, opf.OPTIM_XPATH + '/objectives')

    xd, yd = extract_data_set(file)

    sm = create_model(xd, yd)

    log.info('End of Predictive tool')
Ejemplo n.º 21
0
def create_config(cpacs_path, cpacs_out_path, su2_mesh_path,
                  config_output_path):
    """ Function to create configuration file for SU2 calculation

    Function 'create_config' create an SU2 configuration file from SU2 mesh data
    (marker) and CPACS file specific related parameter (/toolSpecific).
    For all other infomation the value from the default SU2 configuration file
    are used. A new configuration file will be saved in
    /ToolOutput/ToolOutput.cfg

    Source:
       * SU2 configuration file  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
        su2_mesh_path (str): Path to SU2 mesh
        config_output_path (str): Path to the output configuration file

    """

    DEFAULT_CONFIG_PATH = MODULE_DIR + '/files/DefaultConfig_v6.cfg'

    # Get value from CPACS
    tixi = open_tixi(cpacs_path)

    su2_xpath = '/cpacs/toolspecific/CEASIOMpy/aerodynamics/su2'

    # Reference values
    ref_xpath = '/cpacs/vehicles/aircraft/model/reference'
    ref_len = get_value(tixi, ref_xpath + '/length')
    ref_area = get_value(tixi, ref_xpath + '/area')

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

    if fixed_cl == 'NO':
        # Get value from the aeroMap (1 point)
        active_aeroMap_xpath = su2_xpath + '/aeroMapUID'
        aeroMap_uid = get_value(tixi, active_aeroMap_xpath)
        aeroMap_path = tixi.uIDGetXPath(aeroMap_uid)
        apm_path = aeroMap_path + '/aeroPerformanceMap'

        #State = get_states(tixi,apm_path)

        #alt = State.alt_list
        alt = get_value(tixi, apm_path + '/altitude')
        mach = get_value(tixi, apm_path + '/machNumber')
        aoa = get_value(tixi, apm_path + '/angleOfAttack')
        aos = get_value(tixi, apm_path + '/angleOfSideslip')

    else:
        range_xpath = '/cpacs/toolspecific/CEASIOMpy/ranges'
        cruise_alt_xpath = range_xpath + '/cruiseAltitude'
        cruise_mach_xpath = range_xpath + '/cruiseMach'

        # value corresponding to fix CL calulation
        aoa = 0.0  # Will not be used
        aos = 0.0
        tixi, mach = get_value_or_default(tixi, cruise_mach_xpath, 0.78)
        tixi, alt = get_value_or_default(tixi, cruise_alt_xpath, 12000)

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

    # Settings
    settings_xpath = '/cpacs/toolspecific/CEASIOMpy/aerodynamics/su2/settings'
    max_iter_xpath = settings_xpath + '/maxIter'
    cfl_nb_xpath = settings_xpath + '/cflNumber'
    mg_level_xpath = settings_xpath + '/multigridLevel'

    tixi, max_iter = get_value_or_default(tixi, max_iter_xpath, 200)
    tixi, cfl_nb = get_value_or_default(tixi, cfl_nb_xpath, 1.0)
    tixi, mg_level = get_value_or_default(tixi, mg_level_xpath, 3)

    # Mesh Marker
    bc_wall_xpath = '/cpacs/toolspecific/CEASIOMpy/aerodynamics/su2/boundaryConditions/wall'

    bc_wall_list = get_mesh_marker(su2_mesh_path)
    tixi = create_branch(tixi, bc_wall_xpath)
    bc_wall_str = ';'.join(bc_wall_list)
    tixi.updateTextElement(bc_wall_xpath, bc_wall_str)

    close_tixi(tixi, cpacs_out_path)

    # Open default configuration file
    try:
        config_file_object = open(DEFAULT_CONFIG_PATH, 'r')
        config_file_lines = config_file_object.readlines()
        config_file_object.close()
        log.info('Default configuration file has been found and read')
    except Exception:
        log.exception('Problem to open or read default configuration file')

    # Create a dictionary with all the parameters from the default config file
    config_dict = {}
    for line in config_file_lines:
        if '=' in line:
            (key, val) = line.split('=')
            if val.endswith('\n'):
                val = val[:-1]
            config_dict[key] = val

    config_dict_modif = config_dict

    # General parmeters
    config_dict_modif['MESH_FILENAME'] = su2_mesh_path

    config_dict_modif['REF_LENGTH'] = ref_len
    config_dict_modif['REF_AREA'] = ref_area

    # Settings
    config_dict_modif['EXT_ITER'] = int(max_iter)
    config_dict_modif['CFL_NUMBER'] = cfl_nb
    config_dict_modif['MGLEVEL'] = int(mg_level)

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

    # If calculation at CL fix (AOA will not be taken into account)
    config_dict_modif['FIXED_CL_MODE'] = fixed_cl
    config_dict_modif['TARGET_CL'] = target_cl
    config_dict_modif['DCL_DALPHA'] = '0.1'
    config_dict_modif['UPDATE_ALPHA'] = '8'
    config_dict_modif['ITER_DCL_DALPHA'] = '80'

    # Mesh Marker
    bc_wall_str = '(' + ','.join(bc_wall_list) + ')'
    config_dict_modif['MARKER_EULER'] = bc_wall_str
    config_dict_modif['MARKER_FAR'] = ' (Farfield)'
    config_dict_modif['MARKER_SYM'] = ' (0)'
    config_dict_modif['MARKER_PLOTTING'] = bc_wall_str
    config_dict_modif['MARKER_MONITORING'] = bc_wall_str
    config_dict_modif['MARKER_MOVING'] = bc_wall_str

    # Change value if needed or add new parameters in the config file
    for key, value in config_dict_modif.items():
        line_nb = 0
        # Double loop! There is probably a possibility to do something better.
        for i, line in enumerate(config_file_lines):
            if '=' in line:
                (key_def, val_def) = line.split('=')
                if key == key_def:
                    line_nb = i
                    break
        if not line_nb:
            config_file_lines.append(str(key) + ' = ' + str(value) + '\n')
        else:
            if val_def != config_dict_modif[key]:
                config_file_lines[line_nb] = str(key) + ' = ' \
                                           + str(config_dict_modif[key]) + '\n'

    config_file_new = open(config_output_path, 'w')
    config_file_new.writelines(config_file_lines)
    config_file_new.close()
    log.info('ToolOutput.cfg has been written in /ToolOutput.')
Ejemplo n.º 22
0
def get_su2_results(cpacs_path, cpacs_out_path):
    """ Function to write SU2 results in a CPACS file.

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

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

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

    """

    tixi = open_tixi(cpacs_path)

    su2_xpath = '/cpacs/toolspecific/CEASIOMpy/aerodynamics/su2'
    tixi = save_timestamp(tixi, su2_xpath)

    # Get and save Wetted area
    wetted_area = get_wetted_area()
    wetted_area_xpath = '/cpacs/toolspecific/CEASIOMpy/geometry/analysis/wettedArea'
    tixi = create_branch(tixi, wetted_area_xpath)
    tixi.updateDoubleElement(wetted_area_xpath, wetted_area, '%g')

    # Get and save CL/CD ratio
    force_path = MODULE_DIR + '/ToolOutput/forces_breakdown.dat'  # TODO: global ?
    cl_cd = get_efficiency(force_path)
    lDRatio_xpath = '/cpacs/toolspecific/CEASIOMpy/ranges/lDRatio'  # TODO: probalby change xpath and name

    tixi = create_branch(tixi, lDRatio_xpath)
    tixi.updateDoubleElement(lDRatio_xpath, cl_cd, '%g')

    # Save aeroPerformanceMap
    active_aeroMap_xpath = '/cpacs/toolspecific/CEASIOMpy/aerodynamics/su2/aeroMapUID'
    aeroMap_uid = get_value(tixi, active_aeroMap_xpath)
    aeroMap_path = tixi.uIDGetXPath(aeroMap_uid)
    apm_xpath = aeroMap_path + '/aeroPerformanceMap'

    Coef = AeroCoefficient()

    with open(force_path) as f:
        for line in f.readlines():
            if 'Total CL:' in line:
                Coef.cl = float(line.split(':')[1].split('|')[0])
            if 'Total CD:' in line:
                Coef.cd = float(line.split(':')[1].split('|')[0])
            if 'Total CSF:' in line:
                Coef.cs = float(line.split(':')[1].split('|')[0])
            # TODO: Check which axis name corespond to waht: cml, cmd, cms
            if 'Total CMx:' in line:
                Coef.cml = float(line.split(':')[1].split('|')[0])
            if 'Total CMy:' in line:
                Coef.cmd = float(line.split(':')[1].split('|')[0])
            if 'Total CMz:' in line:
                Coef.cms = float(line.split(':')[1].split('|')[0])

    tixi = save_aero_coef(tixi, apm_xpath, Coef)

    # Not finished yet

    close_tixi(tixi, cpacs_out_path)
Ejemplo n.º 23
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)
Ejemplo n.º 24
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)
Ejemplo n.º 25
0
def static_stability_analysis(cpacs_path, cpacs_out_path):
    """Function to analyse a full Aeromap

    Function 'static_stability_analysis' analyses longitudinal static static
    stability and directionnal static.

    Args:
        cpacs_path (str): Path to CPACS file
        cpacs_out_path (str):Path to CPACS output file
        plot (boolean): Choise to plot graph or not

    Returns:
        *   Adrvertisements certifying if the aircraft is stable or Not
        *   In case of longitudinal static UNstability or unvalid test on data:
                -	Plot cms VS aoa for constant Alt, Mach and different aos
                -	Plot cms VS aoa for const alt and aos=0 and different mach
                -	plot cms VS aoa for constant mach, aos=0 and different altitudes
        *  In case of directionnal static UNstability or unvalid test on data:
                -	Pcot cml VS aos for constant Alt, Mach and different aoa
                -	Plot cml VS aos for const alt and aoa and different mach
                -	plot cml VS aos for constant mach, AOA and different altitudes
        *  Plot one graph of  cruising angles of attack for different mach and altitudes

    Make the following tests:            (To put in the documentation)
        *   Check the CPACS path
        *   For longitudinal static stability analysis:
                -   If there is more than one angle of attack for a given altitude, mach, aos
                -   If cml values are only zeros for a given altitude, mach, aos
                -   If there one aoa value which is repeated for a given altitude, mach, aos
        *   For directionnal static stability analysis:
                -   If there is more than one angle of sideslip for a given altitude, mach, aoa
                -   If cms values are only zeros for a given altitude, mach, aoa
                -   If there one aos value which is repeated for a given altitude, mach, aoa
    """

    # TODO: add as CPACS option
    plot_for_different_mach = False  # To check Mach influence
    plot_for_different_alt = False  # To check Altitude influence

    tixi = cpsf.open_tixi(cpacs_path)

    # Get aeromap uid
    aeromap_uid = cpsf.get_value(tixi, STATIC_ANALYSIS_XPATH + '/aeroMapUid')
    log.info('The following aeroMap will be analysed: ' + aeromap_uid)

    show_plots = cpsf.get_value_or_default(
        tixi, STATIC_ANALYSIS_XPATH + '/showPlots', False)
    save_plots = cpsf.get_value_or_default(
        tixi, STATIC_ANALYSIS_XPATH + '/savePlots', False)

    # Aircraft mass configuration
    selected_mass_config_xpath = STATIC_ANALYSIS_XPATH + '/massConfiguration'
    mass_config = cpsf.get_value(tixi, selected_mass_config_xpath)
    # TODO: use get value or default instead and deal with not mass config
    log.info('The aircraft mass configuration used for analysis is: ' +
             mass_config)

    model_xpath = '/cpacs/vehicles/aircraft/model'
    masses_location_xpath = model_xpath + '/analyses/massBreakdown/designMasses'
    mass_config_xpath = masses_location_xpath + '/' + mass_config
    if tixi.checkElement(mass_config_xpath):
        mass_xpath = mass_config_xpath + '/mass'
        m = cpsf.get_value(tixi, mass_xpath)  # aircraft mass [Kg]
    else:
        raise ValueError(
            ' !!! The mass configuration : {} is not defined in the CPACS file !!!'
            .format(mass_config))

    # Wing plane AREA.
    ref_area_xpath = model_xpath + '/reference/area'
    s = cpsf.get_value(
        tixi, ref_area_xpath
    )  # Wing area : s  for non-dimonsionalisation of aero data.

    Coeffs = apmf.get_aeromap(tixi, aeromap_uid)
    Coeffs.print_coef_list()

    alt_list = Coeffs.alt
    mach_list = Coeffs.mach
    aoa_list = Coeffs.aoa
    aos_list = Coeffs.aos
    cl_list = Coeffs.cl
    cd_list = Coeffs.cd
    cml_list = Coeffs.cml
    cms_list = Coeffs.cms
    cmd_list = Coeffs.cmd

    alt_unic = get_unic(alt_list)
    mach_unic = get_unic(mach_list)
    aos_unic = get_unic(aos_list)
    aoa_unic = get_unic(aoa_list)

    # TODO: get incremental map from CPACS
    # Incremental map elevator
    incrementalMap = False  # if increment map available
    # aeromap_xpath = tixi.uIDGetXPath(aeromap_uid)
    # dcms_xpath = aeromap_xpath + '/aeroPerformanceMap/incrementMaps/incrementMap'  + ' ....to complete'

    # TODO from incremental map
    # dcms_list = [0.52649,0.53744,0.54827,0.55898,0.56955,0.58001,0.59033,0.6005,0.61053,0.62043,0.63018,0.63979,0.64926,0.65859,0.66777,0.67684,0.53495,0.54603,0.55699,0.56783,0.57854,0.58912,0.59957,0.60986,0.62002,0.63004,0.63991,0.64964,0.65923,0.66867,0.67798,0.68717,0.55,0.56131,0.5725,0.58357,0.59451,0.60531,0.61598,0.62649,0.63687,0.64709,0.65718,0.66712,0.67691,0.68658,0.69609,0.70548,0.57333,0.585,0.59655,0.60796,0.61925,0.63038,0.64138,0.65224,0.66294,0.67349,0.68389,0.69415,0.70427,0.71424,0.72408,0.7338,0.60814,0.62033,0.63239,0.6443,0.65607,0.6677,0.67918,0.6905,0.70168,0.7127,0.72357,0.7343,0.74488,0.75532,0.76563,0.77581,0.66057,0.6735,0.68628,0.69891,0.71139,0.72371,0.73588,0.74789,0.75974,0.77144,0.78298,0.79438,0.80562,0.81673,0.82772,0.83858,\
    # 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
    # -0.61653,-0.61254,-0.60842,-0.60419,-0.59988,-0.59549,-0.59105,-0.58658,-0.5821,-0.57762,-0.57318,-0.56879,-0.56447,-0.56025,-0.55616,-0.55221,-0.62605,-0.62194,-0.6177,-0.61336,-0.60894,-0.60444,-0.59988,-0.59531,-0.59072,-0.58614,-0.58159,-0.57711,-0.5727,-0.56841,-0.56423,-0.5602,-0.64293,-0.63862,-0.63418,-0.62963,-0.62499,-0.62029,-0.61554,-0.61076,-0.60598,-0.60123,-0.5965,-0.59185,-0.58728,-0.58282,-0.5785,-0.57433,-0.66906,-0.6644,-0.65963,-0.65475,-0.64978,-0.64476,-0.63971,-0.63461,-0.62954,-0.62449,-0.61949,-0.61456,-0.60973,-0.60503,-0.60048,-0.59609,-0.70787,-0.70268,-0.69739,-0.692,-0.68653,-0.68101,-0.67546,-0.66991,-0.66437,-0.65888,-0.65344,-0.6481,-0.64289,-0.63781,-0.6329,-0.62819,-0.76596,-0.75994,-0.75382,-0.74762,-0.74135,-0.73505,-0.72874,-0.72243,-0.71617,-0.70997,-0.70387,-0.69788,-0.69205,-0.68639,-0.68094,-0.67573]
    # dcms are given for a relative deflection of [-1,0,1] of the

    # # TODO get from CPACS
    # elevator_deflection = 15

    # Gather trim aoa conditions
    trim_alt_longi_list = []
    trim_mach_longi_list = []
    trim_aoa_longi_list = []
    trim_aos_longi_list = []
    trim_legend_longi_list = []
    trim_derivative_longi_list = []

    # Gather trim aos_list for different Alt & mach , for aoa = 0
    trim_alt_lat_list = []
    trim_mach_lat_list = []
    trim_aoa_lat_list = []
    trim_aos_lat_list = []
    trim_legend_lat_list = []
    trim_derivative_lat_list = []

    # Gather trim aos_list for different Alt & mach , for aoa = 0
    trim_alt_direc_list = []
    trim_mach_direc_list = []
    trim_aoa_direc_list = []
    trim_aos_direc_list = []
    trim_legend_direc_list = []
    trim_derivative_direc_list = []

    # To store in cpacs result
    longi_unstable_cases = []
    lat_unstable_cases = []
    direc_unstable_cases = []

    cpacs_stability_longi = 'True'
    cpacs_stability_lat = 'True'
    cpacs_stability_direc = 'True'

    # Aero analyses for all given altitude, mach and aos_list, over different
    for alt in alt_unic:

        Atm = get_atmosphere(alt)
        g = Atm.grav
        a = Atm.sos
        rho = Atm.dens

        # Find index of altitude which have the same value
        idx_alt = [i for i in range(len(alt_list)) if alt_list[i] == alt]

        # Prepar trim condition lists
        trim_alt_longi = []
        trim_mach_longi = []
        trim_aoa_longi = []
        trim_aos_longi = []
        trim_legend_longi = []
        trim_derivative_longi = []

        # Prepar trim condition lists
        trim_alt_lat = []
        trim_mach_lat = []
        trim_aoa_lat = []
        trim_aos_lat = []
        trim_legend_lat = []
        trim_derivative_lat = []

        # Prepar trim condition lists
        trim_alt_direc = []
        trim_mach_direc = []
        trim_aoa_direc = []
        trim_aos_direc = []
        trim_legend_direc = []
        trim_derivative_direc = []

        for mach in mach_unic:
            u0 = a * mach
            # Find index of mach which have the same value
            idx_mach = [
                j for j in range(len(mach_list)) if mach_list[j] == mach
            ]

            # Longitudinal stability
            # Analyse in function of the angle of attack for given, alt, mach and aos_list
            # Prepare variables for plots
            plot_cms = []
            plot_aoa = []
            plot_legend = []
            plot_title = r'Pitch moment coefficeint $C_M$ vs $\alpha$ @ Atl = ' + str(
                alt) + 'm, and Mach = ' + str(mach)
            xlabel = r'$\alpha$ [°]'
            ylabel = r'$C_M$ [-]'
            # Init for determining if it's an unstable case
            longitudinaly_stable = True
            # by default, cms don't  cross 0 line
            crossed = False

            # Find index at which  aos= 0
            idx_aos = [j for j in range(len(aos_list)) if aos_list[j] == 0]
            find_idx = get_index(idx_alt, idx_mach, idx_aos)

            # If find_idx is empty an APM function would have corrected before
            # If there there is only one value  in  find_idx for a given Alt, Mach, aos_list, no analyse can be performed
            if len(find_idx) == 1:
                log.info('Longitudinal : only one data, one aoa(' +str(aoa_list[find_idx[0]]) \
                + '), for Altitude =  '+ str(alt) + '[m] , Mach = ' \
                + str(mach) + '  and aos = 0 , no stability analyse will be performed' )
                cpacs_stability_longi = 'NotCalculated'
            elif len(find_idx
                     ) > 1:  # if there is at least 2 values in find_idx :

                # Find all cms_list values for index corresonding to an altitude, a mach, an aos_list=0, and different aoa_list
                cms = []
                aoa = []
                cl = []
                cd = []
                for index in find_idx:
                    cms.append(cms_list[index])
                    aoa.append(aoa_list[index])
                    cl.append(cl_list[index])
                    cd.append(cd_list[index])

                # Save values which will be plot
                plot_cms.append(cms)
                plot_aoa.append(aoa)
                curve_legend = r'$\beta$ = 0°'
                plot_legend.append(curve_legend)

                # If all aoa values are the same while the calculating the derivative, a division by zero will be prevented.
                aoa_good = True
                for jj in range(len(aoa) - 1):
                    if aoa[jj] == aoa[jj + 1]:
                        aoa_good = False
                        log.error(
                            'Alt = {} , at least 2 aoa values are equal in aoa list: {} at Mach= {}, aos = 0'
                            .format(alt, aoa, mach))
                        break

                if aoa_good:
                    # Required lift for level flight
                    cl_required = (m * g) / (0.5 * rho * u0**2 * s)
                    (trim_aoa, idx_trim_before, idx_trim_after,
                     ratio) = trim_condition(alt, mach, cl_required, cl, aoa)

                    if trim_aoa:
                        trim_cms = interpolation(cms, idx_trim_before,
                                                 idx_trim_after, ratio)
                        pitch_moment_derivative_deg = (
                            cms[idx_trim_after] - cms[idx_trim_before]) / (
                                aoa[idx_trim_after] - aoa[idx_trim_before])
                        # Find incremental cms
                        if incrementalMap:
                            for index, mach_number in enumerate(mach_unic, 0):
                                if mach_number == mach:
                                    mach_index = index
                            dcms_before = dcms_list[mach_index * len(aoa_unic)
                                                    + idx_trim_before]
                            dcms_after = dcms_list[mach_index * len(aoa_unic) +
                                                   idx_trim_after]
                            dcms = dcms_before + ratio * (dcms_after -
                                                          dcms_before)
                            trim_elevator_relative_deflection = -trim_cms / dcms
                            trim_elevator = trim_elevator_relative_deflection * elevator_deflection  # Trim elevator deflection in [°]
                        else:
                            dcms = None
                            trim_elevator = None
                    else:
                        trim_cms = None
                        pitch_moment_derivative_deg = None
                        dcms = None
                        trim_elevator = None

                    fig = plt.figure(figsize=(9, 3))
                    plot_title___ = r'$C_L$ and $C_m$ vs $\alpha$ at Mach = {}'.format(
                        mach)
                    plt.title(plot_title___,
                              fontdict=None,
                              loc='center',
                              pad=None)
                    plt.plot(aoa, cl, marker='o', markersize=4, linewidth=1)
                    plt.plot(aoa,
                             cms,
                             marker='+',
                             markerfacecolor='orange',
                             markersize=12)
                    plt.plot([aoa[0], aoa[-1]], [cl_required, cl_required],
                             markerfacecolor='red',
                             markersize=12)
                    plt.legend([r'$C_L$', r'$C_M$', r'$C_{Lrequired}$'])
                    ax = plt.gca()
                    ax.annotate(r'$\alpha$ [°]',
                                xy=(1, 0),
                                ha='right',
                                va='top',
                                xycoords='axes fraction',
                                fontsize=12)
                    # ax.annotate('Coefficient', xy=(0,1), ha='left', va='center', xycoords='axes fraction', fontsize=12)
                    plt.grid(True)

                    if show_plots:
                        plt.show()

                # Conclusion about stability, if the cms curve has crossed the 0 line and there is not 2 repeated aoa for the same alt, mach and aos.
                # if  idx_trim_before != idx_trim_after allow to know if the cm curve crosses the 0 line. '

                if idx_trim_before != idx_trim_after and aoa_good:
                    if pitch_moment_derivative_deg < 0:
                        log.info('Vehicle longitudinaly staticaly stable.')
                        trim_alt_longi.append(alt)
                        trim_mach_longi.append(mach)
                        trim_aoa_longi.append(trim_aoa)
                        trim_aos_longi.append(0)
                        trim_derivative_longi.append(
                            pitch_moment_derivative_deg)

                    elif pitch_moment_derivative_deg == 0:
                        longitudinaly_stable = False
                        log.error(
                            'Alt = ' + str(alt) +
                            'Vehicle longitudinaly staticaly neutral stable.')
                    else:  #pitch_moment_derivative_deg > 0
                        longitudinaly_stable = False
                        log.error(
                            'Alt = ' + str(alt) +
                            'Vehicle *NOT* longitudinaly staticaly stable.')

                # If not stable store the set [alt, mach, aos] at which the aircraft is unstable.
                if not longitudinaly_stable:
                    longi_unstable_cases.append([alt, mach, 0])
                    # To write in the output CPACS that the aircraft is not longitudinaly stable
                    cpacs_stability_longi = 'False'
            #PLot cms VS aoa for constant Alt, Mach and different aos
            if plot_cms:
                plot_multicurve(plot_cms, plot_aoa, plot_legend, plot_title,
                                xlabel, ylabel, show_plots, save_plots)

            ## LATERAL
            plot_cmd = []
            plot_aos = []
            plot_legend = []
            plot_title = r'Roll moment coefficient $C_L$ vs $\beta$ @ Atl = ' + str(
                alt) + 'm, and Mach = ' + str(mach)
            xlabel = r'$\beta$ [°]'
            ylabel = r'$C_L$ [-]'
            # Init for determinig if it is an unstability case
            laterally_stable = True
            # Find INDEX
            for aoa in aoa_unic:

                # by default, don't  cross 0 line
                crossed = False
                idx_aoa = [
                    j for j in range(len(aoa_list)) if aoa_list[j] == aoa
                ]
                find_idx = get_index(idx_alt, idx_mach, idx_aoa)

                # If find_idx is empty an APM function would have corrected before
                # If there there is only one value  in  find_idx for a given Alt, Mach, aos_list, no analyse can be performed
                if len(find_idx) == 1:
                    log.info('Laterral-Directional : only one data, one aos (' + str(aos_list[find_idx[0]])  \
                              +'), for Altitude = '+str(alt)+'[m], Mach = '   \
                              + str(mach) + ' and aoa = ' + str(aoa)           \
                              + ' no stability analyse performed')
                    cpacs_stability_lat = 'NotCalculated'

                elif len(find_idx
                         ) > 1:  #if there is at least 2 values in find_idx
                    cmd = []
                    aos = []
                    for index in find_idx:
                        cmd.append(
                            -cmd_list[index]
                        )  # menus sign because cmd sign convention on ceasiom is the oposite as books convention
                        aos.append(aos_list[index])
                    aos, cmd = order_correctly(
                        aos,
                        cmd)  # To roder the lists with values for growing aos
                    #  If cmd Curve crosses th 0 line more than once na stability analysis can be performed
                    curve_legend = r'$\alpha$ = ' + str(aoa) + r' °'

                    # Save values which will be plotted
                    plot_cmd.append(cmd)
                    plot_aos.append(aos)
                    plot_legend.append(curve_legend)

                    aos_good = True
                    for jj in range(len(aos) - 1):
                        if aos[jj] == aos[jj + 1]:
                            aos_good = False
                            log.error(
                                'Alt = {} , at least 2 aos values are equal in aos list: {} , Mach= {}, aos = {}'
                                .format(alt, aoa, mach, aos))
                            break

                    if aos_good:
                        cruise_aos, roll_moment_derivative, idx_trim_before, idx_trim_after, ratio = trim_derivative(
                            alt, mach, cmd, aos)

                    if idx_trim_before != idx_trim_after and aos_good:
                        if roll_moment_derivative < 0:
                            log.info('Vehicle laterally staticaly stable.')
                            if aoa == 0:
                                trim_alt_lat.append(alt)
                                trim_mach_lat.append(mach)
                                trim_aoa_lat.append(cruise_aos)
                                trim_aos_lat.append(aoa)
                                trim_derivative_lat.append(
                                    roll_moment_derivative)
                        if roll_moment_derivative == 0:
                            laterally_stable = False
                            log.error(
                                'At alt = ' + str(alt) +
                                'Vehicle laterally staticaly neutral stable.')
                        if roll_moment_derivative > 0:
                            laterally_stable = False
                            log.error(
                                'Alt = ' + str(alt) +
                                'Vehicle *NOT* laterally staticaly stable.')

                    # If not stable store the set [alt, mach, aos] at which the aircraft is unstable.
                    if not laterally_stable:
                        lat_unstable_cases.append([alt, mach, aoa])
                        # To write in the output CPACS that the aircraft is not longitudinaly stable
                        cpacs_stability_lat = 'False'

            #PLot cmd VS aos for constant alt, mach and different aoa if not stable
            if plot_cmd:
                plot_multicurve(plot_cmd, plot_aos, plot_legend, plot_title,
                                xlabel, ylabel, show_plots, save_plots)

            ## Directional
            plot_cml = []
            plot_aos = []
            plot_legend = []
            plot_title = r'Yaw moment coefficient $C_N$ vs $\beta$ @ Atl = ' + str(
                alt) + 'm, and Mach = ' + str(mach)
            xlabel = r'$\beta$ [°]'
            ylabel = r'$C_N$ [-]'
            # Init for determinig if it is an unstability case
            dirrectionaly_stable = True
            # Find INDEX
            for aoa in aoa_unic:
                # by default, don't  cross 0 line
                crossed = False
                idx_aoa = [
                    j for j in range(len(aoa_list)) if aoa_list[j] == aoa
                ]
                find_idx = get_index(idx_alt, idx_mach, idx_aoa)

                # If find_idx is empty an APM function would have corrected before
                # If there there is only one value  in  find_idx for a given Alt, Mach, aos_list, no analyse can be performed
                if len(find_idx) == 1:
                    log.info('Laterral-Directional : only one data, one aos (' + str(aos_list[find_idx[0]])  \
                              +'), for Altitude = '+str(alt)+'[m], Mach = '   \
                              + str(mach) + ' and aoa = ' + str(aoa)           \
                              + ' no stability analyse performed')
                    cpacs_stability_direc = 'NotCalculated'

                elif len(find_idx
                         ) > 1:  #if there is at least 2 values in find_idx
                    cml = []
                    aos = []
                    for index in find_idx:
                        cml.append(
                            -cml_list[index]
                        )  # menus sign because cml sign convention on ceasiom is the oposite as books convention
                        aos.append(aos_list[index])
                    aos, cml = order_correctly(
                        aos, cml)  # To order values with growing aos
                    #  If cml Curve crosses th 0 line more than once na stability analysis can be performed
                    curve_legend = r'$\alpha$ = ' + str(aoa) + r' °'

                    # Save values which will be plot
                    plot_cml.append(cml)
                    plot_aos.append(aos)
                    plot_legend.append(curve_legend)

                    aos_good = True
                    for jj in range(len(aos) - 1):
                        if aos[jj] == aos[jj + 1]:
                            aos_good = False
                            log.error(
                                'Alt = {} , at least 2 aos values are equal in aos list: {} , Mach= {}, aos = {}'
                                .format(alt, aoa, mach, aos))
                            break

                    if aos_good:
                        cruise_aos, side_moment_derivative, idx_trim_before, idx_trim_after, ratio = trim_derivative(
                            alt, mach, cml, aos)

                    if idx_trim_before != idx_trim_after and aos_good:
                        if side_moment_derivative > 0:
                            log.info('Vehicle directionnaly staticaly stable.')
                            if aoa == 0:
                                trim_alt_direc.append(alt)
                                trim_mach_direc.append(mach)
                                trim_aoa_direc.append(cruise_aos)
                                trim_aos_direc.append(aoa)
                                trim_derivative_direc.append(
                                    side_moment_derivative)
                        if side_moment_derivative == 0:
                            dirrectionaly_stable = False
                            log.error(
                                'At alt = ' + str(alt) +
                                'Vehicle directionnaly staticaly neutral stable.'
                            )
                        if side_moment_derivative < 0:
                            dirrectionaly_stable = False
                            log.error(
                                'Alt = ' + str(alt) +
                                'Vehicle *NOT* directionnaly staticaly stable.'
                            )

                    # If not stable store the set [alt, mach, aos] at which the aircraft is unstable.
                    if not dirrectionaly_stable:
                        direc_unstable_cases.append([alt, mach, aoa])
                        # To write in the output CPACS that the aircraft is not longitudinaly stable
                        cpacs_stability_direc = 'False'

            # PLot cml VS aos for constant alt, mach and different aoa if not stable
            if plot_cml:
                plot_multicurve(plot_cml, plot_aos, plot_legend, plot_title,
                                xlabel, ylabel, show_plots, save_plots)

        # Add trim conditions for the given altitude (longi analysis)
        if trim_aoa_longi:
            trim_aoa_longi_list.append(trim_aoa_longi)
            trim_mach_longi_list.append(trim_mach_longi)
            trim_legend_longi_list.append('Altitude = ' + str(alt) + '[m]')
            trim_alt_longi_list.append(trim_alt_longi)
            trim_aos_longi_list.append(trim_aos_longi)
            trim_derivative_longi_list.append(trim_derivative_longi)

        if trim_aos_lat:
            trim_aos_lat_list.append(trim_aos_lat)
            trim_mach_lat_list.append(trim_mach_lat)
            trim_legend_lat_list.append('Alt = ' + str(alt) + '[m]')
            trim_alt_lat_list.append(trim_alt_lat)
            trim_aoa_lat_list.append(trim_aoa_lat)
            trim_derivative_lat_list.append(trim_derivative_lat)

        # Add trim conditions for the given altitude (direcanalysis)
        if trim_aos_direc:
            trim_aos_direc_list.append(trim_aos_direc)
            trim_mach_direc_list.append(trim_mach_direc)
            trim_legend_direc_list.append('Alt = ' + str(alt) + '[m]')
            trim_alt_direc_list.append(trim_alt_direc)
            trim_aoa_direc_list.append(trim_aoa_direc)
            trim_derivative_direc_list.append(trim_derivative_direc)

        # MACH PLOTS
        if plot_for_different_mach:  # To check Altitude Mach
            ## LONGI
            # Plot cms vs aoa for const alt and aos = 0 and different mach
            idx_aos = [k for k in range(len(aos_list)) if aos_list[k] == 0]
            plot_cms = []
            plot_aoa = []
            plot_legend = []
            plot_title = r'Pitch moment coefficient $C_M$ vs $\alpha$ @ Atl = ' + str(
                alt) + r'm, and $\beta$ = 0 °'
            xlabel = r'$\alpha$ [°]'
            ylabel = r'$C_M$ [-]'
            # Init for determinig if it is an unstability case
            longitudinaly_stable = True

            for mach in mach_unic:
                idx_mach = [
                    j for j in range(len(mach_list)) if mach_list[j] == mach
                ]
                find_idx = get_index(idx_alt, idx_aos, idx_mach)

                # If there is only one value in Find_idx
                # An error message has been already printed through the first part of the code
                # Check if it is an unstability case detected previously
                for combination in longi_unstable_cases:
                    if combination[0] == alt and combination[
                            1] == mach and combination[2] == aos:
                        longitudinaly_stable = False

                # If there is at list 2 values in find_idx :
                if len(find_idx) > 1:
                    # Find all cms_list values for index corresonding to an altitude, a mach, an aos_list=0, and different aoa_list
                    cms = []
                    aoa = []
                    for index in find_idx:
                        cms.append(cms_list[index])
                        aoa.append(aoa_list[index])
                    # Save values which will be plot
                    plot_cms.append(cms)
                    plot_aoa.append(aoa)
                    curve_legend = 'Mach = ' + str(mach)
                    plot_legend.append(curve_legend)
            #PLot cms VS aoa for constant Alt, aoa and different mach
            if plot_cms:
                plot_multicurve(plot_cms, plot_aoa, plot_legend, plot_title,
                                xlabel, ylabel, show_plots, save_plots)

            ## LATERAL
            # Plot cmd vs aos for const alt and aoa and different mach
            for aoa in aoa_unic:
                idx_aoa = [
                    k for k in range(len(aoa_list)) if aoa_list[k] == aoa
                ]
                plot_cmd = []
                plot_aos = []
                plot_legend = []
                plot_title = r'Roll moment coefficiel $C_L$ vs $\beta$ @ Atl = ' + str(
                    alt) + r'm, and $\alpha$= ' + str(aoa) + r' °'
                xlabel = r'$\beta$ [°]'
                ylabel = r'$C_L$ [-]'

                # Init for determinig if it is an unstability case
                laterally_stable = True

                for mach in mach_unic:
                    idx_mach = [
                        j for j in range(len(mach_list))
                        if mach_list[j] == mach
                    ]
                    find_idx = get_index(idx_alt, idx_aoa, idx_mach)

                    #If there is only one valur in find_idx
                    # An error message has been already printed through the first part of the code

                    # Check if it is an unstability case detected previously
                    for combination in lat_unstable_cases:
                        if combination[0] == alt and combination[
                                1] == mach and combination[2] == aoa:
                            laterally_stable = False

                    # If there is at list 2 values in find_idx :
                    if len(find_idx) > 1:
                        # Find all cmd_list values for index corresonding to an altitude, a mach, an aos_list=0, and different aoa_list
                        cmd = []
                        aos = []
                        for index in find_idx:
                            cmd.append(-cmd_list[index])
                            aos.append(aos_list[index])
                        aos, cmd = order_correctly(
                            aos, cmd)  # To order values with growing aos

                        # Save values which will be plot
                        plot_cmd.append(cmd)
                        plot_aos.append(aos)
                        curve_legend = 'Mach = ' + str(mach)
                        plot_legend.append(curve_legend)

                if plot_cmd:
                    # Plot cmd VS aos for constant Alt, aoa and different mach
                    plot_multicurve(plot_cmd, plot_aos, plot_legend,
                                    plot_title, xlabel, ylabel, show_plots,
                                    save_plots)

            ## Directional
            # Plot cml vs aos for const alt and aoa and different mach
            for aoa in aoa_unic:
                idx_aoa = [
                    k for k in range(len(aoa_list)) if aoa_list[k] == aoa
                ]
                plot_cml = []
                plot_aos = []
                plot_legend = []
                plot_title = r'Yaw moment coefficiel $C_N$ vs $\beta$ @ Atl = ' + str(
                    alt) + r'm, and $\alpha$= ' + str(aoa) + r' °'
                xlabel = r'$\beta$ [°]'
                ylabel = r'$C_N$ [-]'

                # Init for determinig if it is an unstability case
                dirrectionaly_stable = True

                for mach in mach_unic:
                    idx_mach = [
                        j for j in range(len(mach_list))
                        if mach_list[j] == mach
                    ]
                    find_idx = get_index(idx_alt, idx_aoa, idx_mach)
                    #If there is only one valur in find_idx
                    # An error message has been already printed through the first part of the code

                    # Check if it is an unstability case detected previously
                    for combination in direc_unstable_cases:
                        if combination[0] == alt and combination[
                                1] == mach and combination[2] == aoa:
                            dirrectionaly_stable = False

                    # If there is at list 2 values in find_idx :
                    if len(find_idx) > 1:
                        # Find all cml_list values for index corresonding to an altitude, a mach, an aos_list=0, and different aoa_list
                        cml = []
                        aos = []
                        for index in find_idx:
                            cml.append(-cml_list[index])
                            aos.append(aos_list[index])
                        aos, cml = order_correctly(
                            aos, cml)  # To order values with growing aos

                        # Save values which will be plot
                        plot_cml.append(cml)
                        plot_aos.append(aos)
                        curve_legend = 'Mach = ' + str(mach)
                        plot_legend.append(curve_legend)

                if plot_cml:
                    # Plot cml VS aos for constant Alt, aoa and different mach
                    plot_multicurve(plot_cml, plot_aos, plot_legend,
                                    plot_title, xlabel, ylabel, show_plots,
                                    save_plots)
            ############ MACH  PLOTS END ##########

    # TRIM CONDITIONS PLOTS
    # Plot trim_aoa VS mach for different alt
    # If there is at least 1 element in list of trim conditions then, plot them
    if trim_derivative_longi_list:
        log.info('graph : trim aoa vs mach genrated')
        plot_multicurve(trim_aoa_longi_list, trim_mach_longi_list,
                        trim_legend_longi_list, r'$\alpha_{trim}$ vs Mach',
                        'Mach', r'$\alpha_{trim}$ [°]', show_plots, save_plots)
        log.info('graph : pitch moment derivative at trim vs mach genrated')
        plot_multicurve(trim_derivative_longi_list, trim_mach_longi_list,
                        trim_legend_longi_list,
                        r'$C_{M_{\alpha trim}}$ vs Mach', 'Mach',
                        r'$C_{M_{\alpha trim}}$ [1/°]', show_plots, save_plots)

    if trim_derivative_lat_list:
        log.info('graph : roll moment derivative at trim vs mach genrated')
        plot_multicurve(trim_derivative_lat_list, trim_mach_lat_list,
                        trim_legend_lat_list, r'$C_{L_{\beta trim}}$vs Mach',
                        'Mach', r'$C_{L_{\beta trim}}$ [1/°]', show_plots,
                        save_plots)

    if trim_derivative_direc_list:
        log.info('graph : yaw moment at trim vs mach genrated')
        plot_multicurve(trim_derivative_direc_list, trim_mach_direc_list,
                        trim_legend_direc_list,
                        r'$C_{N_{\beta trim}}$ vs Mach', 'Mach',
                        r'$C_{N_{\beta trim}}$ [1/°]', show_plots, save_plots)

    # ALTITUDE PLOTS
    if plot_for_different_alt:  # To check Altitude Influence
        # plot cms VS aoa for constant mach, aos= 0 and different altitudes:
        # Find index of altitude which have the same value
        idx_aos = [i for i in range(len(aos_list)) if aos_list[i] == 0]
        for mach in mach_unic:
            # Find index of mach which have the same value
            idx_mach = [
                j for j in range(len(mach_list)) if mach_list[j] == mach
            ]
            # Prepare variables for plots
            plot_cms = []
            plot_aoa = []
            plot_legend = []
            plot_title = r'Pitch moment coefficient $C_M$ vs $\alpha$ @ Mach = ' + str(
                mach) + r' and $\beta$ = 0°'
            xlabel = r'$\alpha$ [°]'
            ylabel = r'$C_M$ [-]'

            longitudinaly_stable = True

            # Find index of slip angle which have the same value
            for alt in alt_unic:
                idx_alt = [
                    j for j in range(len(alt_list)) if alt_list[j] == alt
                ]
                find_idx = get_index(idx_aos, idx_mach, idx_alt)

                # If find_idx is empty an APM function would have corrected before
                # If there is only one value  in  find_idx for a given Alt, Mach, aos_list, no analyse can be performed
                # An error message has been already printed through the first part of the code

                # Check if it is an unstability case detected previously
                for combination in longi_unstable_cases:
                    if combination[0] == alt and combination[
                            1] == mach and combination[2] == aos:
                        longitudinaly_stable = False

                # If there is at list 2 values in find_idx :
                if len(find_idx) > 1:
                    # Find all cms_list values for index corresonding to an altitude, a mach, an aos_list=0, and different aoa_list
                    cms = []
                    aoa = []
                    for index in find_idx:
                        cms.append(cms_list[index])
                        aoa.append(aoa_list[index])

                    # Save values which will be plot
                    plot_cms.append(cms)
                    plot_aoa.append(aoa)
                    curve_legend = 'Altitude = ' + str(alt) + ' m'
                    plot_legend.append(curve_legend)

            if plot_cms:
                # PLot cms VS aoa for constant  Mach, aos and different Alt
                plot_multicurve(plot_cms, plot_aoa, plot_legend, plot_title,
                                xlabel, ylabel, show_plots, save_plots)

        ## Lateral
        # plot cmd VS aos for constant mach, aoa_list and different altitudes:
        for aoa in aoa_unic:
            # Find index of altitude which have the same value
            idx_aoa = [i for i in range(len(aoa_list)) if aoa_list[i] == aoa]
            for mach in mach_unic:
                # Find index of mach which have the same value
                idx_mach = [
                    j for j in range(len(mach_list)) if mach_list[j] == mach
                ]
                # Prepare variables for plots
                plot_cmd = []
                plot_aos = []
                plot_legend = []
                plot_title = r'Roll moment coefficient $C_L$ vs $\beta$ @ Mach = ' + str(
                    mach) + r' and $\alpha$= ' + str(aoa) + r' °'
                xlabel = r'$\beta$ [°]'
                ylabel = r'$C_L$ [-]'

                laterally_stable = True

                # Find index of slip angle which have the same value
                for alt in alt_unic:
                    idx_alt = [
                        j for j in range(len(alt_list)) if alt_list[j] == alt
                    ]
                    find_idx = get_index(idx_aoa, idx_mach, idx_alt)
                    # If find_idx is empty an APM function would have corrected before
                    # If there there is only one value  in  find_idx for a given Alt, Mach, aos_list, no analyse can be performed
                    # An error message has been already printed through the first part of the code

                    # Check if it is an unstability case detected previously
                    for combination in lat_unstable_cases:
                        if combination[0] == alt and combination[
                                1] == mach and combination[2] == aoa:
                            laterally_stable = False

                    # If there is at list 2 values in find_idx :
                    if len(find_idx) > 1:
                        # Find all cmd_list values for index corresonding to an altitude, a mach, an aos_list=0, and different aoa_list
                        cmd = []
                        aos = []
                        for index in find_idx:
                            cmd.append(-cmd_list[index])
                            aos.append(aos_list[index])

                        # Save values which will be plot
                        plot_cmd.append(cmd)
                        plot_aos.append(aos)
                        curve_legend = 'Altitude = ' + str(alt) + ' m'
                        plot_legend.append(curve_legend)

                if plot_cmd:
                    # PLot cmd VS aos for constant  Mach, aoa and different alt
                    plot_multicurve(plot_cmd, plot_aos, plot_legend,
                                    plot_title, xlabel, ylabel, show_plots,
                                    save_plots)

        ## DIRECTIONAL
        # plot cml VS aos for constant mach, aoa_list and different altitudes:
        for aoa in aoa_unic:
            # Find index of altitude which have the same value
            idx_aoa = [i for i in range(len(aoa_list)) if aoa_list[i] == aoa]
            for mach in mach_unic:
                # Find index of mach which have the same value
                idx_mach = [
                    j for j in range(len(mach_list)) if mach_list[j] == mach
                ]
                # Prepare variables for plots
                plot_cml = []
                plot_aos = []
                plot_legend = []
                plot_title = r'Yaw moment coefficient $C_N$ vs $\beta$ @ Mach = ' + str(
                    mach) + r' and $\alpha$= ' + str(aoa) + r' °'
                xlabel = r'$\beta$ [°]'
                ylabel = r'$C_N$ [-]'

                dirrectionaly_stable = True

                # Find index of slip angle which have the same value
                for alt in alt_unic:
                    idx_alt = [
                        j for j in range(len(alt_list)) if alt_list[j] == alt
                    ]
                    find_idx = get_index(idx_aoa, idx_mach, idx_alt)

                    # Check if it is an unstability case detected previously
                    for combination in direc_unstable_cases:
                        if combination[0] == alt and combination[
                                1] == mach and combination[2] == aoa:
                            dirrectionaly_stable = False

                    # If there is at list 2 values in find_idx :
                    if len(find_idx) > 1:
                        # Find all cml_list values for index corresonding to an altitude, a mach, an aos_list=0, and different aoa_list
                        cml = []
                        aos = []
                        for index in find_idx:
                            cml.append(-cml_list[index])
                            aos.append(aos_list[index])

                        # Save values which will be plot
                        plot_cml.append(cml)
                        plot_aos.append(aos)
                        curve_legend = 'Altitude = ' + str(alt) + ' m'
                        plot_legend.append(curve_legend)

                if plot_cml:
                    # PLot cml VS aos for constant  Mach, aoa and different alt
                    plot_multicurve(plot_cml, plot_aos, plot_legend,
                                    plot_title, xlabel, ylabel, show_plots,
                                    save_plots)

    # Save in the CPACS file stability results:
    trim_alt_longi_list = extract_subelements(trim_alt_longi_list)
    trim_mach_longi_list = extract_subelements(trim_mach_longi_list)
    trim_aoa_longi_list = extract_subelements(trim_aoa_longi_list)
    trim_aos_longi_list = extract_subelements(trim_aos_longi_list)
    trim_derivative_longi_list = extract_subelements(
        trim_derivative_longi_list)

    trim_alt_lat_list = extract_subelements(trim_alt_lat_list)
    trim_mach_lat_list = extract_subelements(trim_mach_lat_list)
    trim_aoa_lat_list = extract_subelements(trim_aoa_lat_list)
    trim_aos_lat_list = extract_subelements(trim_aos_lat_list)
    trim_derivative_lat_list = extract_subelements(trim_derivative_lat_list)

    trim_alt_direc_list = extract_subelements(trim_alt_direc_list)
    trim_mach_direc_list = extract_subelements(trim_mach_direc_list)
    trim_aoa_direc_list = extract_subelements(trim_aoa_direc_list)
    trim_aos_direc_list = extract_subelements(trim_aos_direc_list)
    trim_derivative_direc_list = extract_subelements(
        trim_derivative_direc_list)

    # xpath definition
    # TODO: add uid of the coresponding aeropm for results
    longi_xpath = STATIC_ANALYSIS_XPATH + '/results/longitudinalStaticStable'
    lat_xpath = STATIC_ANALYSIS_XPATH + '/results/lateralStaticStable'
    direc_xpath = STATIC_ANALYSIS_XPATH + '/results/directionnalStaticStable'
    longi_trim_xpath = STATIC_ANALYSIS_XPATH + '/trimConditions/longitudinal'
    lat_trim_xpath = STATIC_ANALYSIS_XPATH + '/trimConditions/lateral'
    direc_trim_xpath = STATIC_ANALYSIS_XPATH + '/trimConditions/directional'

    cpsf.create_branch(tixi, longi_xpath)
    cpsf.create_branch(tixi, lat_xpath)
    cpsf.create_branch(tixi, direc_xpath)

    # Store in the CPACS the stability results
    tixi.updateTextElement(longi_xpath, str(cpacs_stability_longi))
    tixi.updateTextElement(lat_xpath, str(cpacs_stability_lat))
    tixi.updateTextElement(direc_xpath, str(cpacs_stability_direc))

    cpsf.create_branch(tixi, longi_trim_xpath)
    cpsf.create_branch(tixi, lat_trim_xpath)
    cpsf.create_branch(tixi, direc_trim_xpath)

    # TODO: Normaly this "if" is not required, but the tixi function to add a vector does not support an empty vercor...
    if trim_alt_longi_list:
        cpsf.add_float_vector(tixi, longi_trim_xpath + '/altitude',
                              trim_alt_longi_list)
        cpsf.add_float_vector(tixi, longi_trim_xpath + '/machNumber',
                              trim_mach_longi_list)
        cpsf.add_float_vector(tixi, longi_trim_xpath + '/angleOfAttack',
                              trim_aoa_longi_list)
        cpsf.add_float_vector(tixi, longi_trim_xpath + '/angleOfSideslip',
                              trim_aos_longi_list)
    if trim_alt_lat_list:
        cpsf.add_float_vector(tixi, lat_trim_xpath + '/altitude',
                              trim_alt_lat_list)
        cpsf.add_float_vector(tixi, lat_trim_xpath + '/machNumber',
                              trim_mach_lat_list)
        cpsf.add_float_vector(tixi, lat_trim_xpath + '/angleOfAttack',
                              trim_aoa_lat_list)
        cpsf.add_float_vector(tixi, lat_trim_xpath + '/angleOfSideslip',
                              trim_aos_lat_list)
    if trim_alt_direc_list:
        cpsf.add_float_vector(tixi, direc_trim_xpath + '/altitude',
                              trim_alt_direc_list)
        cpsf.add_float_vector(tixi, direc_trim_xpath + '/machNumber',
                              trim_mach_direc_list)
        cpsf.add_float_vector(tixi, direc_trim_xpath + '/angleOfAttack',
                              trim_aoa_direc_list)
        cpsf.add_float_vector(tixi, direc_trim_xpath + '/angleOfSideslip',
                              trim_aos_direc_list)

    cpsf.close_tixi(tixi, cpacs_out_path)
Ejemplo n.º 26
0
def get_su2_results(cpacs_path, cpacs_out_path, wkdir):
    """ Function to write SU2 results in a CPACS file.

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

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

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

    """

    tixi = cpsf.open_tixi(cpacs_path)

    # TODO Check and reactivate that
    # save_timestamp(tixi,SU2_XPATH) <-- ceaf.replace by get get_execution_date()

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

    os.chdir(wkdir)
    dir_list = os.listdir(wkdir)

    # Get and save Wetted area
    wetted_area = get_wetted_area(wkdir)

    wetted_area_xpath = '/cpacs/toolspecific/CEASIOMpy/geometry/analysis/wettedArea'
    cpsf.create_branch(tixi, wetted_area_xpath)

    tixi.updateDoubleElement(wetted_area_xpath, wetted_area, '%g')

    # Get and save CL/CD ratio
    fixed_cl_xpath = SU2_XPATH + '/fixedCL'
    fixed_cl = cpsf.get_value_or_default(tixi, fixed_cl_xpath, 'NO')
    # TODO
    # if fixed_cl == 'YES':
    # find force_file_name = 'forces_breakdown.dat'
    # cl_cd = get_efficiency(force_path)
    # lDRatio_xpath = '/cpacs/toolspecific/CEASIOMpy/ranges/lDRatio' # TODO: probalby change xpath and name
    # cpsf.create_branch(tixi, lDRatio_xpath)
    # tixi.updateDoubleElement(lDRatio_xpath,cl_cd,'%g')

    # Save aeroPerformanceMap
    su2_aeromap_xpath = SU2_XPATH + '/aeroMapUID'
    aeromap_uid = cpsf.get_value(tixi, su2_aeromap_xpath)

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

    # Create an oject to store the aerodynamic coefficients
    apmf.check_aeromap(tixi, aeromap_uid)

    # TODO: create a function to earase previous results...
    Coef2 = apmf.get_aeromap(tixi, aeromap_uid)
    Coef = apmf.AeroCoefficient()
    Coef.alt = Coef2.alt
    Coef.mach = Coef2.mach
    Coef.aoa = Coef2.aoa
    Coef.aos = Coef2.aos

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

    for config_dir in sorted(case_dir_list):
        if os.path.isdir(config_dir):
            os.chdir(config_dir)
            force_file_name = 'forces_breakdown.dat'
            if not os.path.isfile(force_file_name):
                raise OSError('No result force file have been found!')

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

            # Damping derivatives
            rotation_rate_xpath = SU2_XPATH + '/options/rotationRate'
            rotation_rate = cpsf.get_value_or_default(tixi,
                                                      rotation_rate_xpath, 1.0)
            ref_xpath = '/cpacs/vehicles/aircraft/model/reference'
            ref_len = cpsf.get_value(tixi, ref_xpath + '/length')
            adim_rot_rate = rotation_rate * ref_len / velocity

            if '_dp' in config_dir:
                dcl = (cl - Coef.cl[-1]) / adim_rot_rate
                dcd = (cd - Coef.cd[-1]) / adim_rot_rate
                dcs = (cs - Coef.cs[-1]) / adim_rot_rate
                dcml = (cml - Coef.cml[-1]) / adim_rot_rate
                dcmd = (cmd - Coef.cmd[-1]) / adim_rot_rate
                dcms = (cms - Coef.cms[-1]) / adim_rot_rate
                Coef.damping_derivatives.add_damping_der_coef(
                    dcl, dcd, dcs, dcml, dcmd, dcms, '_dp')

            elif '_dq' in config_dir:
                dcl = (cl - Coef.cl[-1]) / adim_rot_rate
                dcd = (cd - Coef.cd[-1]) / adim_rot_rate
                dcs = (cs - Coef.cs[-1]) / adim_rot_rate
                dcml = (cml - Coef.cml[-1]) / adim_rot_rate
                dcmd = (cmd - Coef.cmd[-1]) / adim_rot_rate
                dcms = (cms - Coef.cms[-1]) / adim_rot_rate
                Coef.damping_derivatives.add_damping_der_coef(
                    dcl, dcd, dcs, dcml, dcmd, dcms, '_dq')

            elif '_dr' in config_dir:
                dcl = (cl - Coef.cl[-1]) / adim_rot_rate
                dcd = (cd - Coef.cd[-1]) / adim_rot_rate
                dcs = (cs - Coef.cs[-1]) / adim_rot_rate
                dcml = (cml - Coef.cml[-1]) / adim_rot_rate
                dcmd = (cmd - Coef.cmd[-1]) / adim_rot_rate
                dcms = (cms - Coef.cms[-1]) / adim_rot_rate
                Coef.damping_derivatives.add_damping_der_coef(
                    dcl, dcd, dcs, dcml, dcmd, dcms, '_dr')

            elif '_TED_' in config_dir:

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

                try:
                    print(Coef.IncrMap.dcl)
                except AttributeError:
                    Coef.IncrMap = apmf.IncrementMap(ted_uid)

                # TODO: still in development, for now only 1 ted and 1 defl
                print(ted_uid, defl_angle)

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

                control_parameter = -1

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

            else:  # No damping derivative or control surfaces case
                Coef.add_coefficients(cl, cd, cs, cml, cmd, cms)

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

            os.chdir(wkdir)

    # Save object Coef in the CPACS file
    apmf.save_coefficients(tixi, aeromap_uid, Coef)

    cpsf.close_tixi(tixi, cpacs_out_path)
Ejemplo n.º 27
0
def one_optim_iter():
    """Function to evaluate the value to optimize.

    Function 'one_optim_iter' will exectute in order all the module contained
    in '...' and extract the ... value from the last CPACS file, this value will
    be returned to the optimizer
    CPACSUpdater....

    """

    # Create the parameter in CPACS with 'CPACSUpdater' module
    cpacs_path = mi.get_toolinput_file_path('CPACSUpdater')
    cpacs_out_path = mi.get_tooloutput_file_path('CPACSUpdater')

    tixi = cpsf.open_tixi(cpacs_path)
    wkdir_path = ceaf.create_new_wkdir()
    WKDIR_XPATH = '/cpacs/toolspecific/CEASIOMpy/filesPath/wkdirPath'
    tixi.updateTextElement(WKDIR_XPATH, wkdir_path)

    # TODO: improve this part! (maybe move somewhere else)
    # To delete coef from previous iter
    aeromap_uid = cpsf.get_value(tixi, SU2_XPATH + '/aeroMapUID')
    Coef = apmf.get_aeromap(tixi, aeromap_uid)
    apmf.delete_aeromap(tixi, aeromap_uid)
    apmf.create_empty_aeromap(tixi, aeromap_uid, 'test_optim')
    apmf.save_parameters(tixi, aeromap_uid, Coef)
    cpsf.close_tixi(tixi, cpacs_path)

    # Update the CPACS file with the parameters contained in optim_var_dict
    update_cpacs_file(cpacs_path, cpacs_out_path, optim_var_dict)

    # Run optimisation sub workflow
    wkf.copy_module_to_module('CPACSUpdater', 'out', module_optim[0], 'in')
    wkf.run_subworkflow(module_optim)
    wkf.copy_module_to_module(module_optim[-1], 'out', 'CPACSUpdater', 'in')

    # Extract results  TODO: improve this part
    cpacs_results_path = mi.get_tooloutput_file_path(module_optim[-1])
    log.info('Results will be extracted from:' + cpacs_results_path)
    tixi = cpsf.open_tixi(cpacs_results_path)

    mtom = cpsf.get_value(
        tixi,
        '/cpacs/vehicles/aircraft/model/analyses/massBreakdown/designMasses/mTOM/mass'
    )

    aeromap_uid = cpsf.get_value(tixi, SU2_XPATH + '/aeroMapUID')
    Coef = apmf.get_aeromap(tixi, aeromap_uid)

    cl = Coef.cl[0]
    cd = Coef.cd[0]
    cm = Coef.cms[0]

    log.info('=========================')
    for key, (name, listval, minval, maxval,
              command) in optim_var_dict.items():
        log.info(name, ': ', listval[-1])

    log.info('Cl/Cd: ' + str(cl / cd))
    log.info('Cl: ' + str(cl))
    log.info('Cd: ' + str(cd))
    log.info('Cd: ' + str(cm))
    log.info('MTOM:' + str(mtom))
    log.info('(Cl)/MTOM:' + str(cl / mtom))
    log.info('=========================')

    # TODO: add option to choose what will be returned
    # return -mtom
    # return -cl
    # return cd
    # return -cl/cd
    return -cl / cd / mtom