def check_initial_state(problem): # get initial guess x_state_0, x_control_0, dt = problem.unpack(problem.guess) # make sure at least 2d column vector x_state_0 = atleast_2d_col(x_state_0) x_control_0 = atleast_2d_col(x_control_0) # check numbers of states if not len(x_state_0): problem.Nstate = 0 else: problem.options.N = x_state_0.shape[0] problem.Nstate = x_state_0.shape[1] # check numbers of controls if not len(x_control_0): problem.Ncontrol = 0 else: problem.options.N = x_control_0.shape[0] problem.Ncontrol = x_control_0.shape[1] # variable final time? if not dt: problem.variable_final_time = False else: problem.variable_final_time = True # total number of unknowns problem.Nvars = problem.Ncontrol + problem.Nstate return
def compute_propulsion(self,propulsion_model,conditions,numerics): """ compute_propulsion() gets propulsion conditions Inputs - propulsion_model - a callable that will recieve ... conditions - passed directly to the propulsion model Outputs - results - a data dictionary with ... thrust_force - a 3-column array with rows of total thrust force vectors for each control point, in the body frame fuel_mass_rate - the total fuel mass flow rate for each control point thrust_power - the total propulsion power for each control point Assumptions - +X out nose +Y out starboard wing +Z down """ # for current propulsion models ## TODO: update propulsion modules N = self.numerics.n_control_points eta = conditions.propulsion.throttle[:,0] #state = Data() #state.q = conditions.freestream.dynamic_pressure[:,0] #state.g0 = conditions.freestream.gravity[:,0] #state.V = conditions.freestream.velocity[:,0] #state.M = conditions.freestream.mach_number[:,0] #state.T = conditions.freestream.temperature[:,0] #state.p = conditions.freestream.pressure[:,0] F, mdot, P = propulsion_model(eta, conditions) F_vec = np.zeros([N,3]) F_vec[:,0] = F[:] mdot = atleast_2d_col( mdot ) P = atleast_2d_col( P ) ## TODO --- ## call propulsion model #results = propulsion_model( conditions ) ## unpack results #F = results.thrust_force #mdot = atleast_2d_col( results.fuel_mass_rate ) #P = atleast_2d_col( results.thurst_power ) # pack conditions conditions.frames.body.thrust_force_vector[:,:] = F_vec[:,:] conditions.propulsion.fuel_mass_rate[:,0] = mdot[:,0] conditions.energies.propulsion_power[:,0] = P[:,0] return conditions
def initialize_differentials_dimensionless(segment, state): # unpack numerics = state.numerics N = numerics.number_control_points discretization_method = numerics.discretization_method # get operators x, D, I = discretization_method(N, **numerics) x = atleast_2d_col(x) # pack numerics.dimensionless.control_points = x numerics.dimensionless.differentiate = D numerics.dimensionless.integrate = I return
def initialize_differentials(self,numerics): """ Segment.initialize_differentials(numerics) initialize differentiation and integration operator matricies Inputs - numerics - Data dictionary with fields: dimensionless_time - empty 2D array differentiate_dimensionless - empty 2D array integrate_dimensionless - empty 2D array discretization_method - the method for calculating the above n_control_points - number of control points for operators Outputs: numerics - Data dictionary with fields: dimensionless_time - time control points, non-dimensional, in range [0,1], column vector differentiate_dimensionless - differention operation matrix integrate_dimensionless - integration operation matrix Assumptions: operators are in non-dimensional time, with bounds [0,1] will call numerics.discretization_method(n_control_points,**numerics) to get operators """ # unpack N = numerics.n_control_points discretization_method = numerics.discretization_method # get operators t,D,I = discretization_method(N,**numerics) t = atleast_2d_col(t) # pack numerics.dimensionless_time = t numerics.differentiate_dimensionless = D numerics.integrate_dimensionless = I return numerics
def compute_values(self,altitude,temperature_deviation = 0): """ Computes values from the International Standard Atmosphere Inputs: altitude : geometric altitude (elevation) (m) can be a float, list or 1D array of floats temperature_deviation : delta_isa Outputs: list of conditions - pressure : static pressure (Pa) temperature : static temperature (K) density : density (kg/m^3) speed_of_sound : speed of sound (m/s) dynamic_viscosity : dynamic_viscosity (kg/m-s) Example: atmosphere = SUAVE.Attributes.Atmospheres.Earth.USStandard1976() atmosphere.ComputeValues(1000).pressure """ # unpack zs = altitude gas = self.fluid_properties planet = self.planet grav = self.planet.sea_level_gravity Rad = self.planet.mean_radius gamma = gas.gas_specific_constant delta_isa = temperature_deviation # check properties if not gas == Air(): warn('US Standard Atmosphere not using Air fluid properties') if not planet == Earth(): warn('US Standard Atmosphere not using Earth planet properties') # convert input if necessary zs = atleast_2d_col(zs) # get model altitude bounds zmin = self.breaks.altitude[0] zmax = self.breaks.altitude[-1] # convert geometric to geopotential altitude zs = zs/(1 + zs/Rad) # check ranges if np.amin(zs) < zmin: print "Warning: altitude requested below minimum for this atmospheric model; returning values for h = -2.0 km" zs[zs < zmin] = zmin if np.amax(zs) > zmax: print "Warning: altitude requested above maximum for this atmospheric model; returning values for h = 86.0 km" zs[zs > zmax] = zmax # initialize return data zeros = np.zeros_like(zs) p = zeros * 0.0 T = zeros * 0.0 rho = zeros * 0.0 a = zeros * 0.0 mew = zeros * 0.0 z0 = zeros * 0.0 T0 = zeros * 0.0 p0 = zeros * 0.0 alpha = zeros * 0.0 # populate the altitude breaks # this uses >= and <= to capture both edges and because values should be the same at the edges for i in range( len(self.breaks.altitude)-1 ): i_inside = (zs >= self.breaks.altitude[i]) & (zs <= self.breaks.altitude[i+1]) z0[ i_inside ] = self.breaks.altitude[i] T0[ i_inside ] = self.breaks.temperature[i] p0[ i_inside ] = self.breaks.pressure[i] alpha[ i_inside ] = -(self.breaks.temperature[i+1] - self.breaks.temperature[i])/ \ (self.breaks.altitude[i+1] - self.breaks.altitude[i]) # interpolate the breaks dz = zs-z0 i_isoth = (alpha == 0.) i_adiab = (alpha != 0.) p[i_isoth] = p0[i_isoth] * np.exp(-1.*dz[i_isoth]*grav/(gamma*T0[i_isoth])) p[i_adiab] = p0[i_adiab] * ( (1.-alpha[i_adiab]*dz[i_adiab]/T0[i_adiab]) **(1.*grav/(alpha[i_adiab]*gamma)) ) T = T0 - dz*alpha + delta_isa rho = gas.compute_density(T,p) a = gas.compute_speed_of_sound(T) mew = gas.compute_absolute_viscosity(T) atmo_data = Conditions() atmo_data.expand_rows(zs.shape[0]) atmo_data.pressure = p atmo_data.temperature = T atmo_data.density = rho atmo_data.speed_of_sound = a atmo_data.dynamic_viscosity = mew return atmo_data
def compute_values(self, altitude, temperature=288.15): """Computes atmospheric values. Assumptions: Constant temperature atmosphere Source: U.S. Standard Atmosphere, 1976, U.S. Government Printing Office, Washington, D.C., 1976 Inputs: altitude [m] temperature [K] Outputs: atmo_data. pressure [Pa] temperature [K] speed_of_sound [m/s] dynamic_viscosity [kg/(m*s)] Properties Used: self. fluid_properties.gas_specific_constant [J/(kg*K)] planet.sea_level_gravity [m/s^2] planet.mean_radius [m] breaks. altitude [m] pressure [Pa] """ # unpack zs = altitude gas = self.fluid_properties planet = self.planet grav = self.planet.sea_level_gravity Rad = self.planet.mean_radius gamma = gas.gas_specific_constant # check properties if not gas == Air(): warn( 'Constant_Temperature Atmosphere not using Air fluid properties' ) if not planet == Earth(): warn( 'Constant_Temperature Atmosphere not using Earth planet properties' ) # convert input if necessary zs = atleast_2d_col(zs) # get model altitude bounds zmin = self.breaks.altitude[0] zmax = self.breaks.altitude[-1] # convert geometric to geopotential altitude zs = zs / (1 + zs / Rad) # check ranges if np.amin(zs) < zmin: print "Warning: altitude requested below minimum for this atmospheric model; returning values for h = -2.0 km" zs[zs < zmin] = zmin if np.amax(zs) > zmax: print "Warning: altitude requested above maximum for this atmospheric model; returning values for h = 86.0 km" zs[zs > zmax] = zmax # initialize return data zeros = np.zeros_like(zs) p = zeros * 0.0 T = zeros * 0.0 rho = zeros * 0.0 a = zeros * 0.0 mew = zeros * 0.0 z0 = zeros * 0.0 T0 = zeros * 0.0 p0 = zeros * 0.0 alpha = zeros * 0.0 # populate the altitude breaks # this uses >= and <= to capture both edges and because values should be the same at the edges for i in range(len(self.breaks.altitude) - 1): i_inside = (zs >= self.breaks.altitude[i]) & ( zs <= self.breaks.altitude[i + 1]) z0[i_inside] = self.breaks.altitude[i] T0[i_inside] = temperature p0[i_inside] = self.breaks.pressure[i] self.breaks.temperature[i + 1] = temperature alpha[ i_inside ] = -(temperature - temperature)/ \ (self.breaks.altitude[i+1] - self.breaks.altitude[i]) # interpolate the breaks dz = zs - z0 i_isoth = (alpha == 0.) p = p0 * np.exp(-1. * dz * grav / (gamma * T0)) T = temperature rho = gas.compute_density(T, p) a = gas.compute_speed_of_sound(T) mew = gas.compute_absolute_viscosity(T) atmo_data = Conditions() atmo_data.expand_rows(zs.shape[0]) atmo_data.pressure = p atmo_data.temperature = T atmo_data.density = rho atmo_data.speed_of_sound = a atmo_data.dynamic_viscosity = mew return atmo_data