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'
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()
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 + ' -----------')
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)
def test_aircraft_name(): """Test the function 'aircraft_name'""" name = aircraft_name(CPACS_IN_PATH) assert name == 'Cpacs2Test'
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)
def generate_config_deformed_mesh(cpacs_path, cpacs_out_path, skip_config=False, skip_su2=False): """Function to generate all deform meshes with SU2 from CPACS data Function 'generate_config_deformed_mesh' reads data in the CPACS file and generate all the corresponding directory and config file which allow to generate deformed meshes. Args: cpacs_path (str): Path to CPACS file cpacs_out_path (str):Path to CPACS output file skip_config (bool): skip_su2 (bool): """ tixi = cpsf.open_tixi(cpacs_path) wkdir = ceaf.get_wkdir_or_create_new(tixi) # Get SU2 mesh path su2_mesh_xpath = '/cpacs/toolspecific/CEASIOMpy/filesPath/su2Mesh' su2_mesh_path = cpsf.get_value(tixi, su2_mesh_xpath) if wkdir in su2_mesh_path: log.info('The Baseline SU2 mesh is already in the working directory.') else: mesh_dir = os.path.join(wkdir, 'MESH') if not os.path.isdir(mesh_dir): os.mkdir(mesh_dir) aircraft_name = cpsf.aircraft_name(tixi) su2_mesh_new_path = os.path.join(mesh_dir, aircraft_name + '_baseline.su2') shutil.copyfile(su2_mesh_path, su2_mesh_new_path) tixi.updateTextElement(su2_mesh_xpath, su2_mesh_new_path) if not skip_config: # Control surfaces deflections control_surf_xpath = SU2_XPATH + '/options/clalculateCotrolSurfacesDeflections' control_surf = cpsf.get_value_or_default(tixi, control_surf_xpath, False) if not control_surf: log.warning( 'The CPACS file indicate that Control surface deflection should not be calculated!' ) active_ted_list = [] else: ted_df = get_ted_list(tixi) # TODO: option to calculate only TED selected in cpacs # if ... # active_ted_xpath = SU2_XPATH + '/options/....' # # check element # active_ted_list = cpsf.get_string_vector(tixi,active_ted_xpath) # else: calculate all TED adn all deflections from CPACS # active_ted_list = ted_list for i, row in ted_df.iterrows(): # Unwrap TED data from the dataframe ted_uid = row['ted_uid'] wing_uid = row['wing_uid'] sym_dir = row['sym_dir'] defl_list = row['defl_list'] generate_mesh_def_config(tixi, wkdir, ted_uid, wing_uid, sym_dir, defl_list) if not skip_su2: run_mesh_deformation(tixi, wkdir) cpsf.close_tixi(tixi, cpacs_out_path)
def 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.')
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 ##')
##=============================== 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()
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)
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)
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 ##############')
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)
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 ###############')