def collect_local_performance_outputs(options, atmos, wind, variables, CL, CD, elevation_angle, ua, n, parent, outputs,parameters): xd = variables['xd'] q = xd['q' + str(n) + str(parent)] if 'local_performance' not in list(outputs.keys()): outputs['local_performance'] = {} [CR, f_crosswind, p_loyd, loyd_speed, loyd_phf] = get_loyd_comparison(options, atmos, wind, xd, n, parent, CL, CD, parameters, elevation_angle) norm_ua = cas.mtimes(ua.T, ua)**0.5 outputs['local_performance']['CR' + str(n)] = CR outputs['local_performance']['f_crosswind' + str(n)] = f_crosswind outputs['local_performance']['p_loyd' + str(n)] = p_loyd outputs['local_performance']['loyd_speed' + str(n)] = loyd_speed outputs['local_performance']['loyd_phf' + str(n)] = loyd_phf outputs['local_performance']['radius' + str(n)] = get_radius_of_curvature(variables, n, parent) outputs['local_performance']['speed_ratio' + str(n)] = norm_ua / vect_op.norm(wind.get_velocity(q[2])) outputs['local_performance']['speed_ratio_loyd' + str(n)] = loyd_speed / vect_op.norm(wind.get_velocity(q[2])) outputs['local_performance']['radius_of_curvature' + str(n)] = get_radius_of_curvature(variables, n, parent) return outputs
def test_transform_from_body(): xhat = vect_op.xhat_np() yhat = vect_op.yhat_np() zhat = vect_op.zhat_np() qx_test = np.random.random() * 1000. qy_test = np.random.random() * 1000. qz_test = np.random.random() * 1000. q_upper = qx_test * xhat + qy_test * yhat + qz_test * zhat q_lower = q_upper / 2. x_test = np.random.random() * 100. y_test = np.random.random() * 100. z_test = np.random.random() * 100. test_vec = x_test * xhat + y_test * yhat + z_test * zhat test_mag = vect_op.norm(test_vec) trans_vec = from_body_to_earth(test_vec, q_upper, q_lower) trans_mag = vect_op.norm(trans_vec) norm_error = vect_op.norm(trans_mag - test_mag) reformed_vec = from_earth_to_body(trans_vec, q_upper, q_lower) vector_diff = reformed_vec - test_vec vector_error = cas.mtimes(vector_diff.T, vector_diff) tot_error = norm_error + vector_error epsilon = 1.e-12 if tot_error > epsilon: awelogger.logger.error( 'tether frame transformation test gives error of size: ' + str(tot_error)) return None
def get_segment_force(diam, q_upper, q_lower, dq_upper, dq_lower, atmos, wind, cd_tether_fun): q_average = (q_upper + q_lower) / 2. zz = q_average[2] uw_average = wind.get_velocity(zz) density = atmos.get_density(zz) dq_average = (dq_upper + dq_lower) / 2. ua = uw_average - dq_average ua_norm = vect_op.smooth_norm(ua, 1e-6) ehat_ua = vect_op.smooth_normalize(ua, 1e-6) tether = q_upper - q_lower length = vect_op.norm(tether) length_parallel_to_wind = cas.mtimes(tether.T, ehat_ua) length_perp_to_wind = (length**2. - length_parallel_to_wind**2.)**0.5 reynolds = get_reynolds_number(atmos, ua, diam, q_upper, q_lower) cd = cd_tether_fun(reynolds) drag = cd * 0.5 * density * ua_norm * diam * length_perp_to_wind * ua return drag
def get_loyd_comparison(atmos, wind, xd, n, parent, CL, CD, parameters, elevation_angle=0.): # for elevation angle cosine losses see Van der Lind, p. 477, AWE book q = xd['q' + str(n) + str(parent)] epsilon = 1.e-8 CR = CL * (1. + (CD / (CL + epsilon))**2.)**0.5 windspeed = vect_op.norm(wind.get_velocity(q[2])) power_density = get_power_density(atmos, wind, q[2]) phf_loyd = perf_op.get_loyd_phf(CL, CD, elevation_angle) s_ref = parameters['theta0', 'geometry', 's_ref'] p_loyd = perf_op.get_loyd_power(power_density, CL, CD, s_ref, elevation_angle) speed_loyd = 2. * CR / 3. / CD * windspeed * np.cos(elevation_angle) return [CR, phf_loyd, p_loyd, speed_loyd]
def get_force_from_u_sym_in_earth_frame(vec_u, options, variables, kite, atmos, wind, architecture, parameters): parent = architecture.parent_map[kite] # get relevant variables for kite n q = variables['xd']['q' + str(kite) + str(parent)] coeff = variables['xd']['coeff' + str(kite) + str(parent)] # wind parameters rho_infty = atmos.get_density(q[2]) kite_dcm = get_kite_dcm(options, variables, wind, kite, architecture) Lhat = kite_dcm[:,2] # lift and drag coefficients CL = coeff[0] CD0 = 0. poss_drag_labels_in_order_of_increasing_preference = ['CX', 'CA', 'CD'] for poss_drag_label in poss_drag_labels_in_order_of_increasing_preference: local_parameter_label = '[theta0,aero,' + poss_drag_label + ',0,0]' if local_parameter_label in parameters.labels(): CD0 = vect_op.abs(parameters['theta0', 'aero', poss_drag_label, '0'][0]) CD = CD0 + CL ** 2 / (np.pi * parameters['theta0', 'geometry', 'ar']) s_ref = parameters['theta0', 'geometry', 's_ref'] # lift and drag force f_lift = CL * 1. / 2. * rho_infty * cas.mtimes(vec_u.T, vec_u) * s_ref * Lhat f_drag = CD * 1. / 2. * rho_infty * vect_op.norm(vec_u) * s_ref * vec_u f_aero = f_lift + f_drag return f_aero
def get_kite_only_segment_forces(atmos, outputs, variables, upper_node, architecture, cd_tether_fun): force_lower = cas.DM.zeros((3, 1)) force_upper = cas.DM.zeros((3, 1)) if upper_node in architecture.kite_nodes: kite = upper_node ehat_1 = outputs['aerodynamics']['ehat_chord' + str(kite)] ehat_3 = outputs['aerodynamics']['ehat_span' + str(kite)] alpha = outputs['aerodynamics']['alpha' + str(kite)] d_hat = cas.cos(alpha) * ehat_1 + cas.sin(alpha) * ehat_3 kite_dyn_pressure = outputs['aerodynamics']['dyn_pressure' + str(kite)] q_upper, q_lower, dq_upper, dq_lower = element.get_upper_and_lower_pos_and_vel( variables, upper_node, architecture) length = vect_op.norm(q_upper - q_lower) diam = element.get_element_diameter(variables, upper_node, architecture) air_velocity = outputs['aerodynamics']['air_velocity' + str(kite)] re_number = reynolds.get_reynolds_number(atmos, air_velocity, diam, q_upper, q_lower) cd_tether = cd_tether_fun(re_number) d_mag = (1. / 4.) * cd_tether * kite_dyn_pressure * diam * length force_upper = d_mag * d_hat return force_lower, force_upper
def get_radius_inequality(model_options, variables, kite, parent, parameters): # no projection included... b_ref = parameters['theta0', 'geometry', 'b_ref'] half_span = b_ref / 2. num_ref = model_options['model_bounds']['anticollision_radius']['num_ref'] # half_span - radius < 0 # half_span * den - num < 0 dq = variables['xd']['dq' + str(kite) + str(parent)] ddq = variables['xddot']['ddq' + str(kite) + str(parent)] gamma_dot = cas.vertcat(0., dq[1], dq[2]) gamma_ddot = cas.vertcat(0., ddq[1], ddq[2]) num = cas.mtimes(gamma_dot.T, gamma_dot)**2. den_vec = gamma_ddot * cas.mtimes(gamma_dot.T, gamma_dot) - gamma_dot * cas.mtimes( gamma_dot.T, gamma_ddot) den = vect_op.norm(den_vec) inequality = (half_span * den - num) / num_ref return inequality
def get_dependent_rotation_direction_sign(t, init_options, model, node, ret): velocity = get_velocity_vector(t, init_options, model, node, ret) ehat_normal, ehat_radial, ehat_tangential = get_rotating_reference_frame( t, init_options, model, node, ret) forwards_speed = cas.mtimes(velocity.T, ehat_tangential) forwards_sign = forwards_speed / vect_op.norm(forwards_speed) return forwards_sign
def generate_rotational_dynamics(variables, f_nodes, parameters, outputs, architecture): kite_nodes = architecture.kite_nodes parent_map = architecture.parent_map j_inertia = parameters['theta0', 'geometry', 'j'] xd = variables['SI']['xd'] xddot = variables['SI']['xddot'] cstr_list = mdl_constraint.MdlConstraintList() for kite in kite_nodes: parent = parent_map[kite] moment = f_nodes['m' + str(kite) + str(parent)] rlocal = cas.reshape(xd['r' + str(kite) + str(parent)], (3, 3)) drlocal = cas.reshape(xddot['dr' + str(kite) + str(parent)], (3, 3)) omega = xd['omega' + str(kite) + str(parent)] omega_skew = vect_op.skew(omega) domega = xddot['domega' + str(kite) + str(parent)] tether_moment = outputs['tether_moments']['n{}{}'.format(kite, parent)] # moment = J dot(omega) + omega x (J omega) + [tether moment which is zero if holonomic constraints do not depend on omega] J_dot_omega = cas.mtimes(j_inertia, domega) omega_cross_J_omega = vect_op.cross(omega, cas.mtimes(j_inertia, omega)) omega_derivative = moment - (J_dot_omega + omega_cross_J_omega + tether_moment) rotational_2nd_law = omega_derivative / vect_op.norm( cas.diag(j_inertia)) rotation_dynamics_cstr = cstr_op.Constraint(expr=rotational_2nd_law, name='rotation_dynamics' + str(kite), cstr_type='eq') cstr_list.append(rotation_dynamics_cstr) # Rdot = R omega_skew -> R ( kappa/2 (I - R.T R) + omega_skew ) baumgarte = parameters['theta0', 'kappa_r'] orthonormality = baumgarte / 2. * (cas.DM_eye(3) - cas.mtimes(rlocal.T, rlocal)) ref_frame_deriv_matrix = drlocal - (cas.mtimes( rlocal, orthonormality + omega_skew)) ref_frame_derivative = cas.reshape(ref_frame_deriv_matrix, (9, 1)) ortho_cstr = cstr_op.Constraint(expr=ref_frame_derivative, name='ref_frame_deriv' + str(kite), cstr_type='eq') cstr_list.append(ortho_cstr) return cstr_list, outputs
def collect_environmental_outputs(atmos, wind, q, n, outputs): if 'environment' not in list(outputs.keys()): outputs['environment'] = {} outputs['environment']['windspeed' + str(n)] = vect_op.norm(wind.get_velocity(q[2])) outputs['environment']['pressure' + str(n)] = atmos.get_pressure(q[2]) outputs['environment']['temperature' + str(n)] = atmos.get_temperature(q[2]) outputs['environment']['density' + str(n)] = atmos.get_density(q[2]) return outputs
def get_local_wind_reference_frame(init_options): u_hat = vect_op.xhat_np() n_rot_hat, y_rot_hat, z_rot_hat = tools_init.get_rotor_reference_frame(init_options) if vect_op.norm(u_hat - n_rot_hat) < 1.e-5: v_hat = y_rot_hat w_hat = z_rot_hat else: w_hat = vect_op.normed_cross(u_hat, n_rot_hat) v_hat = vect_op.normed_cross(w_hat, u_hat) return u_hat, v_hat, w_hat
def collect_local_performance_outputs(architecture, atmos, wind, variables, parameters, base_aerodynamic_quantities, outputs): kite = base_aerodynamic_quantities['kite'] q = base_aerodynamic_quantities['q'] airspeed = base_aerodynamic_quantities['airspeed'] CL = base_aerodynamic_quantities['aero_coefficients']['CL'] CD = base_aerodynamic_quantities['aero_coefficients']['CD'] xd = variables['xd'] elevation_angle = get_elevation_angle(xd) parent = architecture.parent_map[kite] if 'local_performance' not in list(outputs.keys()): outputs['local_performance'] = {} [CR, phf_loyd, p_loyd, speed_loyd] = get_loyd_comparison(atmos, wind, xd, kite, parent, CL, CD, parameters, elevation_angle) outputs['local_performance']['CR' + str(kite)] = CR outputs['local_performance']['p_loyd' + str(kite)] = p_loyd outputs['local_performance']['speed_loyd' + str(kite)] = speed_loyd outputs['local_performance']['phf_loyd' + str(kite)] = phf_loyd outputs['local_performance']['speed_ratio' + str(kite)] = airspeed / vect_op.norm( wind.get_velocity(q[2])) outputs['local_performance']['speed_ratio_loyd' + str(kite)] = speed_loyd / vect_op.norm( wind.get_velocity(q[2])) outputs['local_performance'][ 'radius_of_curvature' + str(kite)] = path_based_geom.get_radius_of_curvature( variables, kite, parent) return outputs
def expected_filament_in_list(test_list, expected_filament): filaments = test_list.shape[1] thresh = 1.e-8 for filament in range(filaments): local = test_list[:, filament] comparison = vect_op.norm(local - expected_filament) if comparison < thresh: return True return False
def get_rotor_reference_frame(init_options): n_rot_hat = get_ehat_tether(init_options) n_hat_is_x_hat = vect_op.abs( vect_op.norm(n_rot_hat - vect_op.xhat_np())) < 1.e-4 if n_hat_is_x_hat: y_rot_hat = vect_op.yhat_np() z_rot_hat = vect_op.zhat_np() else: u_hat = vect_op.xhat_np() z_rot_hat = vect_op.normed_cross(u_hat, n_rot_hat) y_rot_hat = vect_op.normed_cross(z_rot_hat, n_rot_hat) return n_rot_hat, y_rot_hat, z_rot_hat
def get_cosgamma_residual(model_options, wind, parent, variables, architecture): cosgamma_var = get_cosgamma_var(variables, parent) u_app = get_rotor_apparent_velocity(model_options, wind, parent, variables, architecture) nhat_var = geom.get_nhat_var(variables, parent) num = cas.mtimes(u_app.T, nhat_var)**2. den = cas.mtimes(u_app.T, u_app) # den^(1/2) = norm(u_app) * norm(nhat) u_ref = vect_op.norm(get_uapp_ref(wind)) resi_unscaled = cosgamma_var**2. * den - num resi = resi_unscaled / u_ref**2. return resi
def get_kite_dcm(t, init_options, model, node, ret): velocity = get_velocity_vector(t, init_options, model, node, ret) ehat_normal, ehat_radial, ehat_tangential = get_rotating_reference_frame( t, init_options, model, node, ret) forwards_speed = cas.mtimes(velocity.T, ehat_tangential) forwards_sign = forwards_speed / vect_op.norm(forwards_speed) ehat_forwards = forwards_sign * ehat_tangential ehat1 = -1. * ehat_forwards ehat3 = ehat_normal ehat2 = vect_op.normed_cross(ehat3, ehat1) kite_dcm = cas.horzcat(ehat1, ehat2, ehat3) return kite_dcm
def collect_environmental_outputs(atmos, wind, base_aerodynamic_quantities, outputs): kite = base_aerodynamic_quantities['kite'] q = base_aerodynamic_quantities['q'] if 'environment' not in list(outputs.keys()): outputs['environment'] = {} outputs['environment']['windspeed' + str(kite)] = vect_op.norm( wind.get_velocity(q[2])) outputs['environment']['pressure' + str(kite)] = atmos.get_pressure(q[2]) outputs['environment']['temperature' + str(kite)] = atmos.get_temperature( q[2]) outputs['environment']['density' + str(kite)] = atmos.get_density(q[2]) return outputs
def compute_position_indicators(power_and_performance, plot_dict): # elevation angle q10 = plot_dict['xd']['q10'] elevation = [] for i in range(q10[0].shape[0]): elevation += [ np.arccos( np.linalg.norm(np.array([q10[0][i], q10[1][i], 0.0])) / np.linalg.norm(np.array([q10[0][i], q10[1][i], q10[2][i]]))) ] elevation = np.mean(elevation) * 180 / np.pi power_and_performance['elevation'] = elevation # average velocity of kites (maybe?) parent_map = plot_dict['architecture'].parent_map number_of_nodes = plot_dict['architecture'].number_of_nodes dq_final = 0. for node in range(1, number_of_nodes): parent = parent_map[node] dq = plot_dict['xd']['dq' + str(node) + str(parent)] parent = parent_map[node] dq_array = cas.vertcat(dq[0][-1], dq[1][-1], dq[2][-1]) dq_norm_float = float(vect_op.norm(dq_array)) dq_final += dq_norm_float dq_final = np.array(dq_final) dq_final /= float(number_of_nodes - 1.) power_and_performance['dq_final'] = dq_final # average connex-point velocity dq10 = plot_dict['xd']['dq10'] dq10hat = [] for i in range(dq10[0].shape[0]): dq = np.array([dq10[0][i], dq10[1][i], dq10[2][i]]) q = np.array([q10[0][i], q10[1][i], q10[2][i]]) dq10hat += [ np.linalg.norm(dq - np.matmul(dq.T, q / np.linalg.norm(q)) * q / np.linalg.norm(q)) ] dq10_av = np.mean(np.array(dq10hat)) power_and_performance['dq10_av'] = dq10_av return power_and_performance
def get_trivial_forces(model_options, variables, atmos, wind, n, parameters, architecture): [diam, q_upper, q_lower, dq_upper, dq_lower, ua_upper, ua_lower] = get_upper_lower_q_and_dq(model_options, variables, wind, n,architecture) length = vect_op.norm(q_upper - q_lower) q_average = 0.5 * (q_upper + q_lower) dq_average = 0.5 * (dq_upper + dq_lower) rho = atmos.get_density(q_average[2]) u_a = wind.get_velocity(q_average[2]) - dq_average cd = parameters['theta0','tether','cd'] drag_force = cd * 0.5 * rho * vect_op.smooth_norm(u_a, 1e-6) * u_a * diam * length force_upper = drag_force / 2. force_lower = drag_force / 2. return [force_lower, force_upper]
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 find_airspeed(init_options, groundspeed, psi): dq_kite = get_velocity_vector_from_psi(init_options, groundspeed, psi) l_t = init_options['xd']['l_t'] ehat_tether = get_ehat_tether(init_options) zz = l_t * ehat_tether[2] wind_model = init_options['model']['wind_model'] u_ref = init_options['model']['wind_u_ref'] z_ref = init_options['model']['wind_z_ref'] z0_air = init_options['model']['wind_z0_air'] exp_ref = init_options['model']['wind_exp_ref'] uu = wind.get_speed(wind_model, u_ref, z_ref, z0_air, exp_ref, zz) * vect_op.xhat_np() u_app = dq_kite - uu airspeed = float(vect_op.norm(u_app)) return airspeed
def get_loyd_comparison(options, atmos, wind, xd, n, parent, CL, CD, parameters, elevation_angle=0.): # for elevation angle cosine losses see Van der Lind, p. 477, AWE book q = xd['q' + str(n) + str(parent)] epsilon = 1.e-8 CR = CL * (1. + (CD / (CL + epsilon))**2.)**0.5 windspeed = vect_op.norm(wind.get_velocity(q[2])) power_density = get_power_density(atmos, wind, q[2]) f_crosswind = 4. / 27. * CR * (CR / CD) ** 2. * np.cos(elevation_angle) ** 3. s_ref = parameters['theta0','geometry','s_ref'] p_loyd = power_density * s_ref * f_crosswind loyd_speed = 2. * CR / 3. / CD * windspeed * np.cos(elevation_angle) loyd_phf = f_crosswind return [CR, f_crosswind, p_loyd, loyd_speed, loyd_phf]
def get_segment_equiv_fun(): seg_info_sym = cas.SX.sym('seg_info_sym', (12, 1)) q_upper = seg_info_sym[:3] q_lower = seg_info_sym[3:6] drag_earthfixed = seg_info_sym[6:9] moment_earthfixed = seg_info_sym[9:12] tether = q_upper - q_lower # frames.test_transforms() drag_body = frames.from_earth_to_body(drag_earthfixed, q_upper, q_lower) moment_body = frames.from_earth_to_body(moment_earthfixed, q_upper, q_lower) moment_body[2] = 0. # no spin on tether segment total_vect = cas.vertcat(drag_body, moment_body) Ainv = frames.get_inverse_equivalence_matrix(vect_op.norm(tether)) equiv_vect = cas.mtimes(Ainv, total_vect) equiv_force_upper_body = equiv_vect[0:3] equiv_force_lower_body = equiv_vect[3:6] equiv_force_upper_earthfixed = frames.from_body_to_earth( equiv_force_upper_body, q_upper, q_lower) equiv_force_lower_earthfixed = frames.from_body_to_earth( equiv_force_lower_body, q_upper, q_lower) equivs = cas.vertcat(equiv_force_upper_earthfixed, equiv_force_lower_earthfixed) segment_equiv_fun = cas.Function('segment_equiv_fun', [seg_info_sym], [equivs]) return segment_equiv_fun
def get_force_and_moment(options, parameters, vec_u_earth, kite_dcm, omega, delta, rho): # we use the vec_u_earth and the kite_dcm to give the relative orientation. # this means, that they must be in the same frame. otherwise, the frame of # the wind vector is not used in this function. alpha = indicators.get_alpha(vec_u_earth, kite_dcm) beta = indicators.get_beta(vec_u_earth, kite_dcm) airspeed = vect_op.norm(vec_u_earth) force_coeff_info, moment_coeff_info = stability_derivatives.stability_derivatives( options, alpha, beta, airspeed, omega, delta, parameters) force_info = {} moment_info = {} force_info['frame'] = force_coeff_info['frame'] moment_info['frame'] = moment_coeff_info['frame'] CF = force_coeff_info['coeffs'] CM = moment_coeff_info['coeffs'] # notice that magnitudes don't change under rotation dynamic_pressure = 1. / 2. * rho * cas.mtimes(vec_u_earth.T, vec_u_earth) planform_area = parameters['theta0', 'geometry', 's_ref'] force = CF * dynamic_pressure * planform_area force_info['vector'] = force b_ref = parameters['theta0', 'geometry', 'b_ref'] c_ref = parameters['theta0', 'geometry', 'c_ref'] reference_lengths = cas.diag(cas.vertcat(b_ref, c_ref, b_ref)) moment = dynamic_pressure * planform_area * cas.mtimes( reference_lengths, CM) moment_info['vector'] = moment return force_info, moment_info
def get_performance_outputs(options, atmos, wind, variables, outputs, parameters,architecture): if 'performance' not in list(outputs.keys()): outputs['performance'] = {} kite_nodes = architecture.kite_nodes xd = variables['xd'] outputs['performance']['freelout'] = xd['dl_t'] / vect_op.norm( wind.get_velocity(xd['q10'][2])) outputs['performance']['elevation'] = get_elevation_angle(variables['xd']) outputs['performance']['p_loyd_total'] = 0. for n in kite_nodes: outputs['performance']['p_loyd_total'] += outputs['local_performance']['p_loyd' + str(n)] [current_power, phf, phf_hubheight, hubheight_power_availability] = get_power_harvesting_factor(options, atmos, wind, variables, parameters,architecture) outputs['performance']['phf'] = phf outputs['performance']['phf_hubheight'] = phf_hubheight outputs['performance']['hubheight_power_availability'] = hubheight_power_availability outputs['performance']['phf_loyd_total'] = outputs['performance']['p_loyd_total'] / hubheight_power_availability outputs['performance']['p_current'] = current_power epsilon = 1.0e-8 p_loyd_total = outputs['performance']['p_loyd_total'] outputs['performance']['loyd_factor'] = current_power / (p_loyd_total + epsilon) outputs['performance']['power_density'] = current_power / len(kite_nodes) / parameters['theta0','geometry','s_ref'] return outputs
def get_equivalent_tether_drag_forces(model_options, diam, q_upper, q_lower, dq_upper, dq_lower, atmos, wind, cd_tether_fun): tether = q_upper - q_lower [total_force_earthfixed, total_moment_earthfixed] = get_total_drag(model_options, diam, q_upper, q_lower, dq_upper, dq_lower, atmos, wind, cd_tether_fun) total_force_body = from_earthfixed_to_body(total_force_earthfixed, q_upper, q_lower) total_moment_body = from_earthfixed_to_body(total_moment_earthfixed, q_upper, q_lower) total_moment_body[2] = 0. total_vect = cas.vertcat(total_force_body, total_moment_body) Ainv = get_inverse_equivalence_matrix(vect_op.norm(tether)) equiv_vect = cas.mtimes(Ainv, total_vect) equiv_force_upper_body = equiv_vect[0:3] equiv_force_lower_body = equiv_vect[3:6] equiv_force_upper_earthfixed = from_body_to_earthfixed(equiv_force_upper_body, q_upper, q_lower) equiv_force_lower_earthfixed = from_body_to_earthfixed(equiv_force_lower_body, q_upper, q_lower) return [equiv_force_upper_earthfixed, equiv_force_lower_earthfixed]
def get_power_density(atmos, wind, zz): power_density = .5 * atmos.get_density( zz) * vect_op.norm(wind.get_velocity(zz)) ** 3. return power_density
def angle_between(a, b): fraction = cas.mtimes(a.T, b) / (vect_op.norm(a) * vect_op.norm(b)) angle = np.arccos(fraction) return angle
def collect_kite_aerodynamics_outputs(options, architecture, atmos, wind, variables, parameters, base_aerodynamic_quantities, outputs): if 'aerodynamics' not in list(outputs.keys()): outputs['aerodynamics'] = {} # unpack kite = base_aerodynamic_quantities['kite'] air_velocity = base_aerodynamic_quantities['air_velocity'] aero_coefficients = base_aerodynamic_quantities['aero_coefficients'] f_aero_earth = base_aerodynamic_quantities['f_aero_earth'] f_aero_body = base_aerodynamic_quantities['f_aero_body'] f_aero_control = base_aerodynamic_quantities['f_aero_control'] f_aero_wind = base_aerodynamic_quantities['f_aero_wind'] f_lift_earth = base_aerodynamic_quantities['f_lift_earth'] f_drag_earth = base_aerodynamic_quantities['f_drag_earth'] f_side_earth = base_aerodynamic_quantities['f_side_earth'] m_aero_body = base_aerodynamic_quantities['m_aero_body'] kite_dcm = base_aerodynamic_quantities['kite_dcm'] q = base_aerodynamic_quantities['q'] f_lift_earth_overwrite = options['aero']['overwrite']['f_lift_earth'] if f_lift_earth_overwrite is not None: f_lift_earth = f_lift_earth_overwrite for name in set(base_aerodynamic_quantities['aero_coefficients'].keys()): outputs['aerodynamics'][ name + str(kite)] = base_aerodynamic_quantities['aero_coefficients'][name] outputs['aerodynamics']['air_velocity' + str(kite)] = air_velocity airspeed = vect_op.norm(air_velocity) outputs['aerodynamics']['airspeed' + str(kite)] = airspeed outputs['aerodynamics']['u_infty' + str(kite)] = wind.get_velocity(q[2]) rho = atmos.get_density(q[2]) outputs['aerodynamics']['air_density' + str(kite)] = rho outputs['aerodynamics']['dyn_pressure' + str(kite)] = 0.5 * rho * cas.mtimes( air_velocity.T, air_velocity) ehat_chord = kite_dcm[:, 0] ehat_span = kite_dcm[:, 1] ehat_up = kite_dcm[:, 2] outputs['aerodynamics']['ehat_chord' + str(kite)] = ehat_chord outputs['aerodynamics']['ehat_span' + str(kite)] = ehat_span outputs['aerodynamics']['ehat_up' + str(kite)] = ehat_up outputs['aerodynamics']['f_aero_body' + str(kite)] = f_aero_body outputs['aerodynamics']['f_aero_control' + str(kite)] = f_aero_control outputs['aerodynamics']['f_aero_earth' + str(kite)] = f_aero_earth outputs['aerodynamics']['f_aero_wind' + str(kite)] = f_aero_wind ortho = cas.reshape(cas.mtimes(kite_dcm.T, kite_dcm) - np.eye(3), (9, 1)) ortho_resi = cas.mtimes(ortho.T, ortho) outputs['aerodynamics']['ortho_resi' + str(kite)] = ortho_resi conversion_resis = [] conversion_targets = { 'control': f_aero_control, 'earth': f_aero_earth, 'wind': f_aero_wind } for f_aero_target in conversion_targets.values(): resi = 1. - vect_op.norm(f_aero_target) / vect_op.norm(f_aero_body) conversion_resis = cas.vertcat(conversion_resis, resi) resi = vect_op.norm(f_aero_earth - f_lift_earth - f_drag_earth - f_side_earth) / vect_op.norm(f_aero_body) conversion_resis = cas.vertcat(conversion_resis, resi) outputs['aerodynamics']['check_conversion' + str(kite)] = conversion_resis outputs['aerodynamics']['f_lift_earth' + str(kite)] = f_lift_earth outputs['aerodynamics']['f_drag_earth' + str(kite)] = f_drag_earth outputs['aerodynamics']['f_side_earth' + str(kite)] = f_side_earth b_ref = parameters['theta0', 'geometry', 'b_ref'] c_ref = parameters['theta0', 'geometry', 'c_ref'] circulation_cross = vect_op.smooth_norm( f_lift_earth) / b_ref / rho / vect_op.smooth_norm( vect_op.cross(air_velocity, ehat_span)) circulation_cl = 0.5 * airspeed**2. * aero_coefficients[ 'CL'] * c_ref / vect_op.smooth_norm( vect_op.cross(air_velocity, ehat_span)) outputs['aerodynamics']['circulation_cross' + str(kite)] = circulation_cross outputs['aerodynamics']['circulation_cl' + str(kite)] = circulation_cl outputs['aerodynamics']['circulation' + str(kite)] = circulation_cross outputs['aerodynamics']['wingtip_ext' + str(kite)] = q + ehat_span * b_ref / 2. outputs['aerodynamics']['wingtip_int' + str(kite)] = q - ehat_span * b_ref / 2. outputs['aerodynamics']['fstar_aero' + str(kite)] = cas.mtimes( air_velocity.T, ehat_chord) / c_ref outputs['aerodynamics']['r' + str(kite)] = kite_dcm.reshape((9, 1)) if int(options['kite_dof']) == 6: outputs['aerodynamics']['m_aero_body' + str(kite)] = m_aero_body outputs['aerodynamics']['mach' + str(kite)] = get_mach( options, atmos, air_velocity, q) outputs['aerodynamics']['reynolds' + str(kite)] = get_reynolds( options, atmos, air_velocity, q, parameters) return outputs
def get_performance_outputs(options, atmos, wind, variables, outputs, parameters, architecture): if 'performance' not in list(outputs.keys()): outputs['performance'] = {} kite_nodes = architecture.kite_nodes xd = variables['xd'] outputs['performance']['freelout'] = xd['dl_t'] / vect_op.norm( wind.get_velocity(xd['q10'][2])) outputs['performance']['elevation'] = get_elevation_angle(variables['xd']) layer_nodes = architecture.layer_nodes for parent in layer_nodes: outputs['performance']['actuator_center' + str(parent)] = actuator_geom.get_center_point( options, parent, variables, architecture) average_radius = 0. number_children = len(architecture.children_map[parent]) for kite in architecture.children_map[parent]: rad_curv_name = 'radius_of_curvature' + str(kite) if rad_curv_name in outputs['local_performance'].keys(): local_radius = outputs['local_performance'][rad_curv_name] else: qkite = variables['xd']['q' + str(kite) + str(parent)] local_radius = vect_op.norm( qkite - outputs['performance']['actuator_center' + str(parent)]) average_radius += local_radius / float(number_children) outputs['performance']['average_radius' + str(parent)] = average_radius outputs['performance']['p_loyd_total'] = 0. for kite in kite_nodes: outputs['performance']['p_loyd_total'] += outputs['local_performance'][ 'p_loyd' + str(kite)] [current_power, phf, phf_hubheight, hubheight_power_availability ] = get_power_harvesting_factor(options, atmos, wind, variables, parameters, architecture) outputs['performance']['phf'] = phf outputs['performance']['phf_hubheight'] = phf_hubheight outputs['performance'][ 'hubheight_power_availability'] = hubheight_power_availability outputs['performance']['phf_loyd_total'] = outputs['performance'][ 'p_loyd_total'] / hubheight_power_availability outputs['performance']['p_current'] = current_power epsilon = 1.0e-8 p_loyd_total = outputs['performance']['p_loyd_total'] outputs['performance']['loyd_factor'] = current_power / (p_loyd_total + epsilon) outputs['performance']['power_density'] = current_power / len( kite_nodes) / parameters['theta0', 'geometry', 's_ref'] return outputs