def transformer(input_file, output_file='output_cpacs.xml', geometry_dict={}):
    """Transforms a CPACS aircraft geometry by rescaling individual sections

    Parameters
    ----------
    input_file : str
        The location of the CPACS file
    output_file : str
        The name of the output file (default output_cpacs.xml)
    geometry_dict : dict
        A dictionary of aircraft geometry parameters with the values
            that the output CPACS file should have
        dict keywords: fuselage_length, wing_span
    """

    fuse_length_change = geometry_dict.get('fuse_length', 'None')

    name = aircraft_name(input_file)
    ag = geometry.geometry_eval(input_file, name)
    fuse_length = ag.fuse_length[0]
    scale = fuse_length_change / fuse_length

    tixi_handle = open_tixi(input_file)
    tixi_handle = section_transformer(tixi_handle, scale, ag.fuse_sec_nb[0])
    tixi_handle = positioning_transformer(tixi_handle, scale)
    close_tixi(tixi_handle, output_file)
    return 'done'
示例#2
0
def plot_aero_coef(cpacs_path, cpacs_out_path):
    """Plot Aero coefficients from the chosen aeroMap in the CPACS file

    Function 'plot_aero_coef' can plot one or several aeromap from the CPACS
    file according to some user option, these option will be shown in the the
    SettingGUI or default values will be used.

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

    # Open TIXI handle
    tixi = cpsf.open_tixi(cpacs_path)
    aircraft_name = cpsf.aircraft_name(tixi)

    # Get aeroMap list to plot
    aeromap_to_plot_xpath = PLOT_XPATH + '/aeroMapToPlot'
    aeromap_uid_list = []

    # Option to select aeromap manualy
    manual_selct = cpsf.get_value_or_default(tixi,
                                             PLOT_XPATH + '/manualSelection',
                                             False)
    if manual_selct:
        aeromap_uid_list = call_select_aeromap(tixi)
        cpsf.create_branch(tixi, aeromap_to_plot_xpath)
        cpsf.add_string_vector(tixi, aeromap_to_plot_xpath, aeromap_uid_list)

    else:
        try:
            aeromap_uid_list = cpsf.get_string_vector(tixi,
                                                      aeromap_to_plot_xpath)
        except:
            # If aeroMapToPlot is not define, select manualy anyway
            aeromap_uid_list = call_select_aeromap(tixi)
            cpsf.create_branch(tixi, aeromap_to_plot_xpath)
            cpsf.add_string_vector(tixi, aeromap_to_plot_xpath,
                                   aeromap_uid_list)

    # Create DataFrame from aeromap(s)
    aeromap_df_list = []
    for aeromap_uid in aeromap_uid_list:
        aeromap_df = apmf.get_datafram_aeromap(tixi, aeromap_uid)
        aeromap_df['uid'] = aeromap_uid
        aeromap_df_list.append(aeromap_df)

    aeromap = pd.concat(aeromap_df_list, ignore_index=True)

    if len(aeromap_uid_list) > 1:
        uid_crit = None
    else:
        uid_crit = aeromap_uid_list[0]

    # Default options
    title = aircraft_name
    criterion = pd.Series([True] * len(aeromap.index))
    groupby_list = ['uid', 'mach', 'alt', 'aos']

    # Get criterion from CPACS
    crit_xpath = PLOT_XPATH + '/criterion'
    alt_crit = cpsf.get_value_or_default(tixi, crit_xpath + '/alt', 'None')
    mach_crit = cpsf.get_value_or_default(tixi, crit_xpath + '/mach', 'None')
    aos_crit = cpsf.get_value_or_default(tixi, crit_xpath + '/aos', 'None')

    cpsf.close_tixi(tixi, cpacs_out_path)

    # Modify criterion and title according to user option
    if len(aeromap['alt'].unique()) == 1:
        title += ' - Alt = ' + str(aeromap['alt'].loc[0])
        groupby_list.remove('alt')
    elif alt_crit not in NONE_LIST:
        criterion = criterion & (aeromap.alt == alt_crit)
        title += ' - Alt = ' + str(alt_crit)
        groupby_list.remove('alt')

    if len(aeromap['mach'].unique()) == 1:
        title += ' - Mach = ' + str(aeromap['mach'].loc[0])
        groupby_list.remove('mach')
    elif mach_crit not in NONE_LIST:
        criterion = criterion & (aeromap.mach == mach_crit)
        title += ' - Mach = ' + str(mach_crit)
        groupby_list.remove('mach')

    if len(aeromap['aos'].unique()) == 1:
        title += ' - AoS = ' + str(aeromap['aos'].loc[0])
        groupby_list.remove('aos')
    elif aos_crit not in NONE_LIST:
        criterion = criterion & (aeromap.aos == aos_crit)
        title += ' - AoS = ' + str(aos_crit)
        groupby_list.remove('aos')

    if uid_crit is not None and len(groupby_list) > 1:
        criterion = criterion & (aeromap.uid == uid_crit)
        title += ' - ' + uid_crit
        groupby_list.remove('uid')

    # Plot settings
    fig, axs = plt.subplots(2, 3)
    fig.suptitle(title, fontsize=14)
    fig.set_figheight(8)
    fig.set_figwidth(15)
    fig.subplots_adjust(left=0.06)
    axs[0, 1].axhline(y=0.0, color='k', linestyle='-')  # Line at Cm=0

    # Plot aerodynamic coerfficients
    for value, grp in aeromap.loc[criterion].groupby(groupby_list):

        legend = write_legend(groupby_list, value)

        axs[0, 0].plot(grp['aoa'], grp['cl'], 'x-', label=legend)
        axs[1, 0].plot(grp['aoa'], grp['cd'], 'x-')
        axs[0, 1].plot(grp['aoa'], grp['cms'], 'x-')
        axs[1, 1].plot(grp['aoa'], grp['cl'] / grp['cd'], 'x-')
        axs[0, 2].plot(grp['cd'], grp['cl'], 'x-')
        axs[1, 2].plot(grp['cl'], grp['cl'] / grp['cd'], 'x-')

    # Set subplot options
    subplot_options(axs[0, 0], 'CL', 'AoA')
    subplot_options(axs[1, 0], 'CD', 'AoA')
    subplot_options(axs[0, 1], 'Cm', 'AoA')
    subplot_options(axs[1, 1], 'CL/CD', 'AoA')
    subplot_options(axs[0, 2], 'CL', 'CD')
    subplot_options(axs[1, 2], 'CL/CD', 'CL')

    fig.legend(loc='upper right')
    plt.show()
示例#3
0
        os.makedirs('ToolOutput')

    if os.path.exists(PATH1):
        log.warning('Center of gravity evaluation only available')
        log.warning('with cpacs file as input')
        log.warning('Moment of inertia evaluation only available')
        log.warning('with cpacs file as input')
        raise Exception('Program ended')
    elif os.path.exists(PATH2):
        out_xml = copyxmlfile.copy_xml(PATH2, 'ToolOutput.xml')
        #os.remove(PATH2)
    else:
        raise Exception ('Error no ToolInput.xml  or user_toolinput file'\
                         + ' in the ToolInput folder ')

    name = aircraft_name(out_xml)

    newpath = 'ToolOutput/' + name
    if not os.path.exists(newpath):
        os.makedirs(newpath)

##========================= BALANCE ANALSIS INPUTS =========================##
    bi = balanceconvclass.BalanceInputs()
    out = balanceconvclass.BalanceOutputs()
    mw = balanceconvclass.MassesWeights()
    (mw, bi) = getdatafromcpacs.get_data(mw, bi, out_xml)

    ##============================== BALANCE ANALYSIS ==========================##

    log.info('------- Starting the balance analysis -------')
    log.info('---------- Aircraft: ' + name + ' -----------')
示例#4
0
def create_SU2_mesh(cpacs_path, cpacs_out_path):
    """ Function to create a simple SU2 mesh form an SUMO file (.smx)

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

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

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

    """

    tixi = cpsf.open_tixi(cpacs_path)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    cpsf.close_tixi(tixi, cpacs_out_path)
    os.chdir(original_dir)
示例#5
0
def test_aircraft_name():
    """Test the function 'aircraft_name'"""

    name = aircraft_name(CPACS_IN_PATH)
    assert name == 'Cpacs2Test'
示例#6
0
def get_weight_estimations(cpacs_path, cpacs_out_path):
    """Function to estimate the all weights for a conventional aircraft.

    Function 'get_weight_estimations' ...

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

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

    """

    # TODO: replace that by a general function??? (same for all modules)
    start = time.time()

    # Removing and recreating the ToolOutput folder.
    if os.path.exists('ToolOutput'):
        shutil.rmtree('ToolOutput')
        os.makedirs('ToolOutput')
    else:
        os.makedirs('ToolOutput')

    # Classes
    # TODO: Use only one class or subclasses
    ui = weightconvclass.UserInputs()
    mw = weightconvclass.MassesWeights()
    out = weightconvclass.WeightOutput()

    if not os.path.exists(cpacs_path):
        raise ValueError('No "ToolInput.xml" file in the ToolInput folder.')

    name = aircraft_name(cpacs_path)

    shutil.copyfile(cpacs_path, cpacs_out_path)  # TODO: shoud not be like that
    newpath = 'ToolOutput/' + name
    if not os.path.exists(newpath):
        os.makedirs(newpath)

    ag = geometry.geometry_eval(cpacs_path, name)
    fuse_length = round(ag.fuse_length[0], 3)
    fuse_width = round(np.amax(ag.fuse_sec_width[:, 0]), 3)
    ind = weightconvclass.InsideDimensions(fuse_length, fuse_width)
    ind.nose_length = round(ag.fuse_nose_length[0], 3)
    ind.tail_length = round(ag.fuse_tail_length[0], 3)
    ind.cabin_length = round(ag.fuse_cabin_length[0], 3)
    wing_area = round(ag.wing_plt_area_main, 3)
    wing_span = round(ag.wing_span[ag.main_wing_index - 1], 3)
    wing_area_tot = np.sum(ag.wing_plt_area)

    #Has been replace by classes function
    # (ind, ui) = getinput.get_user_inputs(ind, ui, ag, cpacs_out_path)
    ui.get_user_inputs(cpacs_out_path)
    ind.get_inside_dim(cpacs_out_path)

    if ui.MAX_FUEL_VOL > 0 and ui.MAX_FUEL_VOL < ag.wing_fuel_vol:
        max_fuel_vol = ui.MAX_FUEL_VOL
    else:
        max_fuel_vol = ag.wing_fuel_vol

    out.PILOT_NB = ui.PILOT_NB  # Number of pilot [-].

    # Massimum payload allowed, set 0 if equal to max passenger mass.
    mw.MAX_PAYLOAD = ui.MAX_PAYLOAD

    # Adding extra length in case of aircraft with second floor [m].
    if ui.IS_DOUBLE_FLOOR == 1:
        cabin_length2 = ind.cabin_length * 1.91
    elif ui.IS_DOUBLE_FLOOR == 2:
        cabin_length2 = ind.cabin_length * 1.20
    elif ui.IS_DOUBLE_FLOOR == 0:
        cabin_length2 = ind.cabin_length
    else:
        log.warning('Warning, double floor index can be only 0 (1 floor),\
                    2 (B747-2nd floor type) or 3 (A380-2nd floor type).\
                    Set Default value (0)')

    ### WEIGHT ANALYSIS
    log.info('------- Starting the weight analysis --------')
    log.info('---------- Aircraft: ' + name + ' -----------')

    # Maximum Take Off Mass Evaluation
    mw.maximum_take_off_mass = estimate_mtom(fuse_length, fuse_width,
                                             wing_area, wing_span, name)

    # Wing loading
    out.wing_loading = mw.maximum_take_off_mass / wing_area_tot

    # Operating Empty Mass evaluation
    mw.operating_empty_mass = estimate_operating_empty_mass(
        mw.maximum_take_off_mass, fuse_length, fuse_width, wing_area,
        wing_span, ui.TURBOPROP)

    # Passengers and Crew mass evaluation
    if ((fuse_width / (1 + (ind.fuse_thick / 100))) >
        (ind.seat_width + ind.aisle_width)):
        (out.pass_nb, out.row_nb, out.abreast_nb, out.aisle_nb,\
         out.toilet_nb, ind) = estimate_passengers(ui.PASS_PER_TOILET,\
                                                cabin_length2, fuse_width, ind)

        get_seat_config(out.pass_nb, out.row_nb, out.abreast_nb, out.aisle_nb,
                        ui.IS_DOUBLE_FLOOR, out.toilet_nb, ui.PASS_PER_TOILET,
                        fuse_length, ind, name)
    else:
        out.pass_nb = 0
        raise Exception('The aircraft can not transport passengers, increase'\
                        + ' fuselage width.' + '\nCabin Width [m] = '\
                        + str((fuse_width/(1 + ind.fuse_thick)))\
                        + ' is less than seat width [m]'\
                        + ' + aisle width [m] = '\
                        + str(ind.seat_width + ind.aisle_width))

    (out.crew_nb, out.cabin_crew_nb, mw.mass_crew)\
        = estimate_crew(out.pass_nb, ui.MASS_PILOT, ui.MASS_CABIN_CREW,\
                        mw.maximum_take_off_mass, out.PILOT_NB)

    mw.mass_payload = out.pass_nb * ui.MASS_PASS + ui.MASS_CARGO

    mw.mass_people = mw.mass_crew + out.pass_nb * ui.MASS_PASS

    maxp = False
    if (mw.MAX_PAYLOAD > 0 and mw.mass_payload > mw.MAX_PAYLOAD):
        mw.mass_payload = mw.MAX_PAYLOAD
        maxp = True
        log.info('With the fixed payload, passenger nb reduced to: '\
                 + str(round(mw.MAX_PAYLOAD / (ui.MASS_PASS),0)))

    # Fuel Mass evaluation
    # Maximum fuel that can be stored with maximum number of passengers.

    if not ui.MAX_FUEL_VOL:  # TODO while retesting, redo fitting
        if ui.TURBOPROP:
            if wing_area > 55.00:
                mw.mass_fuel_max = round(mw.maximum_take_off_mass / 4.6, 3)
            else:
                mw.mass_fuel_max = round(mw.maximum_take_off_mass / 3.6, 3)
        elif wing_area < 90.00:
            if fuse_length < 60.00:
                mw.mass_fuel_max = round(mw.maximum_take_off_mass / 4.3, 3)
            else:
                mw.mass_fuel_max = round(mw.maximum_take_off_mass / 4.0, 3)
        elif wing_area < 300.00:
            if fuse_length < 35.00:
                mw.mass_fuel_max = round(mw.maximum_take_off_mass / 3.6, 3)
            else:
                mw.mass_fuel_max = round(mw.maximum_take_off_mass / 3.8, 3)
        elif wing_area < 400.00:
            mw.mass_fuel_max = round(mw.maximum_take_off_mass / 2.2, 3)
        elif wing_area < 600.00:
            mw.mass_fuel_max = round(mw.maximum_take_off_mass / 2.35, 3)
        else:
            mw.mass_fuel_max = round(mw.maximum_take_off_mass / 2.8, 3)
    else:
        mw.mass_fuel_max = round(max_fuel_vol * ui.FUEL_DENSITY, 3)

    mw.mass_fuel_maxpass = round(mw.maximum_take_off_mass  \
                                 - mw.operating_empty_mass \
                                 - mw.mass_payload, 3)

    if (mw.MAX_FUEL_MASS > 0 and mw.mass_fuel_maxpass > mw.MAX_FUEL_MASS):
        mw.mass_fuel_maxpass = mw.MAX_FUEL_MASS
        log.info('Maximum fuel ammount allowed reached [kg]: ' +
                 str(mw.mass_fuel_maxpass))
        if (mw.maximum_take_off_mass > (mw.mass_fuel_maxpass\
                + mw.operating_empty_mass + mw.mass_payload)):
            mw.mass_cargo = mw.maximum_take_off_mass - (mw.mass_fuel_maxpass\
                          + mw.operating_empty_mass + mw.mass_payload)
            if not maxp:
                log.info('Adding extra payload mass [kg]: '\
                         + str(mw.mass_cargo))
                mw.mass_payload = mw.mass_payload + mw.mass_cargo
            else:
                maximum_take_off_mass = maximum_take_off_mass - mw.mass_cargo
                log.info('With all the constrains on the fuel and payload, '\
                         + 'the maximum take off mass is not reached.'\
                         + '\n Maximum take off mass [kg]: '\
                         + str(maximum_take_off_mass))
    else:
        log.info('Fuel mass with maximum passengers [kg]: '\
                 + str(mw.mass_fuel_maxpass))

    if (mw.MAX_FUEL_MASS > 0 and mw.mass_fuel_max > mw.MAX_FUEL_MASS):
        mw.mass_fuel_max = mw.MAX_FUEL_MASS

    # Zero Fuel Mass evaluation
    mw.zero_fuel_mass = mw.maximum_take_off_mass - mw.mass_fuel_maxpass\
                        + (ui.RES_FUEL_PERC)*mw.mass_fuel_max

    # Log writting  (TODO: maybe create a separate function)
    log.info('---- Geometry evaluation from CPACS file ----')
    log.info('Fuselage length [m]: ' + str(round(fuse_length, 3)))
    log.info('Fuselage width [m]: ' + str(round(fuse_width, 3)))
    log.info('Fuselage mean width [m]: ' + str(round(ag.fuse_mean_width, 3)))
    log.info('Wing Span [m]: ' + str(round(wing_span, 3)))

    log.info('--------- Masses evaluated: -----------')
    log.info('Maximum Take Off Mass [kg]: '\
             + str(int(round(mw.maximum_take_off_mass))))
    log.info('Operating Empty Mass [kg]: '\
             + str(int(round(mw.operating_empty_mass))))
    log.info('Zero Fuel Mass [kg]: '\
             + str(int(round(mw.zero_fuel_mass))))
    log.info('Wing loading [kg/m^2]: '\
             + str(int(round(out.wing_loading))))
    log.info('Maximum ammount of fuel allowed with no passengers [kg]: '\
             + str(int(round(mw.mass_fuel_max))))
    log.info('Maximum ammount of fuel allowed with no passengers [l]: '\
             + str(int(round(mw.mass_fuel_max/ui.FUEL_DENSITY))))
    log.info('--------- Passegers evaluated: ---------')
    log.info('Passengers: ' + str(out.pass_nb))
    log.info('Lavatory: ' + str(out.toilet_nb))
    log.info('Payload mass [kg]: ' + str(mw.mass_payload))
    log.info('------- Crew members evaluated: --------')
    log.info('Pilots: ' + str(out.PILOT_NB))
    log.info('Cabin crew members: ' + str(out.cabin_crew_nb))

    end = time.time()
    log.info('---------------------------------------')
    log.info('Elapsed time [s]: ' + str(round((end - start), 3)))
    log.info('---------------------------------------')
    log.info('############### Weight estimation completed ###############')

    # Outptu writting
    log.info('-------- Generating output text file --------')
    outputweightgen.output_txt(out, mw, ind, ui, name)

    # CPACS writting
    cpacsweightupdate.cpacs_update(mw, out, cpacs_path, cpacs_out_path)
示例#7
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)
示例#8
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.')
示例#9
0
def get_balance_unc_estimations(cpacs_path, cpacs_out_path):
    """Function to estimate inertia value and CoF of an unconventional aircraft.

    Function 'get_balance_unc_estimations' ...

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

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

    """

    # Removing and recreating the ToolOutput folder.
    if os.path.exists('ToolOutput'):
        shutil.rmtree('ToolOutput')
    os.makedirs('ToolOutput')

    if not os.path.exists(cpacs_path):
        raise ValueError('No "ToolInput.xml" file in the ToolInput folder.')

    name = aircraft_name(cpacs_path)

    shutil.copyfile(cpacs_path, cpacs_out_path)  # TODO: shoud not be like that
    newpath = 'ToolOutput/' + name
    if not os.path.exists(newpath):
        os.makedirs(newpath)

    bout = balanceuncclass.BalanceOutputs()

    # BALANCE ANALSIS INPUTS

    bi = balanceuncclass.BalanceInputs()
    mw = balanceuncclass.MassesWeights()
    ui = weightuncclass.UserInputs()
    ed = engineclass.EngineData()

    adui = weightuncclass.AdvancedInputs()

    (mw, ed) = getdatafromcpacs.get_data(ui, bi, mw, ed, cpacs_out_path)

    # GEOMETRY ANALYSIS

    (fus_nb, w_nb) = uncgeomanalysis.get_number_of_parts(cpacs_path)
    if not w_nb:
        log.warning('Aircraft does not have wings')
        raise Exception('Aircraft does not have wings')
    elif not fus_nb:
        (awg, wing_nodes) =\
            uncgeomanalysis.no_fuse_geom_analysis(cpacs_path, ui.FLOORS_NB,     \
                                                  w_nb, ui.H_LIM_CABIN,   \
                                                  ui.FUEL_ON_CABIN, name, \
                                                  ed.TURBOPROP)
    else:
        log.info('Fuselage detected')
        log.info('Number of fuselage: ' + str(int(fus_nb)))
        # Minimum fuselage segment height to be a cabin segment.
        h_min = ui.FLOORS_NB * ui.H_LIM_CABIN
        (afg, awg) = uncgeomanalysis.with_fuse_geom_analysis(cpacs_path, \
                         fus_nb, w_nb, h_min, adui, ed.TURBOPROP, ui.F_FUEL, name)

    ui = getdatafromcpacs.get_user_fuel(fus_nb, ui, cpacs_out_path)

    # BALANCE ANALYSIS

    log.info('----- Generating output text file -----')
    log.info('---- Starting the balance analysis ----')
    log.info('---- Aircraft: ' + name)

    # CENTER OF GRAVITY

    if not fus_nb:
        (bout, airplane_centers_segs) =\
                bwb_center_of_gravity(awg, bout, ui, bi, mw, ed)
    else:
        (bout, airplane_centers_segs) =\
                unc_center_of_gravity(awg, afg, bout, ui, bi, mw, ed)

    # MOMENT OF INERTIA

    if not fus_nb:
        (bout, wx, wy,
         wz) = uncinertia.bwb_inertia_eval(awg, bout, bi, mw, ed,
                                           cpacs_out_path)
    else:
        (bout, fx, fy, fz, wx, wy, wz)\
            = uncinertia.unc_inertia_eval(awg, afg, bout, bi, mw, ed, cpacs_out_path)

    # OUTPUT WRITING

    log.info('----- Generating output text file -----')
    outputbalancegen.output_txt(bout, mw, bi, ed, name)

    # CPACS WRITING
    cpacsbalanceupdate.cpacs_mbd_update(bout, mw, bi, np.sum(mw.ms_zpm),
                                        cpacs_out_path)

    # PLOTS

    log.info('--- Generating aircraft center of gravity plot (.png) ---')
    if not fus_nb:
        outputbalancegen.aircraft_cog_bwb_plot(bout.center_of_gravity, bi, ed,
                                               awg, name)
    else:
        outputbalancegen.aircraft_cog_unc_plot(bout.center_of_gravity, bi, ed,
                                               afg, awg, name)

    # Aircraft Nodes
    #log.info('--- Generating aircraft nodes plot (.png) ---')
    #if not fus_nb:
    #outputbalancegen.aircraft_nodes_bwb_plot(wx, wy, wz, name)
    #else:
    #outputbalancegen.aircraft_nodes_unc_plot(fx, fy, fz, wx, wy, wz, name)

    # Show plots
    plt.show()

    # LOG WRITING

    log.info('---- Center of Gravity coordinates ----')
    log.info('------ Max Payload configuration ------')
    log.info('[x, y, z]: ' + str(bout.center_of_gravity))
    log.info('---------------------------------------')
    log.info('------- Zero Fuel configuration -------')
    log.info('[x, y, z]: ' + str(bout.cg_zfm))
    log.info('---------------------------------------')
    log.info('----- Zero Payload configuration ------')
    log.info('[x, y, z]: ' + str(bout.cg_zpm))
    log.info('---------------------------------------')
    log.info('---------- OEM configuration ----------')
    log.info('[x, y, z]: ' + str(bout.cg_oem))
    log.info('---------------------------------------')

    if bi.USER_CASE:
        log.info('---------- User configuration ---------')
        log.info('Chosen Fuel Percentage: ' + str(bi.F_PERC))
        log.info('Chosen Payload Percentage: ' + str(bi.P_PERC))
        log.info('[x, y, z]: ' + str(bout.cg_user))

    log.info('---------------------------------------')
    log.info('---------- Inertia Evaluation ---------')

    if bi.USER_EN_PLACEMENT:
        log.info('------------ Engine Inertia -----------')
        log.info('Roll moment, Ixx [kgm^2]: ' + str(int(round(bout.Ixxen))))
        log.info('Pitch moment, Iyy [kgm^2]: ' + str(int(round(bout.Iyyen))))
        log.info('Yaw moment, Izz [kgm^2]: ' + str(int(round(bout.Izzen))))
        log.info('Ixy moment [kgm^2]: ' + str(int(round(bout.Ixyen))))
        log.info('Iyz moment [kgm^2]: ' + str(int(round(bout.Iyzen))))
        log.info('Ixz moment [kgm^2]: ' + str(int(round(bout.Ixzen))))
        log.info('---------------------------------------')

    log.info('--------- Lumped mass Inertia ---------')
    log.info('------ Max Payload configuration ------')
    log.info('Roll moment, Ixx [kgm^2]: ' + str(bout.Ixx_lump))
    log.info('Pitch moment, Iyy [kgm^2]: ' + str(bout.Iyy_lump))
    log.info('Yaw moment, Izz [kgm^2]: ' + str(bout.Izz_lump))
    log.info('Ixy moment [kgm^2]: ' + str(bout.Ixy_lump))
    log.info('Iyz moment [kgm^2]: ' + str(bout.Iyz_lump))
    log.info('Ixz moment [kgm^2]: ' + str(bout.Ixz_lump))

    log.info('---------------------------------------')
    log.info('------- Zero Fuel configuration -------')
    log.info('Roll moment, Ixx [kgm^2]: ' + str(bout.Ixx_lump_zfm))
    log.info('Pitch moment, Iyy [kgm^2]: ' + str(bout.Iyy_lump_zfm))
    log.info('Yaw moment, Izz [kgm^2]: ' + str(bout.Izz_lump_zfm))
    log.info('Ixy moment [kgm^2]: ' + str(bout.Ixy_lump_zfm))
    log.info('Iyz moment [kgm^2]: ' + str(bout.Iyz_lump_zfm))
    log.info('Ixz moment [kgm^2]: ' + str(bout.Ixz_lump_zfm))

    log.info('---------------------------------------')
    log.info('------ Zero Payload configuration -----')
    log.info('Roll moment, Ixx [kgm^2]: ' + str(bout.Ixx_lump_zpm))
    log.info('Pitch moment, Iyy [kgm^2]: ' + str(bout.Iyy_lump_zpm))
    log.info('Yaw moment, Izz [kgm^2]: ' + str(bout.Izz_lump_zpm))
    log.info('Ixy moment [kgm^2]: ' + str(bout.Ixy_lump_zpm))
    log.info('Iyz moment [kgm^2]: ' + str(bout.Iyz_lump_zpm))
    log.info('Ixz moment [kgm^2]: ' + str(bout.Ixz_lump_zpm))

    log.info('---------------------------------------')
    log.info('---------- OEM configuration ----------')
    log.info('Roll moment, Ixx [kgm^2]: ' + str(bout.Ixx_lump_oem))
    log.info('Pitch moment, Iyy [kgm^2]: ' + str(bout.Iyy_lump_oem))
    log.info('Yaw moment, Izz [kgm^2]: ' + str(bout.Izz_lump_oem))
    log.info('Ixy moment [kgm^2]: ' + str(bout.Ixy_lump_oem))
    log.info('Iyz moment [kgm^2]: ' + str(bout.Iyz_lump_oem))
    log.info('Ixz moment [kgm^2]: ' + str(bout.Ixz_lump_oem))
    log.info('---------------------------------------')

    if bi.USER_CASE:
        log.info('---------- User configuration ---------')
        log.info('Roll moment, Ixx [kgm^2]: ' + str(bout.Ixx_lump_user))
        log.info('Pitch moment, Iyy [kgm^2]: ' + str(bout.Iyy_lump_user))
        log.info('Yaw moment, Izz [kgm^2]: ' + str(bout.Izz_lump_user))
        log.info('Ixy moment [kgm^2]: ' + str(bout.Ixy_lump_user))
        log.info('Iyz moment [kgm^2]: ' + str(bout.Iyz_lump_user))
        log.info('Ixz moment [kgm^2]: ' + str(bout.Ixz_lump_user))
        log.info('---------------------------------------')

    log.info('##  Uconventional Balance analysis succesfuly completed ##')
示例#10
0
##=============================== PREPROCESSING ============================##
    start = time.time()

    if os.path.exists('ToolOutput'):
        shutil.rmtree('ToolOutput')
        os.makedirs('ToolOutput')
    else:
        os.makedirs('ToolOutput')

    cpacs_in = 'ToolInput/ToolInput.xml'


    if not os.path.exists(cpacs_in):
        raise Exception ('Error, no ToolInput.xml'\
                         + ' file in the ToolInput folder.')
    name = aircraft_name(cpacs_in)

    out_xml = copyxmlfile.copy_xml(cpacs_in, 'ToolOutput.xml')
    newpath = 'ToolOutput/' + name
    if not os.path.exists(newpath):
        os.makedirs(newpath)


##================================ USER INPUTS =============================##
    # All the input data must be defined into the unc_weight_user_input.py
    # file inside the ceasiompy.InputClasses/Unconventioanl folder.

    adui = AdvancedInputs()
    ui = UserInputs()
    mw = MassesWeights()
    out = WeightOutput()
示例#11
0
def create_SU2_mesh(cpacs_path, cpacs_out_path):
    """ Function to create a simple SU2 mesh form an SUMO file (.smx)

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

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

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

    """

    tixi = cpsf.open_tixi(cpacs_path)

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

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

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

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

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

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

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

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

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

        os.remove(su2_mesh_path)

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

    cpsf.close_tixi(tixi, cpacs_out_path)

    os.chdir(original_dir)
示例#12
0
def get_weight_unc_estimations(cpacs_path, cpacs_out_path):
    """Function to estimate the all weights for a unconventional aircraft.

    Function 'get_weight_unc_estimations' ...

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

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

    """

    # Removing and recreating the ToolOutput folder.
    if os.path.exists('ToolOutput'):
        shutil.rmtree('ToolOutput')
    os.makedirs('ToolOutput')

    if not os.path.exists(cpacs_path):
        raise ValueError('No "ToolInput.xml" file in the ToolInput folder.')

    name = aircraft_name(cpacs_path)

    shutil.copyfile(cpacs_path, cpacs_out_path)  # TODO: shoud not be like that
    newpath = 'ToolOutput/' + name
    if not os.path.exists(newpath):
        os.makedirs(newpath)

    # USER INPUTS
    # All the input data must be defined into the unc_weight_user_input.py
    # file inside the ceasiompy.InputClasses/Unconventioanl folder.

    adui = AdvancedInputs()
    ui = UserInputs()
    mw = MassesWeights()
    out = WeightOutput()
    ed = EngineData()
    (ed, ui, adui) = getinput.get_user_inputs(ed, ui, adui, cpacs_out_path)
    if ui.USER_ENGINES:
        (ed) = getinput.get_engine_inputs(ui, ed, cpacs_out_path)

    # GEOMETRY ANALYSIS

    (fus_nb, wing_nb) = uncgeomanalysis.get_number_of_parts(cpacs_path)
    h_min = ui.FLOORS_NB * ui.H_LIM_CABIN

    if not wing_nb:
        log.warning('Aircraft does not have wings')
        raise Exception('Aircraft does not have wings')
    elif not fus_nb:
        (awg, wing_nodes) = uncgeomanalysis.no_fuse_geom_analysis(cpacs_out_path, ui.FLOORS_NB, wing_nb,\
                            h_min, ui.FUEL_ON_CABIN, name, ed.TURBOPROP)
    else:
        log.info('Fuselage detected')
        log.info('Number of fuselage: ' + str(int(fus_nb)))
        # Minimum fuselage segment height to be a cabin segment.
        (afg, awg) =\
            uncgeomanalysis.with_fuse_geom_analysis(cpacs_out_path, fus_nb, wing_nb, h_min, adui,\
                                                    ed.TURBOPROP, ui.F_FUEL, name)

    ui = getinput.get_user_fuel(fus_nb, ui, cpacs_out_path)

    # WEIGHT ANALYSIS
    ## Engine evaluation
    if ui.USER_ENGINES:
        check_ed(ed)
        mw.mass_engines = ed.en_mass * ed.NE

    if fus_nb:
        # Passengers mass
        (out.pass_nb, out.toilet_nb, mw.mass_pass)\
                = estimate_fuse_passengers(fus_nb, ui.FLOORS_NB,\
                    adui.PASS_PER_TOILET, afg.cabin_area, adui.MASS_PASS,\
                    ui.PASS_BASE_DENSITY)
        cabin_area = np.sum(afg.cabin_area)
        # Structure mass
        mw.mass_structure = adui.VRT_STR_DENSITY * adui.VRT_THICK\
            *(np.sum(afg.fuse_surface)\
            + np.sum(awg.total_wings_surface))**adui.VRT_EXP
    else:
        # Passengers mass
        (out.pass_nb, out.toilet_nb, mw.mass_pass)\
                = estimate_wing_passengers(ui.FLOORS_NB,\
                    adui.PASS_PER_TOILET, awg.cabin_area, adui.MASS_PASS,\
                    ui.PASS_BASE_DENSITY)
        cabin_area = awg.cabin_area
        # Structure mass
        mw.mass_structure = adui.VRT_STR_DENSITY * adui.VRT_THICK\
            *np.sum(awg.total_wings_surface)**adui.VRT_EXP

    pass_limit = False
    if ui.MAX_PASS > 0 and out.pass_nb > ui.MAX_PASS:
        out.pass_nb = ui.MAX_PASS
        pass_limit = True
        pass_density = round(out.pass_nb / cabin_area, 2)
        mw.mass_pass = adui.MASS_PASS * out.pass_nb
        log.warning('With the defined maximum number of passengers,')
        log.warning('the number of passengers is reduced to : '\
                    + str(out.pass_nb))
        log.warning('and the passenger density is: ' + str(pass_density))

    #Payload masses
    mw.mass_payload = round(ui.MASS_CARGO + mw.mass_pass, 0)

    if ui.MAX_PAYLOAD > 0 and mw.mass_payload > ui.MAX_PAYLOAD:
        mw.mass_payload = ui.MAX_PAYLOAD
        if ui.MASS_CARGO > ui.MAX_PAYLOAD:
            log.warning('Mass cargo defined exceeds the chosen'\
                        + ' maximum payload, the code do not consider the'\
                        + ' user cargo mass')
            ui.MASS_CARGO = 0.0
        if pass_limit and mw.mass_pass < ui.MAX_PAYLOAD:
            ui.MASS_CARGO = round(ui.MAX_PAYLOAD - mw.mass_pass, 0)
        elif pass_limit and mw.mass_pass > ui.MAX_PAYLOAD:
            log.warning('Pass number defined exceeds the chosen'\
                        + ' maximum payload, the code do not consider the'\
                        + ' user passenger number.')
            mw.mass_pass = ui.MAX_PAYLOAD - ui.MASS_CARGO
            out.pass_nb = int(round(mw.mass_pass / adui.MASS_PASS, 0))
        else:
            mw.mass_pass = ui.MAX_PAYLOAD - ui.MASS_CARGO
            out.pass_nb = int(round(mw.mass_pass / adui.MASS_PASS, 0))
        pass_density = round(out.pass_nb / cabin_area, 2)
        log.warning('With the defined maximum payload and cargo masses,')
        log.warning('the number of passengers is: ' + str(out.pass_nb))
        log.warning('and the passenger density is: ' + str(pass_density))

    ## Fuel mass
    if fus_nb:
        mw.mass_fuse_fuel = estimate_fuse_fuel_mass(afg.fuse_fuel_vol,
                                                    adui.FUEL_DENSITY)
        mw.mass_wing_fuel = estimate_wing_fuel_mass(awg.wing_fuel_vol,
                                                    adui.FUEL_DENSITY)
        mw.mass_fuel_max = mw.mass_wing_fuel + mw.mass_fuse_fuel
    else:
        mw.mass_fuel_max = estimate_wing_fuel_mass(awg.fuel_vol_tot,
                                                   adui.FUEL_DENSITY)

    if ui.MAX_FUEL_VOL > 0\
        and (mw.mass_fuel_max/adui.FUEL_DENSITY)*1000.0 > ui.MAX_FUEL_VOL:
        mw.mass_fuel_max = (ui.MAX_FUEL_VOL * adui.FUEL_DENSITY) / 1000.0

    # Mass Reserve and Unusable Fuel
    mw.mass_fuel_unusable = mw.mass_fuel_max * (adui.RES_FUEL_PERC)

    # Mass Fuel Maxpass
    if not out.pass_nb:
        mw.mass_fuel_maxpass = mw.mass_fuel_max
    elif ed.TURBOPROP:
        mw.mass_fuel_maxpass = mw.mass_fuel_max * (adui.FPM_TP / 100.0)
    else:
        mw.mass_fuel_maxpass = mw.mass_fuel_max * (adui.FPM / 100.0)

    wing_area = np.sum(awg.wing_plt_area)
    mw.maximum_take_off_mass = wing_area * ui.wing_loading
    new_mtom = mw.maximum_take_off_mass
    old_mtom = 0
    it = 0
    mw.zero_fuel_mass = mw.maximum_take_off_mass\
                        - mw.mass_fuel_maxpass
    if mw.zero_fuel_mass < 0:
        mw.maximum_take_off_mass = mw.mass_fuel_maxpass * 2
        mw.zero_fuel_mass = mw.maximum_take_off_mass\
                            - mw.mass_fuel_maxpass
        ui.wing_loading = mw.maximum_take_off_mass / wing_area
        log.warning('Wing loading defined too low,'\
                    + ' starting value modified to [kg/m^2]: '\
                    + str(ui.wing_loading))

    while (abs(old_mtom - new_mtom) / max(old_mtom, new_mtom)) > 0.001:
        old_mtom = new_mtom
        mw.maximum_take_off_mass = new_mtom

        if not ui.USER_ENGINES:
            (mw.mass_engines, ed) = engine_definition(mw, ui, ed)

        # Crew mass
        (out.crew_nb, out.cabin_crew_nb, mw.mass_crew)\
                = estimate_crew(out.pass_nb, adui.MASS_PILOT,\
                                adui.MASS_CABIN_CREW,\
                                mw.maximum_take_off_mass, adui.PILOT_NB)

        # Total people and payload mass on the aircraft
        mw.mass_people = round(mw.mass_crew + mw.mass_pass, 0)

        ## System mass
        mw.mass_systems= round(estimate_system_mass(out.pass_nb, awg.main_wing_surface,\
                               awg.tail_wings_surface, adui.SINGLE_HYDRAULICS, mw, ed),0)

        ## MTOM, OEM, ZFM re-evaluation
        mw.operating_empty_mass = round(mw.mass_systems + mw.mass_crew\
                                        + mw.mass_engines + mw.mass_structure\
                                        + mw.mass_fuel_unusable,0)

        new_mtom = round(mw.operating_empty_mass + mw.mass_payload\
                         + mw.mass_fuel_maxpass)
        mw.zero_fuel_mass = mw.operating_empty_mass + mw.mass_payload

        it += 1
    # End of the iterative process.

    mw.maximum_take_off_mass = new_mtom
    out.wing_loading = new_mtom / wing_area

    # Log writting  (TODO: maybe create a separate function)
    log.info('--------- Masses evaluated: -----------')
    log.info('System mass [kg]: ' + str(int(round(mw.mass_systems))))
    log.info('People mass [kg]: ' + str(int(round(mw.mass_people))))
    log.info('Payload mass [kg]: ' + str(int(round(mw.mass_payload))))
    log.info('Structure mass [kg]: ' + str(int(round(mw.mass_structure))))
    log.info('Total fuel mass [kg]: ' + str(int(round(mw.mass_fuel_max))))
    log.info('Total fuel volume [l]: '\
             + str(int(round(mw.mass_fuel_max/adui.FUEL_DENSITY*1000.0))))
    log.info('Mass of fuel with max passengers [kg]: ' +
             str(int(round(mw.mass_fuel_maxpass))))
    log.info('Volume of fuel with maximum passengers [l]: '\
             + str(int(round(mw.mass_fuel_maxpass/adui.FUEL_DENSITY*1000.0))))
    log.info('Engines mass [kg]: ' + str(int(round(mw.mass_engines))))
    log.info('---------------------------------------')
    log.info('Maximum Take Off Mass [kg]: ' +
             str(int(round(mw.maximum_take_off_mass))))
    log.info('Operating Empty Mass [kg]: ' +
             str(int(round(mw.operating_empty_mass))))
    log.info('Zero Fuel Mass [kg]: ' + str(int(round(mw.zero_fuel_mass))))
    log.info('Wing loading [kg/m^2]: ' + str(int(round(out.wing_loading))))
    log.info('--------- Passegers evaluated: ---------')
    log.info('Passengers: ' + str(out.pass_nb))
    log.info('Toilet: ' + str(int(out.toilet_nb)))
    log.info('------- Crew members evaluated: --------')
    log.info('Pilots: ' + str(adui.PILOT_NB))
    log.info('Cabin crew members: ' + str(out.cabin_crew_nb))
    log.info('---------------------------------------')
    log.info('Number of iterations: ' + str(it))
    log.info('---------------------------------------')
    log.info('### Uconventional Weight analysis succesfuly completed ###')

    # Outptu writting
    log.info('----- Generating output text file -----')
    cpacsweightupdate.cpacs_weight_update(out, mw, ui, cpacs_out_path)
    cpacsweightupdate.toolspecific_update(fus_nb, awg, mw, out, cpacs_out_path)
    cpacsweightupdate.cpacs_engine_update(ui, ed, mw, cpacs_out_path)

    if not fus_nb:
        outputweightgen.output_bwb_txt(ui.FLOORS_NB, ed, out, mw, adui, awg,
                                       name)
    else:
        outputweightgen.output_fuse_txt(fus_nb, ui.FLOORS_NB, ed, out, mw,
                                        adui, awg, afg, name)
示例#13
0
def get_balance_estimations(cpacs_path, cpacs_out_path):
    """Function to estimate inertia value and CoF of an conventional aircraft.

    Function 'get_balance_unc_estimations' ...

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

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

    """

    # Removing and recreating the ToolOutput folder.
    if os.path.exists('ToolOutput'):
        shutil.rmtree('ToolOutput')
    os.makedirs('ToolOutput')

    if not os.path.exists(cpacs_path):
        raise ValueError('No "ToolInput.xml" file in the ToolInput folder.')

    name = aircraft_name(cpacs_path)

    shutil.copyfile(cpacs_path, cpacs_out_path)  # TODO: shoud not be like that
    newpath = 'ToolOutput/' + name
    if not os.path.exists(newpath):
        os.makedirs(newpath)

    # BALANCE ANALSIS INPUTS
    bi = balanceconvclass.BalanceInputs()
    out = balanceconvclass.BalanceOutputs()
    mw = balanceconvclass.MassesWeights()
    (mw, bi) = getdatafromcpacs.get_data(mw, bi, cpacs_out_path)

    # BALANCE ANALYSIS

    log.info('------- Starting the balance analysis -------')
    log.info('---------- Aircraft: ' + name + ' -----------')
    F_PERC_MAXPASS = (mw.mass_fuel_maxpass / mw.mass_fuel_max) * 100

    # CENTER OF GRAVITY---------------------------------------------------------
    ag = geometry.geometry_eval(cpacs_out_path, name)

    log.info('------- Center of Gravity coordinates -------')
    log.info('--------- Max Payload configuration ---------')
    (out.center_of_gravity, mass_seg_i, airplane_centers_segs)\
            = center_of_gravity_evaluation(F_PERC_MAXPASS, 100, ag.cabin_seg,\
                                           ag, mw, bi.WING_MOUNTED)
    log.info('[x, y, z] = ' + str(out.center_of_gravity))
    log.info('---------- Zero Fuel configuration ----------')
    (out.cg_zfm, ms_zfm, airplane_centers_segs)\
            = center_of_gravity_evaluation(0, 100, ag.cabin_seg,\
                                           ag, mw, bi.WING_MOUNTED)
    log.info('[x, y, z] = ' + str(out.cg_zfm))
    log.info('-------- Zero Payload configuration ---------')
    (out.cg_zpm, ms_zpm, airplane_centers_segs)\
            = center_of_gravity_evaluation(100, 0, ag.cabin_seg,\
                                           ag, mw, bi.WING_MOUNTED)
    log.info('[x, y, z] = ' + str(out.cg_zpm))
    log.info('------------- OEM configuration -------------')
    (out.cg_oem, ms_oem, airplane_centers_segs)\
            = center_of_gravity_evaluation(0, 0, ag.cabin_seg,\
                                           ag, mw, bi.WING_MOUNTED)
    log.info('[x, y, z] = ' + str(out.cg_oem))
    if bi.USER_CASE == True:
        if bi.P_PERC < 0 or bi.F_PERC < 0:
            raise Exception('Error, F_PERC and P_PERC can'\
                            + ' not be zero or negative.')
        if (mw.mass_fuel_maxpass*(bi.F_PERC/100.0)\
            + mw.mass_payload*(bi.P_PERC/100.0))\
            > mw.mass_fuel_maxpass + mw.mass_payload:
            log.warning('Exceeding maximum fuel amount with the'\
                        + 'chosen payload mass,'\
                        + 'fuel mass automatically reduced')
            bi.F_PERC = 1 + ((mw.mass_payload/mw.mass_fuel_maxpass)\
                   * (1-(bi.P_PERC/100.0)))
            log.warning('FUEL percentage: ' + str(bi.F_PERC))
        log.info('------------- User configuration ------------')
        (out.cg_user, ms_user, airplane_centers_segs)\
                 = center_of_gravity_evaluation(bi.F_PERC*100, bi.P_PERC,\
                         ag.cabin_seg, ag, mw, bi.WING_MOUNTED)

    # MOMENT OF INERTIA
    center_of_gravity_seg = []
    mass_component = []
    log.info('------------- Inertia Evaluation ------------')
    log.info('------------ Lumped mass Inertia ------------')
    log.info('--------- Max Payload configuration ---------')
    (fx, fy, fz, Ixxf, Iyyf, Izzf, Ixyf, Iyzf, Ixzf)\
            = lumpedmassesinertia.fuselage_inertia(\
                bi.SPACING_FUSE, out.center_of_gravity, mass_seg_i,\
                ag, cpacs_out_path)
    (wx, wy, wz, Ixxw, Iyyw, Izzw, Ixyw, Iyzw, Ixzw)\
            = lumpedmassesinertia.wing_inertia(\
                bi.WPP, bi.SPACING_WING, out.center_of_gravity,\
                mass_seg_i, ag, cpacs_out_path)

    rd = check_rounding(Ixxf + Ixxw, Iyzf + Iyzw)
    out.Ixx_lump = round(Ixxf + Ixxw, rd)
    out.Iyy_lump = round(Iyyf + Iyyw, rd)
    out.Izz_lump = round(Izzf + Izzw, rd)
    out.Ixy_lump = round(Ixyf + Ixyw, rd)
    out.Iyz_lump = round(Iyzf + Iyzw, rd)
    out.Ixz_lump = round(Ixzf + Ixzw, rd)

    log.info('---------- Zero Fuel configuration ----------')
    (fx, fy, fz, Ixxf2, Iyyf2, Izzf2, Ixyf2, Iyzf2, Ixzf2)\
            = lumpedmassesinertia.fuselage_inertia(bi.SPACING_FUSE,\
                out.cg_zfm, ms_zfm, ag, cpacs_out_path)
    (wx, wy, wz, Ixxw2, Iyyw2, Izzw2, Ixyw2, Iyzw2, Ixzw2)\
            = lumpedmassesinertia.wing_inertia(bi.WPP, bi.SPACING_WING,\
                out.cg_zfm, ms_zfm, ag, cpacs_out_path)

    out.Ixx_lump_zfm = round(Ixxf2 + Ixxw2, rd)
    out.Iyy_lump_zfm = round(Iyyf2 + Iyyw2, rd)
    out.Izz_lump_zfm = round(Izzf2 + Izzw2, rd)
    out.Ixy_lump_zfm = round(Ixyf2 + Ixyw2, rd)
    out.Iyz_lump_zfm = round(Iyzf2 + Iyzw2, rd)
    out.Ixz_lump_zfm = round(Ixzf2 + Ixzw2, rd)

    log.info('--------- Zero Payload configuration --------')
    (fx, fy, fz, Ixxf3, Iyyf3, Izzf3, Ixyf3, Iyzf3, Ixzf3)\
            = lumpedmassesinertia.fuselage_inertia(bi.SPACING_FUSE,\
                out.cg_zpm, ms_zpm, ag, cpacs_out_path)
    (wx, wy, wz, Ixxw3, Iyyw3, Izzw3, Ixyw3, Iyzw3, Ixzw3)\
            = lumpedmassesinertia.wing_inertia(bi.WPP, bi.SPACING_WING,\
                out.cg_zpm, ms_zpm, ag, cpacs_out_path)

    out.Ixx_lump_zpm = round(Ixxf3 + Ixxw3, rd)
    out.Iyy_lump_zpm = round(Iyyf3 + Iyyw3, rd)
    out.Izz_lump_zpm = round(Izzf3 + Izzw3, rd)
    out.Ixy_lump_zpm = round(Ixyf3 + Ixyw3, rd)
    out.Iyz_lump_zpm = round(Iyzf3 + Iyzw3, rd)
    out.Ixz_lump_zpm = round(Ixzf3 + Ixzw3, rd)

    log.info('------------- OEM configuration -------------')
    (fx, fy, fz, Ixxf4, Iyyf4, Izzf4, Ixyf4, Iyzf4, Ixzf4)\
            = lumpedmassesinertia.fuselage_inertia(bi.SPACING_FUSE,\
                out.cg_oem, ms_oem, ag, cpacs_out_path)
    (wx, wy, wz, Ixxw4, Iyyw4, Izzw4, Ixyw4, Iyzw4, Ixzw4)\
            = lumpedmassesinertia.wing_inertia(bi.WPP, bi.SPACING_WING,\
                out.cg_oem, ms_oem, ag, cpacs_out_path)

    out.Ixx_lump_oem = round(Ixxf4 + Ixxw4, rd)
    out.Iyy_lump_oem = round(Iyyf4 + Iyyw4, rd)
    out.Izz_lump_oem = round(Izzf4 + Izzw4, rd)
    out.Ixy_lump_oem = round(Ixyf4 + Ixyw4, rd)
    out.Iyz_lump_oem = round(Iyzf4 + Iyzw4, rd)
    out.Ixz_lump_oem = round(Ixzf4 + Ixzw4, rd)

    if bi.USER_CASE:
        log.info('------------- User configuration ------------')
        (fx, fy, fz, Ixxfu, Iyyfu, Izzfu, Ixyfu, Iyzfu, Ixzfu)\
                = lumpedmassesinertia.fuselage_inertia(bi.SPACING_FUSE,\
                    out.cg_user, ms_user, ag, cpacs_out_path)
        (wx, wy, wz, Ixxwu, Iyywu, Izzwu, Ixywu, Iyzwu, Ixzwu)\
                = lumpedmassesinertia.wing_inertia(bi.WPP, bi.SPACING_WING,\
                    out.cg_user, ms_user, ag, cpacs_out_path)

        out.Ixx_lump_user = round(Ixxfu + Ixxwu, rd)
        out.Iyy_lump_user = round(Iyyfu + Iyywu, rd)
        out.Izz_lump_user = round(Izzfu + Izzwu, rd)
        out.Ixy_lump_user = round(Ixyfu + Ixywu, rd)
        out.Iyz_lump_user = round(Iyzfu + Iyzwu, rd)
        out.Ixz_lump_user = round(Ixzfu + Ixzwu, rd)

    # OUTPUT WRITING

    log.info('-------- Generating output text file --------')
    outputbalancegen.output_txt(out, mw, bi, name)

    # CPACS WRITING
    cpacsbalanceupdate.cpacs_mbd_update(out, mw, bi, np.sum(ms_zpm),
                                        cpacs_out_path)

    # PLOTS
    # Aircraft Cog Plot
    log.info('--- Generating aircraft center of gravity plot (.png) ---')
    outputbalancegen.aircraft_cog_plot(out.center_of_gravity, ag, name)

    # Aircraft Nodes
    # Uncomment to plot aircraft nodes.
    #log.info('--- Generating aircraft nodes plot (.png) ---')
    #outputbalancegen.aircraft_nodes_plot(fx, fy, fz, wx, wy, wz, name)

    # Show plots
    plt.show()

    # LOG WRITING
    log.info('---- Center of Gravity coordinates ----')
    log.info('------ Max Payload configuration ------')
    log.info('[x, y, z]: ' + str(out.center_of_gravity))
    log.info('---------------------------------------')
    log.info('------- Zero Fuel configuration -------')
    log.info('[x, y, z]: ' + str(out.cg_zfm))
    log.info('---------------------------------------')
    log.info('----- Zero Payload configuration ------')
    log.info('[x, y, z]: ' + str(out.cg_zpm))
    log.info('---------------------------------------')
    log.info('---------- OEM configuration ----------')
    log.info('[x, y, z]: ' + str(out.cg_oem))
    log.info('---------------------------------------')
    if bi.USER_CASE:
        log.info('---------- User configuration ---------')
        log.info('Chosen Fuel Percentage: ' + str(bi.F_PERC))
        log.info('Chosen Payload Percentage: ' + str(bi.P_PERC))
        log.info('[x, y, z]: ' + str(out.cg_user))
    log.info('---------------------------------------')
    log.info('---------- Inertia Evaluation ---------')
    log.info('--------- Lumped mass Inertia ---------')
    log.info('------ Max Payload configuration ------')
    log.info('Roll moment, Ixx [kgm^2]: ' + str(out.Ixx_lump))
    log.info('Pitch moment, Iyy [kgm^2]: ' + str(out.Iyy_lump))
    log.info('Yaw moment, Izz [kgm^2]: ' + str(out.Izz_lump))
    log.info('Ixy moment [kgm^2]: ' + str(out.Ixy_lump))
    log.info('Iyz moment [kgm^2]: ' + str(out.Iyz_lump))
    log.info('Ixz moment [kgm^2]: ' + str(out.Ixz_lump))
    log.info('---------------------------------------')
    log.info('------- Zero Fuel configuration -------')
    log.info('Roll moment, Ixx [kgm^2]: ' + str(out.Ixx_lump_zfm))
    log.info('Pitch moment, Iyy [kgm^2]: ' + str(out.Iyy_lump_zfm))
    log.info('Yaw moment, Izz [kgm^2]: ' + str(out.Izz_lump_zfm))
    log.info('Ixy moment [kgm^2]: ' + str(out.Ixy_lump_zfm))
    log.info('Iyz moment [kgm^2]: ' + str(out.Iyz_lump_zfm))
    log.info('Ixz moment [kgm^2]: ' + str(out.Ixz_lump_zfm))
    log.info('---------------------------------------')
    log.info('------ Zero Payload configuration -----')
    log.info('Roll moment, Ixx [kgm^2]: ' + str(out.Ixx_lump_zpm))
    log.info('Pitch moment, Iyy [kgm^2]: ' + str(out.Iyy_lump_zpm))
    log.info('Yaw moment, Izz [kgm^2]: ' + str(out.Izz_lump_zpm))
    log.info('Ixy moment [kgm^2]: ' + str(out.Ixy_lump_zpm))
    log.info('Iyz moment [kgm^2]: ' + str(out.Iyz_lump_zpm))
    log.info('Ixz moment [kgm^2]: ' + str(out.Ixz_lump_zpm))
    log.info('---------------------------------------')
    log.info('---------- OEM configuration ----------')
    log.info('Roll moment, Ixx [kgm^2]: ' + str(out.Ixx_lump_oem))
    log.info('Pitch moment, Iyy [kgm^2]: ' + str(out.Iyy_lump_oem))
    log.info('Yaw moment, Izz [kgm^2]: ' + str(out.Izz_lump_oem))
    log.info('Ixy moment [kgm^2]: ' + str(out.Ixy_lump_oem))
    log.info('Iyz moment [kgm^2]: ' + str(out.Iyz_lump_oem))
    log.info('Ixz moment [kgm^2]: ' + str(out.Ixz_lump_oem))
    log.info('---------------------------------------')
    if bi.USER_CASE:
        log.info('---------- User configuration ---------')
        log.info('Roll moment, Ixx [kgm^2]: ' + str(out.Ixx_lump_user))
        log.info('Pitch moment, Iyy [kgm^2]: ' + str(out.Iyy_lump_user))
        log.info('Yaw moment, Izz [kgm^2]: ' + str(out.Izz_lump_user))
        log.info('Ixy moment [kgm^2]: ' + str(out.Ixy_lump_user))
        log.info('Iyz moment [kgm^2]: ' + str(out.Iyz_lump_user))
        log.info('Ixz moment [kgm^2]: ' + str(out.Ixz_lump_user))
        log.info('---------------------------------------')

    log.info('############## Balance estimation completed ##############')
示例#14
0
def create_SU2_mesh(cpacs_path, cpacs_out_path):
    """ Function to create a simple SU2 mesh form an SUMO file (.smx)

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

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

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

    """

    tixi = cpsf.open_tixi(cpacs_path)

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

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

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

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

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

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

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

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

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

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

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

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

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

        os.remove(su2_mesh_path)

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

    cpsf.close_tixi(tixi, cpacs_out_path)

    os.chdir(original_dir)
示例#15
0
def get_range_estimation(cpacs_path, cpacs_out_path):

    if os.path.exists('ToolOutput'):
        shutil.rmtree('ToolOutput')
    os.makedirs('ToolOutput')

    if not os.path.exists(cpacs_path):
        raise ValueError('No "ToolInput.xml" file in the ToolInput folder.')

    name = aircraft_name(cpacs_path)

    shutil.copyfile(cpacs_path, cpacs_out_path)  # TODO: shoud not be like that
    newpath = 'ToolOutput/' + name
    if not os.path.exists(newpath):
        os.makedirs(newpath)

    # RANGE ANALYSIS IMPUTS

    ri = rangeclass.RangeInputs()
    out = rangeclass.RangeOutput()
    mw = rangeclass.MassesWeights()

    (mw, ri) = getdatafromcpacs.get_data(mw, ri, cpacs_out_path)

    if ri.TURBOPROP:
        LDcru = ri.LD
        LDloi = ri.LD * 0.866
    else:
        LDcru = ri.LD * 0.866
        LDloi = ri.LD

    if ri.WINGLET >= 0:
        ri.TSFC_CRUISE = ri.TSFC_CRUISE - 0.05 * ri.WINGLET
    elif ri.WINGLET > 2:
        log.warning('Warning, winglet type index is 1 (medium efficiency),'\
                    + ' 2 (high efficiency). Set no winglet (0)')

    # RANGE ANALYSIS

    log.info('-------- Starting the range analysis --------')
    log.info('---------- Aircraft: ' + name + ' -----------')

    # RANGE AND FUEL CONSUMPTION
    mw = fuel_consumption(LDloi, mw, ri, ri.RES_FUEL_PERC)

    (out.ranges, out.ranges_cru, mw.m_pass_middle)\
        = breguet_cruise_range(LDcru, ri, mw, ri.RES_FUEL_PERC)

    if mw.m_pass_middle:
        out.payloads=[round(mw.mass_payload,0), round(mw.mass_payload,0),\
                      round(mw.m_pass_middle,0), 0]
    else:
        out.payloads=[round(mw.mass_payload,0), round(mw.mass_payload,0),\
                      round(mw.mass_payload,0), 0]

    # CREW MEMBERS CHECK
    if ri.cabin_crew_nb:
        (out.pilot_nb, out.cabin_crew_nb, out.crew_nb,\
         out.mass_crew, out.flight_time)= crew_check(out.ranges[1], ri)

    # OUTPUT WRITING

    log.info('-------- Generating output text file --------')
    outputrangegen.output_txt(LDloi, LDcru, mw, ri, out, name)

    # CPACS WRITING

    cpacsrangeupdate.cpacs_update(ri.MASS_PASS, out, mw, cpacs_out_path)

    if os.path.exists('ToolInput/conv.temp'):
        B = 'BalanceConventional/ToolInput'
    elif os.path.exists('ToolInput/unconv.temp'):
        B = 'BalanceUnconventional/ToolInput'
    elif os.path.exists('ToolInput/nocpacs.temp'):
        log.warning('No Balance analysis without cpacs geometry file')
        B = False
    else:
        raise Exception('Error no conv.temp, unconv.temp '\
                        + 'or nocpacs.temp inside ToolInput folder')

    if os.path.exists('ToolOutput/ToolOutput.xml') and B:
        if os.path.exists('../' + B):
            shutil.rmtree('../' + B)
            os.makedirs('../' + B)
        PATH_BALANCE_OUT = '../' + B + '/ToolInput.xml'
        #shutil.copyfile('ToolOutput/ToolOutput.xml', PATH_BALANCE_OUT)

    # PLOTS
    # Payload vs Range ---------------------------------------------------------
    log.info('---- Generating payload versus range plot ---')
    outputrangegen.payload_range_plot(out.ranges, out.ranges_cru, out.payloads,
                                      mw, name)

    # Show plots
    #plt.show()

    # LOG WRITING
    log.info('------ Mass evaluation completed ------')
    log.info('-------------- Masses -----------------')
    log.info('Payload mass [kg]: ' + str(int(round(mw.mass_payload))))
    log.info('Total fuel mass [kg]: ' + str(int(round(mw.mass_fuel_max))))
    log.info('Mass of fuel with maximum passengers [kg]:' +
             str(int(round(mw.mass_fuel_maxpass))))
    log.info('Maximum Take Off Mass [kg]: ' +
             str(int(round(mw.maximum_take_off_mass))))

    if ri.cabin_crew_nb:
        log.info('------- Suggested crew members --------')
        log.info('Pilots: ' + str(out.pilot_nb))
        log.info('Cabin crew members: ' + str(out.cabin_crew_nb))
        log.info('Flight time [min]: ' + str(int(round(out.flight_time * 60))))

    log.info('--------------- Ranges ----------------')
    log.info('Range with maximum payload [km]: ' +
             str(int(round(out.ranges[1]))))
    log.info('Range with maximum fuel and some payload [km]: ' +
             str(int(round(out.ranges[2]))))
    log.info('Maximum range [km]: ' + str(int(round(out.ranges[-1]))))

    log.info('------------- Cruise Ranges --------------')
    log.info('Cruise range with maximum payload [km]: ' +
             str(int(round(out.ranges_cru[1]))))
    log.info('Cruise range with maximum fuel and some payload [km]: ' +
             str(int(round(out.ranges_cru[2]))))
    log.info('Maximum cruise range [km]: ' +
             str(int(round(out.ranges_cru[-1]))))
    log.info('--- Fuel Consumption  (max passengers) ---')
    log.info('Fuel for take off [kg]: ' + str(int(round(mw.mf_for_to))))
    log.info('Fuel for climb [kg]: ' + str(int(round(mw.mf_for_climb))))
    log.info('Fuel for cruise [kg]: ' + str(int(round(mw.mf_for_cruise))))
    log.info('Fuel for a 30 min loiter [kg]: ' +
             str(int(round(mw.mf_for_loiter))))
    log.info('Fuel for landing [kg]: ' + str(int(round(mw.mf_for_landing))))
    log.info('Total fuel remaining after landing [kg]: ' +
             str(int(round(mw.mf_after_land))))

    log.info('------ Weigth loss (max passengers) ------')
    log.info('Weight after take off [N]: ' + str(int(round(mw.w_after_to))))
    log.info('Weight after climb [N]: ' + str(int(round(mw.w_after_climb))))
    log.info('Weight after cruise [N]: ' + str(int(round(mw.w_after_cruise))))
    log.info('Weight after a 30 min loiter [N]: ' +
             str(int(round(mw.w_after_loiter))))
    log.info('Weight after landing [N]: ' + str(int(round(mw.w_after_land))))

    log.info('############### Range estimation completed ###############')