def func(time_switch): # predict the rest part of the passage heat load T = m.planet.T #fixed temperature t_cf =closed_form(args,m,position,T,aoa=m.aerodynamics.aoa,online=True)[0] # closed-form solution only for length of t mask = (t_cf < time_switch_1) | (t_cf > time_switch) aoa_list = m.aerodynamics.aoa*mask aoa_list = aoa_list.tolist() t_cf, h_cf, gamma_cf, v_cf =closed_form(args,m,position,T,aoa_profile=aoa_list,online=True) # closed form solution with the real aoa (this is real only if control mode 2, if control mode 3, angle of attack taken as pi/2 instead of the correct one) RT = T*m.planet.R S = (v_cf/(2*RT)**0.5) index_tilltsw = (t_cf > t) & (t_cf <= time_switch) #[index for index in range(len(t_cf)) if (t_cf[index]<=time_switch_2 and t_cf[index]>t)] index_remaining = t_cf > time_switch # [index for index in range(len(t_cf)) if (t_cf[index]>time_switch_2)] t_tilltsw = t_cf * index_tilltsw t_tilltsw = np.trim_zeros(t_tilltsw) t_remaining = t_cf * index_remaining t_remaining = np.trim_zeros(t_remaining) if len(t_tilltsw)+len(t_remaining)==0: return Q_past rho = dm(h=h_cf, p=m.planet)[0] rho_tilltsw = rho[index_tilltsw] rho_remaining = rho[index_remaining] aoa_cf = [0]*len(t_tilltsw) S_tilltsw = S[index_tilltsw] heat_rate_tilltsw = heat_rate_calc(args.multiplicative_factor_heatload * m.aerodynamics.thermal_accomodation_factor , rho_tilltsw , T , T , m.planet.R , m.planet.gamma , S_tilltsw , aoa_cf) if len(t_tilltsw)>1: Q_rate_tilltsw=sum(heat_rate_tilltsw)*(t_tilltsw[-1]-t_tilltsw[0])/len(t_tilltsw) else: Q_rate_tilltsw = 0 S_remaining = S[index_remaining] aoa_cf = [m.aerodynamics.aoa] * len(t_remaining) heat_rate_remaining = heat_rate_calc(args.multiplicative_factor_heatload * m.aerodynamics.thermal_accomodation_factor , rho_remaining , T , T , m.planet.R , m.planet.gamma , S_remaining , aoa_cf) if args.control_mode == 3: # Account for max heat rate possible index_hr = heat_rate_remaining > args.max_heat_rate index_hr_not = heat_rate_remaining <= args.max_heat_rate temp = args.max_heat_rate*index_hr heat_rate_remaining= heat_rate_remaining*index_hr_not+temp heat_rate_remaining = heat_rate_remaining.tolist() if len(t_remaining) > 1: Q_rate_remaining = sum(heat_rate_remaining) * (t_remaining[-1] - t_remaining[0]) / len(t_remaining) else: Q_rate_remaining = 0 Q = Q_past+Q_rate_remaining+Q_rate_tilltsw return (Q-m.aerodynamics.heat_load_limit)
def switch_calculation(ip, m,position,args,t,heat_rate_control,reevaluation_mode,current_position = 0): from physical_models.Aerodynamic_models import aerodynamicscoefficient_fM as am import scipy from control.Control import heat_rate_calc from control.heatload_control.utils_timeswitch import lambdas from control.heatload_control.utils_timeswitch import aoa from control.heatload_control.utils_timeswitch import func from utils.closed_form_solution import closed_form import math from physical_models.Density_models import density_exp as dm import config import numpy as np global t_cf, h_cf, gamma_cf, v_cf # Evaluate initial conditions T = m.planet.T # fixed temperature t_cf, h_cf, gamma_cf, v_cf = closed_form(args, m, position, T, aoa=m.aerodynamics.aoa, online=True) # define closed-form solution RT = T * m.planet.R S = (v_cf / (2 * RT) ** 0.5) CL_90, CD_90 = am(np.pi / 2, m.body, T, S[0], m.aerodynamics, montecarlo=0) # Cl and Cd for all the body perpendicular CL_0, CD_0 = am(0, m.body, T, S[0], m.aerodynamics, montecarlo=0) # Cl and Cd for all the body perpendicular CD_slope = (CD_90 - CD_0) / (math.pi * 0.5) coeff = [CD_slope,CL_0, CD_0] # Evaluates max Q aoa_cf = aoa(m,0.1, t_cf , h_cf , gamma_cf , v_cf,coeff)[0] approx_sol = [t_cf , h_cf , gamma_cf , v_cf] delta_Q_max = func(0.1, m, args, coeff, position, heat_rate_control, approx_sol, aoa_cf) delta_Q_min = func(0.0, m, args, coeff, position, heat_rate_control, approx_sol, np.array([0.0]*len(aoa_cf))) if delta_Q_max*delta_Q_min <0.0: k_cf = optimize.brentq(func ,0.0 , 0.1,xtol=1e-7, args =(m,args, coeff,position,heat_rate_control,approx_sol,aoa_cf)) #,xtol=1e-6, elif delta_Q_max < 0.0: return [0.0,0.0] elif delta_Q_min > 0: return [0.0, t_cf[-1]/2]#t_cf[-1]-100] [t_cf,v_cf,gamma_cf,h_cf] = func(k_cf,m,args,coeff, position, heat_rate_control,approx_sol, aoa_cf, approx_calc=True) lambda_switch, lambdav = lambdas(m,aoa_cf, k_cf, t_cf , h_cf , gamma_cf , v_cf,coeff)[0:2] index_array = (lambdav < lambda_switch) temp = t_cf*index_array temp = np.trim_zeros(temp) t_switch = [temp[0],temp[-1]] if abs(t_switch[-1] - t_cf[-1])<5: t_switch[0] -= t_cf[-1]*0.04 elif abs(t_switch[-1] - t_cf[-1])<60: t_switch[0] -= 5 t_switch[1] -= t_switch[1]*0.1 return t_switch
def security_mode(ip, m, position, args, t, heat_rate_control=False): from physical_models.Aerodynamic_models import aerodynamicscoefficient_fM as am import scipy import config from control.Control import heat_rate_calc from utils.closed_form_solution import closed_form import math from physical_models.Density_models import density_exp as dm T = m.planet.T #fixed temperature t_cf, h_cf, gamma_cf, v_cf = closed_form( args, m, position, T, aoa=m.aerodynamics.aoa, online=True) # define closed-form solution RT = T * m.planet.R S = (v_cf / (2 * RT)**0.5) rho = dm(h=h_cf, p=m.planet)[0] # density calculated through exponential density # Security Mode aoa_cf_min = [0] * len(t_cf) heat_rate_min = heat_rate_calc( args.multiplicative_factor_heatload * m.aerodynamics.thermal_accomodation_factor, rho, T, T, m.planet.R, m.planet.gamma, S, aoa_cf_min) index_future = t_cf > t heat_rate_min = heat_rate_min * index_future traj_rate = (t_cf[1] - t_cf[0]) # print(t,config.heat_load_past,(sum(heat_rate_min.tolist()) * traj_rate)+config.heat_load_past) if (sum(heat_rate_min.tolist()) * traj_rate ) + config.heat_load_past > m.aerodynamics.heat_load_limit: # print('here') config.security_mode = True # exit() return [ 0, t_cf[-1] + 10000.0 ] # switch angle of attack to 0 for the rest # security made on the check return [config.time_switch_1, config.time_switch_2]
def aerobraking(ip, m, args): initial_state = m.initialcondition FinalState = True continue_campaign = True numberofpassage = 0 # Initialization cnf.count_numberofpassage = 0 clean_results() # Initialize Solution Results cnf.time_OP = 0 cnf.time_IP = 0 # Aerobraking Campaign while continue_campaign and (FinalState): cnf.index_Mars_Gram_call = 0 cnf.firing_orbit = 0 numberofpassage = 1 + numberofpassage if args.print_res: print("--> START PASSAGE #{}".format(numberofpassage)) t = time.time() if args.Odyssey_sim: args = Odyssey_firing_plan(numberofpassage, args) if ip.tc == 1: # calculate how long before the apoapsis the maneuver should start if args.delta_v != 0.0: if ip.tc == 1: initial_state = propulsion_ic_calcs(m, args, initial_state) elif ip.tc == 2: if round(math.degrees(args.phi)) == 180: print("DECELERATE DRAG FIRING!!") elif round(math.degrees(args.phi)) == 0: print("ACCELERATE DRAG FIRING!") if numberofpassage != 1: # Orbital Elements Result initial_state.a = cnf.solution.orientation.oe[0][-1] initial_state.e = cnf.solution.orientation.oe[1][-1] initial_state.i = cnf.solution.orientation.oe[2][-1] initial_state.OMEGA = cnf.solution.orientation.oe[3][-1] initial_state.omega = cnf.solution.orientation.oe[4][-1] initial_state.m = cnf.solution.performance.mass[-1] initial_state.vi = cnf.solution.orientation.oe[5][-1] m.initialcondition.year = int(cnf.solution.orientation.year[-1]) m.initialcondition.month = int(cnf.solution.orientation.month[-1]) m.initialcondition.day = int(cnf.solution.orientation.day[-1]) m.initialcondition.hour = int(cnf.solution.orientation.hour[-1]) m.initialcondition.min = int(cnf.solution.orientation.min[-1]) m.initialcondition.second = int( cnf.solution.orientation.second[-1]) if (args.drag_passage or args.body_shape == 'Blunted Cone') and continue_campaign: r = m.planet.Rp_e + args.EI * 10**3 initial_state.vi = -math.acos( 1 / initial_state.e * (initial_state.a * (1 - initial_state.e**2) / r - 1)) # Run Simulation continue_campaign = asim(ip, m, initial_state, numberofpassage, args) r_a = cnf.solution.orientation.oe[0][-1] * ( 1 + cnf.solution.orientation.oe[1][-1]) r_p = cnf.solution.orientation.oe[0][-1] * ( 1 - cnf.solution.orientation.oe[1][-1]) elapsed = time.time() - t if args.print_res: print('Computational Time {}s'.format(elapsed)) print("--> PASSAGE #{} COMPLETE".format(numberofpassage)) if args.number_of_orbits == numberofpassage: continue_campaign = False if r_a <= args.final_apoapsis: FinalState = False print('REACHED FINALSTATE! R_a = ', r_a * 1e-3, 'km') print('Thermal Limit overcomed totally', cnf.count_overcome_hr, 'times!') if r_p - m.planet.Rp_e >= 180 * 1e3: FinalState = False print('PERIAPSIS TOO HIGH, FINAL STATE UNREACHABLE! R_a = ', r_p * 1e-3, 'km') print(' ') closed_form(args, m)
def asim(ip, m, time_0, OE, args, k_cf, heat_rate_control, time_switch_2=0, reevaluation_mode=1, time_switch_eval=False): # from physical_models.Gravity_models import gravity_invsquaredandJ2effect as gm if ip.gm == 0: from physical_models.Gravity_models import gravity_const as gm elif ip.gm == 1: from physical_models.Gravity_models import gravity_invsquared as gm elif ip.gm == 2: from physical_models.Gravity_models import gravity_invsquaredandJ2effect as gm # Aerodynamic Model from physical_models.Aerodynamic_models import aerodynamicscoefficient_fM as am # Thermal Model from physical_models.Thermal_models import heatrate_convective_maxwellian as hr_c version = args.MarsGram_version [r0, v0] = orbitalelemtorv(OE, m.planet) if config.count_numberofpassage != 1: t_prev = config.solution.orientation.time[-1] else: t_prev = m.initialcondition.time_rot v0_pp = r_intor_p(r0, v0, m.planet, time_0, t_prev)[1] date_initial = datetime(year=m.initialcondition.year, month=m.initialcondition.month, day=m.initialcondition.day, hour=m.initialcondition.hour, minute=m.initialcondition.min, second=m.initialcondition.second) T = m.planet.T # fixed temperature RT = T * m.planet.R S = (np.linalg.norm(v0_pp) / (2 * RT)**0.5) CL_90, CD_90 = am(np.pi / 2, m.body, T, S, m.aerodynamics, montecarlo=0) # Cl and Cd for all the body perpendicular CL_0, CD_0 = am(0, m.body, T, S, m.aerodynamics, montecarlo=0) # Cl and Cd for all the body perpendicular CD_slope = (CD_90 - CD_0) / (math.pi * 0.5) def f(t0, in_cond, m): # Clock time_real = date_initial + timedelta(seconds=t0) timereal = clock(time_real.year, time_real.month, time_real.day, time_real.hour, time_real.minute, time_real.second) # Assign states pos_ii = in_cond[0:3] # Inertial position pos_ii += 0. vel_ii = in_cond[3:6] # Inertial velocity vel_ii += 0. mass = m.body.Mass # Mass, kg pos_ii_mag = np.linalg.norm(pos_ii) # Inertial position magnitude vel_ii_mag = np.linalg.norm(vel_ii) # Inertial velocity magnitude lambdav_ii = in_cond[6] lambdagamma_ii = in_cond[7] lambdah_ii = in_cond[8] # Assign parameters omega_planet = m.planet.omega gamma = m.planet.gamma area_tot = m.body.Area_tot # TRANSFORM THE STATE # Inertial to planet relative transformation [pos_pp, vel_pp] = r_intor_p( pos_ii, vel_ii, m.planet, t0, t_prev ) # Position vector planet / planet[m] and Velocity vector planet / planet[m / s] pos_pp_mag = np.linalg.norm( pos_pp) # m, magnitude of position vector in PCPF vel_pp_mag = np.linalg.norm(vel_pp) # Orbital Elements OE = rvtoorbitalelement(pos_ii, vel_ii, mass, m.planet) # Angular Momentum Calculations h_ii = np.cross(pos_ii, vel_ii) # Inertial angular momentum vector[m ^ 2 / s] index = 0 for item in h_ii: if item == -0: h_ii[index] = 0 index = index + 1 h_ii_mag = np.linalg.norm( h_ii) # Magnitude of inertial angular momentum vector[m ^ 2 / s] h_pp = np.cross(pos_pp, vel_pp) index = 0 for item in h_pp: if item == -0: h_pp[index] = 0 index = index + 1 h_pp_mag = np.linalg.norm(h_pp) h_pp_hat = h_pp / h_pp_mag # Inertial flight path angle arg = np.median([-1, 1, h_ii_mag / (pos_ii_mag * vel_ii_mag) ]) # limit to[-1, 1] gamma_ii = math.acos(arg) if np.inner(pos_ii, vel_ii) < 0: gamma_ii = -gamma_ii # Relative flight path angle arg = np.median([-1, 1, h_pp_mag / (pos_pp_mag * vel_pp_mag) ]) # limit to[-1, 1] gamma_pp = math.acos(arg) if np.inner(pos_pp, vel_pp) < 0: gamma_pp = -gamma_pp # Derived Quantity Calculations # Compute latitude and longitude LatLong = rtolatlong(pos_pp, m.planet) lat = LatLong[1] lon = LatLong[2] alt = LatLong[0] # Compute NED basis unit vectors uDuNuE = latlongtoNED(LatLong) # nd uD = uDuNuE[0] uE = uDuNuE[2] uN = uDuNuE[1] # Get density, pressure, temperature and winds rho, T_p, wind = dm(h=alt, p=m.planet, OE=OE, lat=lat, lon=lon, timereal=timereal, t0=t0, tf_prev=t_prev, montecarlo=0, Wind=True, args=args, version=version) # Mach number sound_velocity = (gamma * m.planet.R * T_p)**0.5 Mach = vel_pp_mag / sound_velocity S = ((gamma * 0.5)**0.5) * Mach # molecular speed ratio # CD = am(aoa=temp, body=m.body, T=T_p, S=S, args=args, montecarlo=0)[1] # for the lambda_switch calculation, considering prev angle (!Approx!) # CD_90 = am(aoa=np.pi/2, body=m.body, T=T_p, S=S, args=args, montecarlo=0)[1] # Cl and Cd for all the body perpendicular # CD_0 = am(aoa=0, body=m.body, T=T_p, S=S, args=args, montecarlo=0)[1] # Cl and Cd for all the body perpendicular # CD_slope = (CD_90-CD_0)/(math.pi/2) if time_switch_eval == True: lambda_switch = np.divide(k_cf * 2.0 * m.body.Mass * vel_ii_mag, area_tot * CD_slope * np.pi) if args.heat_load_sol == 0: if lambdav_ii < lambda_switch: #correct aoa = 0.0001 else: aoa = m.aerodynamics.aoa elif args.heat_load_sol == 1: if lambdav_ii < lambda_switch: aoa = m.aerodynamics.aoa else: aoa = 0.0001 else: if (args.heat_load_sol == 0 or args.heat_load_sol == 3): if t0 >= config.time_switch_1 and t0 <= time_switch_2: #correct aoa = 0.0001 else: aoa = m.aerodynamics.aoa elif args.heat_load_sol == 1 or args.heat_load_sol == 2: if t0 >= config.time_switch_1 and t0 <= time_switch_2: aoa = m.aerodynamics.aoa else: aoa = 0.0001 # Heat Rate heat_rate = hr_c(S, T_p, m, rho, vel_pp_mag, aoa) ## Add the control for the heat rate if flash == 3 if heat_rate_control == True and heat_rate > args.max_heat_rate: from control.Control import control_solarpanels_heatrate state = [T_p, rho, S] index_ratio = [1] aoa = control_solarpanels_heatrate(ip, m, index_ratio, state) heat_rate = args.max_heat_rate # print('heat rate', heat_rate,'heat load', in_cond[-1]) # print('heat load', in_cond[-1]) # print('heat rate',heat_rate) # Convert wind to pp(PCPF) frame wE = wind[0] # positive to the east , m / s wN = wind[1] # positive to the north , m / s wU = wind[2] # positive up , m / s wind_pp = wN * uN + wE * uE - wU * uD # wind velocity in pp frame , m / s vel_pp_rw = vel_pp + wind_pp # relative wind vector , m / s vel_pp_rw_hat = vel_pp_rw / np.linalg.norm( vel_pp_rw) # relative wind unit vector , nd # Dynamic pressure, CHANGE THE VELOCITY WITH THE WIND VELOCITY q = 0.5 * rho * np.linalg.norm( vel_pp_rw)**2 # base on wind - relative velocity ## Rotation Calculation rot_angle = np.linalg.norm(omega_planet) * t0 # rad L_PI = [[math.cos(rot_angle), math.sin(rot_angle), 0.0], [-math.sin(rot_angle), math.cos(rot_angle), 0.0], [0.0, 0.0, 1.0]] L_PI = [[+0. if x == -0 else x for x in row] for row in L_PI] g_ii = gm(pos_ii_mag, pos_ii, p=m.planet, mass=mass, vel_ii=vel_ii) gravity_ii = mass * g_ii bank_angle = 0.0 lift_pp_hat = np.cross( h_pp_hat, vel_pp_rw_hat ) #perpendicular vector to angular vector and velocity # Vehicle Aerodynamic Forces # CL and CD [CL, CD] = am(aoa=aoa, body=m.body, T=T_p, S=S, args=args, montecarlo=0) # Force calculations drag_pp_hat = -vel_pp_rw_hat # Planet relative drag force direction drag_pp = q * CD * area_tot * drag_pp_hat # Planet relative drag force vector lift_pp = q * CL * area_tot * lift_pp_hat * math.cos( bank_angle) # Planet relative lift force vector drag_ii = np.inner(np.transpose(L_PI), drag_pp) # Inertial drag force vector lift_ii = np.inner(np.transpose(L_PI), lift_pp) # Inertial lift force vector # Total Force # Total inertial external force vector on body [N] force_ii = drag_ii + lift_ii + gravity_ii # g_ii = np.divide(m.planet.g_ref * m.planet.Rp_e ** 2, np.square(pos_ii_mag)) g_ii = np.linalg.norm(g_ii) # EOM # CD = CD_0+aoa*CD_slope lambdav_dot = -3 * k_cf * rho * vel_ii_mag ** 2 * aoa/ math.pi + lambdav_ii * ( rho* area_tot * CD* vel_ii_mag) / mass - \ lambdagamma_ii * ((rho * area_tot * CL) / (2 * mass) + g_ii / vel_ii_mag** 2 + 1 / ( pos_ii_mag)) - lambdah_ii * gamma_ii lambdag_dot = lambdav_ii * g_ii - lambdah_ii * vel_ii_mag lambdah_dot = k_cf * rho * vel_ii_mag** 3 * aoa/ (math.pi * m.planet.H) - lambdav_ii * ( (rho * area_tot *CD * vel_ii_mag ** 2) / (2 * mass * m.planet.H) + 2 * g_ii * gamma_ii/ (pos_ii_mag)) \ + lambdagamma_ii * (rho * area_tot * CL * vel_ii_mag / (2 * mass * m.planet.H) - 2 * g_ii / ( (pos_ii_mag) * vel_ii_mag) + vel_ii_mag / (pos_ii_mag) ** 2) ydot = np.zeros(10) ydot[0:3] = vel_ii ydot[3:6] = force_ii / mass ydot[ 6] = lambdav_dot #-3*k_cf*rho*vel_ii_mag**2*aoa/math.pi + lambdav_ii* (rho * area_tot * CD *vel_ii_mag/ mass)-lambdagamma_ii* (rho * area_tot * CL/(2*mass) +g_ii/vel_ii_mag**2+1/pos_ii_mag)-lambdah_ii*gamma_ii ydot[7] = lambdag_dot #lambdav_ii*g_ii-lambdah_ii*vel_ii_mag ydot[ 8] = lambdah_dot #k_cf*rho*vel_ii_mag**3*aoa/(math.pi*m.planet.H)- \ #lambdav_ii* (rho * area_tot * CD *vel_ii_mag**2/ (2*mass*m.planet.H) + 2*g_ii*gamma_ii/pos_ii_mag)+\ #lambdagamma_ii*(rho*area_tot * CL*vel_ii_mag/(2*mass*m.planet.H)-2*g_ii/(pos_ii_mag*vel_ii_mag)+vel_ii_mag/(pos_ii_mag)**2) ydot[9] = heat_rate return ydot def out_drag_passage(t, y): return ((y[0]**2 + y[1]**2 + y[2]**2)**0.5 - m.planet.Rp_e - args.AE * 10**3) out_drag_passage.terminal = True out_drag_passage.direction = 1 def time_switch_fun(t, y): # time_real = date_initial + timedelta(seconds=t) # timereal = clock(time_real.year, time_real.month, time_real.day, time_real.hour, time_real.minute, time_real.second) # pos_ii = y[0:3] vel_ii = y[3:6] # Inertial velocity vel_ii_mag = np.linalg.norm(vel_ii) # Inertial velocity magnitude # [pos_pp,vel_pp] = r_intor_p(pos_ii, vel_ii, m.planet, t) # LatLong = rtolatlong(pos_pp, m.planet) # lat = LatLong[1] # lon = LatLong[2] # alt = LatLong[0] # rho,T_p,wind = dm(h=alt, p=m.planet, OE=OE, lat=lat, lon=lon, timereal=timereal, t0=t, montecarlo=0,Wind=True, args=args, version = version) # Mach number # sound_velocity = (m.planet.gamma * m.planet.R * T_p) ** 0.5 # Mach = np.linalg.norm(vel_pp) / sound_velocity # S = ((m.planet.gamma*0.5) ** 0.5) * Mach # molecular speed ratio # CD_90 = am(aoa=np.pi/2, body=m.body, T=T_p, S=S, args=args, montecarlo=0)[1] # Cl and Cd for all the body perpendicular # CD_0 = am(aoa=0, body=m.body, T=T_p, S=S, args=args, montecarlo=0)[1] # Cl and Cd for all the body perpendicular # CD_slope = (CD_90-CD_0)/(math.pi/2) lambda_switch = np.divide(k_cf * 2.0 * m.body.Mass * vel_ii_mag, m.body.Area_tot * CD_slope * np.pi) return (lambda_switch - y[6]) time_switch_fun.terminal = False if time_switch_eval == True: # Density # from physical_models.Density_models import density_exp as dm if args.density_model == 'Exponential': from physical_models.Density_models import density_exp as dm elif args.density_model == 'MARSGram': from physical_models.Density_models import marsgram as dm # SOLVE EQUATIONS OF MOTIONS - 1 steps # USE CLOSED FORM SOLUTION TO DEFINE lambda_zero: T = m.planet.T #fixed temperature t_cf, h_cf, gamma_cf, v_cf = closed_form( args, m, OE, T, aoa=m.aerodynamics.aoa, online=True) # define closed-form solution # # RT = T * m.planet.R # S = (v_cf / (2 * RT) ** 0.5) # CL_90, CD_90 = am(np.pi / 2, m.body, T, S[0], m.aerodynamics, # montecarlo=0) # Cl and Cd for all the body perpendicular # CL_0, CD_0 = am(0, m.body, T, S[0], m.aerodynamics, montecarlo=0) # Cl and Cd for all the body perpendicular # CD_slope = (CD_90 - CD_0) / (math.pi * 0.5) # # coeff = [CD_slope,CL_0, CD_0] # approx_sol = [t_cf, h_cf, gamma_cf, v_cf] # aoa_cf = aoa(m,k_cf, t_cf , h_cf , gamma_cf , v_cf,coeff)[0] # incond_lambda = func(k_cf, m, args, coeff, OE, heat_rate_control, approx_sol, aoa_cf, initial_guess=True) lambdav = v_cf[-1] #incond_lambda[0]#v_cf[-1] lambdag = 0.0 #incond_lambda[1]#0.0 lambdah = m.planet.mu / ( m.planet.Rp_e + h_cf[-1] )**2 #incond_lambda[2]#m.planet.mu / (m.planet.Rp_e + h_cf[-1]) ** 2 lambda_v_fin = 10000 lambda_h_fin = 10000 lambda_gamma_fin = 10000 lambda_v_fin_actual = 0 lambda_gamma_fin_actual = 0 lambda_h_fin_actual = 0 count = 0 while abs(lambda_v_fin_actual - lambda_v_fin) > 0.1 or abs( lambda_gamma_fin_actual - lambda_gamma_fin) > 0.1 or abs(lambda_h_fin_actual - lambda_h_fin) > 0.01: count += 1 in_cond = [ r0[0], r0[1], r0[2], v0[0], v0[1], v0[2], lambdav, lambdag, lambdah, 0 ] # Run Simulation eomfunction = lambda t, in_cond: f(t, in_cond, m) solution = solve_ivp(eomfunction, t_span=(time_0, time_0 + 1500), y0=in_cond, max_step=5, method='RK45', dense_output=True, events=[out_drag_passage]) r_fin = (solution.y[0, -1]**2 + solution.y[1, -1]**2 + solution.y[2, -1]**2)**0.5 v_fin = (solution.y[3, -1]**2 + solution.y[4, -1]**2 + solution.y[5, -1]**2)**0.5 Q_fin = solution.y[-1, -1] lambda_v_fin = v_fin lambda_gamma_fin = 0.0 lambda_h_fin = m.planet.mu / (r_fin)**2 lambda_v_fin_actual = solution.y[6, -1] lambda_gamma_fin_actual = solution.y[7, -1] lambda_h_fin_actual = solution.y[8, -1] in_cond = [ solution.y[0, -1], solution.y[1, -1], solution.y[2, -1], solution.y[3, -1], solution.y[4, -1], solution.y[5, -1], lambda_v_fin, lambda_gamma_fin, lambda_h_fin, Q_fin ] if (abs(lambda_v_fin_actual - lambda_v_fin) < 0.1 and abs(lambda_gamma_fin_actual - lambda_gamma_fin) < 0.1 and abs(lambda_h_fin_actual - lambda_h_fin) < 0.01 ) or count > 4: break solution = solve_ivp(eomfunction, t_span=(solution.t_events[0], -10), y0=in_cond, max_step=5, method='RK45', dense_output=True, events=[out_drag_passage]) # import matplotlib.pyplot as plt # plt.plot(solution.t, solution.y[6]) # plt.show() lambdav = solution.y[6, -1] lambdag = solution.y[7, -1] lambdah = solution.y[8, -1] # print(abs(lambda_v_fin_actual - lambda_v_fin), abs(lambda_gamma_fin_actual - lambda_gamma_fin), # abs(lambda_h_fin_actual - lambda_h_fin)) # print('check',abs(lambda_v_fin_actual - lambda_v_fin) > 0.1 or abs(lambda_gamma_fin_actual - lambda_gamma_fin) > 0.1 or abs(lambda_h_fin_actual - lambda_h_fin) > 0.01) # print('check',abs(lambda_v_fin_actual - lambda_v_fin) > 0.1 and abs(lambda_gamma_fin_actual - lambda_gamma_fin) > 0.1 and abs(lambda_h_fin_actual - lambda_h_fin) > 0.01) # rerun the simulation with smaller step-size and the right lambda zero # Initial condition initialization in_cond = [ r0[0], r0[1], r0[2], v0[0], v0[1], v0[2], lambdav, lambdag, lambdah, 0 ] if args.density_model == 'Exponential': from physical_models.Density_models import density_exp as dm elif args.density_model == 'MARSGram': from physical_models.Density_models import marsgram as dm # from physical_models.Density_models import marsgram as dm eomfunction = lambda t, in_cond: f(t, in_cond, m) solution = solve_ivp(eomfunction, t_span=(time_0, time_0 + 1500), y0=in_cond, max_step=0.5, method='RK45', events=[out_drag_passage, time_switch_fun]) temp = solution.t_events[1] # print('intersections', temp) ## time switch definition time_switch = [0, 0] if len(temp) == 2: time_switch = temp # if abs(time_switch[1] - solution.t[-1]): # time_switch[0] -= 0.1 elif len(temp) == 1: time_switch[0] = temp time_switch[1] = solution.t[-1] else: # second time evaluation # Density from physical_models.Density_models import density_exp as dm1 if args.density_model == 'Exponential': from physical_models.Density_models import density_exp as dm elif args.density_model == 'MARSGram': from physical_models.Density_models import marsgram as dm # SOLVE EQUATIONS OF MOTIONS - 1 steps temp_0 = 0 tp = 1000 # Initial condition initialization in_cond = [ r0[0], r0[1], r0[2], v0[0], v0[1], v0[2], 0, 0, 0, config.heat_load_past ] if reevaluation_mode == 1: # bigger step for the first times revaluation is performed eomfunction = lambda t, in_cond: f(t, in_cond, m) solution = solve_ivp(eomfunction, t_span=(time_0, time_0 + 1000), y0=in_cond, max_step=1, method='RK23', dense_output=False, events=[out_drag_passage]) elif reevaluation_mode == 2: # stricter conditions for the last times revaluation is performed eomfunction = lambda t, in_cond: f(t, in_cond, m) solution = solve_ivp(eomfunction, t_span=(time_0, time_0 + 1000), y0=in_cond, max_step=1, method='RK23', dense_output=False, events=[out_drag_passage]) return solution.y return solution.y, time_switch
def func(k_cf, m, args, coeff, position, heat_rate_control, approx_sol, aoa_cf, initial_guess=False, approx_calc=False): t_cf, h_cf, gamma_cf, v_cf = approx_sol # global t_cf , h_cf , gamma_cf , v_cf # initialize heat load temp_Q = 1000 Q_prec = 0 count = 0 while temp_Q > 1e-3: # stop if two following trajectory evaluation provides the same Q # define angle of attack lagrangian multipliers T = m.planet.T # fixed temperature [aoa_cf, in_cond_lambda ] = aoa(m, k_cf, t_cf, h_cf, gamma_cf, v_cf, coeff, np.ndarray.tolist( aoa_cf)) # update angle of attack profile with new k t_cf, h_cf, gamma_cf, v_cf = closed_form( args, m, position, T, aoa=m.aerodynamics.aoa, online=True, aoa_profile=np.ndarray.tolist(aoa_cf) ) # re-evaluate the closed form solution using previous angle of attack profile a = (m.planet.gamma * m.planet.R * T)**0.5 M = v_cf / a S = (m.planet.gamma * 0.5)**0.5 * M rho = dm( h=h_cf, p=m.planet)[0] # density calculated through exponential density heat_rate = heat_rate_calc( args.multiplicative_factor_heatload * m.aerodynamics.thermal_accomodation_factor, rho, T, T, m.planet.R, m.planet.gamma, S, aoa_cf ) # (list(map(heat_rate_calc, m.aerodynamics.thermal_accomodation_factor,rho,T,T,m.planet.R,m.planet.gamma, S, aoa_cf))) if heat_rate_control == True: # Account for max heat rate possible index_hr = heat_rate > args.max_heat_rate heat_rate[index_hr] = args.max_heat_rate #heat_rate[0:len(config.heat_rate_list)] = config.heat_rate_list Q = sum(heat_rate) * t_cf[-1] / len(t_cf) # update error temp_Q = Q - Q_prec # print('temp_Q', temp_Q, 'Q_prec', Q_prec,'Q',Q, 'count', count) Q_prec = Q count += 1 if initial_guess: return in_cond_lambda elif approx_calc: return t_cf, v_cf, gamma_cf, h_cf delta_Q = (Q - m.aerodynamics.heat_load_limit) # print(delta_Q) return delta_Q