def test_aircraft_name(): """Test the function aircraft_name.""" # Get name form the CPACS file path cpacs_in = str( Path( Path(__file__).parents[4], "test_files/CPACSfiles/D150_simple.xml")) assert aircraft_name(cpacs_in) == "D150" # Get name form TIXI handle tixi = open_tixi(cpacs_in) assert aircraft_name(tixi) == "D150"
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 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 = open_tixi(cpacs_path) wkdir = get_results_directory("SU2Run") # Get SU2 mesh path su2_mesh_xpath = "/cpacs/toolspecific/CEASIOMpy/filesPath/su2Mesh" su2_mesh_path = 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) ac_name = aircraft_name(tixi) su2_mesh_new_path = os.path.join(mesh_dir, ac_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 = 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 = 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) tixi.save(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 deflection angles to generate """ tigl = open_tigl(tixi) ac_name = aircraft_name(tixi) DEFAULT_CONFIG_PATH = MODULE_DIR + "/files/DefaultConfig_v7.cfg" cfg = ConfigFile(DEFAULT_CONFIG_PATH) config_dir_name = ac_name + "_TED_" + ted_uid # TODO: add check or remove if already 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 = get_value(tixi, REF_XPATH + "/length") ref_area = get_value(tixi, REF_XPATH + "/area") ref_ori_moment_x = get_value_or_default(tixi, REF_XPATH + "/point/x", 0.0) ref_ori_moment_y = get_value_or_default(tixi, REF_XPATH + "/point/y", 0.0) ref_ori_moment_z = 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, ac_name + "_baseline.su2") cfg["MESH_FILENAME"] = "../" + ac_name + "_baseline.su2" # Mesh Marker bc_wall_list, engine_bc_list = 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) cfg.write_file(config_path, overwrite=True) 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 = ac_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) cfg.write_file(config_path, overwrite=True) log.info(config_path + " have has been written.") if sym_dir: # TODO: add a condition for anti symmetric 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 = ac_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) cfg.write_file(config_path, overwrite=True) log.info(config_path + " have has been written.")
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 """ # Removing and recreating the ToolOutput folder. if os.path.exists("ToolOutput"): shutil.rmtree("ToolOutput") 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)") cabin_length2 = ind.cabin_length # 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: mw.maximum_take_off_mass = mw.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(mw.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)) 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 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 ###############")
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 log.info("------------- Inertia Evaluation ------------") log.info("------------ Lumped mass Inertia ------------") log.info("--------- Max Payload configuration ---------") (_, _, _, Ixxf, Iyyf, Izzf, Ixyf, Iyzf, Ixzf) = lumpedmassesinertia.fuselage_inertia(bi.SPACING_FUSE, out.center_of_gravity, mass_seg_i, ag, cpacs_out_path) (_, _, _, 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 ----------") (_, _, _, Ixxf2, Iyyf2, Izzf2, Ixyf2, Iyzf2, Ixzf2) = lumpedmassesinertia.fuselage_inertia(bi.SPACING_FUSE, out.cg_zfm, ms_zfm, ag, cpacs_out_path) (_, _, _, 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 --------") (_, _, _, Ixxf3, Iyyf3, Izzf3, Ixyf3, Iyzf3, Ixzf3) = lumpedmassesinertia.fuselage_inertia(bi.SPACING_FUSE, out.cg_zpm, ms_zpm, ag, cpacs_out_path) (_, _, _, 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 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 ##")
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 = open_tixi(cpacs_path) sumo_dir = get_results_directory("SUMOAutoMesh") su2_mesh_path = os.path.join(sumo_dir, "ToolOutput.su2") sumo_file_xpath = "/cpacs/toolspecific/CEASIOMpy/filesPath/sumoFilePath" sumo_file_path = 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 = 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 with change_working_dir(sumo_dir): command = ["open", "/Applications/SUMO/dwfsumo.app/"] # /Applications/SUMO/dwfsumo.app/Contents/MacOS/dwfsumo # -batch output=su2 -tetgen-options=pq1.16VY ToolOutput.smx os.system(" ".join(command)) input("Press ENTER to continue...") elif current_os == "Linux": log.info("Your OS is Linux") # Check if SUMO is installed soft_dict = get_install_path(["sumo"]) # Run SUMO in batch output = "-output=su2" options = "-tetgen-options=pq1.16VY" # See Tetgen help for more options # Command line to run: sumo -batch -output=su2 -tetgen-options=pq1.16VY ToolOutput.smx command = [ soft_dict["sumo"], "-batch", output, options, sumo_file_path ] with change_working_dir(sumo_dir): 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 NotImplementedError("OS not supported yet!") else: raise OSError("OS not recognize!") # Copy the mesh in the MESH directory su2_mesh_name = aircraft_name(tixi) + "_baseline.su2" su2_mesh_new_path = os.path.join(sumo_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.") create_branch(tixi, SU2MESH_XPATH) tixi.updateTextElement(SU2MESH_XPATH, su2_mesh_new_path) os.remove(su2_mesh_path) else: raise ValueError("No SU2 Mesh file has been generated!") tixi.save(cpacs_out_path)