def test_open_tigl(): """Test the function 'open_tigl'""" # Create TIGL handle for a valid TIXI handles tixi_handle = open_tixi(CPACS_IN_PATH) tigl_handle = open_tigl(tixi_handle) assert tigl_handle # Raise error for an invalid TIXI handles with pytest.raises(AttributeError): tixi_handle = open_tigl('invalid_TIGL_handle')
def cpacs_engine_update(ui, ed, mw, out_xml): """ The function that update the cpacs file after the Weight_unc_main program. INPUT (class) mw --Arg.: MassesWeihts class. (class) ui --Arg.: UserInputs class. (class) ed --Arg.: EngineData class. ##======= Class are defined in the Input_Classes folder =======## (char) out_xml --Arg.: Path of the output file. OUTPUT (file) cpacs.xml --Out.: Updated cpacs file. """ tixi = cpf.open_tixi(out_xml) tigl = cpf.open_tigl(tixi) # Path creation ========================================================== EN_PATH = '/cpacs/vehicles/engines' if tixi.checkElement(EN_PATH): tixi.removeElement(EN_PATH) for e in range(0, ed.NE): EN_PATH = '/cpacs/vehicles/engines/engine' + str(e + 1) tixi = cpf.create_branch(tixi, EN_PATH, True) EN_UID = 'EngineuID_' + str(e + 1) tixi = cpf.add_uid(tixi, EN_PATH, EN_UID) tixi.createElement(EN_PATH, 'name') if not ed.EN_NAME[e]: EN_NAME = 'Engine_' + str(e + 1) tixi.updateTextElement(EN_PATH + '/name', EN_NAME) else: tixi.updateTextElement(EN_PATH + '/name', ed.EN_NAME[e]) ENA_PATH = EN_PATH + '/analysis/mass' tixi = cpf.create_branch(tixi, ENA_PATH, False) tixi = cpf.add_uid(tixi, EN_PATH, EN_UID + '_mass') tixi.createElement(ENA_PATH, 'mass') tixi.updateDoubleElement(ENA_PATH + '/mass', ed.en_mass, '%g') ENT_PATH = EN_PATH + '/analysis' tixi.createElement(ENT_PATH, 'thrust00') tixi.updateDoubleElement(ENT_PATH + '/thrust00', ed.max_thrust, '%g') # Saving and closing the new cpacs file inside the ToolOutput folder ----- tixi.saveDocument(out_xml) cpf.close_tixi(tixi, out_xml) # Openign and closing again the cpacs file, formatting purpose ----------- tixi = cpf.open_tixi(out_xml) tigl = cpf.open_tigl(tixi) tixi.saveDocument(out_xml) cpf.close_tixi(tixi, out_xml) return ()
def update_cpacs_file(cpacs_path, cpacs_out_path, optim_var_dict): """Function to update a CPACS file with value from the optimiser This function sets the new values of the design variables given by the routine driver to the CPACS file, using the Tigl and Tixi handler. Source: * See CPACSCreator api function, Args: cpacs_path (str): Path to CPACS file to update cpacs_out_path (str):Path to the updated CPACS file optim_var_dict (dict): Dictionary containing all the variable value/min/max and command to modify a CPACS file """ tixi = cpsf.open_tixi(cpacs_path) tigl = cpsf.open_tigl(tixi) aircraft = get_aircraft(tigl) # help(aircraft) wings = aircraft.get_wings() # help(wings) fuselage = aircraft.get_fuselages().get_fuselage(1) # help(fuselage) # Other functions which could be useful # help(wings.get_wing(1).get_section(1)) # uid = wings.get_wing(1).get_section(2).get_uid() # help(wings.get_wing(1).get_positioning_transformation(uid)) # wings.get_wing(1).get_section(2).set_rotation(geometry.CTiglPoint(40,40,-4)) # airfoil = wings.get_wing(1).get_section(1).get_section_element(1).get_airfoil_uid() # help(airfoil) # wings.get_wing(1).get_section(1).get_section_element(1).set_airfoil_uid('NACA0006') # scal = wings.get_wing(1).get_section(1).get_section_element(1).get_scaling() # help(wings.get_wing(1).get_section(2)) # Perform update of all the variable contained in 'optim_var_dict' for name, (val_type, listval, minval, maxval, getcommand, setcommand) in optim_var_dict.items(): if val_type == 'des' and listval[0] not in ['-', 'True', 'False']: if setcommand not in ['-', '']: # Define variable (var1,var2,..) locals()[str(name)] = listval[-1] # Execute the command coresponding to the variable if ';' in setcommand: # if more than one command on the line command_split = setcommand.split(';') for setcommand in command_split: eval(setcommand) else: eval(setcommand) else: xpath = getcommand tixi.updateTextElement(xpath, str(listval[-1])) aircraft.write_cpacs(aircraft.get_uid()) tigl.close() cpsf.close_tixi(tixi, cpacs_out_path)
def init_geom_var_dict(tixi): """Create design variable dictionary Return the dictionary of the design variables using the TIGL library. Add design variables and constrains relative to the aircraft fuselages to the dictionnary. Args: tixi (handle) : Handle of the CPACS file Returns: geom_var_dict (dict) : dictionary with the geometric parameters of the routine. """ tigl = cpsf.open_tigl(tixi) aircraft = cpud.get_aircraft(tigl) fuse_nb = aircraft.get_fuselage_count() if fuse_nb: init_fuse_param(aircraft, fuse_nb) wing_nb = aircraft.get_wing_count() if wing_nb: init_wing_param(aircraft, wing_nb) return geom_var_dict
def test_estimate_skin_friction_coef(): """Test function 'estimate_skin_friction_coef' """ # Test 1 wetted_area = 1 wing_area = 1 wing_span = 1 mach = 1 alt = 1 cd0 = estimate_skin_friction_coef(wetted_area,wing_area,wing_span,mach,alt) assert cd0 == approx(0.005320707210958961) # Test 2, with "real values" tixi = open_tixi(CPACS_IN_PATH) tigl = open_tigl(tixi) analyses_xpath = '/cpacs/toolspecific/CEASIOMpy/geometry/analyses' wetted_area = get_value(tixi,analyses_xpath + '/wettedArea') wing_area, wing_span = get_largest_wing_dim(tixi,tigl) mach = 0.78 alt = 12000 cd0 = estimate_skin_friction_coef(wetted_area,wing_area,wing_span,mach,alt) assert cd0 == approx(0.01998328842386761)
def init_design_var_dict(tixi): """ Return the dictionary of the design variables using the TIGL library. Parameters ---------- tigl : tigl3_handler Returns ------- design_var_dict : TYPE """ tigl = cpsf.open_tigl(tixi) aircraft = cpud.get_aircraft(tigl) # fuse_nb = aircraft.get_fuselage_count() # if fuse_nb: # init_fuse_param(aircraft, fuse_nb) wing_nb = aircraft.get_wing_count() if wing_nb: init_wing_param(aircraft, wing_nb) init_specials(tixi) return design_var_dict
def write_inouts(v, inout, tixi): """Write inputs or outputs to cpacs. Write the specified input or the predicted output of the model to the CPACS file. Args: v (DataFrame): Contains the inout, locations. inout (np.array): Values of the inout. Returns: None. """ tigl = cpsf.open_tigl(tixi) aircraft = cpud.get_aircraft(tigl) wings = aircraft.get_wings() fuselage = aircraft.get_fuselages().get_fuselage(1) v.fillna('-', inplace=True) for i, name in enumerate(v.index): if v.loc[name, 'setcmd'] != '-': exec('{} = {}'.format(name, inout[0][i])) eval(v.loc[name, 'setcmd']) elif v.loc[name, 'getcmd'] != '-': xpath = v.loc[name, 'getcmd'] cpsf.create_branch(tixi, xpath) tixi.updateDoubleElement(xpath, inout[0][i], '%g') tigl.close()
def write_outputs(y, outputs): """Write outputs to cpacs. Write the predicted output of the model to the CPACS file. Args: y (DataFrame): Contains the outputs, locations. outputs (np.array): Values of the outputs. Returns: None. """ tixi = cpsf.open_tixi(cpacs_path) tigl = cpsf.open_tigl(tixi) aircraft = cpud.get_aircraft(tigl) wings = aircraft.get_wings() fuselage = aircraft.get_fuselages().get_fuselage(1) y.fillna('-', inplace=True) for i, name in enumerate(y.index): if y.loc[name, 'setcmd'] != '-': exec('{} = {}'.format(name, outputs[0][i])) eval(y.loc[name, 'setcmd']) elif y.loc[name, 'getcmd'] != '-': xpath = y.loc[name, 'getcmd'] cpsf.create_branch(tixi, xpath) tixi.updateDoubleElement(xpath, outputs[0][i], '%g') tigl.close() cpsf.close_tixi(tixi, cpacs_path_out)
def add_skin_friction(cpacs_path, cpacs_out_path): """ Function to add the skin frinction drag coeffienct to the CPACS file Function 'add_skin_friction' add the skin friction drag 'cd0' to the CPACS file, then it could be added to the drag coeffienct obtain with Euler calcualtions or other methods Args: cpacs_path (str): Path to CPACS file cpacs_out_path (str): Path to CPACS output file """ tixi = open_tixi(cpacs_path) tigl = open_tigl(tixi) wing_area_max, wing_span_max = get_largest_wing_dim(tixi, tigl) analysis_xpath = '/cpacs/toolspecific/CEASIOMpy/geometry/analysis' range_xpath = '/cpacs/toolspecific/CEASIOMpy/ranges' # Requiered input data from CPACS wetted_area = get_value(tixi, analysis_xpath + '/wettedArea') # Not requiered input data (a default value will be used if no # value has been found in the CPACS file) wing_area_xpath = analysis_xpath + '/wingArea' tixi, wing_area = get_value_or_default(tixi, wing_area_xpath, wing_area_max) if wing_area != wing_area_max: log.warning('Wing area found in the CPACS file /toolspecific is \ different from the one calculated from geometry, \ /toolspecific value will be used') wing_span_xpath = analysis_xpath + '/wingSpan' tixi, wing_span = get_value_or_default(tixi, wing_span_xpath, wing_span_max) if wing_span != wing_span_max: log.warning('Wing span found in the CPACS file /toolspecific is \ different from the one calculated from geometry, \ /toolspecific value will be used') cruise_alt_xpath = range_xpath + '/cruiseAltitude' tixi, cruise_alt = get_value_or_default(tixi, cruise_alt_xpath, 12000) cruise_mach_xpath = range_xpath + '/cruiseMach' tixi, cruise_mach = get_value_or_default(tixi, cruise_mach_xpath, 0.78) # Calculate Cd0 cd0 = estimate_skin_friction_coef(wetted_area,wing_area,wing_span, \ cruise_mach,cruise_alt) # Save Cd0 in the CPACS file cd0_xpath = '/cpacs/toolspecific/CEASIOMpy/aerodynamics/skinFriction/cd0' tixi = create_branch(tixi, cd0_xpath) tixi.updateDoubleElement(cd0_xpath, cd0, '%g') log.info('Skin friction drag coeffienct (cd0) has been saved in the \ CPACS file') close_tixi(tixi, cpacs_out_path)
def update_cpacs_file(cpacs_path, cpacs_out_path, optim_var_dict): """Function to update a CPACS file with value from ... Function 'update_cpacs_file' .... Source: * See CPACSCreator api function, Args: cpacs_path (str): Path to CPACS file to update cpacs_out_path (str):Path to the updated CPACS file optim_var_dict (dict): Dictionary containing all the variable value/min/max and command to modify a CPACS file """ tixi = cpsf.open_tixi(cpacs_path) tigl = cpsf.open_tigl(tixi) aircraft = get_aircraft(tigl) # help(aircraft) wings = aircraft.get_wings() # help(wings) fuselage = aircraft.get_fuselages().get_fuselage(1) # help(fuselage) # Other functions which could be useful # help(wings.get_wing(1).get_section(1)) # uid = wings.get_wing(1).get_section(2).get_uid() # help(wings.get_wing(1).get_positioning_transformation(uid)) # wings.get_wing(1).get_section(2).set_rotation(geometry.CTiglPoint(40,40,-4)) # airfoil = wings.get_wing(1).get_section(1).get_section_element(1).get_airfoil_uid() # help(airfoil) # wings.get_wing(1).get_section(1).get_section_element(1).set_airfoil_uid('NACA0006') # scal = wings.get_wing(1).get_section(1).get_section_element(1).get_scaling() # help(wings.get_wing(1).get_section(2)) # Perform update of all the variable contained in 'optim_var_dict' for key, (name, listval, minval, maxval, setcommand, getcommand) in optim_var_dict.items(): # Define variable (var1,var2,..) locals()[str(key)] = listval[-1] # Execute the command coresponding to the variable if ';' in setcommand: # if more than one command on the line command_split = setcommand.split(';') for setcommand in command_split: eval(setcommand) else: eval(setcommand) aircraft.write_cpacs(aircraft.get_uid()) tixi.save(cpacs_out_path)
def test_get_largest_wing_dim(): """Test function 'get_largest_wing_dim' """ tixi = open_tixi(CPACS_IN_PATH) tigl = open_tigl(tixi) wing_area_max, wing_span_max = get_largest_wing_dim(tixi,tigl) assert wing_area_max == approx(122.32551815387066) assert wing_span_max == approx(33.915185246594945)
def cpacs_engine_update(ui, ed, mw, cpacs_out_path): """ The function that update the cpacs file after the Weight_unc_main program. Args: mw (class): MassesWeihts class. ui (class): UserInputs class. ed (class): EngineData class. cpacs_out_path (str): Path of the CPACS output file. """ tixi = cpsf.open_tixi(cpacs_out_path) tigl = cpsf.open_tigl(tixi) EN_XPATH = '/cpacs/vehicles/engines' if tixi.checkElement(EN_XPATH): tixi.removeElement(EN_XPATH) for e in range(0,ed.NE): EN_XPATH = '/cpacs/vehicles/engines/engine' + str(e+1) cpsf.create_branch(tixi, EN_XPATH, True) EN_UID = 'EngineuID_' + str(e+1) cpsf.add_uid(tixi, EN_XPATH, EN_UID) tixi.createElement(EN_XPATH, 'name') if not ed.EN_NAME[e]: EN_NAME = 'Engine_' + str(e+1) tixi.updateTextElement(EN_XPATH + '/name', EN_NAME) else: tixi.updateTextElement(EN_XPATH + '/name', ed.EN_NAME[e]) ENA_XPATH = EN_XPATH + '/analysis/mass' cpsf.create_branch(tixi, ENA_XPATH, False) cpsf.add_uid(tixi, EN_XPATH, EN_UID+'_mass') tixi.createElement(ENA_XPATH, 'mass') tixi.updateDoubleElement(ENA_XPATH + '/mass', ed.en_mass, '%g') ENT_XPATH = EN_XPATH + '/analysis' tixi.createElement(ENT_XPATH, 'thrust00') tixi.updateDoubleElement(ENT_XPATH + '/thrust00', ed.max_thrust, '%g') cpsf.close_tixi(tixi, cpacs_out_path) return()
def aeromap_calculation(sm, tixi): """Make a prediction using only the aeromap entries. By using only the aeromap functions this module is way faster to execute. Only works with the aeromap as the other values of the CPACs are not vectors and have to be evaluated with a different CPACS every time. Args: sm (Surrogate model object): Surrogate used to predict the function output. tixi (Tixi handle): Handle of the current CPACS. Returns: None. """ tigl = cpsf.open_tigl(tixi) aircraft = cpud.get_aircraft(tigl) wings = aircraft.get_wings() fuselage = aircraft.get_fuselages().get_fuselage(1) aeromap_uid = apmf.get_current_aeromap_uid(tixi, 'SMUse') log.info('Using aeromap :'+aeromap_uid) Coef = apmf.get_aeromap(tixi, aeromap_uid) inputs = np.array([Coef.alt, Coef.mach, Coef.aoa, Coef.aos]).T outputs = sm.predict_values(inputs) # Re-initiates the values of the results to write the new ones Coef.cl = [] Coef.cd = [] Coef.cs = [] Coef.cml = [] Coef.cmd = [] Coef.cms = [] for i in range(outputs.shape[0]): Coef.add_coefficients(outputs[i, 0], outputs[i, 1], outputs[i, 2], outputs[i, 3], outputs[i, 4], outputs[i, 5]) Coef.print_coef_list() apmf.save_coefficients(tixi, aeromap_uid, Coef) tigl.close()
def get_inputs(x): """Get input for the surrogate model. Retrieve the inputs from the cpacs and return them as a numpy array. Args: x (DataFrame): Contains the inputs locations. Returns: inputs (np.array): Array of floats. """ tixi = cpsf.open_tixi(cpacs_path) tigl = cpsf.open_tigl(tixi) aircraft = cpud.get_aircraft(tigl) wings = aircraft.get_wings() fuselage = aircraft.get_fuselages().get_fuselage(1) inputs = [] am_uid = apmf.get_current_aeromap_uid(tixi, 'SMUse') am_index = apmf.get_aeromap_index(tixi, am_uid) xpath = apmf.AEROPERFORMANCE_XPATH + '/aeroMap' + am_index + '/aeroPerformanceMap/' x.set_index('Name', inplace=True) for name in x.index: if x.loc[name, 'setcmd'] != '-': inputs.append(eval(x.loc[name, 'getcmd'])) else: if name in apmf.COEF_LIST + apmf.XSTATES: x.loc[name, 'getcmd'] = xpath + name inputs.append(tixi.getDoubleElement(x.loc[name, 'getcmd'])) tigl.close() cpsf.close_tixi(tixi, cpacs_path) inputs = np.array([inputs]) return inputs
def cpacs_mbd_update(out, mw, bi, ms_zpm, out_xml): """ The function updates the cpacs file after the Balance unconventional program. INPUT (float) mass_pass --Arg.: Passenger mass, countig also the extra mass. (class) out --Arg.: BalanceOutput class. (class) mw --Arg.: MassesWeights class. (class) bi --Arg.: BalanceInput class. ##======= Classes are defined in the InputClasses folder =======## (cahr) out_xml --Arg.: Path of the output file. OUTPUT (file) cpacs.xml --Out.: Updated cpacs file. """ tixi = cpf.open_tixi(out_xml) tigl = cpf.open_tigl(tixi) # CREATING PATH ========================================================== MB_PATH = '/cpacs/vehicles/aircraft/'\ + 'model/analyses/massBreakdown' MD_PATH = MB_PATH + '/designMasses' MTOM_PATH = MD_PATH + '/mTOM' MZFM_PATH = MD_PATH + '/mZFM' OEM_PATH = MB_PATH + '/mOEM/massDescription' J_PATH = OEM_PATH + '/massInertia/J' CG_PATH = OEM_PATH + '/location/' tixi = cpf.create_branch(tixi, MTOM_PATH + '/location/x', False) tixi = cpf.create_branch(tixi, MTOM_PATH + '/location/y', False) tixi = cpf.create_branch(tixi, MTOM_PATH + '/location/z', False) tixi = cpf.create_branch(tixi, MTOM_PATH + '/massInertia/Jxx', False) tixi = cpf.create_branch(tixi, MTOM_PATH + '/massInertia/Jyy', False) tixi = cpf.create_branch(tixi, MTOM_PATH + '/massInertia/Jzz', False) tixi = cpf.create_branch(tixi, MTOM_PATH + '/massInertia/Jxy', False) tixi = cpf.create_branch(tixi, MTOM_PATH + '/massInertia/Jyz', False) tixi = cpf.create_branch(tixi, MTOM_PATH + '/massInertia/Jxz', False) tixi = cpf.create_branch(tixi, MZFM_PATH + '/location/x', False) tixi = cpf.create_branch(tixi, MZFM_PATH + '/location/y', False) tixi = cpf.create_branch(tixi, MZFM_PATH + '/location/z', False) tixi = cpf.create_branch(tixi, MZFM_PATH + '/massInertia/Jxx', False) tixi = cpf.create_branch(tixi, MZFM_PATH + '/massInertia/Jyy', False) tixi = cpf.create_branch(tixi, MZFM_PATH + '/massInertia/Jzz', False) tixi = cpf.create_branch(tixi, MZFM_PATH + '/massInertia/Jxy', False) tixi = cpf.create_branch(tixi, MZFM_PATH + '/massInertia/Jyz', False) tixi = cpf.create_branch(tixi, MZFM_PATH + '/massInertia/Jxz', False) tixi = cpf.create_branch(tixi, OEM_PATH + '/location/x', False) tixi = cpf.create_branch(tixi, OEM_PATH + '/location/y', False) tixi = cpf.create_branch(tixi, OEM_PATH + '/location/z', False) tixi = cpf.create_branch(tixi, OEM_PATH + '/massInertia/Jxx', False) tixi = cpf.create_branch(tixi, OEM_PATH + '/massInertia/Jyy', False) tixi = cpf.create_branch(tixi, OEM_PATH + '/massInertia/Jzz', False) tixi = cpf.create_branch(tixi, OEM_PATH + '/massInertia/Jxy', False) tixi = cpf.create_branch(tixi, OEM_PATH + '/massInertia/Jyz', False) tixi = cpf.create_branch(tixi, OEM_PATH + '/massInertia/Jxz', False) # DESIGN MASSES ========================================================== # MTOM ------------------------------------------------------------------- tixi.uIDSetToXPath(MTOM_PATH + '/location', 'MTOMloc') tixi.updateDoubleElement(MTOM_PATH + '/location'+'/x',\ out.center_of_gravity[0], '%g') tixi.updateDoubleElement(MTOM_PATH + '/location'+'/y',\ out.center_of_gravity[1], '%g') tixi.updateDoubleElement(MTOM_PATH + '/location'+'/z',\ out.center_of_gravity[2], '%g') tixi.updateDoubleElement(MTOM_PATH + '/massInertia' + '/Jxx',\ out.Ixx_lump, '%g') tixi.updateDoubleElement(MTOM_PATH + '/massInertia' + '/Jyy',\ out.Iyy_lump,'%g') tixi.updateDoubleElement(MTOM_PATH + '/massInertia' + '/Jzz',\ out.Izz_lump, '%g') tixi.updateDoubleElement(MTOM_PATH + '/massInertia' + '/Jxy',\ out.Ixy_lump, '%g') tixi.updateDoubleElement(MTOM_PATH + '/massInertia' + '/Jyz',\ out.Iyz_lump,'%g') tixi.updateDoubleElement(MTOM_PATH + '/massInertia' + '/Jxz',\ out.Ixz_lump, '%g') # MZFM ------------------------------------------------------------------- tixi = cpf.add_uid(tixi, MZFM_PATH + '/location', 'MZFMloc') # updating path tixi.updateDoubleElement(MZFM_PATH + '/location' + '/x',\ out.cg_zpm[0], '%g') tixi.updateDoubleElement(MZFM_PATH + '/location' + '/y',\ out.cg_zpm[1], '%g') tixi.updateDoubleElement(MZFM_PATH + '/location' + '/z',\ out.cg_zpm[2], '%g') tixi.updateDoubleElement(MZFM_PATH + '/massInertia'\ + '/Jxx', out.Ixx_lump_zfm, '%g') tixi.updateDoubleElement(MZFM_PATH + '/massInertia'\ + '/Jyy', out.Iyy_lump_zfm, '%g') tixi.updateDoubleElement(MZFM_PATH + '/massInertia'\ + '/Jzz', out.Izz_lump_zfm, '%g') tixi.updateDoubleElement(MZFM_PATH + '/massInertia'\ + '/Jxy', out.Ixy_lump_zfm, '%g') tixi.updateDoubleElement(MZFM_PATH + '/massInertia'\ + '/Jyz', out.Iyz_lump_zfm, '%g') tixi.updateDoubleElement(MZFM_PATH + '/massInertia'\ + '/Jxz', out.Ixz_lump_zfm, '%g') # OEM ==================================================================== tixi = cpf.add_uid(tixi, OEM_PATH + '/location', 'OEMloc') tixi.updateDoubleElement((CG_PATH + 'x'), out.cg_oem[0], '%g') tixi.updateDoubleElement((CG_PATH + 'y'), out.cg_oem[1], '%g') tixi.updateDoubleElement((CG_PATH + 'z'), out.cg_oem[2], '%g') tixi.updateDoubleElement((J_PATH + 'xx'), out.Ixx_lump_oem, '%g') tixi.updateDoubleElement((J_PATH + 'yy'), out.Iyy_lump_oem, '%g') tixi.updateDoubleElement((J_PATH + 'zz'), out.Izz_lump_oem, '%g') tixi.updateDoubleElement((J_PATH + 'xy'), out.Ixy_lump_oem, '%g') tixi.updateDoubleElement((J_PATH + 'yz'), out.Iyz_lump_oem, '%g') tixi.updateDoubleElement((J_PATH + 'xz'), out.Ixz_lump_oem, '%g') # ZPM INERTIA ============================================================ B_PATH = '/cpacs/toolspecific/CEASIOMpy/balance' ZPM_PATH = B_PATH + '/mZPM' tixi = cpf.create_branch(tixi, ZPM_PATH + '/name', False) tixi.updateTextElement(ZPM_PATH + '/name', 'Maximum zero payload mass') tixi = cpf.create_branch(tixi, ZPM_PATH + '/description', False) tixi.updateTextElement(ZPM_PATH + '/description', 'Maximum '\ + 'zero payload mass [kg], CoG coordinate [m] and '\ + 'moment of inertia.') tixi = cpf.create_branch(tixi, ZPM_PATH + '/mass', False) tixi.updateDoubleElement(ZPM_PATH + '/mass',\ ms_zpm, '%g') tixi = cpf.create_branch(tixi, ZPM_PATH + '/location/x', False) tixi = cpf.create_branch(tixi, ZPM_PATH + '/location/y', False) tixi = cpf.create_branch(tixi, ZPM_PATH + '/location/z', False) tixi = cpf.create_branch(tixi, ZPM_PATH + '/massInertia/Jxx', False) tixi = cpf.create_branch(tixi, ZPM_PATH + '/massInertia/Jyy', False) tixi = cpf.create_branch(tixi, ZPM_PATH + '/massInertia/Jzz', False) tixi = cpf.create_branch(tixi, ZPM_PATH + '/massInertia/Jxy', False) tixi = cpf.create_branch(tixi, ZPM_PATH + '/massInertia/Jyz', False) tixi = cpf.create_branch(tixi, ZPM_PATH + '/massInertia/Jxz', False) LOC_PATH = ZPM_PATH + '/location' MOI_PATH = ZPM_PATH + '/massInertia' tixi = cpf.add_uid(tixi, ZPM_PATH, 'MZPM') tixi = cpf.add_uid(tixi, LOC_PATH, 'MZPMloc') tixi.updateDoubleElement((LOC_PATH + '/x'), out.cg_zpm[0], '%g') tixi.updateDoubleElement((LOC_PATH + '/y'), out.cg_zpm[1], '%g') tixi.updateDoubleElement((LOC_PATH + '/z'), out.cg_zpm[2], '%g') tixi.updateDoubleElement((MOI_PATH + '/Jxx'), out.Ixx_lump_zpm, '%g') tixi.updateDoubleElement((MOI_PATH + '/Jyy'), out.Iyy_lump_zpm, '%g') tixi.updateDoubleElement((MOI_PATH + '/Jzz'), out.Izz_lump_zpm, '%g') tixi.updateDoubleElement((MOI_PATH + '/Jxy'), out.Ixy_lump_zpm, '%g') tixi.updateDoubleElement((MOI_PATH + '/Jyz'), out.Iyz_lump_zpm, '%g') tixi.updateDoubleElement((MOI_PATH + '/Jxz'), out.Ixz_lump_zpm, '%g') # USER CASE ============================================================== if bi.USER_CASE: UC_PATH = '/cpacs/toolspecific/CEASIOMpy/balance/userBalance' LOC_PATH = UC_PATH + '/location' MOI_PATH = UC_PATH + '/massInertia' tixi = cpf.create_branch(tixi, LOC_PATH + '/x', False) tixi = cpf.create_branch(tixi, LOC_PATH + '/y', False) tixi = cpf.create_branch(tixi, LOC_PATH + '/z', False) tixi = cpf.create_branch(tixi, MOI_PATH + '/Jxx', False) tixi = cpf.create_branch(tixi, MOI_PATH + '/Jyy', False) tixi = cpf.create_branch(tixi, MOI_PATH + '/Jzz', False) tixi = cpf.create_branch(tixi, MOI_PATH + '/Jxy', False) tixi = cpf.create_branch(tixi, MOI_PATH + '/Jyz', False) tixi = cpf.create_branch(tixi, MOI_PATH + '/Jxz', False) tixi = cpf.add_uid(tixi, LOC_PATH, 'USERloc') tixi.updateDoubleElement((LOC_PATH + '/x'), out.cg_user[0], '%g') tixi.updateDoubleElement((LOC_PATH + '/y'), out.cg_user[1], '%g') tixi.updateDoubleElement((LOC_PATH + '/z'), out.cg_user[2], '%g') tixi.updateDoubleElement((MOI_PATH + '/Jxx'), out.Ixx_lump_user, '%g') tixi.updateDoubleElement((MOI_PATH + '/Jyy'), out.Iyy_lump_user, '%g') tixi.updateDoubleElement((MOI_PATH + '/Jzz'), out.Izz_lump_user, '%g') tixi.updateDoubleElement((MOI_PATH + '/Jxy'), out.Ixy_lump_user, '%g') tixi.updateDoubleElement((MOI_PATH + '/Jyz'), out.Iyz_lump_user, '%g') tixi.updateDoubleElement((MOI_PATH + '/Jxz'), out.Ixz_lump_user, '%g') # Saving and closing the new cpacs file inside the ToolOutput folder ----- tixi.saveDocument(out_xml) cpf.close_tixi(tixi, out_xml) # Openign and closing again the cpacs file, formatting purpose ----------- tixi = cpf.open_tixi(out_xml) tigl = cpf.open_tigl(tixi) tixi.saveDocument(out_xml) cpf.close_tixi(tixi, out_xml) return ()
def generate_su2_config(cpacs_path, cpacs_out_path, wkdir): """Function to create SU2 confif file. Function 'generate_su2_config' reads data in the CPACS file and generate configuration files for one or multible flight conditions (alt,mach,aoa,aos) Source: * SU2 config template: https://github.com/su2code/SU2/blob/master/config_template.cfg Args: cpacs_path (str): Path to CPACS file cpacs_out_path (str):Path to CPACS output file wkdir (str): Path to the working directory """ # Get value from CPACS tixi = cpsf.open_tixi(cpacs_path) tigl = cpsf.open_tigl(tixi) # Get SU2 mesh path su2_mesh_xpath = '/cpacs/toolspecific/CEASIOMpy/filesPath/su2Mesh' su2_mesh_path = cpsf.get_value(tixi,su2_mesh_xpath) # Get reference values ref_xpath = '/cpacs/vehicles/aircraft/model/reference' ref_len = cpsf.get_value(tixi,ref_xpath + '/length') ref_area = cpsf.get_value(tixi,ref_xpath + '/area') ref_ori_moment_x = cpsf.get_value_or_default(tixi,ref_xpath+'/point/x',0.0) ref_ori_moment_y = cpsf.get_value_or_default(tixi,ref_xpath+'/point/y',0.0) ref_ori_moment_z = cpsf.get_value_or_default(tixi,ref_xpath+'/point/z',0.0) # Get SU2 settings settings_xpath = SU2_XPATH + '/settings' max_iter_xpath = settings_xpath + '/maxIter' max_iter = cpsf.get_value_or_default(tixi, max_iter_xpath,200) cfl_nb_xpath = settings_xpath + '/cflNumber' cfl_nb = cpsf.get_value_or_default(tixi, cfl_nb_xpath,1.0) mg_level_xpath = settings_xpath + '/multigridLevel' mg_level = cpsf.get_value_or_default(tixi, mg_level_xpath,3) # Mesh Marker bc_wall_xpath = SU2_XPATH + '/boundaryConditions/wall' bc_wall_list = su2f.get_mesh_marker(su2_mesh_path) cpsf.create_branch(tixi, bc_wall_xpath) bc_wall_str = ';'.join(bc_wall_list) tixi.updateTextElement(bc_wall_xpath,bc_wall_str) # Fixed CL parameters fixed_cl_xpath = SU2_XPATH + '/fixedCL' fixed_cl = cpsf.get_value_or_default(tixi, fixed_cl_xpath,'NO') target_cl_xpath = SU2_XPATH + '/targetCL' target_cl = cpsf.get_value_or_default(tixi, target_cl_xpath,1.0) if fixed_cl == 'NO': active_aeroMap_xpath = SU2_XPATH + '/aeroMapUID' aeromap_uid = cpsf.get_value(tixi,active_aeroMap_xpath) log.info('Configuration file for ""' + aeromap_uid + '"" calculation will be created.') # Get parameters of the aeroMap (alt,ma,aoa,aos) Param = apmf.get_aeromap(tixi,aeromap_uid) param_count = Param.get_count() if param_count >= 1: alt_list = Param.alt mach_list = Param.mach aoa_list = Param.aoa aos_list = Param.aos else: raise ValueError('No parametre have been found in the aeroMap!') else: # if fixed_cl == 'YES': log.info('Configuration file for fixed CL calculation will be created.') range_xpath = '/cpacs/toolspecific/CEASIOMpy/ranges' # Parameters fixed CL calulation param_count = 1 # These parameters will not be used aoa_list = [0.0] aos_list = [0.0] cruise_mach_xpath= range_xpath + '/cruiseMach' mach = cpsf.get_value_or_default(tixi,cruise_mach_xpath,0.78) mach_list = [mach] cruise_alt_xpath= range_xpath + '/cruiseAltitude' alt = cpsf.get_value_or_default(tixi,cruise_alt_xpath,12000) alt_list = [alt] aeromap_uid = 'aeroMap_fixedCL_SU2' description = 'AeroMap created for SU2 fixed CL value of: ' + str(target_cl) apmf.create_empty_aeromap(tixi, aeromap_uid, description) Parameters = apmf.AeroCoefficient() Parameters.alt = alt_list Parameters.mach = mach_list Parameters.aoa = aoa_list Parameters.aos = aos_list apmf.save_parameters(tixi,aeromap_uid,Parameters) tixi.updateTextElement(SU2_XPATH+ '/aeroMapUID',aeromap_uid) # Get and modify the default configuration file cfg = su2f.read_config(DEFAULT_CONFIG_PATH) # General parmeters cfg['REF_LENGTH'] = ref_len cfg['REF_AREA'] = ref_area cfg['REF_ORIGIN_MOMENT_X'] = ref_ori_moment_x cfg['REF_ORIGIN_MOMENT_Y'] = ref_ori_moment_y cfg['REF_ORIGIN_MOMENT_Z'] = ref_ori_moment_z # Settings cfg['INNER_ITER'] = int(max_iter) cfg['CFL_NUMBER'] = cfl_nb cfg['MGLEVEL'] = int(mg_level) # Fixed CL mode (AOA will not be taken into account) cfg['FIXED_CL_MODE'] = fixed_cl cfg['TARGET_CL'] = target_cl cfg['DCL_DALPHA'] = '0.1' cfg['UPDATE_AOA_ITER_LIMIT'] = '50' cfg['ITER_DCL_DALPHA'] = '80' # TODO: correct value for the 3 previous parameters ?? # Mesh Marker bc_wall_str = '(' + ','.join(bc_wall_list) + ')' cfg['MARKER_EULER'] = bc_wall_str cfg['MARKER_FAR'] = ' (Farfield)' # TODO: maybe make that a variable cfg['MARKER_SYM'] = ' (0)' # TODO: maybe make that a variable? cfg['MARKER_PLOTTING'] = bc_wall_str cfg['MARKER_MONITORING'] = bc_wall_str cfg['MARKER_MOVING'] = '( NONE )' # TODO: when do we need to define MARKER_MOVING? cfg['DV_MARKER'] = bc_wall_str # Parameters which will vary for the different cases (alt,mach,aoa,aos) for case_nb in range(param_count): cfg['MESH_FILENAME'] = su2_mesh_path alt = alt_list[case_nb] mach = mach_list[case_nb] aoa = aoa_list[case_nb] aos = aos_list[case_nb] Atm = get_atmosphere(alt) pressure = Atm.pres temp = Atm.temp cfg['MACH_NUMBER'] = mach cfg['AOA'] = aoa cfg['SIDESLIP_ANGLE'] = aos cfg['FREESTREAM_PRESSURE'] = pressure cfg['FREESTREAM_TEMPERATURE'] = temp cfg['ROTATION_RATE'] = '0.0 0.0 0.0' config_file_name = 'ConfigCFD.cfg' case_dir_name = ''.join(['Case',str(case_nb).zfill(2), '_alt',str(alt), '_mach',str(round(mach,2)), '_aoa',str(round(aoa,1)), '_aos',str(round(aos,1))]) case_dir_path = os.path.join(wkdir,case_dir_name) if not os.path.isdir(case_dir_path): os.mkdir(case_dir_path) config_output_path = os.path.join(wkdir,case_dir_name,config_file_name) su2f.write_config(config_output_path,cfg) # Damping derivatives damping_der_xpath = SU2_XPATH + '/options/clalculateDampingDerivatives' damping_der = cpsf.get_value_or_default(tixi,damping_der_xpath,False) if damping_der: rotation_rate_xpath = SU2_XPATH + '/options/rotationRate' rotation_rate = cpsf.get_value_or_default(tixi,rotation_rate_xpath,1.0) cfg['GRID_MOVEMENT'] = 'ROTATING_FRAME' cfg['ROTATION_RATE'] = str(rotation_rate) + ' 0.0 0.0' os.mkdir(os.path.join(wkdir,case_dir_name+'_dp')) config_output_path = os.path.join(wkdir,case_dir_name+'_dp',config_file_name) su2f.write_config(config_output_path,cfg) cfg['ROTATION_RATE'] = '0.0 ' + str(rotation_rate) + ' 0.0' os.mkdir(os.path.join(wkdir,case_dir_name+'_dq')) config_output_path = os.path.join(wkdir,case_dir_name+'_dq',config_file_name) su2f.write_config(config_output_path,cfg) cfg['ROTATION_RATE'] = '0.0 0.0 ' + str(rotation_rate) os.mkdir(os.path.join(wkdir,case_dir_name+'_dr')) config_output_path = os.path.join(wkdir,case_dir_name+'_dr',config_file_name) su2f.write_config(config_output_path,cfg) log.info('Damping derivatives cases directory has been created.') # Control surfaces deflections control_surf_xpath = SU2_XPATH + '/options/clalculateCotrolSurfacesDeflections' control_surf = cpsf.get_value_or_default(tixi,control_surf_xpath,False) if control_surf: # Get deformed mesh list su2_def_mesh_xpath = SU2_XPATH + '/availableDeformedMesh' if tixi.checkElement(su2_def_mesh_xpath): su2_def_mesh_list = cpsf.get_string_vector(tixi,su2_def_mesh_xpath) else: log.warning('No SU2 deformed mesh has been found!') su2_def_mesh_list = [] for su2_def_mesh in su2_def_mesh_list: mesh_path = os.path.join(wkdir,'MESH',su2_def_mesh) config_dir_path = os.path.join(wkdir,case_dir_name+'_'+su2_def_mesh.split('.')[0]) os.mkdir(config_dir_path) cfg['MESH_FILENAME'] = mesh_path config_file_name = 'ConfigCFD.cfg' config_output_path = os.path.join(wkdir,config_dir_path,config_file_name) su2f.write_config(config_output_path,cfg) # TODO: change that, but if it is save in tooloutput it will be erease by results... cpsf.close_tixi(tixi,cpacs_path)
def add_skin_friction(cpacs_path, cpacs_out_path): """ Function to add the skin frinction drag coeffienct to aerodynamic coefficients Function 'add_skin_friction' add the skin friction drag 'cd0' to the SU2 and pyTornado aeroMap, if their UID is not geven, it will add skin friction to all aeroMap. For each aeroMap it creates a new aeroMap where the skin friction drag coeffienct is added with the correct projcetions. Args: cpacs_path (str): Path to CPACS file cpacs_out_path (str): Path to CPACS output file """ tixi = cpsf.open_tixi(cpacs_path) tigl = cpsf.open_tigl(tixi) wing_area_max, wing_span_max = get_largest_wing_dim(tixi, tigl) analyses_xpath = '/cpacs/toolspecific/CEASIOMpy/geometry/analysis' # Requiered input data from CPACS wetted_area = cpsf.get_value(tixi, analyses_xpath + '/wettedArea') # Wing area/span, default values will be calated if no value found in the CPACS file wing_area_xpath = analyses_xpath + '/wingArea' wing_area = cpsf.get_value_or_default(tixi, wing_area_xpath, wing_area_max) wing_span_xpath = analyses_xpath + '/wingSpan' wing_span = cpsf.get_value_or_default(tixi, wing_span_xpath, wing_span_max) aeromap_uid_list = [] # Try to get aeroMapToCalculate aeroMap_to_clculate_xpath = SF_XPATH + '/aeroMapToCalculate' if tixi.checkElement(aeroMap_to_clculate_xpath): aeromap_uid_list = cpsf.get_string_vector(tixi, aeroMap_to_clculate_xpath) else: aeromap_uid_list = [] # If no aeroMap in aeroMapToCalculate, get all existing aeroMap if len(aeromap_uid_list) == 0: try: aeromap_uid_list = apmf.get_aeromap_uid_list(tixi) except: raise ValueError( 'No aeroMap has been found in this CPACS file, skin friction cannot be added!' ) # Get unique aeroMap list aeromap_uid_list = list(set(aeromap_uid_list)) new_aeromap_uid_list = [] # Add skin friction to all listed aeroMap for aeromap_uid in aeromap_uid_list: log.info('adding skin friction coefficients to: ' + aeromap_uid) # Get orignial aeroPerformanceMap AeroCoef = apmf.get_aeromap(tixi, aeromap_uid) AeroCoef.complete_with_zeros() # Create new aeroCoefficient object to store coef with added skin friction AeroCoefSF = apmf.AeroCoefficient() AeroCoefSF.alt = AeroCoef.alt AeroCoefSF.mach = AeroCoef.mach AeroCoefSF.aoa = AeroCoef.aoa AeroCoefSF.aos = AeroCoef.aos # Iterate over all cases case_count = AeroCoef.get_count() for case in range(case_count): # Get parameters for this case alt = AeroCoef.alt[case] mach = AeroCoef.mach[case] aoa = AeroCoef.aoa[case] aos = AeroCoef.aos[case] # Calculate Cd0 for this case cd0 = estimate_skin_friction_coef(wetted_area,wing_area,wing_span, \ mach,alt) # Projection of cd0 on cl, cd and cs axis #TODO: Should Cd0 be projected or not??? aoa_rad = math.radians(aoa) aos_rad = math.radians(aos) cd0_cl = cd0 * math.sin(aoa_rad) cd0_cd = cd0 * math.cos(aoa_rad) * math.cos(aos_rad) cd0_cs = cd0 * math.sin(aos_rad) # Update aerodynamic coefficients cl = AeroCoef.cl[case] + cd0_cl cd = AeroCoef.cd[case] + cd0_cd cs = AeroCoef.cs[case] + cd0_cs # Shoud we change something? e.i. if a force is not apply at aero center...? if len(AeroCoef.cml): cml = AeroCoef.cml[case] else: cml = 0.0 # Shoud be change, just to test pyTornado if len(AeroCoef.cmd): cmd = AeroCoef.cmd[case] else: cmd = 0.0 if len(AeroCoef.cms): cms = AeroCoef.cms[case] else: cms = 0.0 # Add new coefficients into the aeroCoefficient object AeroCoefSF.add_coefficients(cl, cd, cs, cml, cmd, cms) # Create new aeroMap UID aeromap_sf_uid = aeromap_uid + '_SkinFriction' new_aeromap_uid_list.append(aeromap_sf_uid) # Create new description description_xpath = tixi.uIDGetXPath(aeromap_uid) + '/description' sf_description = cpsf.get_value( tixi, description_xpath) + ' Skin friction has been add to this AeroMap.' apmf.create_empty_aeromap(tixi, aeromap_sf_uid, sf_description) # Save aeroCoefficient object Coef in the CPACS file apmf.save_parameters(tixi, aeromap_sf_uid, AeroCoefSF) apmf.save_coefficients(tixi, aeromap_sf_uid, AeroCoefSF) # Get aeroMap list to plot plot_xpath = '/cpacs/toolspecific/CEASIOMpy/aerodynamics/plotAeroCoefficient' aeromap_to_plot_xpath = plot_xpath + '/aeroMapToPlot' if tixi.checkElement(aeromap_to_plot_xpath): aeromap_uid_list = cpsf.get_string_vector(tixi, aeromap_to_plot_xpath) new_aeromap_to_plot = aeromap_uid_list + new_aeromap_uid_list new_aeromap_to_plot = list(set(new_aeromap_to_plot)) cpsf.add_string_vector(tixi, aeromap_to_plot_xpath, new_aeromap_to_plot) else: cpsf.create_branch(tixi, aeromap_to_plot_xpath) cpsf.add_string_vector(tixi, aeromap_to_plot_xpath, new_aeromap_uid_list) log.info('AeroMap "' + aeromap_uid + '" has been added to the CPACS file') cpsf.close_tixi(tixi, cpacs_out_path)
def get_user_fuel(f_nb, ui, cpacs_in): """ Function to extract from the xml file the required input data, the code will use the default value when they are missing. INPUT (int) f_nb --Arg.: Number of fuselage. (class) ui --Arg.: UserInputs class. ##======= Classes are defined in the InputClasses folder =======## (char) cpacs_in --Arg.: Relative location of the xml file in the ToolInput folder (cpacs option) or relative location of the temp. xml file in the ToolOutput folder (input option). OUTPUT (class) ui --Out.: UserInputs class. (file) cpacs_in --Out.: Updated cpasc file """ log.info('Starting data extraction from CPACS file') # Path creation ========================================================== tixi = cpf.open_tixi(cpacs_in) FUEL_PATH = '/cpacs/toolspecific/CEASIOMpy/fuels' tixi = cpf.create_branch(tixi, FUEL_PATH, False) if f_nb: for i in range(0, f_nb): if f_nb > 1: F = 'fuelOnCabin' + str(i+1) else: F = 'fuelOnCabin' print((FUEL_PATH + '/' + F)) if not tixi.checkElement(FUEL_PATH + '/' + F): tixi.createElement(FUEL_PATH, F) tixi.updateDoubleElement(FUEL_PATH + '/' + F,\ ui.F_FUEL[i], '%g') else: ui.F_FUEL[i] = tixi.getDoubleElement(FUEL_PATH + '/' + F) else: if not tixi.checkElement(FUEL_PATH + '/fuelOnCabin'): tixi.createElement(FUEL_PATH, 'fuelOnCabin') tixi.updateDoubleElement(FUEL_PATH + '/fuelOnCabin',\ ui.FUEL_ON_CABIN, '%g') else: temp = tixi.updateDoubleElement(FUEL_PATH + '/fuelOnCabin',\ ui.FUEL_ON_CABIN, '%g') if temp != ui.FUEL_ON_CABIN and temp > 0: ui.FUEL_ON_CABIN = temp log.info('Data from CPACS file succesfully extracted') # Saving and closing the cpacs file -------------------------------------- tixi.saveDocument(cpacs_in) cpf.close_tixi(tixi, cpacs_in) # Openign and closing again the cpacs file ------------------------------- tixi = cpf.open_tixi(cpacs_in) tigl = cpf.open_tigl(tixi) tixi.saveDocument(cpacs_in) cpf.close_tixi(tixi, cpacs_in) return(ui)
def geom_eval(w_nb, awg, cpacs_in): """ Main function to evaluate the wings geometry. ARGUMENTS (integer) w_nb --Arg.: Number of wings [-]. (class) awg --Arg.: AircraftWingGeometry class look at aircraft_geometry_class.py in the classes folder for explanation. (char) cpacs_in -- Arg.: Cpacs xml file location. RETURN (class) awg --Out.: AircraftWingGeometry class updated. """ ##===========================================================================## log.info('-----------------------------------------------------------') log.info('---------- Analysing wing geometry ------------------------') log.info('-----------------------------------------------------------') # Opening tixi and tigl tixi = cpf.open_tixi(cpacs_in) tigl = cpf.open_tigl(tixi) ## ---------------------------------------------------------------------------- ## INITIALIZATION 1 ----------------------------------------------------------- ## ---------------------------------------------------------------------------- awg.w_nb = w_nb awg.wing_nb = w_nb wing_plt_area_xz = [] wing_plt_area_yz = [] wingUID = [] ## ---------------------------------------------------------------------------- ## COUNTING 2 ----------------------------------------------------------------- ## Counting sections and segments---------------------------------------------- ## ---------------------------------------------------------------------------- for i in range(1, awg.w_nb + 1): double = 1 awg.wing_sym.append(tigl.wingGetSymmetry(i)) if awg.wing_sym[i - 1] != 0: double = 2 # To consider the real amount of wing # when they are defined using symmetry awg.wing_nb += 1 awg.wing_sec_nb.append(tigl.wingGetSectionCount(i)) awg.wing_seg_nb.append(tigl.wingGetSegmentCount(i)) awg.wing_vol.append(tigl.wingGetVolume(i) * double) # x-y plane awg.wing_plt_area.append(tigl.wingGetReferenceArea(i, 1) * double) # x-z plane wing_plt_area_xz.append(tigl.wingGetReferenceArea(i, 2) * double) # y-z plane wing_plt_area_yz.append(tigl.wingGetReferenceArea(i, 3) * double) if (awg.wing_plt_area[i-1] > wing_plt_area_xz[i-1]\ and awg.wing_plt_area[i-1] > wing_plt_area_yz[i-1]): awg.is_horiz.append(True) if awg.wing_sym[i - 1] != 0: awg.is_horiz.append(True) else: awg.is_horiz.append(False) if awg.wing_sym[i - 1] != 0: awg.is_horiz.append(False) awg.wing_tot_vol += awg.wing_vol[i - 1] ## Checking segment and section connection and reordering them (awg.wing_sec_nb, start_index, seg_sec, wing_sec_index)\ = check_segment_connection(wing_plt_area_xz, wing_plt_area_yz,\ awg, tigl) ## ---------------------------------------------------------------------------- ## INITIALIZATION 2 ----------------------------------------------------------- ## ---------------------------------------------------------------------------- max_wing_sec_nb = np.amax(awg.wing_sec_nb) max_wing_seg_nb = np.amax(awg.wing_seg_nb) wing_center_section_point = np.zeros((max_wing_sec_nb, awg.w_nb, 3)) awg.wing_center_seg_point = np.zeros((max_wing_seg_nb, awg.wing_nb, 3)) awg.wing_seg_vol = np.zeros((max_wing_seg_nb, awg.w_nb)) awg.wing_mac = np.zeros((4, awg.w_nb)) awg.wing_sec_thicknes = np.zeros((max_wing_sec_nb, awg.w_nb)) ##===========================================================================## ## ---------------------------------------------------------------------------- ## WING ANALYSIS -------------------------------------------------------------- ## ---------------------------------------------------------------------------- ## Wing: MAC,chords,thicknes,span,plantform area ------------------------------ b = 0 for i in range(1, awg.w_nb + 1): wingUID.append(tigl.wingGetUID(i)) mac = tigl.wingGetMAC(wingUID[i - 1]) (wpx, wpy, wpz) = tigl.wingGetChordPoint(i, 1, 0.0, 0.0) (wpx2, wpy2, wpz2) = tigl.wingGetChordPoint(i, 1, 0.0, 1.0) awg.wing_max_chord.append(np.sqrt((wpx2-wpx)**2 + (wpy2-wpy)**2\ + (wpz2-wpz)**2)) (wpx, wpy, wpz) = tigl.wingGetChordPoint(i, awg.wing_seg_nb[i - 1], 1.0, 0.0) (wpx2,wpy2,wpz2) = tigl.wingGetChordPoint(i,awg.wing_seg_nb[i-1],\ 1.0,1.0) awg.wing_min_chord.append(np.sqrt((wpx2-wpx)**2 + (wpy2-wpy)**2\ + (wpz2-wpz)**2) ) for k in range(1, 5): awg.wing_mac[k - 1][i - 1] = mac[k - 1] for jj in range(1, awg.wing_seg_nb[i - 1] + 1): j = int(seg_sec[jj - 1, i - 1, 2]) cle = tigl.wingGetChordPoint(i, j, 0.0, 0.0) awg.wing_seg_vol[j - 1][i - 1] = tigl.wingGetSegmentVolume(i, j) lp = tigl.wingGetLowerPoint(i, j, 0.0, 0.0) up = tigl.wingGetUpperPoint(i, j, 0.0, 0.0) if np.all(cle == lp): L = 0.25 else: L = 0.75 if np.all(cle == up): U = 0.25 else: U = 0.75 (wplx, wply, wplz) = tigl.wingGetLowerPoint(i, j, 0.0, L) (wpux, wpuy, wpuz) = tigl.wingGetUpperPoint(i, j, 0.0, U) wing_center_section_point[j - 1][i - 1][0] = (wplx + wpux) / 2 wing_center_section_point[j - 1][i - 1][1] = (wply + wpuy) / 2 wing_center_section_point[j - 1][i - 1][2] = (wplz + wpuz) / 2 awg.wing_sec_thicknes[j-1][i-1] = np.sqrt((wpux-wplx)**2\ + (wpuy-wply)**2 + (wpuz-wplz)**2) j = int(seg_sec[awg.wing_seg_nb[i - 1] - 1, i - 1, 2]) (wplx, wply, wplz) = tigl.wingGetLowerPoint(\ i,awg.wing_seg_nb[i-1],1.0,L) (wpux, wpuy, wpuz) = tigl.wingGetUpperPoint(\ i,awg.wing_seg_nb[i-1],1.0,U) awg.wing_sec_thicknes[j][i-1] = np.sqrt((wpux-wplx)**2\ + (wpuy-wply)**2 + (wpuz-wplz)**2) wing_center_section_point[awg.wing_seg_nb[i - 1]][i - 1][0] = (wplx + wpux) / 2 wing_center_section_point[awg.wing_seg_nb[i - 1]][i - 1][1] = (wply + wpuy) / 2 wing_center_section_point[awg.wing_seg_nb[i - 1]][i - 1][2] = (wplz + wpuz) / 2 awg.wing_sec_mean_thick.append(np.mean(\ awg.wing_sec_thicknes[0:awg.wing_seg_nb[i-1]+1,i-1])) # Wing Span Evaluation, Considering symmetry awg.wing_span.append(round(tigl.wingGetSpan(wingUID[i - 1]), 3)) a = np.amax(awg.wing_span) ## Evaluating the index that corresponds to the main wing if a > b: awg.main_wing_index = i b = a # Main wing plantform area awg.wing_plt_area_main = awg.wing_plt_area[awg.main_wing_index - 1] # Wing segment length evaluatin function awg = getwingsegmentlength(awg, wing_center_section_point) awg.w_seg_sec = seg_sec # Wings wetted area for i in range(1, awg.w_nb + 1): a = str(wingUID[i - 1]) s = tigl.wingGetSurfaceArea(i) if awg.wing_sym[i - 1] != 0: s *= 2 if i == awg.main_wing_index: awg.main_wing_surface = s else: awg.tail_wings_surface.append(s) awg.total_wings_surface += s # Evaluating the point at the center of each segment, the center # is placed at 1/4 of the chord, symmetry is considered. a = 0 c = False for i in range(1, int(awg.wing_nb) + 1): if c: c = False continue for jj in range(1, awg.wing_seg_nb[i - a - 1] + 1): j = int(seg_sec[jj - 1, i - a - 1, 2]) awg.wing_center_seg_point[j-1][i-1][0]\ = (wing_center_section_point[j-1][i-a-1][0]\ + wing_center_section_point[j][i-a-1][0])/2 awg.wing_center_seg_point[j-1][i-1][1]\ = (wing_center_section_point[j-1][i-a-1][1]\ + wing_center_section_point[j][i-a-1][1])/2 awg.wing_center_seg_point[j-1][i-1][2]\ = (wing_center_section_point[j-1][i-a-1][2]\ + wing_center_section_point[j][i-a-1][2])/2 if awg.wing_sym[i - 1 - a] != 0: if awg.wing_sym[i - 1 - a] == 1: symy = 1 symx = 1 symz = -1 if awg.wing_sym[i - 1 - a] == 2: symy = -1 symx = 1 symz = 1 if awg.wing_sym[i - 1 - a] == 3: symy = 1 symx = -1 symz = 1 awg.wing_center_seg_point[:,i,0]\ = awg.wing_center_seg_point[:,i-1,0] * symx awg.wing_center_seg_point[:,i,1]\ = awg.wing_center_seg_point[:,i-1,1] * symy awg.wing_center_seg_point[:,i,2]\ = awg.wing_center_seg_point[:,i-1,2] * symz c = True a += 1 cpf.close_tixi(tixi, cpacs_in) # log info display ------------------------------------------------------------ log.info('-----------------------------------------------------------') log.info('---------- Wing Results -----------------------------------') log.info('Number of Wings [-]: ' + str(awg.wing_nb)) log.info('Wing symmetry plane [-]: ' + str(awg.wing_sym)) log.info('Number of wing sections (not counting symmetry) [-]: '\ + str(awg.wing_sec_nb)) log.info('Number of wing segments (not counting symmetry) [-]: '\ + str(awg.wing_seg_nb)) log.info('Wing Span (counting symmetry)[m]: \n' + str(awg.wing_span)) log.info('Wing MAC length [m]: ' + str(awg.wing_mac[0, ])) log.info('Wing MAC x,y,z coordinate [m]: \n' + str(awg.wing_mac[1:4, ])) log.info('Wings sections thicknes [m]: \n' + str(awg.wing_sec_thicknes)) log.info('Wings sections mean thicknes [m]: \n'\ + str(awg.wing_sec_mean_thick)) log.info('Wing segments length [m]: \n' + str(awg.wing_seg_length)) log.info('Wing max chord length [m]: \n' + str(awg.wing_max_chord)) log.info('Wing min chord length [m]: \n' + str(awg.wing_min_chord)) log.info('Main wing plantform area [m^2]: ' + str(awg.wing_plt_area_main)) log.info('Main wing wetted surface [m^2]: '\ + str(awg.main_wing_surface)) log.info('Tail wings wetted surface [m^2]: \n'\ + str(awg.tail_wings_surface)) log.info('Total wings wetted surface [m^2]: \n'\ + str(awg.total_wings_surface)) log.info('Wings plantform area [m^2]: \n'\ + str(awg.wing_plt_area)) log.info('Volume of each wing [m^3]: ' + str(awg.wing_vol)) log.info('Total wing volume [m^3]: ' + str(awg.wing_tot_vol)) log.info('-----------------------------------------------------------') return (awg)
def fuselage_inertia(SPACING, center_of_gravity, mass_seg_i, afg,\ cpacs_in): """Thefunction evaluates the inertia of the fuselage using the lumped masses method. INPUT (float) SPACING --Arg.: Maximum distance between fuselage nodes [m]. (float_array) center_of_gravity --Arg.: x,y,z coordinates of the CoG. (float_array) mass_seg_i --Arg.: Mass of each segment of each component of the aircraft. (class) afg --Arg.: AircraftFuseGeometry class. ##======= Class is defined in the InputClasses folder =======## (char) cpacs_in --Arg.: Cpacs xml file location. OUTPUT (float) sfx --Out.: Lumped nodes x-coordinate [m]. (float) sfy --Out.: Lumped nodes y-coordinate [m]. (float) sfz --Out.: Lumped nodes z-coordinate [m]. (float) Ixx --Out.: Moment of inertia respect to the x-axis [kgm^2]. (float) Iyy --Out.: Moment of inertia respect to the y-axis [kgm^]. (float) Izz --Out.: Moment of inertia respect to the z-axis [kgm^2]. """ tixi = open_tixi(cpacs_in) tigl = open_tigl(tixi) sfx = [] sfy = [] sfz = [] Ixx = 0 Iyy = 0 Izz = 0 Ixy = 0 Iyz = 0 Ixz = 0 log.info('-------------------------------------------------------------') log.info('---- Evaluating fuselage nodes for lumped masses inertia ----') log.info('-------------------------------------------------------------') for f in range(1, afg.fus_nb + 1): for i in afg.f_seg_sec[:, f - 1, 2]: fx = [] fy = [] fz = [] #Number of subdivisions along the longitudinal axis subd_l = math.ceil( (afg.fuse_seg_length[int(i) - 1][f - 1] / SPACING)) #Number of subdivisions along the perimeter SUBD_C0 = math.ceil( (afg.fuse_sec_per[int(i) - 1][f - 1] / SPACING)) #Number of subdivisions along the radial axis subd_r = math.ceil( ((afg.fuse_sec_width[int(i) - 1][f - 1] / 2) / SPACING)) if subd_l == 0: subd_l = 1.0 if SUBD_C0 == 0: SUBD_C0 = 1.0 if subd_r == 0: subd_r = 1.0 eta = 1.0 / (subd_l) zeta = 1.0 / (SUBD_C0) D0 = np.sqrt(np.arange(subd_r * SUBD_C0) / float(subd_r * SUBD_C0)) D = np.array([t for t in (D0 - (D0[-1] - 0.98)) if not t < 0]) (xc, yc, zc) = afg.fuse_center_section_point[int(i) - 1][f - 1][:] for j in range(int(subd_l) + 1): et = j * eta for k in range(int(SUBD_C0) + 1): ze = k * zeta (x0, y0, z0) = tigl.fuselageGetPoint(f, int(i), et, ze) fx.append(x0) fy.append(y0) fz.append(z0) sfx.append(x0) sfy.append(y0) sfz.append(z0) if subd_r > 0.0: deltar = np.sqrt((y0 - yc)**2 + (z0 - zc)**2) * D theta = np.pi * (3 - np.sqrt(5)) * np.arange(len(D)) x = np.zeros(np.shape(deltar)) + x0 y = yc + deltar * np.cos(theta) z = zc + deltar * np.sin(theta) fx.extend(x) fy.extend(y) fz.extend(z) sfx.extend(x) sfy.extend(y) sfz.extend(z) M = mass_seg_i[int(i) - 1, f - 1] / np.max(np.shape(fx)) fcx = (fx - (np.zeros((np.shape(fx))) + center_of_gravity[0])) fcy = (fy - (np.zeros((np.shape(fx))) + center_of_gravity[1])) fcz = (fz - (np.zeros((np.shape(fx))) + center_of_gravity[2])) Ixx += np.sum(M * np.add(fcy**2, fcz**2)) Iyy += np.sum(M * np.add(fcx**2, fcz**2)) Izz += np.sum(M * np.add(fcx**2, fcy**2)) Ixy += np.sum(M * fcx * fcy) Iyz += np.sum(M * fcy * fcz) Ixz += np.sum(M * fcx * fcz) return (sfx, sfy, sfz, Ixx, Iyy, Izz, Ixy, Iyz, Ixz)
def wing_inertia(subd_c, SPACING, fuse, center_of_gravity, mass_seg_i, awg, cpacs_in): """The function evaluates the inertia of the wings using the lumped masses method. INPUT (float) subd_c --Arg.: Number of subdivisions along the perimeter on each surface, total number of points for each section subd_c * 2 (float) SPACING --Arg.: Maximum distance between wing nodes along the span [m]. (float) fuse --Arg.: Number of fuselages. (float_array) center_of_gravity --Arg.: x,y,z coordinates of the CoG. (float_array) mass_seg_i --Arg.: Mass of each segment of each component of the aircraft. (class) awg --Arg.: AircraftWingGeometry class. ##======= Class is defined in the InputClasses folder =======## (char) cpacs_in --Arg.: Cpacs xml file location. OUTPUT (float) swx --Out.: Lumped nodes x-coordinate [m]. (float) swy --Out.: Lumped nodes y-coordinate [m]. (float) swz --Out.: Lumped nodes z-coordinate [m]. (float) Ixx --Out.: Moment of inertia respect to the x-axis [kgm^2]. (float) Iyy --Out.: Moment of inertia respect to the y-axis [kgm^]. (float) Izz --Out.: Moment of inertia respect to the z-axis [kgm^2]. """ tixi = open_tixi(cpacs_in) tigl = open_tigl(tixi) log.info('-------------------------------------------------------------') log.info('------ Evaluating wing nodes for lumped masses inertia ------') log.info('-------------------------------------------------------------') Ixx = 0 Iyy = 0 Izz = 0 Ixy = 0 Iyz = 0 Ixz = 0 swx = [] swy = [] swz = [] a = 0 for w in range(1, awg.w_nb + 1): DEN = 0.0 for d in range(int(subd_c + 2)): DEN = DEN + d zeta = 1.0 / DEN for i in awg.w_seg_sec[:, w - 1, 2]: if i == 0.0: break wx = [] wy = [] wz = [] #Number of subdivisions along the longitudinal axis subd_l = math.ceil( (awg.wing_seg_length[int(i) - 1][w + a - 1] / SPACING)) if subd_l == 0: subd_l = 1 eta = 1.0 / subd_l et = 0.0 (xc, yc, zc) = awg.wing_center_seg_point[int(i) - 1][w + a - 1][:] for j in range(int(subd_l) + 1): et = j * eta (xle, yle, zle) = tigl.wingGetLowerPoint(w, int(i), et, 0.0) (xle2, yle2, zle2) = tigl.wingGetLowerPoint(w, int(i), et, 1.0) if xle < xle2: ZLE = 0.0 ze = 0.0 else: ZLE = 1.0 ze = 1.0 wx.extend((xle, xle2)) wy.extend((yle, yle2)) wz.extend((zle, zle2)) swx.extend((xle, xle2)) swy.extend((yle, yle2)) swz.extend((zle, zle2)) for k in range(int(subd_c) + 1): if ZLE == 0.0: ze += float(k) * zeta elif ZLE == 1.0: ze -= float(k) * zeta (xl, yl, zl) = tigl.wingGetLowerPoint(w, int(i), et, ze) (xu, yu, zu) = tigl.wingGetUpperPoint(w, int(i), et, ze) wx.extend((xl, xu)) wy.extend((yl, yu)) wz.extend((zl, zu)) swx.extend((xl, xu)) swy.extend((yl, yu)) swz.extend((zl, zu)) M = mass_seg_i[int(i) - 1, fuse + w + a - 1] / np.max(np.shape(wx)) wcx = (wx - (np.zeros((np.shape(wx))) + center_of_gravity[0])) wcy = (wy - (np.zeros((np.shape(wy))) + center_of_gravity[1])) wcz = (wz - (np.zeros((np.shape(wz))) + center_of_gravity[2])) Ixx += np.sum(M * np.add(wcy**2, wcz**2)) Iyy += np.sum(M * np.add(wcx**2, wcz**2)) Izz += np.sum(M * np.add(wcx**2, wcy**2)) Ixy += np.sum(M * wcx * wcy) Iyz += np.sum(M * wcy * wcz) Ixz += np.sum(M * wcx * wcz) if awg.wing_sym[int(w) - 1] != 0: if awg.wing_sym[int(w) - 1] == 1: # x-y plane symy = 1 + np.zeros(np.shape(wy)) symx = 1 + np.zeros(np.shape(wx)) symz = -1 + np.zeros(np.shape(wz)) elif awg.wing_sym[int(w) - 1] == 2: # x-z plane symy = -1 + np.zeros(np.shape(wy)) symx = 1 + np.zeros(np.shape(wx)) symz = 1 + np.zeros(np.shape(wz)) elif awg.wing_sym[int(w) - 1] == 3: # y-z plane symy = 1 + np.zeros(np.shape(wy)) symx = -1 + np.zeros(np.shape(wx)) symz = 1 + np.zeros(np.shape(wz)) wx_t = wx * symx wy_t = wy * symy wz_t = wz * symz [swx.append(x) for x in wx_t] [swy.append(y) for y in wy_t] [swz.append(z) for z in wz_t] M = mass_seg_i[int(i) - 1, fuse + w + a - 1] / np.max( np.shape(wx_t)) wcx_t = (wx_t - (np.zeros( (np.shape(wx_t))) + center_of_gravity[0])) wcy_t = (wy_t - (np.zeros( (np.shape(wy_t))) + center_of_gravity[1])) wcz_t = (wz_t - (np.zeros( (np.shape(wz_t))) + center_of_gravity[2])) Ixx += np.sum(M * np.add(wcy_t**2, wcz_t**2)) Iyy += np.sum(M * np.add(wcx_t**2, wcz_t**2)) Izz += np.sum(M * np.add(wcx_t**2, wcy_t**2)) Ixy += np.sum(M * wcx_t * wcy_t) Iyz += np.sum(M * wcy_t * wcz_t) Ixz += np.sum(M * wcx_t * wcz_t) if awg.wing_sym[int(w) - 1] != 0: a += 1 return (swx, swy, swz, Ixx, Iyy, Izz, Ixy, Iyz, Ixz)
def fuse_geom_eval(ag, cpacs_in): """ Main function to evaluate the fuselage geometry. INPUT (class) ag --Arg.: AircraftGeometry class. ##======= Class is defined in the InputClasses folder =======## (char) cpacs_in -- Arg.: Cpacs xml file location OUTPUT (class) ag --Out.: AircraftGeometry class updated . """ ##===========================================================================## log.info('---------------------------------------------') log.info('-------- Analysing fuselage geometry --------') log.info('---------------------------------------------') # Opening tixi and tigl tixi = cpf.open_tixi(cpacs_in) tigl = cpf.open_tigl(tixi) ## ---------------------------------------------------------------------------- ## COUNTING 1 ----------------------------------------------------------------- ## Counting fuselage number --------------------------------------------------- ## ---------------------------------------------------------------------------- f_nb = tixi.getNamedChildrenCount( '/cpacs/vehicles/aircraft\ /model/fuselages', 'fuselage') ## ---------------------------------------------------------------------------- ## INITIALIZATION 1 ----------------------------------------------------------- ## ---------------------------------------------------------------------------- ag.f_nb = f_nb ag.fuse_nb = f_nb i = ag.f_nb ## ---------------------------------------------------------------------------- ## COUNTING 2 ----------------------------------------------------------------- ## Counting sections and segments---------------------------------------------- ## ---------------------------------------------------------------------------- double = 1 ag.fuse_sym.append(tigl.fuselageGetSymmetry(i)) if ag.fuse_sym[i - 1] != 0: ag.fuse_nb += 1 double = 2 ag.fuse_sec_nb.append(tigl.fuselageGetSectionCount(i)) ag.fuse_seg_nb.append(tigl.fuselageGetSegmentCount(i)) ag.fuse_vol.append(tigl.fuselageGetVolume(i) * double) ## Checking segment and section connection and reordering them (ag.fuse_sec_nb, start_index, seg_sec, fuse_sec_index)\ = check_segment_connection(f_nb, ag.fuse_seg_nb,\ ag.fuse_sec_nb, tigl) ## ---------------------------------------------------------------------------- ## INITIALIZATION 2 ----------------------------------------------------------- ## ---------------------------------------------------------------------------- max_sec_nb = np.amax(ag.fuse_sec_nb) max_seg_nb = np.amax(ag.fuse_seg_nb) ag.fuse_sec_circ = np.zeros((max_sec_nb, f_nb)) ag.fuse_sec_width = np.zeros((max_sec_nb, f_nb)) ag.fuse_sec_rel_dist = np.zeros((max_sec_nb, f_nb)) ag.fuse_seg_index = np.zeros((max_sec_nb, f_nb)) ag.fuse_seg_length = np.zeros((max_seg_nb, f_nb)) fuse_center_section_point = np.zeros((max_sec_nb, f_nb, 3)) ag.fuse_center_seg_point = np.zeros((max_seg_nb, ag.fuse_nb, 3)) ag.fuse_center_sec_point = np.zeros((max_sec_nb, ag.fuse_nb, 3)) ag.fuse_seg_vol = np.zeros((max_seg_nb, f_nb)) ##===========================================================================## ## ---------------------------------------------------------------------------- ## FUSELAGE ANALYSIS ---------------------------------------------------------- ## ---------------------------------------------------------------------------- ## Aircraft total length ------------------------------------------------------ ag.tot_length = tigl.configurationGetLength() ## Evaluating fuselage: sections circumference, segments volume and length --- (ag.fuse_sec_rel_dist[:,i-1],ag.fuse_seg_index[:,i-1])\ = rel_dist(i,ag.fuse_sec_nb[i-1],ag.fuse_seg_nb[i-1],\ tigl,seg_sec[:,i-1,:],start_index[i-1]) ag.fuse_length.append(ag.fuse_sec_rel_dist[-1, i - 1]) for j in range(1, ag.fuse_seg_nb[i - 1] + 1): k = int(ag.fuse_seg_index[j][i - 1]) ag.fuse_sec_circ[j][i-1]\ = tigl.fuselageGetCircumference(i,k,1.0) (fpx, fpy, fpz) = tigl.fuselageGetPoint(i, k, 1.0, 0.0) (fpx2, fpy2, fpz2) = tigl.fuselageGetPoint(i, k, 1.0, 0.5) ag.fuse_seg_vol[j - 1][i - 1] = abs(tigl.fuselageGetSegmentVolume( i, k)) fuse_center_section_point[j][i - 1][0] = (fpx + fpx2) / 2 fuse_center_section_point[j][i - 1][1] = (fpy + fpy2) / 2 fuse_center_section_point[j][i - 1][2] = (fpz + fpz2) / 2 hw1 = 0 hw2 = 0 for zeta in np.arange(0.0, 1.0, 0.001): (fpx, fpy, fpz) = tigl.fuselageGetPoint(i, k, 1.0, zeta) if abs(fpz - fuse_center_section_point[j][i - 1][2]) < 0.01: if (fpy > fuse_center_section_point[j][i - 1][1] and hw1 == 0): hw1 = abs(fpy - fuse_center_section_point[j][i - 1][1]) elif (fpy < fuse_center_section_point[j][i - 1][1] and hw2 == 0): hw2 = abs(fpy - fuse_center_section_point[j][i - 1][1]) break ag.fuse_sec_width[j][i - 1] = hw1 + hw2 (fslpx, fslpy, fslpz) = tigl.fuselageGetPoint(1, k, 0.0, 0.0) (fslpx2, fslpy2, fslpz2) = tigl.fuselageGetPoint(1, k, 1.0, 0.0) ag.fuse_seg_length[j - 1][i - 1] = abs(fslpx2 - fslpx) k = int(ag.fuse_seg_index[1][i - 1]) ag.fuse_sec_circ[0][i - 1] = tigl.fuselageGetCircumference(i, k, 0.0) (fpx, fpy, fpz) = tigl.fuselageGetPoint(i, k, 0.0, 0.0) (fpx2, fpy2, fpz2) = tigl.fuselageGetPoint(i, k, 0.0, 0.5) fuse_center_section_point[0][i - 1][0] = (fpx + fpx2) / 2 fuse_center_section_point[0][i - 1][1] = (fpy + fpy2) / 2 fuse_center_section_point[0][i - 1][2] = (fpz + fpz2) / 2 hw1 = 0 hw2 = 0 for zeta in np.arange(0.0, 1.0, 0.001): (fpx, fpy, fpz) = tigl.fuselageGetPoint(i, k, 0.0, zeta) if abs(fpz - fuse_center_section_point[0][i - 1][2]) < 0.01: if (fpy > fuse_center_section_point[0][i - 1][1] and hw1 == 0): hw1 = abs(fpy - fuse_center_section_point[0][i - 1][1]) elif (fpy < fuse_center_section_point[0][i - 1][1] and hw2 == 0): hw2 = abs(fpy - fuse_center_section_point[0][i - 1][1]) break ag.fuse_sec_width[0][i - 1] = hw1 + hw2 ag.fuse_mean_width.append(np.mean(ag.fuse_sec_width[:, i - 1])) ## Evaluating the point at the center of each segment, symmetry is considered a = 0 cs = False for i in range(int(ag.fuse_nb)): if cs: cs = False continue for j in range(1, ag.fuse_seg_nb[i - a - 1] + 1): ag.fuse_center_seg_point[j-1][i-1][0]\ = (fuse_center_section_point[j-1][i-a-1][0]\ + fuse_center_section_point[j][i-a-1][0])/2 ag.fuse_center_seg_point[j-1][i-1][1]\ = (fuse_center_section_point[j-1][i-a-1][1]\ + fuse_center_section_point[j][i-a-1][1])/2 ag.fuse_center_seg_point[j-1][i-1][2]\ = (fuse_center_section_point[j-1][i-a-1][2]\ + fuse_center_section_point[j][i-a-1][2])/2 ag.fuse_center_sec_point[j-1][i-1][:]\ = fuse_center_section_point[j-1][i-a-1][:] if ag.fuse_sym[i - 1 - a] != 0: if ag.fuse_sym[i - 1 - a] == 1: symy = 1 symx = 1 symz = -1 if ag.fuse_sym[i - 1 - a] == 2: symy = -1 symx = 1 symz = 1 if ag.fuse_sym[i - 1 - a] == 3: symy = 1 symx = -1 symz = 1 ag.fuse_center_seg_point[:,i,0]\ = ag.fuse_center_seg_point[:,i-1,0] * symx ag.fuse_center_seg_point[:,i,1]\ = ag.fuse_center_seg_point[:,i-1,1] * symy ag.fuse_center_seg_point[:,i,2]\ = ag.fuse_center_seg_point[:,i-1,2] * symz ag.fuse_center_sec_point[j-1][i][:]\ = fuse_center_section_point[j-1][i-a-1][:] cs = True a += 1 # Evaluating cabin length and volume, nose length and tail_length ------------ ex = False corr = 1.25 + np.zeros((1, f_nb)) c = False cabin_nb = np.zeros((1, f_nb)) cabin_seg = np.zeros((max_seg_nb, f_nb)) cabin_length = 0 cabin_volume = 0 nose_length = 0 tail_length = 0 for j in range(1, ag.fuse_seg_nb[i - 1] + 1): if (round(ag.fuse_sec_width[j][i-1],3)\ == round(np.amax(ag.fuse_sec_width[:,i-1]),3)): cabin_length += ag.fuse_seg_length[j - 1, i - 1] cabin_volume += ag.fuse_seg_vol[j - 1, i - 1] cabin_seg[j - 1][i - 1] = 1 c = True elif not c: nose_length += ag.fuse_seg_length[j - 1, i - 1] if cabin_length >= 0.65 * ag.fuse_length[i - 1]: # If the aircraft is designed with 1 or more sections with # maximum width and the sun of their length is greater the 65% # of the total length, the cabin will be considered only in those # sections tail_length = ag.fuse_length[i - 1] - cabin_length - nose_length cabin_nb[i - 1] = 1 ex = True while ex is False: c = False cabin_seg = np.zeros((max_seg_nb, f_nb)) nose_length = 0 tail_length = 0 cabin_length = 0 cabin_volume = 0 for j in range(1, ag.fuse_seg_nb[i - 1] + 1): if (ag.fuse_sec_width[j][i-1] >= (corr[i-1]\ * ag.fuse_mean_width[i-1])): cabin_length += ag.fuse_seg_length[j - 1, i - 1] cabin_volume += ag.fuse_seg_vol[j - 1, i - 1] cabin_seg[j - 1][i - 1] = 1 c = True elif c: tail_length += ag.fuse_seg_length[j - 1, i - 1] else: nose_length += ag.fuse_seg_length[j - 1, i - 1] if corr[i - 1] > 0.0 and cabin_length < (0.20 * ag.fuse_length[i - 1]): corr[i - 1] -= 0.05 else: ex = True ag.fuse_nose_length.append(nose_length) ag.fuse_tail_length.append(tail_length) ag.fuse_cabin_length.append(cabin_length) ag.fuse_cabin_vol.append(cabin_volume) ag.f_seg_sec = seg_sec ag.cabin_nb = cabin_nb ag.cabin_seg = cabin_seg ag.fuse_mean_width = ag.fuse_mean_width[0] cpf.close_tixi(tixi, cpacs_in) # log info display ------------------------------------------------------------ log.info('---------------------------------------------') log.info('---------- Geometry Evaluations -------------') log.info('---------- USEFUL INFO ----------------------\n'\ + 'If fuselage or wing number is greater than 1 the '\ + 'informations\nof each part is listed in an '\ + 'array ordered per column progressively') log.info('Symmetry output: 0 = no symmetry, 1 = x-y, '\ + '2 = x-z, 3 = y-z planes') log.info('---------------------------------------------') log.info('---------- Fuselage Results -----------------') log.info('Number of fuselage [-]: ' + str(ag.fuse_nb)) log.info('Fuselage symmetry plane [-]: ' + str(ag.fuse_sym)) log.info('Number of fuselage sections (not counting symmetry) [-]: '\ + str(ag.fuse_sec_nb)) log.info('Number of fuselage segments (not counting symmetry) [-]: '\ + str(ag.fuse_seg_nb)) log.info('Cabin segments array [-]: ' + str(cabin_seg)) log.info('Fuse Length [m]: ' + str(ag.fuse_length)) log.info('Fuse nose Length [m]: ' + str(ag.fuse_nose_length)) log.info('Fuse cabin Length [m]: ' + str(ag.fuse_cabin_length)) log.info('Fuse tail Length [m]: ' + str(ag.fuse_tail_length)) log.info('Aircraft Length [m]: ' + str(ag.tot_length)) log.info('Circumference of each section of each fuselage [m]: \n'\ + str(ag.fuse_sec_circ)) log.info('Relative distance of each section of each fuselage [m]: \n'\ + str(ag.fuse_sec_rel_dist)) log.info('Length of each segment of each fuselage [m]: \n'\ + str(ag.fuse_seg_length)) log.info('Mean fuselage width [m]: ' + str(ag.fuse_mean_width)) log.info('Width of each section of each fuselage [m]: \n'\ + str(ag.fuse_sec_width)) log.info('Volume of all the segmetns of each fuselage [m^3]: \n'\ + str(ag.fuse_seg_vol)) log.info('Volume of each cabin [m^3]: ' + str(ag.fuse_cabin_vol)) log.info('Volume of each fuselage [m^3]: ' + str(ag.fuse_vol)) log.info('---------------------------------------------') return (ag)
def get_user_inputs(ed, ui, adui, cpacs_in): """ Function to extract from the xml file the required input data, the code will use the default value when they are missing. INPUT (class) adui --Arg.: AdvancedInputs class. (class) ed --Arg.: EngineData class. (class) ui --Arg.: UserInputs class. ##======= Classes are defined in the InputClasses folder =======## (char) cpacs_in --Arg.: Relative location of the xml file in the ToolInput folder (cpacs option) or relative location of the temp. xml file in the ToolOutput folder (input option). OUTPUT (class) adui --Out.: AdvancedInputs class updated (class) ui --Out.: UserInputs class updated. (class) ed --AOut.:EngineData class updated. (file) cpacs_in --Out.: Updated cpasc file """ log.info('Starting data extraction from CPACS file') # Path creation ========================================================== tixi = cpf.open_tixi(cpacs_in) # toolspecific CEASIOM_PATH = '/cpacs/toolspecific/CEASIOMpy' GEOM_PATH = CEASIOM_PATH + '/geometry' RANGE_PATH = CEASIOM_PATH + '/ranges' W_PATH = CEASIOM_PATH + '/weight' C_PATH = W_PATH + '/crew' PILOTS_PATH = C_PATH + '/pilots' CC_PATH = C_PATH + '/cabinCrewMembers' PASS_PATH = W_PATH + '/passengers' ML_PATH = W_PATH + '/massLimits' PROP_PATH = CEASIOM_PATH + '/propulsion' FUEL_PATH = '/cpacs/toolspecific/CEASIOMpy/fuels' tixi = cpf.create_branch(tixi, FUEL_PATH, False) tixi = cpf.create_branch(tixi, GEOM_PATH, False) tixi = cpf.create_branch(tixi, RANGE_PATH, False) tixi = cpf.create_branch(tixi, PILOTS_PATH, False) tixi = cpf.create_branch(tixi, CC_PATH, False) tixi = cpf.create_branch(tixi, PASS_PATH, False) tixi = cpf.create_branch(tixi, ML_PATH, False) tixi = cpf.create_branch(tixi, PROP_PATH, False) # cpacs/vehicles MC_PATH = '/cpacs/vehicles/aircraft/model/analyses/massBreakdown/'\ + 'payload/mCargo/massDescription' F_PATH = '/cpacs/vehicles/fuels/fuel' tixi = cpf.create_branch(tixi, MC_PATH, False) tixi = cpf.create_branch(tixi, F_PATH, False) tixi = cpf.add_uid(tixi, F_PATH, 'kerosene') # Gathering data ========================================================= # Geometry =============================================================== if not tixi.checkElement(GEOM_PATH + '/description'): tixi.createElement(GEOM_PATH, 'description') tixi.updateTextElement(GEOM_PATH + '/description', 'User '\ + 'geometry input') # Number of floors. if not tixi.checkElement(GEOM_PATH + '/floorsNb'): tixi.createElement(GEOM_PATH, 'floorsNb') tixi.updateDoubleElement(GEOM_PATH + '/floorsNb',\ ui.FLOORS_NB, '%g') else: temp = tixi.getDoubleElement(GEOM_PATH + '/floorsNb') if temp != ui.FLOORS_NB and temp > 0: ui.FLOORS_NB = temp # Extracting fuselage material data. if not tixi.checkElement(GEOM_PATH + '/virtualThick'): tixi.createElement(GEOM_PATH, 'virtualThick') tixi.updateDoubleElement(GEOM_PATH + '/virtualThick',\ adui.VRT_THICK, '%g') else: temp = tixi.getDoubleElement(GEOM_PATH + '/virtualThick') if temp != adui.VRT_THICK and temp > 0: adui.VRT_THICK = temp if not tixi.checkElement(GEOM_PATH + '/virtualDensity'): tixi.createElement(GEOM_PATH, 'virtualDensity') tixi.updateDoubleElement(GEOM_PATH + '/virtualDensity',\ adui.VRT_STR_DENSITY, '%g') else: temp = tixi.getDoubleElement(GEOM_PATH + '/virtualDensity') if temp != adui.VRT_STR_DENSITY and temp > 0: adui.VRT_STR_DENSITY = temp if not tixi.checkElement(GEOM_PATH + '/cabinHeight'): tixi.createElement(GEOM_PATH, 'cabinHeight') tixi.updateDoubleElement(GEOM_PATH + '/cabinHeight',\ ui.H_LIM_CABIN, '%g') else: temp = tixi.getDoubleElement(GEOM_PATH + '/cabinHeight') if temp != ui.H_LIM_CABIN and temp > 0: ui.H_LIM_CABIN = temp # People ================================================================= # Pilots user input data if not tixi.checkElement(PILOTS_PATH + '/pilotNb'): tixi.createElement(PILOTS_PATH, 'pilotNb') tixi.updateIntegerElement(PILOTS_PATH + '/pilotNb',\ adui.PILOT_NB, '%i') else: temp = tixi.getIntegerElement(PILOTS_PATH + '/pilotNb') if temp != adui.PILOT_NB and temp > 0: adui.PILOT_NB = temp if not tixi.checkElement(PILOTS_PATH + '/pilotMass'): tixi.createElement(PILOTS_PATH, 'pilotMass') tixi.updateDoubleElement(PILOTS_PATH + '/pilotMass',\ adui.MASS_PILOT, '%g') else: temp = tixi.getDoubleElement(PILOTS_PATH + '/pilotMass') if temp != adui.MASS_PILOT and temp > 0: adui.MASS_PILOT = temp # Cabin crew user input data if not tixi.checkElement(CC_PATH + '/cabinCrewMemberMass'): tixi.createElement(CC_PATH, 'cabinCrewMemberMass') tixi.updateDoubleElement(CC_PATH + '/cabinCrewMemberMass',\ adui.MASS_CABIN_CREW, '%g') else: temp = tixi.getDoubleElement(CC_PATH + '/cabinCrewMemberMass') if temp != adui.MASS_CABIN_CREW and temp > 0: adui.MASS_CABIN_CREW = temp # Passengers user input data if not tixi.checkElement(PASS_PATH + '/passMass'): tixi.createElement(PASS_PATH, 'passMass') tixi.updateDoubleElement(PASS_PATH + '/passMass',\ adui.MASS_PASS, '%g') else: temp = tixi.getDoubleElement(PASS_PATH+ '/passMass') if temp != adui.MASS_PASS and temp > 0: adui.MASS_PASS = temp if tixi.checkElement(PASS_PATH + '/passNb'): temp = tixi.getIntegerElement(PASS_PATH+ '/passNb') if temp != ui.MAX_PASS and temp > 0: ui.MAX_PASS = temp if not tixi.checkElement(PASS_PATH + '/passDensity'): tixi.createElement(PASS_PATH, 'passDensity') tixi.updateDoubleElement(PASS_PATH + '/passDensity',\ ui.PASS_BASE_DENSITY, '%i') else: temp = tixi.getDoubleElement(PASS_PATH + '/passDensity') if temp != ui.PASS_BASE_DENSITY and temp > 0: ui.PASS_BASE_DENSITY = temp if not tixi.checkElement(PASS_PATH + '/passPerToilet'): tixi.createElement(PASS_PATH, 'passPerToilet') tixi.updateIntegerElement(PASS_PATH + '/passPerToilet',\ adui.PASS_PER_TOILET, '%i') else: temp = tixi.getIntegerElement(PASS_PATH + '/passPerToilet') if temp != adui.PASS_PER_TOILET and temp > 0: adui.PASS_PER_TOILET = temp # Fuel =================================================================== if not tixi.checkElement(F_PATH + '/density'): tixi.createElement(F_PATH, 'density') tixi.updateDoubleElement(F_PATH + '/density',\ adui.FUEL_DENSITY, '%g') else: temp = tixi.getDoubleElement(F_PATH + '/density') if temp != adui.FUEL_DENSITY and temp > 0: adui.FUEL_DENSITY = temp if not tixi.checkElement(FUEL_PATH + '/resFuelPerc'): tixi.createElement(FUEL_PATH, 'resFuelPerc') tixi.updateDoubleElement(FUEL_PATH + '/resFuelPerc',\ adui.RES_FUEL_PERC, '%g') else: temp = tixi.getDoubleElement(FUEL_PATH + '/resFuelPerc') if temp != adui.RES_FUEL_PERC and temp > 0: adui.RES_FUEL_PERC = temp # Weight ================================================================= # Mass limits data if not tixi.checkElement(ML_PATH + '/description'): tixi.createElement(ML_PATH, 'description') tixi.updateTextElement(ML_PATH + '/description', 'Desired max fuel '\ + 'volume [m^3] and payload mass [kg]') if not tixi.checkElement(ML_PATH + '/maxPayload'): tixi.createElement(ML_PATH, 'maxPayload') tixi.updateDoubleElement(ML_PATH + '/maxPayload',\ ui.MAX_PAYLOAD, '%g') else: temp = tixi.getDoubleElement(ML_PATH + '/maxPayload') if temp != ui.MAX_PAYLOAD and temp != 0: ui.MAX_PAYLOAD = temp if not tixi.checkElement(ML_PATH + '/maxFuelVol'): tixi.createElement(ML_PATH, 'maxFuelVol') tixi.updateDoubleElement(ML_PATH + '/maxFuelVol',\ ui.MAX_FUEL_VOL, '%g') else: temp = tixi.getDoubleElement(ML_PATH + '/maxFuelVol') if temp != ui.MAX_FUEL_VOL and temp != 0: ui.MAX_FUEL_VOL = temp if tixi.checkElement(MC_PATH + '/massCargo'): temp = tixi.getDoubleElement(MC_PATH + '/massCargo') if temp != ui.MASS_CARGO and temp != 0: ui.MASS_CARGO = temp # If the cargo mass is defined in the UserInputs class will be added # in the CPACS file after the analysis. # Flight ================================================================= if not tixi.checkElement(RANGE_PATH + '/lDRatio'): tixi.createElement(RANGE_PATH, 'lDRatio') tixi.updateDoubleElement(RANGE_PATH + '/lDRatio',\ ui.LD, '%g') else: temp = tixi.getIntegerElement(RANGE_PATH + '/lDRatio') if temp != ui.LD and temp > 0: ui.LD = temp if not tixi.checkElement(RANGE_PATH + '/cruiseSpeed'): tixi.createElement(RANGE_PATH, 'cruiseSpeed') tixi.updateDoubleElement(RANGE_PATH + '/cruiseSpeed',\ ui.CRUISE_SPEED, '%g') else: temp = tixi.getIntegerElement(RANGE_PATH + '/cruiseSpeed') if temp != ui.CRUISE_SPEED and temp > 0: ui.CRUISE_SPEED = temp TSFC_PATH = PROP_PATH + '/tSFC' tixi = cpf.create_branch(tixi, TSFC_PATH, False) if not tixi.checkElement(TSFC_PATH + '/tsfcCruise'): tixi.createElement(TSFC_PATH, 'tsfcCruise') tixi.updateDoubleElement(TSFC_PATH + '/tsfcCruise',\ ed.TSFC_CRUISE, '%g') else: temp = tixi.getDoubleElement(TSFC_PATH + '/tsfcCruise') if temp != ed.TSFC_CRUISE and temp > 0: ed.TSFC_CRUISE = temp if not tixi.checkElement(PROP_PATH + '/userEngineOption'): tixi.createElement(PROP_PATH, 'userEngineOption') if ui.USER_ENGINES: tixi.updateTextElement(PROP_PATH + '/userEngineOption', 'True') else: tixi.updateTextElement(PROP_PATH + '/userEngineOption', 'False') else: temp = tixi.getTextElement(PROP_PATH + '/userEngineOption') if temp == 'False': ui.USER_ENGINES = False else: ui.USER_ENGINES = True if not tixi.checkElement(PROP_PATH + '/singleHydraulics'): tixi.createElement(PROP_PATH, 'singleHydraulics') if adui.SINGLE_HYDRAULICS: tixi.updateTextElement(PROP_PATH + '/singleHydraulics', 'True') else: tixi.updateTextElement(PROP_PATH + '/singleHydraulics', 'False') else: temp = tixi.getTextElement(PROP_PATH + '/singleHydraulics') if temp == 'False': adui.SINGLE_HYDRAULICS = False else: adui.SINGLE_HYDRAULICS = True log.info('Data from CPACS file succesfully extracted') # Saving and closing the cpacs file -------------------------------------- tixi.saveDocument(cpacs_in) cpf.close_tixi(tixi, cpacs_in) # Openign and closing again the cpacs file ------------------------------- tixi = cpf.open_tixi(cpacs_in) tigl = cpf.open_tigl(tixi) tixi.saveDocument(cpacs_in) cpf.close_tixi(tixi, cpacs_in) return(ed, ui, adui)
def cpacs_weight_update(out, mw, out_xml): """ The function updates the cpacs file after the Weight analysis. INPUT (class) out --Arg.: WeightOutput class. (class) mw --Arg.: MassesWeights class. (char) out_xml --Arg.: Path of the output file. ##======= Classes are defined in the classes folder =======## OUTPUT (file) cpacs.xml --Out.: Updated cpacs file. """ tixi = cpf.open_tixi(out_xml) tigl = cpf.open_tigl(tixi) # Path creation ========================================================== MB_PATH = '/cpacs/vehicles/aircraft/model/analyses/massBreakdown' if tixi.checkElement(MB_PATH): tixi.removeElement(MB_PATH) MD_PATH = MB_PATH + '/designMasses' MTOM_PATH = MD_PATH + '/mTOM' MZFM_PATH = MD_PATH + '/mZFM' MF_PATH = MB_PATH + '/fuel/massDescription' OEM_PATH = MB_PATH + '/mOEM/massDescription' PAY_PATH = MB_PATH + '/payload/massDescription' MC_PATH = MB_PATH + '/payload/mCargo' OIM_PATH = MB_PATH + '/mOEM/mOperatorItems/mCrewMembers'\ + '/massDescription' tixi = cpf.create_branch(tixi, MTOM_PATH + '/mass', False) tixi = cpf.create_branch(tixi, MZFM_PATH + '/mass', False) tixi = cpf.create_branch(tixi, MF_PATH + '/mass', False) tixi = cpf.create_branch(tixi, OEM_PATH + '/mass', False) tixi = cpf.create_branch(tixi, PAY_PATH + '/mass', False) tixi = cpf.create_branch(tixi, MC_PATH, False) tixi = cpf.create_branch(tixi, OIM_PATH + '/mass', False) # DESIGN MASSES ========================================================== tixi = cpf.add_uid(tixi, MTOM_PATH, 'MTOM') tixi.createElement(MTOM_PATH, 'name') tixi.updateTextElement(MTOM_PATH + '/name', 'Maximum take-off mass') tixi.createElement(MTOM_PATH, 'description') tixi.updateTextElement(MTOM_PATH + '/description', 'Maximum '\ + 'take off mass [kg], CoG coordinate [m] and '\ + 'moment of inertia.') tixi.updateDoubleElement(MTOM_PATH + '/mass',\ mw.maximum_take_off_mass, '%g') # MZFM ------------------------------------------------------------------- tixi = cpf.add_uid(tixi, MZFM_PATH, 'MZFM') tixi.createElement(MZFM_PATH, 'name') tixi.updateTextElement(MZFM_PATH + '/name', 'Maximum zero fuel mass') tixi.createElement(MZFM_PATH, 'description') tixi.updateTextElement(MZFM_PATH + '/description', 'Maximum '\ + 'zero fuel mass [kg] and corresponding CoG '\ + 'coordinate [m], moment of inertia.') tixi.updateDoubleElement(MZFM_PATH + '/mass', mw.zero_fuel_mass, '%g') # FUEL MASS ============================================================== tixi = cpf.add_uid(tixi, MF_PATH, 'MFM') tixi.createElement(MF_PATH, 'name') tixi.updateTextElement(MF_PATH + '/name', 'Max fuel mass') tixi.createElement(MF_PATH, 'description') tixi.updateTextElement(MF_PATH + '/description', 'Maximum '\ + 'fuel mass [kg].') tixi.updateDoubleElement(MF_PATH + '/mass', mw.mass_fuel_max, '%g') # OEM ==================================================================== tixi = cpf.add_uid(tixi, OEM_PATH, 'OEM') tixi.createElement(OEM_PATH, 'name') tixi.updateTextElement(OEM_PATH + '/name', 'Operating empty mass') tixi.createElement(OEM_PATH, 'description') tixi.updateTextElement(OEM_PATH + '/description', 'Operating empty'\ + ' mass [kg] and related inertia [kgm^2].') tixi.updateDoubleElement(OEM_PATH + '/mass', mw.operating_empty_mass, '%g') tixi.updateDoubleElement(OIM_PATH + '/mass', mw.mass_crew, '%g') tixi = cpf.add_uid(tixi, OIM_PATH, 'massCrew') # PAYLOAD MASS AND FUEL WITH MAX PAYLOAD ================================= tixi = cpf.add_uid(tixi, PAY_PATH, 'MPM') tixi.createElement(PAY_PATH, 'name') tixi.updateTextElement(PAY_PATH + '/name', 'Max payload mass') tixi.createElement(PAY_PATH, 'description') tixi.updateTextElement(PAY_PATH + '/description', 'Maximum '\ + 'payload mass [kg].') tixi.updateDoubleElement(PAY_PATH + '/mass', mw.mass_payload, '%g') if mw.mass_cargo: tixi.createElement(MC_PATH, 'massCargo') tixi.updateDoubleElement(MC_PATH + '/massCargo', mw.mass_cargo, '%g') # Saving and closing the new cpacs file inside the ToolOutput folder ----- tixi.saveDocument(out_xml) cpf.close_tixi(tixi, out_xml) # Openign and closing again the cpacs file, formatting purpose ----------- tixi = cpf.open_tixi(out_xml) tigl = cpf.open_tigl(tixi) tixi.saveDocument(out_xml) cpf.close_tixi(tixi, out_xml) return()
def get_engine_inputs(ui, ed, cpacs_in): """ Function to extract from the xml file the required input data, the code will use the default value when they are missing. INPUT (class) ui --Arg.: UserInputs class. (class) ed --Arg.: EngineData class. ##======= Class ares defined in the InputClasses folder =======## (char) cpacs_in --Arg.: Relative location of the xml file in the ToolInput folder (cpacs option) or relative location of the temp. xml file in the ToolOutput folder (input option). OUTPUT (class) ed --Out.: EngineData class. (file) cpacs_in --Out.: Updated cpasc file """ log.info('Starting engine data extraction from CPACS file') # Path creation ========================================================== tixi = cpf.open_tixi(cpacs_in) CEASIOM_PATH = '/cpacs/toolspecific/CEASIOMpy' PROP_PATH = CEASIOM_PATH + '/propulsion' tixi = cpf.create_branch(tixi, PROP_PATH, False) # Propulsion ============================================================= if not tixi.checkElement(PROP_PATH + '/turboprop'): tixi = cpf.create_branch(tixi, PROP_PATH, False) tixi.createElement(PROP_PATH, 'turboprop') if ed.TURBOPROP: tixi.updateTextElement(PROP_PATH + '/turboprop', 'True') else: tixi.updateTextElement(PROP_PATH + '/turboprop', 'False') else: temp = tixi.getTextElement(PROP_PATH + '/turboprop') if temp == 'False': ed.TURBOPROP = False else: ed.TURBOPROP = True if not tixi.checkElement(PROP_PATH + '/auxiliaryPowerUnit'): tixi.createElement(PROP_PATH, 'auxiliaryPowerUnit') if ed.APU: tixi.updateTextElement(PROP_PATH + '/auxiliaryPowerUnit', 'True') else: tixi.updateTextElement(PROP_PATH + '/auxiliaryPowerUnit', 'False') else: temp = tixi.getTextElement(PROP_PATH + '/auxiliaryPowerUnit') if temp == 'False': ed.APU = False else: ed.APU = True if not tixi.checkElement(PROP_PATH + '/engineNumber'): tixi.createElement(PROP_PATH, 'engineNumber') tixi.updateIntegerElement(PROP_PATH + '/engineNumber', ed.NE, '%i') else: ed.NE = tixi.getIntegerElement(PROP_PATH + '/engineNumber') #Engines mp = [] tp = [] EN_PATH = '/cpacs/vehicles/engines' if tixi.checkElement(EN_PATH): for e in range(0,ed.NE-1): EN_PATH = '/cpacs/vehicles/engines' if ed.NE > 1: EN_PATH += '/engine' + str(e+1) else: EN_PATH += '/engine' if not tixi.checkElement(EN_PATH): raise Exception('Engine definition inclomplete, missing'\ + ' one or more engines in the cpacs file') if not tixi.checkElement(EN_PATH + '/name'): ed.EN_NAME.append('Engine_' + str(e+1)) tixi.createElement(EN_PATH, 'name') tixi.updateTextElement(EN_PATH + '/name', ed.EN_NAME[e]) else: if e > len(ed.EN_NAME): ed.EN_NAME.append(tixi.getTextElement(EN_PATH + '/name')) ENA_PATH = EN_PATH + '/analysis/mass' if tixi.checkElement(ENA_PATH + '/mass'): ed.en_mass = tixi.getDoubleElement(ENA_PATH + '/mass') mp.append(ed.en_mass) if e>0 and ed.en_mass != mp[e-1]: raise Exception('The engines have different masses, this'\ + ' can lead to an unbalanced aircraft') elif ed.en_mass: tixi.createElement(ENA_PATH, 'mass') tixi.updateDoubleElement(ENA_PATH + '/mass', ed.en_mass, '%g') else: raise Exception('Engine definition inclomplete, missing'\ + ' engine mass in the cpacs file') ENT_PATH = EN_PATH + '/analysis' if tixi.checkElement(ENT_PATH + '/thrust00'): ed.max_thrust = tixi.getDoubleElement(ENT_PATH + '/thrust00') tp.append(ed.max_thrust) if e>0 and ed.max_thrust != tp[e-1]: raise Exception('The engines have different thrust, this') #+ ' can lead to an unbalanced flight') elif ed.max_thrust: tixi.createElement(ENT_PATH, 'thrust00') tixi.updateDoubleElement(ENT_PATH + '/thrust00', ed.max_thrust, '%g') else: raise Exception('Engine definition inclomplete, missing'\ + ' engine thrust in the cpacs file') log.info('Data from CPACS file succesfully extracted') # Saving and closing the cpacs file -------------------------------------- tixi.saveDocument(cpacs_in) cpf.close_tixi(tixi, cpacs_in) # Openign and closing again the cpacs file ------------------------------- tixi = cpf.open_tixi(cpacs_in) tigl = cpf.open_tigl(tixi) tixi.saveDocument(cpacs_in) cpf.close_tixi(tixi, cpacs_in) return(ed)
def toolspecific_update(mw, out, out_xml): """ The function updates the cpacs file after the Weight analysis. INPUT (class) mw --Arg.: MassesWeights class. (class) out --Arg.: WeightOutput class. ##======= Classes are defined in the classes folder =======## (char) out_xml --Arg.: Path of the output file. OUTPUT (file) cpacs.xml --Out.: Updated cpacs file. """ tixi = cpf.open_tixi(out_xml) # Path creation ========================================================== CEASIOM_PATH = '/cpacs/toolspecific/CEASIOMpy' W_PATH = CEASIOM_PATH + '/weight' C_PATH = W_PATH + '/crew' PASS_PATH = W_PATH + '/passengers' # Path update ============================================================ if not tixi.checkElement(C_PATH + '/cabinCrewMembers/cabinCrewMemberNb'): tixi.createElement(C_PATH + '/cabinCrewMembers', 'cabinCrewMemberNb') tixi.updateDoubleElement(C_PATH + '/cabinCrewMembers/cabinCrewMemberNb',\ out.cabin_crew_nb, '%g') if not tixi.checkElement(PASS_PATH + '/passNb'): tixi.createElement(PASS_PATH, 'passNb') tixi.updateIntegerElement(PASS_PATH + '/passNb', out.pass_nb, '%i') if not tixi.checkElement(PASS_PATH + '/rowNb'): tixi.createElement(PASS_PATH, 'rowNb') tixi.updateIntegerElement(PASS_PATH + '/rowNb', out.row_nb, '%i') if not tixi.checkElement(PASS_PATH + '/aisleNb'): tixi.createElement(PASS_PATH, 'aisleNb') tixi.updateIntegerElement(PASS_PATH + '/aisleNb', out.aisle_nb, '%i') if not tixi.checkElement(PASS_PATH + '/toiletNb'): tixi.createElement(PASS_PATH, 'toiletNb') tixi.updateIntegerElement(PASS_PATH + '/toiletNb', out.toilet_nb, '%i') if not tixi.checkElement(PASS_PATH + '/abreastNb'): tixi.createElement(PASS_PATH, 'abreastNb') tixi.updateIntegerElement(PASS_PATH + '/abreastNb', out.abreast_nb, '%i') if not tixi.checkElement(PASS_PATH + '/fuelMassMaxpass'): tixi.createElement(PASS_PATH, 'fuelMassMaxpass') FMP_PATH = PASS_PATH + '/fuelMassMaxpass' if not tixi.checkElement(FMP_PATH + '/description'): tixi.createElement(FMP_PATH, 'description') tixi.updateTextElement(FMP_PATH + '/description', 'Maximum amount of '\ + 'fuel with maximum payload [kg]') if not tixi.checkElement(FMP_PATH + '/mass'): tixi.createElement(FMP_PATH, 'mass') tixi.updateDoubleElement(FMP_PATH + '/mass', mw.mass_fuel_maxpass, '%g') # Saving and closing the new cpacs file inside the ToolOutput folder ----- tixi.saveDocument(out_xml) cpf.close_tixi(tixi, out_xml) # Openign and closing again the cpacs file, formatting purpose ----------- tixi = cpf.open_tixi(out_xml) tigl = cpf.open_tigl(tixi) tixi.saveDocument(out_xml) cpf.close_tixi(tixi, out_xml) return()
def wing_geom_eval(ag, cpacs_in): """ Main function to evaluate the wings geometry ARGUMENTS (class) ag --Arg.: AircraftGeometry class. ##======= Class are defined in the InputClasses folder =======## (char) cpacs_in -- Arg.: Cpacs xml file location. RETURN (class) ag --Out.: AircraftGeometry class updated. """ ##===========================================================================## log.info('---------------------------------------------') log.info('---------- Analysing wing geometry ----------') log.info('---------------------------------------------') # Opening tixi and tigl tixi = open_tixi(cpacs_in) tigl = open_tigl(tixi) ## ---------------------------------------------------------------------------- ## COUNTING 1 ----------------------------------------------------------------- ## Counting wing number without symmetry -------------------------------------- ## ---------------------------------------------------------------------------- w_nb = tixi.getNamedChildrenCount( '/cpacs/vehicles/aircraft\ /model/wings', 'wing') ## ---------------------------------------------------------------------------- ## INITIALIZATION 1 ----------------------------------------------------------- ## ---------------------------------------------------------------------------- ag.w_nb = w_nb ag.wing_nb = w_nb wing_plt_area_xz = [] wing_plt_area_yz = [] wingUID = [] ## ---------------------------------------------------------------------------- ## COUNTING 2 ----------------------------------------------------------------- ## Counting sections and segments---------------------------------------------- ## ---------------------------------------------------------------------------- b = 0 for i in range(1, w_nb + 1): double = 1 ag.wing_sym.append(tigl.wingGetSymmetry(i)) if ag.wing_sym[i - 1] != 0: double = 2 # To consider the real amount of wing # when they are defined using symmetry ag.wing_nb += 1 ag.wing_sec_nb.append(tigl.wingGetSectionCount(i)) ag.wing_seg_nb.append(tigl.wingGetSegmentCount(i)) ag.wing_vol.append(tigl.wingGetVolume(i) * double) # x-y plane ag.wing_plt_area.append(tigl.wingGetReferenceArea(i, 1) * double) # x-z plane wing_plt_area_xz.append(tigl.wingGetReferenceArea(i, 2) * double) # y-z plane wing_plt_area_yz.append(tigl.wingGetReferenceArea(i, 3) * double) ag.wing_tot_vol = ag.wing_tot_vol + ag.wing_vol[i - 1] wingUID.append(tigl.wingGetUID(i)) ag.wing_span.append(tigl.wingGetSpan(wingUID[i - 1])) a = np.amax(ag.wing_span) # Evaluating the index that corresponds to the main wing if a > b: ag.main_wing_index = i b = a ## Checking segment and section connection and reordering them (ag.wing_sec_nb, start_index, seg_sec, wing_sec_index)\ = check_segment_connection(wing_plt_area_xz, wing_plt_area_yz,\ ag, tigl) ## ---------------------------------------------------------------------------- ## INITIALIZATION 2 ----------------------------------------------------------- ## ---------------------------------------------------------------------------- max_wing_sec_nb = np.amax(ag.wing_sec_nb) max_wing_seg_nb = np.amax(ag.wing_seg_nb) wing_center_section_point = np.zeros((max_wing_sec_nb, w_nb, 3)) ag.wing_center_seg_point = np.zeros((max_wing_seg_nb, ag.wing_nb, 3)) ag.wing_seg_vol = np.zeros((max_wing_seg_nb, w_nb)) ag.wing_fuel_seg_vol = np.zeros((max_wing_seg_nb, w_nb)) ag.wing_fuel_vol = 0 ag.wing_mac = np.zeros((4, w_nb)) ag.wing_sec_thicknes = np.zeros((max_wing_sec_nb + 1, w_nb)) ##===========================================================================## ## ---------------------------------------------------------------------------- ## WING ANALYSIS -------------------------------------------------------------- ## ---------------------------------------------------------------------------- # Main wing plantform area ag.wing_plt_area_main = ag.wing_plt_area[ag.main_wing_index - 1] ## Wing: MAC,chords,thicknes,span,plantform area ------------------------------ for i in range(1, w_nb + 1): mac = tigl.wingGetMAC(wingUID[i - 1]) (wpx, wpy, wpz) = tigl.wingGetChordPoint(i, 1, 0.0, 0.0) (wpx2, wpy2, wpz2) = tigl.wingGetChordPoint(i, 1, 0.0, 1.0) ag.wing_max_chord.append(np.sqrt((wpx2-wpx)**2 + (wpy2-wpy)**2\ + (wpz2-wpz)**2)) (wpx, wpy, wpz) = tigl.wingGetChordPoint(i, ag.wing_seg_nb[i - 1], 1.0, 0.0) (wpx2,wpy2,wpz2) = tigl.wingGetChordPoint(i,ag.wing_seg_nb[i-1],\ 1.0,1.0) ag.wing_min_chord.append(np.sqrt((wpx2-wpx)**2 + (wpy2-wpy)**2\ + (wpz2-wpz)**2) ) for k in range(1, 5): ag.wing_mac[k - 1][i - 1] = mac[k - 1] for jj in range(1, ag.wing_seg_nb[i - 1] + 1): j = int(seg_sec[jj - 1, i - 1, 2]) cle = tigl.wingGetChordPoint(i, j, 0.0, 0.0) ag.wing_seg_vol[j - 1][i - 1] = tigl.wingGetSegmentVolume(i, j) lp = tigl.wingGetLowerPoint(i, j, 0.0, 0.0) up = tigl.wingGetUpperPoint(i, j, 0.0, 0.0) if np.all(cle == lp) == True: L = 0.25 else: L = 0.75 if np.all(cle == up) == True: U = 0.25 else: U = 0.75 (wplx, wply, wplz) = tigl.wingGetLowerPoint(i, j, 0.0, L) (wpux, wpuy, wpuz) = tigl.wingGetUpperPoint(i, j, 0.0, U) wing_center_section_point[j - 1][i - 1][0] = (wplx + wpux) / 2 wing_center_section_point[j - 1][i - 1][1] = (wply + wpuy) / 2 wing_center_section_point[j - 1][i - 1][2] = (wplz + wpuz) / 2 ag.wing_sec_thicknes[j-1][i-1] = np.sqrt((wpux-wplx)**2\ + (wpuy-wply)**2 + (wpuz-wplz)**2) j = int(seg_sec[ag.wing_seg_nb[i - 1] - 1, i - 1, 2]) (wplx, wply, wplz) = tigl.wingGetLowerPoint(\ i,ag.wing_seg_nb[i-1],1.0,L) (wpux, wpuy, wpuz) = tigl.wingGetUpperPoint(\ i,ag.wing_seg_nb[i-1],1.0,U) ag.wing_sec_thicknes[j][i-1] = np.sqrt((wpux-wplx)**2\ + (wpuy-wply)**2 + (wpuz-wplz)**2) wing_center_section_point[ag.wing_seg_nb[i - 1]][i - 1][0] = (wplx + wpux) / 2 wing_center_section_point[ag.wing_seg_nb[i - 1]][i - 1][1] = (wply + wpuy) / 2 wing_center_section_point[ag.wing_seg_nb[i - 1]][i - 1][2] = (wplz + wpuz) / 2 ag.wing_sec_mean_thick.append(np.mean(\ ag.wing_sec_thicknes[0:ag.wing_seg_nb[i-1]+1,i-1])) # Evaluating wing fuel tank volume in the main wings if abs(round(ag.wing_plt_area[i-1],3) - ag.wing_plt_area_main)\ < 0.001: tp_ratio = ag.wing_min_chord[i - 1] / ag.wing_max_chord[i - 1] ratio = round(tp_ratio * ag.wing_plt_area[i - 1] / 100, 1) if ratio >= 1.0: ag.wing_fuel_vol = round(ag.wing_vol[i - 1] * 0.8, 2) elif ratio >= 0.5: ag.wing_fuel_vol = round(ag.wing_vol[i - 1] * 0.72, 2) else: ag.wing_fuel_vol = round(ag.wing_vol[i - 1] * 0.5, 2) for j in seg_sec[:, i - 1, 2]: if j == 0.0: break ag.wing_fuel_seg_vol[int(j)-1][i-1]\ = round((ag.wing_seg_vol[int(j)-1][i-1]\ /(sum(ag.wing_vol))) * ag.wing_fuel_vol,2) if ag.wing_plt_area[i-1] > wing_plt_area_xz[i-1] and\ ag.wing_plt_area[i-1] > wing_plt_area_yz[i-1]: ag.is_horiz.append(True) if ag.wing_sym[i - 1] != 0: ag.is_horiz.append(True) else: ag.is_horiz.append(False) if ag.wing_sym[i - 1] != 0: ag.is_horiz.append(False) # Wing segment length evaluatin function ag = get_wing_segment_length(ag, wing_center_section_point) # Evaluating the point at the center of each segment, the center # is placed at 1/4 of the chord, symmetry is considered. a = 0 c = False for i in range(1, int(ag.wing_nb) + 1): if c: c = False continue for jj in range(1, ag.wing_seg_nb[i - a - 1] + 1): j = int(seg_sec[jj - 1, i - a - 1, 2]) ag.wing_center_seg_point[j-1][i-1][0]\ = (wing_center_section_point[j-1][i-a-1][0]\ + wing_center_section_point[j][i-a-1][0])/2 ag.wing_center_seg_point[j-1][i-1][1]\ = (wing_center_section_point[j-1][i-a-1][1]\ + wing_center_section_point[j][i-a-1][1])/2 ag.wing_center_seg_point[j-1][i-1][2]\ = (wing_center_section_point[j-1][i-a-1][2]\ + wing_center_section_point[j][i-a-1][2])/2 if ag.wing_sym[i - 1 - a] != 0: if ag.wing_sym[i - 1 - a] == 1: symy = 1 symx = 1 symz = -1 if ag.wing_sym[i - 1 - a] == 2: symy = -1 symx = 1 symz = 1 if ag.wing_sym[i - 1 - a] == 3: symy = 1 symx = -1 symz = 1 ag.wing_center_seg_point[:,i,0]\ = ag.wing_center_seg_point[:,i-1,0] * symx ag.wing_center_seg_point[:,i,1]\ = ag.wing_center_seg_point[:,i-1,1] * symy ag.wing_center_seg_point[:,i,2]\ = ag.wing_center_seg_point[:,i-1,2] * symz c = True a += 1 ag.w_seg_sec = seg_sec close_tixi(tixi, cpacs_in) # log info display ------------------------------------------------------------ log.info('---------------------------------------------') log.info('--------------- Wing Results ----------------') log.info('Number of Wings [-]: ' + str(ag.wing_nb)) log.info('Wing symmetry plane [-]: ' + str(ag.wing_sym)) log.info('Number of wing sections (not counting symmetry) [-]: '\ + str(ag.wing_sec_nb)) log.info('Number of wing segments (not counting symmetry) [-]: '\ + str(ag.wing_seg_nb)) log.info('Wing Span [m]: ' + str(ag.wing_span)) log.info('Wing MAC length [m]: ' + str(ag.wing_mac[0, ])) log.info('Wing MAC x,y,z coordinate [m]: \n' + str(ag.wing_mac[1:4, ])) log.info('Wings sections thicknes [m]: ' + str(ag.wing_sec_thicknes)) log.info('Wings sections mean thicknes [m]: '\ + str(ag.wing_sec_mean_thick)) log.info('Wing segments length [m]: ' + str(ag.wing_seg_length)) log.info('Wing max chord length [m]: ' + str(ag.wing_max_chord)) log.info('Wing min chord length [m]: ' + str(ag.wing_min_chord)) log.info('Main wing plantform area [m^2]: ' + str(ag.wing_plt_area_main)) log.info('Wings plantform area [m^2]: '\ + str(ag.wing_plt_area)) log.info('Volume of each wing [m^3]: ' + str(ag.wing_vol)) log.info('Total wing volume [m^3]: ' + str(ag.wing_tot_vol)) log.info('Wing volume for fuel storage [m^3]: '\ + str(ag.wing_fuel_vol)) log.info('---------------------------------------------') return (ag)
def wing_check_thickness(h_min, awg, cpacs_in, TP, FUEL_ON_CABIN=0): """ The fuction subdivides the main wing into nodes and defines the fuel and cabin volumes. INPUT (float) h_min --Arg.: Minimum height for the fuselage [m]. (class) awg --Arg.: AircraftWingGeometry class look at aircraft_geometry_class.py in the classes folder for explanation. (char) cpacs_in --Arg.: Relative position of the xml file. (boolean) TP --Arg.: True if the aircraft is a turboprop. (float) FUEL_ON_CABIN --Arg.: Percentage of the cabin volume used for fuel storaging instead for passengers. (default 0%) OUTPUT (float-array) wing_nodes --Out.: 3D array containing the nodes coordinates (x,y,z) [m,m,m]. (class) awg --Arg.: AircraftWingGeometry class look at aircraft_geometry_class.py in the classes folder for explanation. """ log.info('-----------------------------------------------------------') log.info('----------- Evaluating fuselage and wing volume -----------') log.info('-----------------------------------------------------------') tixi = cpf.open_tixi(cpacs_in) tigl = cpf.open_tigl(tixi) SPACING = 0.1 subd_c = 30 # Number of subdivisions along the perimeter # on eachsurface, total number of points for each section # subd_c * 2 DEN = 0.0 w = awg.main_wing_index - 1 wing_nodes = 0 c = False for d in range(1, subd_c + 2): DEN += d zeta = 1.0 / DEN for i in awg.w_seg_sec[:, w, 2]: if i == 0.0: break w_temp = np.zeros((2, subd_c + 2, 3)) #Number of subdivisions along the longitudinal axis subd_l = math.ceil((awg.wing_seg_length[int(i) - 1][w] / SPACING)) if subd_l == 0: subd_l = 1 eta = 1.0 / subd_l et = 0.0 (xc, yc, zc) = awg.wing_center_seg_point[int(i) - 1][w][:] for j in range(0, int(subd_l) - 1): (xle, yle, zle) = tigl.wingGetLowerPoint(w + 1, int(i), et, 0.0) (xle2, yle2, zle2) = tigl.wingGetLowerPoint(w + 1, int(i), et, 1.0) if xle < xle2: ZLE = 0.0 ze = 0.0 else: ZLE = 1.0 ze = 1.0 for k in range(0, subd_c + 2): if ZLE == 0.0: ze += float(k) * zeta elif ZLE == 1.0: ze -= float(k) * zeta (xl, yl, zl) = tigl.wingGetLowerPoint(w + 1, int(i), et, ze) (xu, yu, zu) = tigl.wingGetUpperPoint(w + 1, int(i), et, ze) w_temp[0, k, :] = (xu, yu, zu) w_temp[1, k, :] = (xl, yl, zl) if c is False: wing_nodes = w_temp c = True else: wing_nodes = np.concatenate((wing_nodes, w_temp), axis=0) et = j * eta (rows, columns, pages) = wing_nodes.shape # wing_nodes 3D matrix: the even rows and the zero row correspond # to the upper profile of the wing, while all the odd rows correspond # to the lower profile. The columns contain the coordinates of each nodes. # The page 0,1 and 2 contain respectively the x,y and z coordinate. h_max = [] h_mean = [] y_sec = [] for r in range(0, rows - 1, 2): h_max_temp = 0 z_min = 9999 z_max = 0 h = [] for c in range(0, columns): (xu, yu, zu) = wing_nodes[r, c, :] (xl, yl, zl) = wing_nodes[r + 1, c, :] h.append(abs(zu - zl)) if abs(zu - zl) > h_max_temp: h_max_temp = abs(zu - zl) if r == 0: if zl < z_min: (x13, y13, z13) = (xl, yl, zl) z_min = zl if zu > z_max: (x14, y14, z14) = (xu, yu, zu) z_max = zu else: if zl < z_min: (x23_t, y23_t, z23_t) = (xl, yl, zl) z_min = zl if zu > z_max: (x24_t, y24_t, z24_t) = (xu, yu, zu) z_max = zu h_max.append(h_max_temp) h_mean.append(np.mean(h)) y_sec.append(yl) if np.mean(h) >= h_min: h_mean_cabin = np.mean(h_mean) awg.y_max_cabin = yl seg = r if r != 0: (x23, y23, z23) = (x23_t, y23_t, z23_t) (x24, y24, z24) = (x24_t, y24_t, z24_t) else: (x11, y11, z11) = wing_nodes[0, 0, :] (x12, y12, z12) = wing_nodes[0, -1, :] (x21, y21, z21) = wing_nodes[seg, 0, :] (x22, y22, z22) = wing_nodes[seg, -1, :] break for c in range(0, columns): (xu, yu, zu) = wing_nodes[0, c, :] (xl, yl, zl) = wing_nodes[1, c, :] if abs(zu - zl) >= h_min: xs1 = xu zs1u = zu zs1l = zl yse1 = yl break for c in range(0, columns): (xu, yu, zu) = wing_nodes[seg, c, :] (xl, yl, zl) = wing_nodes[seg + 1, c, :] if abs(zu - zl) >= h_min: xs2 = xu zs2u = zu zs2l = zl yse2 = yl break for c in range(columns - 1, -1, -1): (xu, yu, zu) = wing_nodes[0, c, :] (xl, yl, zl) = wing_nodes[1, c, :] if abs(zu - zl) >= h_min: xe1 = xu ze1u = zu ze1l = zl break for c in range(columns - 1, -1, -1): (xu, yu, zu) = wing_nodes[seg, c, :] (xl, yl, zl) = wing_nodes[seg + 1, c, :] if abs(zu - zl) >= h_min: xe2 = xu ze2u = zu ze2l = zl break awg.cabin_area = 0.5 * abs(xs1*yse2 + xs2*yse2 + xe2*yse1 + xe1*yse1\ - xs2*yse1 - xe2*yse2 - xe1*yse2 - xs1*yse1) fuse_plt_area = 0.5 * abs(x11*y21 + x21*y22 + x22*y12 + x12*y11\ - x21*y11 - x22*y21 - x12*y22 - x11*y12) fuse_frontal_area = 0.5 * abs(y24*z23 + y23*z13 + y13*z14 + y14*z24\ - z24*y23 - z23*y13 - z13*y14 -z14*y24) c1 = math.sqrt((x11 - x12)**2 + (y11 - y12)**2 + (z11 - z12)**2) c2 = math.sqrt((x21 - x22)**2 + (y21 - y22)**2 + (z21 - z22)**2) awg.cabin_span = abs(awg.y_max_cabin - y11) awg.fuse_vol = (0.95 * fuse_frontal_area) * (fuse_plt_area/(awg.cabin_span))\ / (math.sqrt(1+(c2/c1))) if awg.wing_sym[w - 1] != 0: awg.fuse_vol *= 2 awg.cabin_area *= 2 awg.cabin_vol = (awg.cabin_area * h_min) delta_vol = (awg.fuse_vol - awg.cabin_vol) awg.fuse_fuel_vol = (float(FUEL_ON_CABIN) / 100.0) * delta_vol if TP: t = 0.5 else: t = 0.55 awg.wing_fuel_vol = t * (awg.wing_vol[w] - awg.fuse_vol) awg.fuel_vol_tot = awg.fuse_fuel_vol + awg.wing_fuel_vol # log info display ------------------------------------------------------------ log.info('--------------------- Main wing Volumes -------------------') log.info('Wing volume [m^3]: ' + str(awg.wing_vol[w])) log.info('Cabin volume [m^3]: ' + str(awg.cabin_vol)) log.info('Volume of the wing as fuselage [m^3]: ' + str(awg.fuse_vol)) log.info('Volume of the remaining portion of the wing [m^3]: '\ + str(awg.wing_vol[w] - awg.fuse_vol)) log.info('Fuel volume in the fuselage [m^3]: ' + str(awg.fuse_fuel_vol)) log.info('Fuel volume in the wing [m^3]: ' + str(awg.wing_fuel_vol)) log.info('Total fuel Volume [m^3]: ' + str(awg.fuel_vol_tot)) log.info('-----------------------------------------------------------') return (awg, wing_nodes)
def get_user_inputs(ind, ui, ag, cpacs_in, cpacs): """ The function to extracts from the XML file the required input data, the code will use the default value when they are missing. INPUT (class) ind --Arg.: InsideDimensions class. (class) ui --Arg.: UserInputs class. ##======= Classes are defined in the InputClasses folder =======## (class) ag --Arg.: AircraftGeometry class ##======= Classes are defined in the InputClasses folder ======## (char) cpacs_in --Arg.: Relative location of the xml file in the ToolInput folder (cpacs option) or relative location of the temp. xml file in the ToolOutput folder (input option). (char) cpacs --Arg.: cpacs True or False option OUTPUT (class) ind --Out.: InsideDimensions class updated (class) ui --Out.: UserInputs class updated. ##====== Classes are defined in the InputClasses folder ======## (file) cpacs_in --Out.: Updated cpasc file """ log.info('Starting data extraction from CPACS file') # Path creation ========================================================== tixi = cpf.open_tixi(cpacs_in) CESAIOM_PATH = '/cpacs/toolspecific/CEASIOMpy' GEOM_PATH = CESAIOM_PATH + '/geometry' FUEL_PATH = CESAIOM_PATH + '/fuels' W_PATH = CESAIOM_PATH + '/weight' C_PATH = W_PATH + '/crew' pilots_path = C_PATH + '/pilots' CC_PATH = C_PATH + '/cabinCrewMembers' PASS_PATH = W_PATH + '/passengers' ML_PATH = W_PATH + '/massLimits' PROP_PATH = CESAIOM_PATH + '/propulsion' F_PATH = '/cpacs/vehicles/fuels/fuel' MC_PATH = '/cpacs/vehicles/aircraft/model/analyses/massBreakdown/'\ + 'payload/mCargo/massDescription' tixi = cpf.create_branch(tixi, MC_PATH, False) tixi = cpf.create_branch(tixi, FUEL_PATH, False) tixi = cpf.create_branch(tixi, GEOM_PATH, False) tixi = cpf.create_branch(tixi, pilots_path, False) tixi = cpf.create_branch(tixi, CC_PATH, False) tixi = cpf.create_branch(tixi, PASS_PATH, False) tixi = cpf.create_branch(tixi, ML_PATH, False) tixi = cpf.create_branch(tixi, PROP_PATH, False) tixi = cpf.create_branch(tixi, F_PATH, False) tixi = cpf.add_uid(tixi, F_PATH, 'kerosene') ### Geometry ============================================================= if not tixi.checkElement(GEOM_PATH + '/description'): tixi.createElement(GEOM_PATH, 'description') tixi.updateTextElement(GEOM_PATH + '/description', 'User '\ + 'geometry input') # Extracting geometry input data (Double Floor) if not tixi.checkElement(GEOM_PATH + '/isDoubleFloor'): tixi.createElement(GEOM_PATH, 'isDoubleFloor') tixi.updateIntegerElement(GEOM_PATH + '/isDoubleFloor',\ ui.IS_DOUBLE_FLOOR, '%i') else: temp = tixi.getIntegerElement(GEOM_PATH + '/isDoubleFloor') if temp != ui.IS_DOUBLE_FLOOR: ui.IS_DOUBLE_FLOOR = temp # Extracting geometry input data (seatWidth) if not tixi.checkElement(GEOM_PATH + '/seatWidth'): tixi.createElement(GEOM_PATH, 'seatWidth') tixi.updateDoubleElement(GEOM_PATH + '/seatWidth',\ ind.seat_width, '%g') else: temp = tixi.getDoubleElement(GEOM_PATH + '/seatWidth') if temp != ind.seat_width and temp > 0: ind.seat_width = temp # Extracting geometry input data (seatLength) if not tixi.checkElement(GEOM_PATH + '/seatLength'): tixi.createElement(GEOM_PATH, 'seatLength') tixi.updateDoubleElement(GEOM_PATH + '/seatLength',\ ind.seat_length, '%g') else: temp = tixi.getDoubleElement(GEOM_PATH + '/seatLength') if temp != ind.seat_length and temp > 0: ind.seat_length = temp # Extracting geometry input data (aisleWidth) if not tixi.checkElement(GEOM_PATH + '/aisleWidth'): tixi.createElement(GEOM_PATH, 'aisleWidth') tixi.updateDoubleElement(GEOM_PATH + '/aisleWidth',\ ind.aisle_width, '%g') else: temp = tixi.getDoubleElement(GEOM_PATH + '/aisleWidth') if temp != ind.aisle_width and temp > 0: ind.aisle_width = temp # Extracting geometry input data (fuseThick) if not tixi.checkElement(GEOM_PATH + '/fuseThick'): tixi.createElement(GEOM_PATH, 'fuseThick') tixi.updateDoubleElement(GEOM_PATH + '/fuseThick',\ ind.fuse_thick, '%g') else: temp = tixi.getDoubleElement(GEOM_PATH + '/fuseThick') if temp != ind.fuse_thick and temp > 0: ind.fuse_thick = temp # Extracting geometry input data (toiletLength) if not tixi.checkElement(GEOM_PATH + '/toiletLength'): tixi.createElement(GEOM_PATH, 'toiletLength') tixi.updateDoubleElement(GEOM_PATH + '/toiletLength',\ ind.toilet_length, '%g') else: temp = tixi.getDoubleElement(GEOM_PATH + '/toiletLength') if temp != ind.toilet_length and temp > 0: ind.toilet_length = temp ### Weight =============================================================== # Pilots user input data if not tixi.checkElement(pilots_path + '/pilotNb'): tixi.createElement(pilots_path, 'pilotNb') tixi.updateIntegerElement(pilots_path + '/pilotNb',\ ui.PILOT_NB, '%i') else: temp = tixi.getIntegerElement(pilots_path + '/pilotNb') if temp != ui.PILOT_NB and temp > 0: ui.PILOT_NB = temp if not tixi.checkElement(pilots_path + '/pilotMass'): tixi.createElement(pilots_path, 'pilotMass') tixi.updateDoubleElement(pilots_path + '/pilotMass',\ ui.MASS_PILOT, '%g') else: temp = tixi.getDoubleElement(pilots_path + '/pilotMass') if temp != ui.MASS_PILOT and temp > 0: ui.MASS_PILOT = temp # Cabin crew user input data if not tixi.checkElement(CC_PATH + '/cabinCrewMemberMass'): tixi.createElement(CC_PATH, 'cabinCrewMemberMass') tixi.updateDoubleElement(CC_PATH + '/cabinCrewMemberMass',\ ui.MASS_CABIN_CREW, '%g') else: temp = tixi.getDoubleElement(CC_PATH + '/cabinCrewMemberMass') if temp != ui.MASS_CABIN_CREW and temp > 0: ui.MASS_CABIN_CREW = temp # Passengers user input data if not tixi.checkElement(PASS_PATH + '/passMass'): tixi.createElement(PASS_PATH, 'passMass') tixi.updateDoubleElement(PASS_PATH + '/passMass',\ ui.MASS_PASS, '%g') else: temp = tixi.getDoubleElement(PASS_PATH + '/passMass') if temp != ui.MASS_PASS and temp > 0: ui.MASS_PASS = temp if not tixi.checkElement(PASS_PATH + '/passPerToilet'): tixi.createElement(PASS_PATH, 'passPerToilet') tixi.updateIntegerElement(PASS_PATH + '/passPerToilet',\ ui.PASS_PER_TOILET, '%i') else: temp = tixi.getIntegerElement(PASS_PATH + '/passPerToilet') if temp != ui.PASS_PER_TOILET and temp > 0: ui.PASS_PER_TOILET = temp # Mass limits data if not tixi.checkElement(ML_PATH + '/description'): tixi.createElement(ML_PATH, 'description') tixi.updateTextElement(ML_PATH + '/description', 'Desired max fuel '\ + 'volume [m^3] and payload mass [kg]') if not tixi.checkElement(ML_PATH + '/maxPayload'): tixi.createElement(ML_PATH, 'maxPayload') tixi.updateDoubleElement(ML_PATH + '/maxPayload',\ ui.MAX_PAYLOAD, '%g') else: temp = tixi.getDoubleElement(ML_PATH + '/maxPayload') if temp != ui.MAX_PAYLOAD and temp > 0: ui.MAX_PAYLOAD = temp if not tixi.checkElement(ML_PATH + '/maxFuelVol'): tixi.createElement(ML_PATH, 'maxFuelVol') tixi.updateDoubleElement(ML_PATH + '/maxFuelVol',\ ui.MAX_FUEL_VOL, '%g') else: temp = tixi.getDoubleElement(ML_PATH + '/maxFuelVol') if temp != ui.MAX_FUEL_VOL and temp > 0: ui.MAX_FUEL_VOL = temp if tixi.checkElement(MC_PATH + '/massCargo'): temp = tixi.getDoubleElement(MC_PATH + '/massCargo') if temp != ui.MASS_CARGO and temp != 0: ui.MASS_CARGO = temp # Fuel density =========================================================== if not tixi.checkElement(F_PATH + '/density'): tixi.createElement(F_PATH, 'density') tixi.updateDoubleElement(F_PATH + '/density',\ ui.FUEL_DENSITY, '%g') else: temp = tixi.getDoubleElement(F_PATH + '/density') if temp != ui.FUEL_DENSITY and temp > 0: ui.FUEL_DENSITY = temp # Propulsion ============================================================= if not tixi.checkElement(PROP_PATH + '/turboprop'): tixi = cpf.create_branch(tixi, PROP_PATH, False) tixi.createElement(PROP_PATH, 'turboprop') if ui.TURBOPROP: tixi.updateTextElement(PROP_PATH + '/turboprop', 'True') else: tixi.updateTextElement(PROP_PATH + '/turboprop', 'False') else: temp = tixi.getTextElement(PROP_PATH + '/turboprop') if temp == 'False': ui.TURBOPROP = False else: ui.TURBOPROP = True if not tixi.checkElement(FUEL_PATH + '/resFuelPerc'): tixi.createElement(FUEL_PATH, 'resFuelPerc') tixi.updateDoubleElement(FUEL_PATH + '/resFuelPerc',\ ui.RES_FUEL_PERC, '%g') else: temp = tixi.getDoubleElement(FUEL_PATH + '/resFuelPerc') if temp != ui.RES_FUEL_PERC and temp > 0: ui.RES_FUEL_PERC = temp log.info('Data from CPACS file succesfully extracted') # Saving and closing the cpacs file -------------------------------------- tixi.saveDocument(cpacs_in) cpf.close_tixi(tixi, cpacs_in) # Openign and closing again the cpacs file ------------------------------- tixi = cpf.open_tixi(cpacs_in) tigl = cpf.open_tigl(tixi) tixi.saveDocument(cpacs_in) cpf.close_tixi(tixi, cpacs_in) return (ind, ui)
def get_ted_list(tixi): """ Get a list of all the TED found in the CPACS file. Function 'get_ted_list' looks in the CPACS file for all the Trailin Edge Devices (TED), saved them in a Pandas DataFrame with for each one corresponding: * Wing uID * Component Segment uiD * Symmetry direction (x,y,z or '') * Deflection list Source: * TIXI functions : http://tixi.sourceforge.net/Doc/ Args: tixi (handles): TIXI Handle Returns: ted_df (Dataframe): Pandas Dataframe containing all the parameters mentioned in the description of the function """ tigl = cpsf.open_tigl(tixi) ted_df = pd.DataFrame({ 'ted_uid': [], 'comp_seg_uid': [], 'wing_uid': [], 'sym_dir': [], 'defl_list': [] }) if tixi.checkElement(WINGS_XPATH): wing_cnt = tixi.getNamedChildrenCount(WINGS_XPATH, 'wing') log.info(str(wing_cnt) + ' wings has been found.') else: wing_cnt = 0 log.warning('No wings has been found in this CPACS file!') for i_wing in range(wing_cnt): wing_xpath = WINGS_XPATH + '/wing[' + str(i_wing + 1) + ']' wing_uid = cpsf.get_uid(tixi, wing_xpath) log.info(wing_uid) comp_segments_xpath = wing_xpath + '/componentSegments' if tixi.checkElement(comp_segments_xpath): comp_seg_cnt = tixi.getNamedChildrenCount(comp_segments_xpath, 'componentSegment') log.info(str(comp_seg_cnt) + ' component segments has been found.') else: comp_seg_cnt = 0 log.warning('No Component segment has been found for this wing!') for c_seg in range(comp_seg_cnt): comp_seg_xpath = comp_segments_xpath + '/componentSegment[' + str( c_seg + 1) + ']' comp_seg_uid = cpsf.get_uid(tixi, comp_seg_xpath) log.info(comp_seg_uid) teds_xpath = comp_seg_xpath + '/controlSurfaces/trailingEdgeDevices' if tixi.checkElement(teds_xpath): ted_cnt = tixi.getNamedChildrenCount(teds_xpath, 'trailingEdgeDevice') log.info( str(ted_cnt) + ' trailing edge devices has been found:') else: ted_cnt = 0 log.warning( 'No trailing edge device has been found for this wing!') for ted in range(ted_cnt): ted_xpath = teds_xpath + '/trailingEdgeDevice[' + str(ted + 1) + ']' ted_uid = cpsf.get_uid(tixi, ted_xpath) log.info(ted_uid) sym_dir = get_ted_symmetry(tixi, ted_uid) defl_list, _ = get_ted_deflections(tixi, ted_uid) ted_df.loc[len(ted_df)] = [ ted_uid, comp_seg_uid, wing_uid, sym_dir, defl_list ] return (ted_df)