def filament(seg_data, epsilon=1.e-2): try: point_obs = seg_data[:3] point_1 = seg_data[3:6] point_2 = seg_data[6:9] Gamma = seg_data[9] vec_1 = point_obs - point_1 vec_2 = point_obs - point_2 vec_0 = point_2 - point_1 r1 = vect_op.smooth_norm(vec_1) r2 = vect_op.smooth_norm(vec_2) r0 = vect_op.smooth_norm(vec_0) factor = Gamma / (4. * np.pi) num = (r1 + r2) den_ori = (r1 * r2) * (r1 * r2 + cas.mtimes(vec_1.T, vec_2)) den_reg = (epsilon * r0)**2. den = den_ori + den_reg dir = vect_op.cross(vec_1, vec_2) scale = factor * num / den sol = dir * scale except: message = 'something went wrong while computing the filament biot-savart induction. proceed with zero induced velocity from this filament.' awelogger.logger.error(message) raise Exception(message) return sol
def get_f_val(model_options, wind, parent, variables, architecture): dl_t = variables['xd']['dl_t'] u_infty = get_actuator_freestream_velocity(model_options, wind, parent, variables, architecture) f_val = dl_t / vect_op.smooth_norm(u_infty) return f_val
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_radius_of_curvature(variables, kite, parent): dq = variables['xd']['dq' + str(kite) + str(parent)] ddq = variables['xddot']['ddq' + str(kite) + str(parent)] gamma_dot = dq gamma_ddot = ddq # from frenet vectors + curvature definition # r = || gamma' || / (e1' cdot e2) # e1 = gamma' / || gamma' || # e1' = ( gamma" || gamma' ||^2 - gamma' (gamma' cdot gamma") ) / || gamma' ||^3 # e2 = ebar2 / || ebar2 || # ebar2 = gamma" - (gamma' cdot gamma") gamma' / || gamma' ||^2 # .... # r = || gamma' ||^4 // || gamma" || gamma' ||^2 - gamma' (gamma' cdot gamma") || num = cas.mtimes(gamma_dot.T, gamma_dot)**2. + 1.0e-8 den_vec = gamma_ddot * cas.mtimes(gamma_dot.T, gamma_dot) - gamma_dot * cas.mtimes( gamma_dot.T, gamma_ddot) den = vect_op.smooth_norm(den_vec) radius = num / den return radius
def get_local_induced_velocity(model_options, variables, wind, parent, architecture): u_app = get_rotor_apparent_velocity(model_options, wind, parent, variables, architecture) nhat = geom.get_nhat_var(variables, parent) a_val = get_local_induction_factor(model_options, variables, parent) u_ind = -1. * a_val * vect_op.smooth_norm(u_app) * nhat return u_ind
def get_df_val(model_options, wind, parent, variables, architecture): if 'ddl_t' in variables['xd'].keys(): ddl_t = variables['xd']['ddl_t'] else: ddl_t = variables['u']['ddl_t'] u_infty = get_actuator_freestream_velocity(model_options, wind, parent, variables, architecture) df_val = ddl_t / vect_op.smooth_norm(u_infty) return df_val
def get_nhat_residual(model_options, parent, variables, parameters, architecture): nhat_val = get_normal_axis(model_options, parent, variables, parameters, architecture) nhat_var = get_nhat_var(variables, parent) nvec_resi = nhat_var - nhat_val factor_resi = vect_op.smooth_norm(nhat_var) - 1. resi = cas.vertcat(nvec_resi, factor_resi) return resi
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 get_element_drag_and_moment_fun(wind, atmos, cd_tether_fun): info_sym = cas.SX.sym('info_sym', (16, 1)) q_upper = info_sym[:3] q_lower = info_sym[3:6] dq_upper = info_sym[6:9] dq_lower = info_sym[9:12] diam = info_sym[12] q_seg_avg = info_sym[13:16] q_average = (q_upper + q_lower) / 2. zz = q_average[2] ua = get_uapp(q_upper, q_lower, dq_upper, dq_lower, wind) epsilon = 1.e-6 ua_norm = vect_op.smooth_norm(ua, epsilon) ehat_ua = vect_op.smooth_normalize(ua, epsilon) tether = q_upper - q_lower length_sq = cas.mtimes(tether.T, tether) length_parallel_to_wind = cas.mtimes(tether.T, ehat_ua) length_perp_to_wind = vect_op.smooth_sqrt( length_sq - length_parallel_to_wind**2., epsilon) re_number = reynolds.get_reynolds_number(atmos, ua, diam, q_upper, q_lower) cd = cd_tether_fun(re_number) density = atmos.get_density(zz) drag = cd * 0.5 * density * ua_norm * diam * length_perp_to_wind * ua moment_arm = q_average - q_seg_avg moment = vect_op.cross(moment_arm, drag) element_drag_fun = cas.Function('element_drag_fun', [info_sym], [drag]) element_moment_fun = cas.Function('element_moment_fun', [info_sym], [moment]) return element_drag_fun, element_moment_fun
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 get_mach(options, atmos, ua, q): norm_ua = vect_op.smooth_norm(ua) a = atmos.get_speed_of_sound( q[2]) mach = norm_ua / a return mach
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 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_outputs(options, atmos, wind, variables, outputs, parameters, architecture): parent_map = architecture.parent_map kite_nodes = architecture.kite_nodes xd = variables['xd'] elevation_angle = indicators.get_elevation_angle(xd) for n in kite_nodes: parent = parent_map[n] # get relevant variables for kite n q = xd['q' + str(n) + str(parent)] dq = xd['dq' + str(n) + str(parent)] coeff = xd['coeff' + str(n) + str(parent)] # wind parameters rho_infty = atmos.get_density(q[2]) uw_infty = wind.get_velocity(q[2]) # apparent air velocity if options['induction_model'] == 'actuator': ua = actuator_disk_flow.get_kite_effective_velocity( options, variables, wind, n, parent, architecture) else: ua = uw_infty - dq # relative air speed ua_norm = vect_op.smooth_norm(ua, epsilon=1e-8) # ua_norm = mtimes(ua.T, ua) ** 0.5 # in kite body: if parent > 0: grandparent = parent_map[parent] qparent = xd['q' + str(parent) + str(grandparent)] else: qparent = np.array([0., 0., 0.]) ehat_r = (q - qparent) / vect_op.norm(q - qparent) ehat_t = vect_op.normed_cross(ua, ehat_r) ehat_s = vect_op.normed_cross(ehat_t, ua) # roll angle psi = coeff[1] ehat_l = cas.cos(psi) * ehat_s + cas.sin(psi) * ehat_t ehat_span = cas.cos(psi) * ehat_t - cas.sin(psi) * ehat_s ehat_chord = ua / ua_norm # implicit direct cosine matrix (for plotting only) r = cas.horzcat(ehat_chord, ehat_span, ehat_l) # lift and drag coefficients CL = coeff[0] CD = parameters['theta0', 'aero', 'CD0'] + 0.02 * CL**2 # lift and drag force f_lift = CL * 1. / 2. * rho_infty * cas.mtimes( ua.T, ua) * parameters['theta0', 'geometry', 's_ref'] * ehat_l f_drag = CD * 1. / 2. * rho_infty * ua_norm * parameters['theta0', 'geometry', 's_ref'] * ua f_side = cas.DM(np.zeros((3, 1))) f_aero = f_lift + f_drag m_aero = cas.DM(np.zeros((3, 1))) CA = CD CN = CL CY = cas.DM(0.) aero_coefficients = {} aero_coefficients['CD'] = CD aero_coefficients['CL'] = CL aero_coefficients['CA'] = CA aero_coefficients['CN'] = CN aero_coefficients['CY'] = CY outputs = indicators.collect_kite_aerodynamics_outputs( options, atmos, ua, ua_norm, aero_coefficients, f_aero, f_lift, f_drag, f_side, m_aero, ehat_chord, ehat_span, r, q, n, outputs, parameters) outputs = indicators.collect_environmental_outputs( atmos, wind, q, n, outputs) outputs = indicators.collect_aero_validity_outputs( options, xd, ua, n, parent, outputs, parameters) outputs = indicators.collect_local_performance_outputs( options, atmos, wind, variables, CL, CD, elevation_angle, ua, n, parent, outputs, parameters) outputs = indicators.collect_power_balance_outputs( variables, n, outputs, architecture) return outputs