def test_layer_names(): """Test layer names""" # Converter (layer boundaries are defined based on geopotential height) H2h = Atmosphere.geop2geom_height eps = 1e-6 # Single value input assert Atmosphere(H2h(-3e3)).layer_name[0] == 'troposphere' assert Atmosphere(H2h(0)).layer_name[0] == 'troposphere' assert Atmosphere(H2h(11e3 + eps)).layer_name[0] == 'tropopause' assert Atmosphere(H2h(15e3)).layer_name[0] == 'tropopause' assert Atmosphere(H2h(20e3 + eps)).layer_name[0] == 'stratosphere' assert Atmosphere(H2h(25e3)).layer_name[0] == 'stratosphere' assert Atmosphere(H2h(32e3)).layer_name[0] == 'stratosphere' assert Atmosphere(H2h(47e3 + eps)).layer_name[0] == 'stratopause' assert Atmosphere(H2h(50e3)).layer_name[0] == 'stratopause' assert Atmosphere(H2h(51e3 + eps)).layer_name[0] == 'mesosphere' assert Atmosphere(H2h(75e3)).layer_name[0] == 'mesosphere' assert Atmosphere(H2h(80e3)).layer_name[0] == 'mesosphere' # Test matrix h = np.array([[0, 12, 22], [30, 49, 75]]) * 1e3 expected = np.char.array([['troposphere', 'tropopause', 'stratosphere'], ['stratosphere', 'stratopause', 'mesosphere']]) computed = Atmosphere(h).layer_name assert np.testing.assert_array_equal(computed, expected) is None
def validate_result(p, airplane, runway, flap_angle): ## Ground roll mu = 0.025 g = 9.80665 atmos = Atmosphere(runway.elevation) VR = p.get_val('traj.initial_run.timeseries.states:V')[-1] T0 = p.get_val('traj.initial_run.timeseries.thrust')[0] TR = p.get_val('traj.initial_run.timeseries.thrust')[-1] W0 = p.get_val('traj.initial_run.timeseries.states:mass')[0] * g WR = p.get_val('traj.initial_run.timeseries.states:mass')[-1] * g Sngr_opt = p.get_val('traj.initial_run.timeseries.states:x')[-1] CLg = p.get_val('traj.initial_run.timeseries.CLg')[-1] CDg = p.get_val('traj.initial_run.timeseries.CD')[-1] agV0 = g * (T0 / W0 - mu - runway.slope) agVR = g * ((TR / WR - mu) - (CDg - mu * CLg) * atmos.density[0] * VR**2 / (2 * WR / airplane.wing.area) - runway.slope) k = ((1 - agVR / agV0) / math.log(agV0 / agVR)) agave = k * agV0 Sngr = VR**2 / (2 * agave) print( f"Sngr: {Sngr}, Sngr_opt: {Sngr_opt}, diff: {(Sngr_opt - Sngr)/Sngr_opt * 100}" ) ## Rotation Vlof = p.get_val('traj.rotation.timeseries.states:V')[-1] tr = p.get_val('traj.rotation.timeseries.time')[-1] - p.get_val( 'traj.rotation.timeseries.time')[0] alpha_max = p.get_val('traj.rotation.timeseries.states:theta')[-1] Sr = 0.5 * (VR + Vlof) * tr Sr_opt = p.get_val('traj.rotation.timeseries.states:x')[-1] - Sngr_opt print( f"Sngr: {Sr}, Sngr_opt: {Sr_opt}, diff: {(Sr_opt - Sr) / Sr_opt * 100}, alpha_max: {alpha_max}, tr: {tr}" ) p.get_val('traj.transition.timeseries.time')[-1] - p.get_val( 'traj.rotation.timeseries.time')[-1] ## Transition if flap_angle == 0: CLmax = 1.4156 elif flap_angle == 5: CLmax = 2.0581687373857513 elif flap_angle == 10: CLmax = 2.1299732557370072 else: CLmax = 2.2234101823709764 vlof_vs = p.get_val('traj.transition.timeseries.V_Vstall')[0] deltaCL = 0.5 * (vlof_vs**2 - 1) * (CLmax * (vlof_vs**2 - 0.53) + 0.38) W = p.get_val('traj.rotation.timeseries.states:mass')[-1] * g Rtr = 2 * (W / airplane.wing.area) / (atmos.density[0] * g * deltaCL) T = p.get_val('traj.rotation.timeseries.thrust')[-1] D = p.get_val('traj.rotation.timeseries.D')[-1] theta = (T - D) / W Str = Rtr * math.sin(theta) htr = Str * theta / 2 hscreen = p.get_val('traj.transition.timeseries.h_mlg', units='m')[-1] if htr > hscreen: Scl = 0 if htr < hscreen: Scl = (hscreen - htr) / math.tan(theta) Sa = Str + Scl Sa_opt = p.get_val('traj.transition.timeseries.states:x')[-1] - p.get_val( 'traj.transition.timeseries.states:x')[0] print(f"Sa: {Sa}, Sa_opt: {Sa_opt}, diff: {(Sa_opt - Sa) / Sa_opt * 100}") Sroskam = Sngr + Sr + Sa Sopt = p.get_val('traj.transition.timeseries.x_mlg')[-1] print( f"Sroskam: {Sroskam}, Programa: {Sopt}, diff: {(Sopt - Sroskam)/Sopt * 100}" )
def test_repr(): assert repr(Atmosphere(0)) == 'Atmosphere(array([0.]))' assert repr(Atmosphere([1, 100, 1000 ])) == 'Atmosphere(array([ 1., 100., 1000.]))'
current_dir = os.path.dirname(os.path.realpath(__file__)) parent_dir = os.path.dirname(current_dir) sys.path.append(parent_dir) from aircraft import JetStar import numpy as np import matplotlib.pyplot as plt from ambiance import Atmosphere from Interpolacao import DragPolar from scipy.optimize import fsolve import Cruzeiro as cr # ============================================= jet = JetStar(1) sealevel = Atmosphere(0) beta = 9296 rho0 = sealevel.density[0] drag_asc = DragPolar() drag_asc.CLp = 0 # ============================================= def gamma(h,T0,n,W,V): T = cr.jet_buoyancy(h, T0, n)[0] D = cr.total_drag(V, h)[0][0] return (T - D)/W def h_dot(h,T0,n,W,V):
from ambiance import Atmosphere print("alt,pressure,temperature") for level in range(-300, 30000, 1): atm = Atmosphere(level) print("%s,%s,%s" % (level, atm.pressure[0], atm.temperature[0]))
def test_str(): assert str(Atmosphere(0)) == 'Atmosphere([0.0])' assert str(Atmosphere([1, 100, 1000])) == 'Atmosphere([1.0, 100.0, 1000.0])'
def air_density(Temp, h): '''densidade fora da ISA; Temp em Celcius''' P = Atmosphere(h).pressure[0] Temp_isa_mod = Atmosphere(h).temperature[0] + Temp - (15) rho = P / (R_gas * Temp_isa_mod) return rho
def computeDerivedVariables(self, t, state, models): from models.flight import FlightModel from rellipsoid import earth from ambiance import Atmosphere surfaceAltitude = assumptions.launchSeaLevelAltitude.get( ) + models["flight"]["state"][FlightModel.states_z] if surfaceAltitude < 0: surfaceAltitude = 0 if surfaceAltitude > 80000: surfaceAltitude = 80000 atmosphere = Atmosphere(surfaceAltitude) pressure = atmosphere.pressure[0] density = atmosphere.density[0] speedOfSound = atmosphere.speed_of_sound[0] temperature = atmosphere.temperature[0] pressure = pressure * (assumptions.initialAtmosphericPressure.get() / seaLevelPressure) density = density * (assumptions.initialAtmosphericPressure.get() / seaLevelPressure) speedOfSound = speedOfSound * ( assumptions.initialAtmosphericPressure.get() / seaLevelPressure) temperature = temperature * ( assumptions.initialAtmosphericTemperature.get() / seaLevelTemperature) viscosity = atmosphere.dynamic_viscosity[0] thermalConductivity = atmosphere.thermal_conductivity[0] velocityThroughAir = np.linalg.norm([ models["flight"]["state"][FlightModel.states_vx], models["flight"]["state"][FlightModel.states_vy], models["flight"]["state"][FlightModel.states_vz] ]) dynamicPressure = 0.5 * density * velocityThroughAir * velocityThroughAir stagnationPressure = pressure - dynamicPressure airCp = CP.PropsSI('CPMASS', 'T', temperature, 'P', pressure, 'air') airCv = CP.PropsSI('CVMASS', 'T', temperature, 'P', pressure, 'air') airGamma = airCp / airCv mach = velocityThroughAir / speedOfSound # This is the adiabatic stagnation temperature on the surface of the rocket stagnationTemperature = temperature * ( 1 + (airGamma - 1) / 2 * mach * mach) launchLatitudeRadians = assumptions.launchLatitudeDegrees.get( ) / 180 * math.pi # todo for future: take into account the present latitude, not just the starting one verticalGravity, northwardGravity = earth.get_analytic_gravity( launchLatitudeRadians, surfaceAltitude) return [ pressure, density, speedOfSound, verticalGravity, northwardGravity, viscosity, thermalConductivity, temperature, dynamicPressure, stagnationPressure, stagnationTemperature ]
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import numpy as np import matplotlib.pyplot as plt from ambiance import Atmosphere # Make an atmosphere object heights = np.linspace(-5e3, 80e3, num=1000) atmosphere = Atmosphere(heights) # Make plot plt.plot(atmosphere.temperature_in_celsius, heights / 1000) plt.ylabel('Height [km]') plt.xlabel('Temperature [°C]') plt.grid() plt.show()
def generate_su2_cfd_config(cpacs_path, cpacs_out_path, wkdir): """Function to create SU2 confif file. Function 'generate_su2_cfd_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 cpacs = CPACS(cpacs_path) # Get SU2 mesh path su2_mesh_path = get_value(cpacs.tixi, SU2MESH_XPATH) # Get SU2 settings max_iter_xpath = SU2_XPATH + "/settings/maxIter" max_iter = get_value_or_default(cpacs.tixi, max_iter_xpath, 200) cfl_nb_xpath = SU2_XPATH + "/settings/cflNumber" cfl_nb = get_value_or_default(cpacs.tixi, cfl_nb_xpath, 1.0) mg_level_xpath = SU2_XPATH + "/settings/multigridLevel" mg_level = get_value_or_default(cpacs.tixi, mg_level_xpath, 3) # Mesh Marker bc_wall_xpath = SU2_XPATH + "/boundaryConditions/wall" bc_farfield_xpath = SU2_XPATH + "/boundaryConditions/farfield" bc_wall_list, engine_bc_list = get_mesh_marker(su2_mesh_path) create_branch(cpacs.tixi, bc_wall_xpath) bc_wall_str = ";".join(bc_wall_list) cpacs.tixi.updateTextElement(bc_wall_xpath, bc_wall_str) create_branch(cpacs.tixi, bc_farfield_xpath) bc_farfiled_str = ";".join(engine_bc_list) cpacs.tixi.updateTextElement(bc_farfield_xpath, bc_farfiled_str) # Fixed CL parameters fixed_cl_xpath = SU2_XPATH + "/fixedCL" fixed_cl = get_value_or_default(cpacs.tixi, fixed_cl_xpath, "NO") target_cl_xpath = SU2_XPATH + "/targetCL" target_cl = get_value_or_default(cpacs.tixi, target_cl_xpath, 1.0) if fixed_cl == "NO": active_aeroMap_xpath = SU2_XPATH + "/aeroMapUID" aeromap_uid = get_value(cpacs.tixi, active_aeroMap_xpath) log.info( f'Configuration file for "{aeromap_uid}" calculation will be created.' ) active_aeromap = cpacs.get_aeromap_by_uid(aeromap_uid) # Get parameters of the aeroMap (altitude, machNumber, angleOfAttack, angleOfSideslip) alt_list = active_aeromap.get("altitude").tolist() mach_list = active_aeromap.get("machNumber").tolist() aoa_list = active_aeromap.get("angleOfAttack").tolist() aos_list = active_aeromap.get("angleOfSideslip").tolist() param_count = len(alt_list) else: # if fixed_cl == 'YES': log.info( "Configuration file for fixed CL calculation will be created.") # Parameters fixed CL calulation param_count = 1 # Create a new aeroMap fix_cl_aeromap = cpacs.create_aeromap("aeroMap_fixedCL_SU2") fix_cl_aeromap.description = "AeroMap created for SU2 fixed CL value of: " + str( target_cl) # Get cruise mach and altitude cruise_mach_xpath = RANGE_XPATH + "/cruiseMach" mach = get_value_or_default(cpacs.tixi, cruise_mach_xpath, 0.78) cruise_alt_xpath = RANGE_XPATH + "/cruiseAltitude" alt = get_value_or_default(cpacs.tixi, cruise_alt_xpath, 12000) # Add new parameters to the aeroMap and save it fix_cl_aeromap.add_row(alt=alt, mach=mach, aos=0.0, aoa=0.0) fix_cl_aeromap.save() # Parameter lists alt_list = [alt] mach_list = [mach] aoa_list = [0.0] aos_list = [0.0] # Get and modify the default configuration file cfg = ConfigFile(DEFAULT_CONFIG_PATH) # General parmeters cfg["REF_LENGTH"] = cpacs.aircraft.ref_lenght cfg["REF_AREA"] = cpacs.aircraft.ref_area cfg["REF_ORIGIN_MOMENT_X"] = cpacs.aircraft.ref_point_x cfg["REF_ORIGIN_MOMENT_Y"] = cpacs.aircraft.ref_point_y cfg["REF_ORIGIN_MOMENT_Z"] = cpacs.aircraft.ref_point_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, " + ",".join(engine_bc_list) + ")" 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 = Atmosphere(alt) cfg["MACH_NUMBER"] = mach cfg["AOA"] = aoa cfg["SIDESLIP_ANGLE"] = aos cfg["FREESTREAM_PRESSURE"] = Atm.pressure[0] cfg["FREESTREAM_TEMPERATURE"] = Atm.temperature[0] 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) cfg.write_file(config_output_path, overwrite=True) # Damping derivatives damping_der_xpath = SU2_XPATH + "/options/clalculateDampingDerivatives" damping_der = get_value_or_default(cpacs.tixi, damping_der_xpath, False) if damping_der: rotation_rate_xpath = SU2_XPATH + "/options/rotationRate" rotation_rate = get_value_or_default(cpacs.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) cfg.write_file(config_output_path, overwrite=True) 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) cfg.write_file(config_output_path, overwrite=True) 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) cfg.write_file(config_output_path, overwrite=True) log.info("Damping derivatives cases directory has been created.") # Control surfaces deflections control_surf_xpath = SU2_XPATH + "/options/clalculateCotrolSurfacesDeflections" control_surf = get_value_or_default(cpacs.tixi, control_surf_xpath, False) if control_surf: # Get deformed mesh list su2_def_mesh_xpath = SU2_XPATH + "/availableDeformedMesh" if cpacs.tixi.checkElement(su2_def_mesh_xpath): su2_def_mesh_list = get_string_vector(cpacs.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) cfg.write_file(config_output_path, overwrite=True) # TODO: change that, but if it is save in tooloutput it will be erease by results... cpacs.save_cpacs(cpacs_out_path, overwrite=True)