def get_list_from_last_ring(options, variables, architecture, kite): wake_nodes = options['induction']['vortex_wake_nodes'] rings = wake_nodes - 1 if rings < 1: message = 'insufficient wake nodes for creating a filament list: wake_nodes = ' + str( wake_nodes) awelogger.logger.error(message) return [] last_tracked_wake_node = wake_nodes - 1 ring = rings far_convection_time = options['induction']['vortex_far_convection_time'] u_ref = options['induction']['vortex_u_ref'] LENE = tools.get_wake_node_position_si(options, variables, kite, 'int', last_tracked_wake_node) LEPE = tools.get_wake_node_position_si(options, variables, kite, 'ext', last_tracked_wake_node) TENE = LENE + far_convection_time * u_ref * vect_op.xhat() TEPE = LEPE + far_convection_time * u_ref * vect_op.xhat() strength_prev = tools.get_ring_strength_si(options, variables, kite, ring - 1) strength = strength_prev filament_list = make_horseshoe_list(LENE, LEPE, TEPE, TENE, strength, strength_prev) return filament_list
def get_induction_factor_at_observer(options, filament_list, x_obs, u_zero, n_hat=vect_op.xhat()): u_ind = get_induced_velocity_at_observer(options, filament_list, x_obs, n_hat=n_hat) a_calc = -1. * u_ind / u_zero return a_calc
def get_body_axes(q_upper, q_lower): tether = q_upper - q_lower xhat = vect_op.xhat() yhat = vect_op.yhat() ehat_z = vect_op.normalize(tether) ehat_x = vect_op.normed_cross(yhat, tether) ehat_y = vect_op.normed_cross(ehat_z, ehat_x) return ehat_x, ehat_y, ehat_z
def get_MM_matrix(): MM11 = 1.69765 MM22 = 0.113177 MM33 = 0.113177 MM_col1 = MM11 * vect_op.xhat() MM_col2 = MM22 * vect_op.yhat() MM_col3 = MM33 * vect_op.zhat() MM = cas.horzcat(MM_col1, MM_col2, MM_col3) return MM
def test(test_list): options = {} options['induction'] = {} options['induction']['vortex_epsilon'] = 0. x_obs = 0.5 * vect_op.xhat_np() u_ind = get_induced_velocity_at_observer(options, test_list, x_obs) xhat_component = cas.mtimes(u_ind.T, vect_op.xhat()) if not (xhat_component == 0): message = 'induced velocity at observer does not work as expected. ' \ 'test u_ind component in plane of QSVR (along xhat) is ' + str(xhat_component) awelogger.logger.error(message) raise Exception(message) yhat_component = cas.mtimes(u_ind.T, vect_op.yhat()) if not (yhat_component == 0): message = 'induced velocity at observer does not work as expected. ' \ 'test u_ind component in plane of QSVR (along yhat) is ' + str(yhat_component) awelogger.logger.error(message) raise Exception(message) zhat_component = cas.mtimes(u_ind.T, vect_op.zhat()) sign_along_zhat = vect_op.sign(zhat_component) sign_comparison = (sign_along_zhat - (-1))**2. if not (sign_comparison < 1.e-8): message = 'induced velocity at observer does not work as expected. ' \ 'sign of test u_ind component out-of-plane of QSVR (projected on zhat) is ' + str(sign_along_zhat) awelogger.logger.error(message) raise Exception(message) calculated_norm = vect_op.norm(u_ind) expected_norm = 0.752133 norm_comparison = (calculated_norm - expected_norm)**2. if not (norm_comparison < 1.e-8): message = 'induced velocity at observer does not work as expected. ' \ 'squared difference of norm of test u_ind vector is ' + str(norm_comparison) awelogger.logger.error(message) raise Exception(message) return None
def get_induction_factor_at_kite(options, filament_list, wind, variables, parameters, architecture, kite_obs, n_hat=vect_op.xhat()): x_obs = variables['xd']['q' + str(kite_obs) + str(architecture.parent_map[kite_obs])] parent = architecture.parent_map[kite_obs] u_zero_vec = actuator_flow.get_uzero_vec(options, wind, parent, variables, parameters, architecture) u_zero = vect_op.smooth_norm(u_zero_vec) a_calc = get_induction_factor_at_observer(options, filament_list, x_obs, u_zero, n_hat=n_hat) return a_calc
def test(): point_obs = vect_op.yhat() point_1 = 1000. * vect_op.zhat() point_2 = -1. * point_1 Gamma = 1. epsilon = 1.e-2 seg_data = cas.vertcat(point_obs, point_1, point_2, Gamma, epsilon) vec_found = filament(seg_data) val_normalize = 1. / (2. * np.pi) vec_norm = vec_found / val_normalize difference = vec_norm - vect_op.xhat() resi = cas.mtimes(difference.T, difference) thresh = 1.e-6 if resi > thresh: message = 'biot-savart filament induction test gives error of size: ' + str( resi) awelogger.logger.error(message) raise Exception(message) return None
def get_aerodynamic_outputs(options, atmos, wind, variables, outputs, parameters, architecture): xd = variables['xd'] b_ref = parameters['theta0', 'geometry', 'b_ref'] c_ref = parameters['theta0', 'geometry', 'c_ref'] s_ref = parameters['theta0', 'geometry', 's_ref'] reference_lengths = cas.diag(cas.vertcat(b_ref, c_ref, b_ref)) kite_nodes = architecture.kite_nodes for kite in kite_nodes: parent = architecture.parent_map[kite] q = xd['q' + str(kite) + str(parent)] dq = xd['dq' + str(kite) + str(parent)] vec_u_eff = tools.get_u_eff_in_earth_frame(options, variables, wind, kite, architecture) u_eff = vect_op.smooth_norm(vec_u_eff) rho = atmos.get_density(q[2]) q_eff = 0.5 * rho * cas.mtimes(vec_u_eff.T, vec_u_eff) if int(options['kite_dof']) == 3: kite_dcm = three_dof_kite.get_kite_dcm(options, variables, wind, kite, architecture) elif int(options['kite_dof']) == 6: kite_dcm = six_dof_kite.get_kite_dcm(kite, variables, architecture) else: message = 'unsupported kite_dof chosen in options: ' + str( options['kite_dof']) awelogger.logger.error(message) if int(options['kite_dof']) == 3: framed_forces = tools.get_framed_forces(vec_u_eff, kite_dcm, variables, kite, architecture) m_aero_body = cas.DM.zeros((3, 1)) elif int(options['kite_dof']) == 6: framed_forces = tools.get_framed_forces(vec_u_eff, kite_dcm, variables, kite, architecture) framed_moments = tools.get_framed_moments(vec_u_eff, kite_dcm, variables, kite, architecture) m_aero_body = framed_moments['body'] else: message = 'unsupported kite_dof chosen in options: ' + str( options['kite_dof']) awelogger.logger.error(message) f_aero_body = framed_forces['body'] f_aero_wind = framed_forces['wind'] f_aero_control = framed_forces['control'] f_aero_earth = framed_forces['earth'] coeff_body = f_aero_body / q_eff / s_ref CA = coeff_body[0] CY = coeff_body[1] CN = coeff_body[2] f_drag_wind = f_aero_wind[0] * vect_op.xhat() f_side_wind = f_aero_wind[1] * vect_op.yhat() f_lift_wind = f_aero_wind[2] * vect_op.zhat() f_drag_earth = frames.from_wind_to_earth(vec_u_eff, kite_dcm, f_drag_wind) f_side_earth = frames.from_wind_to_earth(vec_u_eff, kite_dcm, f_side_wind) f_lift_earth = frames.from_wind_to_earth(vec_u_eff, kite_dcm, f_lift_wind) coeff_wind = f_aero_wind / q_eff / s_ref CD = coeff_wind[0] CS = coeff_wind[1] CL = coeff_wind[2] CM = cas.mtimes(cas.inv(reference_lengths), m_aero_body) / q_eff / s_ref Cl = CM[0] Cm = CM[1] Cn = CM[2] aero_coefficients = {} aero_coefficients['CD'] = CD aero_coefficients['CS'] = CS aero_coefficients['CL'] = CL aero_coefficients['CA'] = CA aero_coefficients['CY'] = CY aero_coefficients['CN'] = CN aero_coefficients['Cl'] = Cl aero_coefficients['Cm'] = Cm aero_coefficients['Cn'] = Cn aero_coefficients['LoverD'] = CL / CD base_aerodynamic_quantities = {} base_aerodynamic_quantities['kite'] = kite base_aerodynamic_quantities['air_velocity'] = vec_u_eff base_aerodynamic_quantities['airspeed'] = u_eff base_aerodynamic_quantities['aero_coefficients'] = aero_coefficients base_aerodynamic_quantities['f_aero_earth'] = f_aero_earth base_aerodynamic_quantities['f_aero_body'] = f_aero_body base_aerodynamic_quantities['f_aero_control'] = f_aero_control base_aerodynamic_quantities['f_aero_wind'] = f_aero_wind base_aerodynamic_quantities['f_lift_earth'] = f_lift_earth base_aerodynamic_quantities['f_drag_earth'] = f_drag_earth base_aerodynamic_quantities['f_side_earth'] = f_side_earth base_aerodynamic_quantities['m_aero_body'] = m_aero_body base_aerodynamic_quantities['kite_dcm'] = kite_dcm base_aerodynamic_quantities['q'] = q base_aerodynamic_quantities['dq'] = dq outputs = indicators.collect_kite_aerodynamics_outputs( options, architecture, atmos, wind, variables, parameters, base_aerodynamic_quantities, outputs) outputs = indicators.collect_environmental_outputs( atmos, wind, base_aerodynamic_quantities, outputs) outputs = indicators.collect_aero_validity_outputs( options, base_aerodynamic_quantities, outputs) outputs = indicators.collect_local_performance_outputs( architecture, atmos, wind, variables, parameters, base_aerodynamic_quantities, outputs) outputs = indicators.collect_power_balance_outputs( options, architecture, variables, base_aerodynamic_quantities, outputs) return outputs
def compute_vortex_verification_points(plot_dict, cosmetics, idx_at_eval, kdx): kite_plane_induction_params = get_kite_plane_induction_params( plot_dict, idx_at_eval) architecture = plot_dict['architecture'] filament_list = reconstruct_filament_list(plot_dict, idx_at_eval) number_of_kites = architecture.number_of_kites radius = kite_plane_induction_params['average_radius'] center = kite_plane_induction_params['center'] u_infty = kite_plane_induction_params['u_infty'] u_zero = u_infty verification_points = plot_dict['options']['model']['aero']['vortex'][ 'verification_points'] half_points = int(verification_points / 2.) + 1 psi0_base = plot_dict['options']['solver']['initialization']['psi0_rad'] mu_grid_min = kite_plane_induction_params['mu_start_by_path'] mu_grid_max = kite_plane_induction_params['mu_end_by_path'] psi_grid_min = psi0_base - np.pi / float(number_of_kites) + float( kdx) * 2. * np.pi / float(number_of_kites) psi_grid_max = psi0_base + np.pi / float(number_of_kites) + float( kdx) * 2. * np.pi / float(number_of_kites) # define mu with respect to kite mid-span radius mu_grid_points = np.linspace(mu_grid_min, mu_grid_max, verification_points, endpoint=True) length_mu = mu_grid_points.shape[0] beta = np.linspace(0., np.pi / 2, half_points) cos_front = 0.5 * (1. - np.cos(beta)) cos_back = -1. * cos_front[::-1] psi_grid_unscaled = cas.vertcat(cos_back, cos_front) + 0.5 psi_grid_points_cas = psi_grid_unscaled * (psi_grid_max - psi_grid_min) + psi_grid_min psi_grid_points_np = np.array(psi_grid_points_cas) psi_grid_points_recenter = np.deg2rad(np.rad2deg(psi_grid_points_np)) psi_grid_points = np.unique(psi_grid_points_recenter) length_psi = psi_grid_points.shape[0] # reserve mesh space y_matr = np.ones((length_psi, length_mu)) z_matr = np.ones((length_psi, length_mu)) a_matr = np.ones((length_psi, length_mu)) for mdx in range(length_mu): mu_val = mu_grid_points[mdx] for pdx in range(length_psi): psi_val = psi_grid_points[pdx] r_val = mu_val * radius ehat_radial = vect_op.zhat_np() * cas.cos( psi_val) - vect_op.yhat_np() * cas.sin(psi_val) added = r_val * ehat_radial x_obs = center + added unscaled = mu_val * ehat_radial a_ind = float( vortex_flow.get_induction_factor_at_observer( plot_dict['options']['model'], filament_list, x_obs, u_zero, n_hat=vect_op.xhat())) unscaled_y_val = float(cas.mtimes(unscaled.T, vect_op.yhat_np())) unscaled_z_val = float(cas.mtimes(unscaled.T, vect_op.zhat_np())) y_matr[pdx, mdx] = unscaled_y_val z_matr[pdx, mdx] = unscaled_z_val a_matr[pdx, mdx] = a_ind y_list = np.array(cas.reshape(y_matr, (length_psi * length_mu, 1))) z_list = np.array(cas.reshape(z_matr, (length_psi * length_mu, 1))) return y_matr, z_matr, a_matr, y_list, z_list
def get_ehat_tether(options): inclination = options['incid_deg'] * np.pi / 180. ehat_tether = np.cos(inclination) * vect_op.xhat() + np.sin( inclination) * vect_op.zhat() return ehat_tether
def __process_interpolation_Variables(interpolation_variables, configurations, model): """Create casadi functions mapping interpolation variables to states :type interpolation_variables: dict :param interpolation_variables: variables defining the interpolation :type configurations: dict :param configurations: parameters defining a given configuration :type model: awebox.model_dir.model :param model: system model :rtype: dict, casadi.struct_symSX """ # initialize dict rotation_matrix = {} rotation_matrix['q00'] = np.eye(3) rotation_matrix['dq00'] = np.zeros([3, 3]) kite_nodes = model.architecture.kite_nodes parent_nodes = model.architecture.parent_map parent_nodes[0] = 0 number_of_nodes = model.architecture.number_of_nodes kite_dof = model.kite_dof trajectory_type = model.options['trajectory']['type'] conf_0 = configurations['conf_0'] conf_f = configurations['conf_f'] l_s = configurations['l_s'] l_i = configurations['l_i'] ## generate casadi expressions # generate symbolic variables sinterp = __get_sstruct(interpolation_variables) sstates = {} sstates['var'] = {} sstates['var']['q00'] = 0. sstates['dvar'] = {} sstates['dvar']['q00'] = 0. sstates['ddvar'] = {} sstates['ddvar']['q00'] = 0. # generate dict to store functions in sstates_functions = {} # generate casadi functions: inteprolation variables -> states l_t = sinterp['var', 'l_t'] for node in range(1, number_of_nodes): parent_node = parent_nodes[node] node_str = str(node) + str(parent_node) grandparent_node = parent_nodes[parent_node] parent_str = str(parent_node) + str(grandparent_node) grandgrandparent_node = parent_nodes[grandparent_node] grandparent_str = str(grandparent_node) + str(grandgrandparent_node) if (node == 1) and ( node not in kite_nodes ): # first node parameterized with main tether length a = cas.mtimes((conf_f['q' + node_str] - conf_0['q' + node_str]).T, (conf_f['q' + node_str] - conf_0['q' + node_str])) if a == 0: e_t = vect_op.normalize(conf_0['q' + node_str]) else: b = 2 * cas.mtimes( conf_0['q' + node_str].T, (conf_f['q' + node_str] - conf_0['q' + node_str])) c = cas.mtimes(conf_0['q' + node_str].T, conf_0['q' + node_str]) - l_t**2 D = b**2 - 4 * a * c x1 = (-b + np.sqrt(D)) / (2 * a) x2 = (-b - np.sqrt(D)) / (2 * a) #if x2 >= 0: # s = x2 #else: # s = x1 s = x1 e_t = 1. / l_t * ( conf_0['q' + node_str] + s * (conf_f['q' + node_str] - conf_0['q' + node_str])) sstates['var']['q' + node_str] = l_t * e_t rotation_matrix = compute_rotation_matrices( sinterp.prefix['var'], node_str, parent_str, rotation_matrix) else: if (node in kite_nodes): if node == 1: tether_length = l_t else: tether_length = l_s Phi = sinterp['var', 'Phi' + node_str] Omega = sinterp['var', 'Omega' + node_str] parent = sstates['var']['q' + parent_str] grandparent = sstates['var']['q' + grandparent_str] radius = tether_length * np.sin(Phi) l_x = tether_length * np.cos(Phi) # define axis of rotation if node != 1: axis_of_rot = parent - grandparent axis_of_rot = vect_op.normalize(axis_of_rot) else: inclination = sinterp['var', 'inclination' + node_str] axis_of_rot = np.zeros([3, 1]) axis_of_rot[0] = np.cos(inclination) axis_of_rot[2] = np.sin(inclination) e_hat_x = axis_of_rot e_hat_y = vect_op.normed_cross(e_hat_x, vect_op.zhat()) e_hat_z = vect_op.normed_cross(e_hat_y, e_hat_x) e_hat_r = e_hat_z * np.sin(Omega) + e_hat_y * np.cos(Omega) sstates['var']['q' + node_str] = sstates['var'][ 'q' + parent_str] + e_hat_r * radius + e_hat_x * l_x else: tether_length = l_i rotation_matrix = compute_rotation_matrices( sinterp.prefix['var'], node_str, parent_str, rotation_matrix) tether_vector = vect_op.xhat() tether_vector = cas.mtimes(rotation_matrix['q' + node_str], tether_vector) sstates['var']['q' + node_str] = sstates['var'][ 'q' + parent_str] + tether_vector * tether_length sstates['dvar']['q' + node_str] = cas.mtimes( cas.jacobian(sstates['var']['q' + node_str], sinterp['var']), sinterp['dvar']) # create rotational kinematics if int(kite_dof) == 6: # iterate over all kite ndoes if node in kite_nodes: # get node strings parent = parent_nodes[node] node_str = str(node) + str(parent) grandparent = parent_nodes[parent] parent_str = str(parent) + str(grandparent) grandgrandparent = parent_nodes[grandparent] grandparent_str = str(grandparent) + str(grandgrandparent) # compute dcm matrix for node e_hat_1, e_hat_2, e_hat_3 = __get_kite_axis( sstates, node_str, parent_str, grandparent_str, trajectory_type) dcm = ct.horzcat(e_hat_1, e_hat_2, e_hat_3) dcm_column = ct.reshape(dcm, (9, 1)) # compute rotation around axis omega_norm = vect_op.norm( sstates['dvar']['q' + node_str]) / radius if trajectory_type == 'lift_mode': omega_vector = vect_op.normalize(axis_of_rot) * omega_norm elif trajectory_type == 'nominal_landing': omega_vector = cas.DM([0, 0, 0]) # put in state dict sstates['omega' + node_str] = omega_vector sstates['r' + node_str] = dcm_column # generate functions sstates_functions['q' + node_str] = cas.Function( 'q' + node_str, [sinterp], [sstates['var']['q' + node_str]]) sstates_functions['dq' + node_str] = cas.Function( 'dq' + node_str, [sinterp], [sstates['dvar']['q' + node_str]]) if int(kite_dof) == 6 and node in kite_nodes: sstates_functions['r' + node_str] = cas.Function( 'r' + node_str, [sinterp], [sstates['r' + node_str]]) sstates_functions['omega' + node_str] = cas.Function( 'omega' + node_str, [sinterp], [sstates['omega' + node_str]]) return sstates_functions, sinterp