def initial_guess_actuator_xd(init_options, nlp, formulation, model, V_init): level_siblings = model.architecture.get_all_level_siblings() time_final = init_options['precompute']['time_final'] omega_norm = init_options['precompute']['angular_speed'] tgrid_coll = nlp.time_grids['coll'](time_final) dict = {} dict['a'] = cas.DM(init_options['xd']['a']) dict['asin'] = cas.DM(0.) dict['acos'] = cas.DM(0.) dict['ct'] = 4. * dict['a'] * (1. - dict['a']) dict['bar_varrho'] = cas.DM(1.) var_type = 'xd' for name in struct_op.subkeys(model.variables, var_type): name_stripped, _ = struct_op.split_name_and_node_identifier(name) if 'psi' in name_stripped: V_init = set_azimuth_variables(V_init, init_options, name, model, nlp, tgrid_coll, level_siblings, omega_norm) elif name_stripped in dict.keys(): V_init = tools_init.insert_dict(dict, var_type, name, name_stripped, V_init) return V_init
def initial_guess_actuator_xl(init_options, nlp, formulation, model, V_init): level_siblings = model.architecture.get_all_level_siblings() time_final = init_options['precompute']['time_final'] omega_norm = init_options['precompute']['angular_speed'] tgrid_coll = nlp.time_grids['coll'](time_final) u_hat, v_hat, w_hat = get_local_wind_reference_frame(init_options) uzero_matr = cas.horzcat(u_hat, v_hat, w_hat) uzero_matr_cols = cas.reshape(uzero_matr, (9, 1)) n_rot_hat, y_rot_hat, z_rot_hat = tools_init.get_rotor_reference_frame(init_options) rot_matr = cas.horzcat(n_rot_hat, y_rot_hat, z_rot_hat) rot_matr_cols = cas.reshape(rot_matr, (9, 1)) dict = {} dict['rot_matr'] = rot_matr_cols dict['area'] = cas.DM(1.) dict['cmy'] = cas.DM(0.) dict['cmz'] = cas.DM(0.) dict['uzero_matr'] = uzero_matr_cols dict['g_vec_length'] = cas.DM(1.) dict['n_vec_length'] = cas.DM(1.) dict['z_vec_length'] = cas.DM(1.) dict['u_vec_length'] = cas.DM(1.) dict['varrho'] = cas.DM(1.) dict['qzero'] = cas.DM(1.) dict['gamma'] = get_gamma_angle(init_options) dict['cosgamma'] = np.cos(dict['gamma']) dict['singamma'] = np.sin(dict['gamma']) dict['chi'] = get_chi_angle(init_options, 'xl') dict['coschi'] = np.cos(dict['chi']) dict['sinchi'] = np.sin(dict['chi']) dict['tanhalfchi'] = np.tan(dict['chi'] / 2.) dict['sechalfchi'] = 1. / np.cos(dict['chi'] / 2.) dict['LL'] = cas.DM([0.375, 0., 0., 0., -1., 0., 0., -1., 0.]) dict['corr'] = 1. - init_options['xd']['a'] var_type = 'xl' for name in struct_op.subkeys(model.variables, 'xl'): name_stripped, _ = struct_op.split_name_and_node_identifier(name) if 'psi' in name_stripped: V_init = set_azimuth_variables(V_init, init_options, name, model, nlp, tgrid_coll, level_siblings, omega_norm) elif name_stripped in dict.keys(): V_init = tools_init.insert_dict(dict, var_type, name, name_stripped, V_init) return V_init
def collect_inputs(alpha, beta, airspeed, omega, delta, parameters, named_frame): # delta: # aileron left-right [right teu+, rad], ... positive delta a -> negative roll # elevator [ted+, rad], ... positive delta e -> negative pitch # rudder [tel+, rad]) ... positive delta r -> positive yaw deltaa = delta[0] deltae = delta[1] deltar = delta[2] p, q, r = get_p_q_r(airspeed, omega, parameters, named_frame) inputs = {} inputs['0'] = cas.DM(1.) inputs['alpha'] = alpha inputs['beta'] = beta inputs['p'] = p inputs['q'] = q inputs['r'] = r inputs['deltaa'] = deltaa inputs['deltae'] = deltae inputs['deltar'] = deltar for combi_1 in ['alpha', 'beta']: for combi_2 in ['deltaa', 'deltae', 'deltar']: inputs[combi_1 + '_' + combi_2] = inputs[combi_1] * inputs[combi_2] return inputs
def find_compromised_battery_cost(nlp_numerics_options, V, P, emergency_scenario, model): n_k = nlp_numerics_options['n_k'] if (len(model.architecture.kite_nodes) == 1 or nlp_numerics_options['system_model']['kite_dof'] == 6 or emergency_scenario[0] != 'broken_battery'): compromised_battery_cost = cas.DM(0.0) elif emergency_scenario[0] == 'broken_battery': actuator_len = V['u', 0, 'dcoeff21'].shape[0] broken_actuator = slice(0, actuator_len) broken_kite = emergency_scenario[1] broken_kite_parent = model.architecture.parent_map[broken_kite] compromised_battery_cost = 0.0 for j in range(n_k): broken_str = 'dcoeff' + str(broken_kite) + str(broken_kite_parent) compromised_battery_cost += cas.mtimes( V['u', j, broken_str, broken_actuator].T, V['u', j, broken_str, broken_actuator]) compromised_battery_cost *= 1. / n_k compromised_battery_cost = P[ 'cost', 'compromised_battery'] * compromised_battery_cost return compromised_battery_cost
def summation_check_on_potential_and_kinetic_power(trial, thresh, results): types = ['pot', 'kin'] kin_comp = np.array(trial.visualization.plot_dict['outputs'] ['power_balance_comparison']['kinetic'][0]) pot_comp = np.array(trial.visualization.plot_dict['outputs'] ['power_balance_comparison']['potential'][0]) comp_timeseries = {'pot': pot_comp, 'kin': kin_comp} # extract info tgrid = trial.visualization.plot_dict['time_grids']['ip'] power_balance = trial.visualization.plot_dict['outputs']['power_balance'] for type in types: sum_timeseries = np.zeros(tgrid.shape) for keyname in list(power_balance.keys()): if type in keyname: timeseries = power_balance[keyname][0] sum_timeseries += timeseries difference = cas.DM(sum_timeseries - comp_timeseries[type]) error = float(cas.mtimes(difference.T, difference)) if error > thresh: awelogger.logger.warning( 'some of the power based on ' + type + '. energy must have gotten lost, since a summation check fails. Considering trial ' + trial.name + ' with ' + str(error) + ' > ' + str(thresh)) results['power_summation_check_' + type] = False else: results['power_summation_check_' + type] = True return results
def add_groundstation_mass(options, node_masses, parameters): m_groundstation = parameters['theta0', 'ground_station', 'm_gen'] node_masses['groundstation'] += m_groundstation if not options['ground_station']['in_lag_dyn']: node_masses['groundstation'] = cas.DM(0.) print("node_masses['groundstation']") print(node_masses['groundstation']) return node_masses
def collect_aero_validity_outputs(options, xd, ua, n, parent, outputs, parameters): if 'aero_validity' not in list(outputs.keys()): outputs['aero_validity'] = {} tightness = options['model_bounds']['aero_validity']['scaling'] num_ref = options['model_bounds']['aero_validity']['num_ref'] if 'aerodynamics' not in list(outputs.keys()): outputs['aerodynamics'] = {} alpha = cas.DM(0.) beta = cas.DM(0.) if int(options['kite_dof']) == 6: r = cas.reshape(xd['r' + str(n) + str(parent)], (3, 3)) ehat1 = r[:, 0] # chordwise, froml_e tot_e ehat2 = r[:, 1] # spanwise, fromp_e ton_e ehat3 = r[:, 2] # up alpha = get_alpha(ua, r) beta = get_beta(ua, r) alpha_min = options['aero']['alpha_min_deg']*np.pi/180.0 alpha_max = options['aero']['alpha_max_deg']*np.pi/180.0 beta_min = options['aero']['beta_min_deg']*np.pi/180.0 beta_max = options['aero']['beta_max_deg']*np.pi/180.0 alpha_ub = (cas.mtimes(ua.T, ehat3) - cas.mtimes(ua.T, ehat1) * alpha_max) * tightness / num_ref alpha_lb = (- cas.mtimes(ua.T, ehat3) + cas.mtimes(ua.T, ehat1) * alpha_min) * tightness / num_ref beta_ub = (cas.mtimes(ua.T, ehat2) - cas.mtimes(ua.T, ehat1) * beta_max) * tightness / num_ref beta_lb = (- cas.mtimes(ua.T, ehat2) + cas.mtimes(ua.T, ehat1) * beta_min) * tightness / num_ref outputs['aero_validity']['alpha_ub' + str(n)] = alpha_ub outputs['aero_validity']['alpha_lb' + str(n)] = alpha_lb outputs['aero_validity']['beta_ub' + str(n)] = beta_ub outputs['aero_validity']['beta_lb' + str(n)] = beta_lb outputs['aerodynamics']['alpha' + str(n)] = alpha outputs['aerodynamics']['beta' + str(n)] = beta outputs['aerodynamics']['alpha_deg' + str(n)] = alpha * 180. / np.pi outputs['aerodynamics']['beta_deg' + str(n)] = beta * 180. / np.pi return outputs
def get_temperature(self, zz): params = self.__params.prefix['theta0', 'atmosphere'] options = self.__options if options['model'] == 'isa': t = params['t_ref'] - params['gamma_air'] * zz elif options['model'] == 'windshear': t = params['t_ref'] - params['gamma_air'] * zz elif options['model'] == 'log_wind': t = cas.DM(params['t_ref']) elif options['model'] == 'uniform': t = cas.DM(params['t_ref']) elif options['model'] == 'datafile': t = params['t_ref'] - params['gamma_air'] * zz else: raise ValueError( 'failure: unsupported atmospheric option chosen: %s', options['model']) return t
def get_density(self, zz): params = self.__params.prefix['theta0', 'atmosphere'] options = self.__options if options['model'] == 'isa': t = self.get_temperature(zz) rho = params['rho_ref'] * (t / params['t_ref'])**( params['g'] / params['gamma_air'] / params['r'] - 1.0) elif options['model'] == 'log_wind': rho = cas.DM(params['rho_ref']) elif options['model'] == 'uniform': rho = cas.DM(1.) elif options['model'] == 'datafile': rho = self.get_pressure(zz) / \ params['r'] / self.get_temperature(zz) else: raise ValueError( 'failure: unsupported atmospheric option chosen: %s', options['model']) return rho
def get_pressure(self, zz): params = self.__params.prefix['theta0', 'atmosphere'] options = self.__options if options['model'] == 'isa': p = self.get_density(zz) * \ params['r'] * self.get_temperature(zz) elif options['model'] == 'log_wind': p = cas.DM(params['p_ref']) elif options['model'] == 'uniform': p = cas.DM(params['p_ref']) elif options['model'] == 'datafile': p = cas.DM( params['p_ref'] ) # constant value for now, could be computed with the files.. # raise ValueError('failure: unsupported atmospheric option chosen: %s', options['model']) else: raise ValueError( 'failure: unsupported atmospheric option chosen: %s', options['model']) return p
def get_viscosity(self, zz): params = self.__params.prefix['theta0', 'atmosphere'] options = self.__options if options['model'] == 'isa': mu = params['mu_ref'] * ( params['t_ref'] + params['c_sutherland'] ) / (self.get_temperature(zz) + params['c_sutherland']) * ( self.get_temperature(zz) / params['t_ref'])**(3.0 / 2.0) elif options['model'] == 'log_wind': mu = cas.DM(params['mu_ref']) elif options['model'] == 'uniform': mu = cas.DM(params['mu_ref']) elif options['model'] == 'datafile': mu = params['mu_ref'] * ( params['t_ref'] + params['c_sutherland'] ) / (self.get_temperature(zz) + params['c_sutherland']) * ( self.get_temperature(zz) / params['t_ref'])**(3.0 / 2.0) else: raise ValueError( 'failure: unsupported atmospheric option chosen: %s', options['model']) return mu
def add_groundstation_kinetic(options, parameters, node_masses_si, variables_si, outputs): # = 1/2 i omega_gen^2, with no-slip condition # add mass of first half of main tether, and the mass of wound tether. total_groundstation_mass = node_masses_si['groundstation'] tether_ground_station_mass = cas.DM(0.) if options['tether']['use_wound_tether']: total_groundstation_mass += node_masses_si['m00'] tether_ground_station_mass = node_masses_si['m00'] dq10 = variables_si['xd']['dq10'] q10 = variables_si['xd']['q10'] l_t = variables_si['xd']['l_t'] speed_groundstation = cas.mtimes(dq10.T, q10) / l_t #if (not g_s_in_lagr_dyn) and (use_generator_model) if not options['ground_station']['in_lag_dyn'] and options['generator']['type']: e_kinetic = cas.DM(0.) elif options['ground_station']['in_lag_dyn'] and options['ground_station']['name']: radius_winch = parameters['theta0','ground_station','r_gen'] j_gen = parameters['theta0','ground_station','j_gen'] j_winch = parameters['theta0','ground_station','j_winch'] e_kinetic = 0.5 * (j_gen + j_winch) * speed_groundstation ** 2 * 1/radius_winch**2 e_kinetic += 0.5 * tether_ground_station_mass * speed_groundstation ** 2 else: e_kinetic = 0.25 * total_groundstation_mass * speed_groundstation ** 2. print("e_kinetic") print(e_kinetic) outputs['e_kinetic']['groundstation'] = e_kinetic return outputs
def make_side_plot(ax, vertically_stacked_array, side, plot_color, plot_marker=' ', label=None, alpha=1, linestyle='-'): vsa = np.array(cas.DM(vertically_stacked_array)) if vsa.shape[0] == 3 and (not vsa.shape[1] == 3): vsa = vsa.T if side == 'isometric': ax.plot(vsa[:, 0], vsa[:, 1], zs=vsa[:, 2], color=plot_color, marker=plot_marker, label=label, alpha=alpha, linestyle=linestyle) else: side_num = '' for sdx in side: if sdx == 'x': side_num += '0' elif sdx == 'y': side_num += '1' elif sdx == 'z': side_num += '2' idx = int(side_num[0]) jdx = int(side_num[1]) ax.plot(vsa[:, idx], vsa[:, jdx], color=plot_color, marker=plot_marker, label=label, alpha=alpha, linestyle=linestyle) return None
def var_scaled_to_si(var_type, var_name, var_scaled, scaling): scaling_defined_for_variable = (var_type in scaling.keys()) and ( var_name in scaling[var_type].keys()) if scaling_defined_for_variable: scale = scaling[var_type][var_name] if scale.shape == (1, 1): use_unit_scaling = (scale == cas.DM(1.)) or (scale == 1.) if use_unit_scaling: return var_scaled else: return var_scaled * scale else: matrix_factor = cas.diag(scale) return cas.mtimes(matrix_factor, var_scaled) else: return var_scaled
def guess_values_at_time(t, init_options, model, formulation, tf_guess, ntp_dict): n_min_0 = ntp_dict['n_min_0'] d_min_0 = ntp_dict['d_min_0'] n_min_f = ntp_dict['n_min_f'] d_min_f = ntp_dict['d_min_f'] l_s = model.variable_bounds['theta']['l_s']['lb'] * init_options['theta'][ 'l_s'] l_i = model.variable_bounds['theta']['l_i']['lb'] * init_options['theta'][ 'l_i'] ret = {} for name in struct_op.subkeys(model.variables, 'xd'): ret[name] = 0.0 parent_map = model.architecture.parent_map parent_map[0] = -1 number_of_nodes = model.architecture.number_of_nodes V_0 = formulation.xi_dict['V_pickle_initial'] V_f = formulation.xi_dict['V_pickle_terminal'] q_n = {} q_0 = {} q_f = {} phi_0 = {} phi_f = {} phi_n = {} theta_0 = {} theta_f = {} theta_n = {} dphi_n = {} dtheta_n = {} x_t_0 = {} x_t_f = {} dq_n = {} dl_0 = formulation.xi_dict['V_pickle_initial'][ 'coll_var', n_min_0, d_min_0, 'xd', 'dl_t'] * init_options['xd']['l_t'] l_0 = formulation.xi_dict['V_pickle_initial'][ 'coll_var', n_min_0, d_min_0, 'xd', 'l_t'] * init_options['xd']['l_t'] l_f = formulation.xi_dict['V_pickle_terminal'][ 'coll_var', n_min_f, d_min_f, 'xd', 'l_t'] * init_options['xd']['l_t'] dl_f = formulation.xi_dict['V_pickle_terminal'][ 'coll_var', n_min_f, d_min_f, 'xd', 'dl_t'] * init_options['xd']['l_t'] c1 = (l_f - l_0 - 0.5 * tf_guess * dl_0 - 0.5 * tf_guess * dl_f) / (1. / 6. * tf_guess**3 - 0.25 * tf_guess**3) c2 = (dl_f - dl_0 - 0.5 * tf_guess**2 * c1) / tf_guess c3 = dl_0 c4 = l_0 l_t = 1. / 6. * t**3 * c1 + 0.5 * t**2 * c2 + t * c3 + c4 dl_t = 0.5 * t**2 * c1 + t * c2 + c3 ddl_t = t**2 * c2 + t * c1 q_0['q0-1'] = cas.DM([0.0, 0.0, 0.0]) q_f['q0-1'] = cas.DM([0.0, 0.0, 0.0]) for node in range(1, number_of_nodes): parent = parent_map[node] node_str = 'q' + str(node) + str(parent) q_0[node_str] = V_0['coll_var', n_min_0, d_min_0, 'xd', node_str] q_f[node_str] = V_f['coll_var', n_min_f, d_min_f, 'xd', node_str] for node in range(1, number_of_nodes): parent = parent_map[node] grandparent = parent_map[parent] tether_str = 'q' + str(node) + str(parent) x_t_0[tether_str] = vect_op.normalize( q_0['q' + str(node) + str(parent)] - q_0['q' + str(parent) + str(grandparent)]) x_t_f[tether_str] = vect_op.normalize( q_f['q' + str(node) + str(parent)] - q_f['q' + str(parent) + str(grandparent)]) vec_plus = vect_op.normalize(q_0['q31'] - q_0['q21']) vec_par = vect_op.normalize(x_t_0['q21'] * l_s + 0.5 * (q_0['q31'] - q_0['q21'])) vec_orth = vect_op.normed_cross(vec_par, vec_plus) for node in range(2, number_of_nodes): x_0 = cas.mtimes(vec_par.T, l_s * x_t_0['q' + str(node) + str(parent)]) y_0 = cas.mtimes(vec_plus.T, l_s * x_t_0['q' + str(node) + str(parent)]) z_0 = cas.mtimes(vec_orth.T, l_s * x_t_0['q' + str(node) + str(parent)]) theta_0['q' + str(node) + str(parent)] = np.arcsin(z_0 / l_s) phi_0['q' + str(node) + str(parent)] = np.arctan2(y_0, x_0) x_f = cas.mtimes(vec_par.T, l_s * x_t_f['q' + str(node) + str(parent)]) y_f = cas.mtimes(vec_plus.T, l_s * x_t_f['q' + str(node) + str(parent)]) z_f = cas.mtimes(vec_orth.T, l_s * x_t_f['q' + str(node) + str(parent)]) theta_f['q' + str(node) + str(parent)] = np.arcsin(z_f / l_s) phi_f['q' + str(node) + str(parent)] = np.arctan2(y_f, x_f) for node in range(2, number_of_nodes): parent = parent_map[node] phi_n['q' + str(node) + str(parent)] = phi_0['q' + str(node) + str( parent)] + t / tf_guess * (phi_f['q' + str(node) + str(parent)] - phi_0['q' + str(node) + str(parent)]) dphi_n['q' + str(node) + str(parent)] = 1. / tf_guess * ( phi_f['q' + str(node) + str(parent)] - phi_0['q' + str(node) + str(parent)]) theta_n['q' + str(node) + str(parent)] = theta_0['q' + str(node) + str( parent)] + t / tf_guess * (theta_f['q' + str(node) + str(parent)] - theta_0['q' + str(node) + str(parent)]) dtheta_n['q' + str(node) + str(parent)] = 1. / tf_guess * ( theta_f['q' + str(node) + str(parent)] - theta_0['q' + str(node) + str(parent)]) a = cas.mtimes((q_f['q10'] - q_0['q10']).T, (q_f['q10'] - q_0['q10'])) b = 2 * cas.mtimes(q_0['q10'].T, (q_f['q10'] - q_0['q10'])) c = cas.mtimes(q_0['q10'].T, q_0['q10']) - l_t**2 dc = -2 * l_t * dl_t D = b**2 - 4 * a * c dD = -4 * a * dc x1 = (-b + np.sqrt(D)) / (2 * a) x2 = (-b - np.sqrt(D)) / (2 * a) s = x2 ds = -1. / (2 * a) * 1. / (2 * np.sqrt(D)) * dD e_t = 1. / l_t * (q_0['q10'] + s * (q_f['q10'] - q_0['q10'])) de_t = 1. / l_t * (ds * (q_f['q10'] - q_0['q10'])) - 1. / l_t**2 * dl_t * ( q_0['q10'] + s * (q_f['q10'] - q_0['q10'])) q_n['q10'] = l_t * e_t dq_n['q10'] = dl_t * e_t + l_t * de_t for node in range(2, number_of_nodes): parent = parent_map[node] nstr = 'q' + str(node) + str(parent) q_n[nstr] = q_n['q10'] + ( np.sin(phi_n[nstr]) * np.cos(theta_n[nstr]) * vec_plus + np.cos(phi_n[nstr]) * np.cos(theta_n[nstr]) * vec_par + np.sin(theta_n[nstr]) * vec_orth) * l_s dq_n[nstr] = dq_n['q10'] + ( -np.cos(phi_n[nstr]) * np.sin(theta_n[nstr]) * dtheta_n[nstr] * dphi_n[nstr] * vec_plus + np.sin(phi_n[nstr]) * np.sin(theta_n[nstr]) * dtheta_n[nstr] * dphi_n[nstr] * vec_par + np.cos(theta_n[nstr]) * dtheta_n[nstr] * vec_orth) * l_s for node in range(1, number_of_nodes): parent = parent_map[node] ret['q' + str(node) + str(parent)] = q_n['q' + str(node) + str(parent)] ret['dq' + str(node) + str(parent)] = dq_n['q' + str(node) + str(parent)] ret['l_t'] = l_t ret['dl_t'] = dl_t return ret
def from_control_to_body(vector): rot = cas.diag(cas.DM([-1., 1., -1.])) transformed = cas.mtimes(rot, vector) return transformed
def guess_values_at_time(t, init_options, model, formulation, tf_guess, ntp_dict): n_min = ntp_dict['n_min'] d_min = ntp_dict['d_min'] l_s = model.variable_bounds['theta']['l_s']['lb'] * init_options['theta']['l_s'] l_i = model.variable_bounds['theta']['l_i']['lb'] * init_options['theta']['l_i'] ret = {} for name in struct_op.subkeys(model.variables, 'xd'): ret[name] = 0.0 kite_nodes = model.architecture.kite_nodes parent_map = model.architecture.parent_map parent_map[0] = -1 number_of_nodes = model.architecture.number_of_nodes V_0 = formulation.xi_dict['V_pickle_initial'] q_n = {} q_0 = {} x_t = {} dq_n = {} q_0['q0-1'] = cas.DM([0.0, 0.0, 0.0]) for node in range(1, number_of_nodes): parent = parent_map[node] node_str = 'q' + str(node) + str(parent) q_0[node_str] = V_0['coll_var', n_min, d_min, 'xd', node_str] for node in range(1, number_of_nodes): parent = parent_map[node] grandparent = parent_map[parent] tether_str = 't' + str(node) + str(parent) x_t[tether_str] = vect_op.normalize( q_0['q' + str(node) + str(parent)] - q_0['q' + str(parent) + str(grandparent)]) dl_0 = formulation.xi_dict['V_pickle_initial']['coll_var', n_min, d_min, 'xd', 'dl_t'] * init_options['xd']['l_t'] l_0 = formulation.xi_dict['V_pickle_initial']['coll_var', n_min, d_min, 'xd', 'l_t'] * init_options['xd']['l_t'] l_f = model.variable_bounds['xd']['q10']['lb'][2] / x_t['t10'][2] dl_f = 0 c1 = (l_f - l_0 - 0.5 * tf_guess * dl_0 - 0.5 * tf_guess * dl_f) / (1. / 6. * tf_guess ** 3 - 0.25 * tf_guess ** 3) c2 = (dl_f - dl_0 - 0.5 * tf_guess ** 2 * c1) / tf_guess c3 = dl_0 c4 = l_0 l_t = 1. / 6. * t ** 3 * c1 + 0.5 * t ** 2 * c2 + t * c3 + c4 dl_t = 0.5 * t ** 2 * c1 + t * c2 + c3 ddl_t = t ** 2 * c2 + t * c1 q_n['q0-1'] = cas.DM([0.0, 0.0, 0.0]) for node in range(1, number_of_nodes): parent = parent_map[node] grandparent = parent_map[parent] if node == 1: seg_length = l_t elif node in kite_nodes: seg_length = l_s else: seg_length = l_i q_n['q' + str(node) + str(parent)] = x_t['t' + str(node) + str(parent)] * seg_length + q_n[ 'q' + str(parent) + str(grandparent)] if node == 1: dq_n['dq' + str(node) + str(parent)] = dl_t * x_t['t' + str(node) + str(parent)] else: dq_n['dq' + str(node) + str(parent)] = dq_n['dq10'] for node in range(1, number_of_nodes): parent = parent_map[node] ret['q' + str(node) + str(parent)] = q_n['q' + str(node) + str(parent)] ret['dq' + str(node) + str(parent)] = dq_n['dq' + str(node) + str(parent)] ret['l_t'] = l_t ret['dl_t'] = dl_t # ret['ddl_t'] = ddl_t return ret
def add_groundstation_potential(outputs): # the winch is at ground level e_potential = cas.DM(0.) outputs['e_potential']['groundstation'] = e_potential 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
def guess_wake_gamma_val(init_options): # already scaled! gamma = cas.DM(1.) return gamma
def test(gamma_scale=1.): architecture = archi.Architecture({1: 0}) options = {} options['induction'] = {} options['induction']['vortex_gamma_scale'] = gamma_scale options['induction']['vortex_wake_nodes'] = 2 options['induction']['vortex_far_convection_time'] = 1. options['induction']['vortex_u_ref'] = 1. options['induction']['vortex_position_scale'] = 1. kite = architecture.kite_nodes[0] xd_struct = cas.struct([ cas.entry("wx_" + str(kite) + "_ext_0", shape=(3, 1)), cas.entry("wx_" + str(kite) + "_ext_1", shape=(3, 1)), cas.entry("wx_" + str(kite) + "_int_0", shape=(3, 1)), cas.entry("wx_" + str(kite) + "_int_1", shape=(3, 1)) ]) xl_struct = cas.struct([cas.entry("wg_" + str(kite) + "_0")]) var_struct = cas.struct_symSX( [cas.entry('xd', struct=xd_struct), cas.entry('xl', struct=xl_struct)]) variables = var_struct(0.) variables['xd', 'wx_' + str(kite) + '_ext_0'] = 0.5 * vect_op.yhat_np() variables['xd', 'wx_' + str(kite) + '_int_0'] = -0.5 * vect_op.yhat_np() variables['xd', 'wx_' + str(kite) + '_ext_1'] = variables['xd', 'wx_' + str(kite) + '_ext_0'] + vect_op.xhat_np() variables['xd', 'wx_' + str(kite) + '_int_1'] = variables['xd', 'wx_' + str(kite) + '_int_0'] + vect_op.xhat_np() variables['xl', 'wg_' + str(kite) + '_0'] = 1. / gamma_scale test_list = get_list(options, variables, architecture) filaments = test_list.shape[1] filament_count_test = filaments - 6 if not (filament_count_test == 0): message = 'filament list does not work as expected. difference in number of filaments in test_list = ' + str( filament_count_test) awelogger.logger.error(message) raise Exception(message) LE_expected = cas.DM(np.array([0., -0.5, 0., 0., 0.5, 0., 1.])) PE_expected = cas.DM(np.array([0., 0.5, 0., 1., 0.5, 0., 1.])) TE_expected = cas.DM(np.array([1., -0.5, 0., 0., -0.5, 0., 1.])) expected_filaments = { 'leading edge': LE_expected, 'positive edge': PE_expected, 'trailing edge': TE_expected } for type in expected_filaments.keys(): expected_filament = expected_filaments[type] expected_in_list = expected_filament_in_list(test_list, expected_filament) if not expected_in_list: message = 'filament list does not work as expected. ' + type + \ ' test filament not in test_list.' awelogger.logger.error(message) with np.printoptions(precision=3, suppress=True): print('test_list:') print(np.array(test_list)) raise Exception(message) NE_not_expected = cas.DM(np.array([1., -0.5, 0., 1., 0.5, 0., -1.])) not_expected_filaments = {'negative edge': NE_not_expected} for type in not_expected_filaments.keys(): not_expected_filament = not_expected_filaments[type] is_reasonable = not (expected_filament_in_list(test_list, not_expected_filament)) if not is_reasonable: message = 'filament list does not work as expected. ' + type + \ ' test filament in test_list.' awelogger.logger.error(message) with np.printoptions(precision=3, suppress=True): print('test_list:') print(np.array(test_list)) raise Exception(message) return test_list
def get_winch_cstr(options, atmos, wind, variables_si, parameters, outputs, architecture): cstr_list = mdl_constraint.MdlConstraintList() t_em = cas.DM(0.) if options['generator']['type'] != None and options['generator'][ 'type'] != 'experimental': if not options['tether']['use_wound_tether']: raise ValueError( 'Invalid user_options: use_wound_tether = False, when you use a generator model with ODEs it have to be True' ) if options['ground_station']['in_lag_dyn']: raise ValueError( 'Invalid user_options: in_lag_dyn = True, when you use a generator model with ODEs it have to be False or when you dont want to use the default winch' ) t_em = t_em_ode(options, variables_si, outputs, parameters, architecture) if not options['ground_station']['in_lag_dyn']: radius_winch = parameters['theta0', 'ground_station', 'r_gen'] #not optinal j_gen = parameters['theta0', 'ground_station', 'j_gen'] j_winch = parameters['theta0', 'ground_station', 'j_winch'] f_winch = parameters['theta0', 'ground_station', 'f_winch'] l_t_full = variables_si['theta']['l_t_full'] phi = (l_t_full - variables_si['xd']['l_t']) / radius_winch omega = -variables_si['xd']['dl_t'] / radius_winch domega = -variables_si['xddot']['ddl_t'] / radius_winch t_tether = -variables_si['xa']['lambda10'] * variables_si['xd'][ 'l_t'] * radius_winch t_frict = -f_winch * omega t_inertia = j_winch * domega t_inertia += variables_si['theta'][ 'diam_t']**2 / 4 * np.pi * parameters['theta0', 'tether', 'rho'] * radius_winch**3 * ( omega * omega + domega * phi) # rhs = t_tether + t_em + t_frict lhs = t_inertia omega = variables_si['xd']['dl_t'] / radius_winch domega = variables_si['xddot']['ddl_t'] / radius_winch phi = (l_t_full - variables_si['xd']['l_t']) / radius_winch rhs = (j_gen + j_winch) * variables_si['xddot']['ddl_t'] / radius_winch rhs += variables_si['theta']['diam_t']**2 / 4 * np.pi * parameters[ 'theta0', 'tether', 'rho'] * radius_winch**3 * (-omega * omega + domega * phi) lhs = variables_si['xa']['lambda10'] * variables_si['xd'][ 'l_t'] * radius_winch - t_em if options['generator']['gear_train']['used']: j_gen = parameters['theta0', 'ground_station', 'j_gen'] j_winch = parameters['theta0', 'ground_station', 'j_winch'] #normaly rigid body f_gen = parameters['theta0', 'ground_station', 'f_gen'] k = variables_si['theta']['k_gear'] t_win = j_winch * variables_si['xddot'][ 'ddl_t'] / radius_winch + options['scaling']['theta'][ 'diam_t']**2 / 4 * np.pi * parameters[ 'theta0', 'tether', 'rho'] * radius_winch**3 * ( -omega * omega + domega * phi) # j_gen *= k**2 t_tether = -variables_si['xa']['lambda10'] * variables_si['xd'][ 'l_t'] * radius_winch t_gen = j_gen * variables_si['xddot']['ddl_t'] / radius_winch lhs = -t_gen - t_win rhs = t_tether + k * t_em #+ omega*(f_winch + f_gen*k**2) if options['generator']['gear_train']['used']: k = variables_si['theta']['k_gear'] # dk = variables_si['xddot']['dk_gear'] # dk_ineq = dk # dk_ineq_cstr = cstr_op.Constraint(expr=dk_ineq, name='dk_ineq', cstr_type='eq') # cstr_list.append(dk_ineq_cstr) # len_zstl = 0.1 delta_r = 0.05 rho_zstl = 2700 j_zstl = np.pi * len_zstl * rho_zstl * ( -3 * k * radius_winch**2 * delta_r**2 + 2 * k**2 * delta_r**3 * radius_winch + 2 * delta_r * radius_winch**3 - 1 / 2 * k**3 * delta_r**4) j_gen_zstl = k**3 * j_gen + j_zstl t_tether = variables_si['xa']['lambda10'] * variables_si['xd'][ 'l_t'] * radius_winch t_angular_momentum = (j_gen_zstl + k * j_winch) * domega t_angular_momentum_tether = k * variables_si['theta'][ 'diam_t']**2 / 4 * np.pi * parameters['theta0', 'tether', 'rho'] t_angular_momentum_tether *= radius_winch**3 * (-omega * omega + domega * phi) rhs = t_angular_momentum + t_angular_momentum_tether rhs += omega * (f_winch * k**3) lhs = t_tether * k - k**2 * t_em if options['generator']['type'] == 'pmsm': generator = generator_ode(options, variables_si, outputs, parameters, architecture) cstr_list.append(generator) # sign = variables_si['u']['sign'] # sign_eq = sign**2 - 4*sign + 3 # sign_ineq = -variables_si['u']['v_sq']/(sign) # sign_eq = cstr_op.Constraint(expr=sign_eq, name='sign_eq', cstr_type='eq') # cstr_list.append(sign_eq) # sign_ineq = cstr_op.Constraint(expr=sign_ineq, name='sign_ineq', cstr_type='ineq') # cstr_list.append(sign_ineq) #sign = p_el_sign(options, variables_si, outputs, parameters, architecture) #cstr_list.append(sign) torque = lhs - rhs print("torque") print(torque) winch_cstr = cstr_op.Constraint(expr=torque, name='winch', cstr_type='eq') cstr_list.append(winch_cstr) return cstr_list