def initialise(self): self.h[0] = self.h_init self.V[0] = self.V_init self.gamma[0] = self.gamma_init self.g[0] = grav_sphere(self.g_0, self.R, self.h_init) self.solver_rho[0], self.solver_a[0], self.solver_p[0], \ self.solver_T[0], self.solver_mu[0] = \ interpolate_atmosphere(self, self.h_init) self.p_dyn[0] = fcl.p_dyn(rho=self.solver_rho[0], V=self.V[0]) self.Ma[0] = self.V[0] / self.solver_a[0] self.mfp[0] = fcl.mean_free_path(self.solver_T[0], self.solver_p[0], self.atmosphere.d) self.Kn[0] = self.mfp[0] / self.spacecraft.L self.Re[0] = fcl.Reynolds(self.solver_rho[0], self.V[0], self.spacecraft.L, self.solver_mu[0]) if self.console_output == True: print 'MODEL INITIALISED. INITIAL STEP COUNT: %i' % self.steps_storage return None
def simulate_dopri(self, dt=1E-2): """ Run trajectory calculations using explicit Runge-Kutta method of order 4(5) from Dormand & Prince """ # Set timestep for ODE solver self.dt = dt self.time_steps = np.cumsum(self.dt * np.ones(self.steps_storage)) # Create ODE object from SciPy using Dormand-Prince RK solver self.eq = integrate.ode(traj_3DOF_dt).set_integrator('dop853', nsteps=1E8, rtol=1E-10) # Set initial conditions y_init = [self.V_init, self.gamma_init, self.h_init, self.r[0]] self.eq.set_initial_value(y_init, t=self.time_steps[0]) # Generate counter index = 1 self.index = index # Initial conditions are: V, gamma, h, r. These are at index = 0 # Other parameters (like dynamic pressure and gravitational # attraction) are calculated for this step (also index = 0) # ODE solver then calculates V, gamma, h, and r at the next step (index = 1) # Then parameters and updated as above, and the loop continues. # So: # INIT: Define V, gamma, h, r @ start # Calculate parameters @ start # SOLVE: Find V, gamma, h, r # # Solve ODE system using conditional statement based on altitude while self.h[index-1] > 0: # Update ODE solver parameters from spacecraft object and # atmospheric model at each separate time step if self.spacecraft.aero_coeffs_type == 'CONSTANT': params = [self.R, self.g[index-1], self.spacecraft.ballistic_coeff, self.solver_rho[index-1], self.spacecraft.Cl, self.spacecraft.Cd] self.eq.set_f_params(params) elif self.spacecraft.aero_coeffs_type == 'VARIABLE': self.spacecraft.update_aero(self.index, self.Re[index-1], self.Ma[index-1], self.Kn[index-1]) params = [self.R, self.g[index-1], self.spacecraft.ballistic_coeff[index-1], self.solver_rho[index-1], self.spacecraft.Cl[index-1], self.spacecraft.Cd[index-1]] self.eq.set_f_params(params) # Solve ODE system (sol[V, gamma, h, r]) self.sol[index, :] = self.eq.integrate(self.time_steps[index]) # Unpack ODE solver results into storage structures self.V[index] = self.sol[index, 0] self.gamma[index] = self.sol[index, 1] self.h[index] = self.sol[index, 2] self.r[index] = self.sol[index, 3] # Interpolate for freestream density in atmosphere model # (this avoids a direct call to an atmosphere model, allowing more # flexibility when coding as different models have different interfaces) self.solver_rho[index], self.solver_a[index], \ self.solver_p[index], self.solver_T[index], \ self.solver_mu[index] = interpolate_atmosphere(self, self.h[index]) # Calculate gravitational acceleration at current altitude self.g[index] = grav_sphere(self.g_0, self.R, self.h[index]) # Calculate dynamic pressure iteration results self.p_dyn[index] = fcl.p_dyn(rho=params[3], V=self.sol[index, 0]) # Calculate Mach, Knudsen, and Reynolds numbers self.Ma[index] = self.V[index] / self.solver_a[index] self.mfp[index] = fcl.mean_free_path(self.solver_T[index], self.solver_p[index], self.atmosphere.d) self.Kn[index] = self.mfp[index] / self.spacecraft.L self.Re[index] = fcl.Reynolds(self.solver_rho[index], self.V[index], self.spacecraft.L, self.solver_mu[index]) # Save inputs for inspection self.solver_time[index] = self.eq.t self.y_input[index, :] = self.eq.y # Advance iteration counter index += 1 self.index = index # Check if solution storage array has reached maximum size if index == len(self.sol)-10: self.extend() #print index # Print solution progress to check for stability if self.console_output == True: if np.mod(index, self.steps_storage/100) == 0: print 'ITERATION: %i; ALTITUDE: %f km' % (index, self.h[index-1]/1000) # Subtract 1 from counter so that indexing is more convenient later on self.index -= 1 # Truncate solution arrays to remove trailing zeros self.truncate() # Perform final step calculations for p_dyn, g, etc. self.final_step_event() #self.final_step_assign() # Perform post solver calculations #self.post_calc() print 'TRAJECTORY COMPUTED (RK 4/5)' print '%i ITERATIONS, TIMESTEP = %f s, TOTAL TIME = %f s' % \ (self.index, self.dt, self.solver_time[self.index-1]) return [self.sol, self.h, self.y_input, self.p_dyn, self.Ma]