def FIM_t(xpdot, b, criterion): ''' computes FIM at a given time. b is the bonary variable which selects or not the time point ''' n_x = 2 n_theta = 4 FIM_sample = np.zeros([n_theta, n_theta]) FIM_0 = cad.inv((((10.0 - 0.001)**2) / 12) * cad.SX.eye(n_theta)) FIM_sample += FIM_0 for i in range(np.shape(xpdot)[0] - 1): xp_r = cad.reshape(xpdot[i + 1], (n_x, n_theta)) # vv = np.zeros([ntheta[0], ntheta[0], 1 + N]) # for i in range(0, 1 + N): FIM_sample += b[i] * xp_r.T @ np.linalg.inv( np.array([[0.01, 0], [0, 0.05]]) ) @ xp_r # + np.linalg.inv(np.array([[0.01, 0, 0, 0], [0, 0.05, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0.2]])) # FIM = solve(FIM1, SX.eye(FIM1.size1())) # [Q, R] = qr(FIM1.expand()) if criterion == 'D_optimal': # objective = -cad.log(cad.det(FIM_sample) + 1e-10) objective = -2 * cad.sum1(cad.log(cad.diag( cad.chol(FIM_sample)))) # by Cholesky factorisation # objective = -cad.log((cad.det(FIM_sample)**2)) # objective = -cad.det(FIM_sample) elif criterion == 'A_optimal': objective = -cad.log(cad.trace(FIM_sample) + 1e-10) return objective
def getWind(): z0 = conf['z0'] zt_roughness = conf['zt_roughness'] zsat = 0.5*(z+C.sqrt(z*z)) wind_x = dae['w0']*C.log((zsat+zt_roughness+2)/zt_roughness)/C.log(z0/zt_roughness) # wind_x = dae['w0'] return wind_x
def plotLogProbVsDistance(): spchar = " " rspace = np.linspace(-0.1, 0.75, num=1000) for theta_val in (theta_low, theta_high): uspace_type = [ -log(1 + exp(-beta[0] - beta[1] * theta_val - beta[2] * rval)) for rval in rspace ] ax3.plot(rspace, uspace_type, color=color_type_map[theta_val], label=f"Utility{spchar}for Type {theta_val}", zorder=-1) low_index = theta.index(theta_low) high_index = theta.index(theta_high) # yvals_inverted = [0 if v==1 else 1 for v in yvals] # gp_inverted = [i for i,v in enumerate(yvals_inverted) if v==1] # xlist_inverted = [ gp_inverted[np.argmin([dist[i][j] for j in gp_inverted])] for i in range(nIndiv)] # r_inverted = [dist[i][xlist_inverted[i]] for i in range(nIndiv)] r_inverted = list(reversed(rvals)) r_inverted_and_not = {1: rvals, 0: r_inverted} utility_inverted_and_not = { inversion: sum([ -log(1 + exp(-beta[0] - beta[1] * theta[ind] - beta[2] * rvals_possibly_inverted[ind])) for ind in range(nIndiv) ]) for inversion, rvals_possibly_inverted in r_inverted_and_not.items() } for inversion, rvals_possibly_inverted in r_inverted_and_not.items(): for ind in reversed(range(nIndiv)): ax3.scatter( rvals_possibly_inverted[ind], [ -log(1 + exp(-beta[0] - beta[1] * theta[ind] - beta[2] * rvals_possibly_inverted[ind])) ], marker="+", c=[facility_color_map[inversion]], s=[facility_size_options[inversion]], label= f"Utility from{spchar}{facility_states[inversion].lower()} facility (Sum: {utility_inverted_and_not[inversion]:.02})", zorder=1) # for ind in range(len(theta)): # ax3.scatter(r_inverted[ind],[1/(1+exp(-beta[0] - beta[1]*theta[ind] - beta[2]*r_inverted[ind]))],marker = "+",c=[facility_color_map[0]],s=[facility_size_options[0]],label=f"Utility from {facility_states[0]} facility") legend_dict = { artist.properties().get('label'): artist for artist in ax3.collections.copy() + ax3.lines.copy() if "no_legend" not in artist.properties().get('label') } # ax3.legend(legend_dict.values(),legend_dict.keys(),loc='upper center', bbox_to_anchor=(0.5, -0.2), ncol=len(legend_dict),fontsize='small') ax3.legend(legend_dict.values(), legend_dict.keys(), loc='best', fontsize='small') ax3.set_xlabel("distance from nearest selected facility") ax3.set_ylabel("$log[P(Success)]$") ax3.set_title("$log[P(success)]$ vs Distance Differs by Type")
def loglikilihood(r, params1, params2, ): running_sum = 0 p_1_tm1 = 1 p_2_tm1 = 0 g_1_tm1 = 1 g_2_tm1 = 1 h_1_tm1 = .25 ** 2 / STEPS h_2_tm1 = .25 ** 2 / STEPS p_1_tm1_agg_1 = .5 p_1_tm1_agg_2 = .5 pm1 = params1 pm2 = params2 p_1, p_2, h_1, h_2 = [], [], [], [] for t in xrange(1, len(r)): r_t = r[t] P_t = get_P_t(pm1.d, pm1.e, r_t) Q_t = get_Q_t(pm2.d, pm2.e, r_t) p_1_t = p_1_t_f(P_t, Q_t, g_1_tm1, p_1_tm1, g_2_tm1) p_2_t = 1 - p_1_t #import pdb; pdb.set_trace() p_1_tm1_agg_1 = p_1_tm1_agg_1_f(pm1.d, pm1.e, pm1.lamb, pm1.gamma, h_1_tm1, p_1_tm1, pm2.d, pm2.e, pm2.lamb, pm2.gamma, h_2_tm1, p_2_tm1) p_1_tm1_agg_2 = 1- p_1_tm1_agg_1 h_tm1_agg_1 = h_tm1_agg_i(p_1_tm1_agg_1, h_1_tm1, h_2_tm1, pm1.lamb, pm1.gamma, pm2.lamb, pm2.gamma) h_tm1_agg_2 = h_tm1_agg_i(p_1_tm1_agg_2, h_1_tm1, h_2_tm1, pm1.lamb, pm1.gamma, pm2.lamb, pm2.gamma) delta_t_agg_1 = delta_t_agg_i(p_1_tm1_agg_1, r_t, pm1.lamb, pm1.gamma, pm2.lamb, pm2.gamma, h_1_tm1, h_2_tm1) delta_t_agg_2 = delta_t_agg_i(p_1_tm1_agg_2, r_t, pm1.lamb, pm1.gamma, pm2.lamb, pm2.gamma, h_1_tm1, h_2_tm1) h_1_t = h_i_t(pm1.omega, pm1.alpha, pm1.beta, pm1.b, pm1.c, pm1.mu, pm1.v, h_tm1_agg_1, delta_t_agg_1) h_2_t = h_i_t(pm2.omega, pm2.alpha, pm2.beta, pm2.b, pm2.c, pm2.mu, pm2.v, h_tm1_agg_2, delta_t_agg_2) #if t % 50 == 1: # import pdb; pdb.set_trace() # print (h_1_tm1 * STEPS)**.5, (h_1_t * STEPS)**.5 f_1_t = f(r_t, h_1_tm1, pm1.lamb, pm1.gamma) f_2_t = f(r_t, h_2_tm1, pm2.lamb, pm2.gamma) #import pdb; pdb.set_trace() running_sum += casadi.log(f_1_t) running_sum += casadi.log(f_2_t) p_1_tm1 = p_1_t p_2_tm1 = p_2_t g_1_tm1 = f_1_t g_2_tm1 = f_2_t h_1_tm1 = h_1_t h_2_tm1 = h_2_t p_1.append(p_1_t) p_2.append(p_2_t) h_1.append(h_1_t) h_2.append(h_2_t) return -running_sum, (p_1, p_2, h_1, h_2)
def getWind(): if conf['wind_model']['name'] == 'wind_shear': # use a logarithmic wind shear model # wind(z) = w0 * log((z+zt)/zt) / log(z0/zt) # where w0 is wind at z0 altitude # zt is surface roughness characteristic length z0 = conf['wind_model']['z0'] zt_roughness = conf['wind_model']['zt_roughness'] return dae['w0']*C.log((-z+zt_roughness)/zt_roughness)/C.log(z0/zt_roughness) elif conf['wind_model']['name'] == 'constant': # constant wind return dae['w0']
def getWind(): if conf['wind_model']['name'] == 'wind_shear': # use a logarithmic wind shear model # wind(z) = w0 * log((z+zt)/zt) / log(z0/zt) # where w0 is wind at z0 altitude # zt is surface roughness characteristic length z0 = conf['wind_model']['z0'] zt_roughness = conf['wind_model']['zt_roughness'] return dae['w0'] * C.log( (-z + zt_roughness) / zt_roughness) / C.log(z0 / zt_roughness) elif conf['wind_model']['name'] == 'constant': # constant wind return dae['w0']
def Model(param, x, args): T = x[:, 0] A, B = param[0], param[1] return exp( A / 8.31446 + B / (8.31446 * T) - (68.2 / 8.31446) * log(T / 298.15)) # Pvp calculation - vectorized
def Cd_profile_2412(alpha, Re_c): # A curve fit I did to a NACA 2412 airfoil in incompressible flow. # Within -2 < alpha < 12 and 10^5 < Re_c < 10^7, has R^2 = 0.9713 print( "Warning: Cd_profile_e216() recommended over Cd_profile_2412(); those are MUCH more accurate fits." ) Re_c = cas.fmax(Re_c, 1) log_Re = cas.log(Re_c) CD0 = -5.249 Re0 = 15.61 Re1 = 15.31 alpha0 = 1.049 alpha1 = -4.715 cx = 0.009528 cxy = -0.00588 cy = 0.04838 log_CD = CD0 + cx * (alpha - alpha0)**2 + cy * (log_Re - Re0)**2 + cxy * ( alpha - alpha1) * (log_Re - Re1 ) # basically, a rotated paraboloid in logspace CD = cas.exp(log_CD) return CD
def mass_hpa_propeller(diameter, max_power, include_variable_pitch_mechanism=False): """ Returns the estimated mass of a propeller assembly for low-disc-loading applications (human powered airplane, paramotor, etc.) :param diameter: diameter of the propeller [m] :param max_power: maximum power of the propeller [W] :param include_variable_pitch_mechanism: boolean, does this propeller have a variable pitch mechanism? :return: estimated weight [kg] """ smoothmax = lambda value1, value2, hardness: cas.log( cas.exp(hardness * value1) + cas.exp(hardness * value2) ) / hardness # soft maximum mass_propeller = ( 0.495 * (diameter / 1.25)**1.6 * smoothmax(0.6, max_power / 14914, hardness=5)**2 ) # Baselining to a 125cm E-Props Top 80 Propeller for paramotor, with some sketchy scaling assumptions # Parameters on diameter exponent and min power were chosen such that Daedalus propeller is roughly on the curve. mass_variable_pitch_mech = 216.8 / 800 * mass_propeller # correlation to Daedalus data: http://journals.sfu.ca/ts/index.php/ts/article/viewFile/760/718 if include_variable_pitch_mechanism: mass_propeller += mass_variable_pitch_mech return mass_propeller
def Cd_cylinder(Re_D, subcritical_only=False): """ Returns the drag coefficient of a cylinder in crossflow as a function of its Reynolds number. :param Re_D: Reynolds number, referenced to diameter :param subcritical_only: Determines whether the model models purely subcritical (Re < 300k) cylinder flows. Useful, since this model is now convex and can be more well-behaved. :return: Drag coefficient """ csigc = 5.5766722118597247 csigh = 23.7460859935990563 csub0 = -0.6989492360435040 csub1 = 1.0465189382830078 csub2 = 0.7044228755898569 csub3 = 0.0846501115443938 csup0 = -0.0823564417206403 csupc = 6.8020230357616764 csuph = 9.9999999999999787 csupscl = -0.4570690347113859 x = cas.log10(Re_D) if subcritical_only: Cd = 10**(csub0 * x + csub1) + csub2 + csub3 * x return Cd else: log10_Cd = ( (cas.log10(10**(csub0 * x + csub1) + csub2 + csub3 * x)) * (1 - 1 / (1 + cas.exp(-csigh * (x - csigc)))) + (csup0 + csupscl / csuph * cas.log(cas.exp(csuph * (csupc - x)) + 1)) * (1 / (1 + cas.exp(-csigh * (x - csigc))))) Cd = 10**log10_Cd return Cd
def __init__(self, state_probabilities, asset_values): self.state_probabilities = state_probabilities self.asset_values = asset_values self.validate() n_states = self.n_states n_assets = self.n_assets self.opti = opti = casadi.Opti() self.expressions = {} p_asset_values = opti.parameter(n_states, n_assets) opti.set_value(p_asset_values, asset_values) p_state_probabilities = opti.parameter(n_states) opti.set_value(p_state_probabilities, state_probabilities) v_coded = opti.variable(n_assets) coded_total = casadi.sum1(v_coded) asset_weights = v_coded / (coded_total + 1) # the rest is cash cash = 1.0 / (coded_total + 1) # 1-sum(weights) state_values = casadi.mtimes(p_asset_values, asset_weights) + cash kelly_criterion = casadi.dot(casadi.log(state_values), p_state_probabilities) opti.minimize(-kelly_criterion) opti.subject_to(v_coded >= 0) opti.set_initial(v_coded, np.ones(n_assets)) opti.solver('ipopt') self.expressions = DS({ name: value for name, value in locals().items() if isinstance(value, casadi.MX) })
def solve_enumerative(): bbax = bax() yvals = np.zeros((nFac), dtype=int) rvals = np.zeros((nIndiv)) uvals = np.full((nIndiv), -np.inf) for ind, gp in enumerate(bbax.bax_gen(nFac, nSelectedFac)): gp = gp.toList() xlist = [ gp[np.argmin([dist[i][j] for j in gp])] for i in range(nIndiv) ] r = [dist[i][xlist[i]] for i in range(nIndiv)] u = [ -log(1 + exp(-beta[0] - beta[1] * theta[i] - beta[2] * r[i])) for i in range(nIndiv) ] if sum(u) > sum(uvals): uvals = u rvals = r yvals = np.zeros((nFac), dtype=int) yvals[gp] = 1 fstar = sum(uvals) prob_success = np.exp(uvals) print(f"Solved enumeratively") return yvals, rvals, uvals, prob_success, fstar
def calc_xs_full_ode(Ex, Ey, e_hat, y_hat, state_compressor): t = cs.SX.sym('t', 1) x_sym = cs.SX.sym('x', sc.nm) y_sym = cs.SX.sym('y', ny) e_sym = cs.SX.sym('e', sc.nr) Ex_sym = cs.SX.sym('Ex', sc.nr, sc.nm) Ey_sym = cs.SX.sym('Ex', sc.nr, Ey.shape[1]) v = e_sym * v_star * (1 + Ex_sym @ cs.log(x_sym / sc.x_star) + Ey @ np.log(y_hat)) v_fun = cs.Function('v', [x_sym, e_sym, Ex_sym], [v]) ode = cs.mtimes(cs.DM(N), v_fun(x_sym, e_sym, Ex_sym)) integrator = cs.integrator( 'full', 'cvodes', { 't': t, 'x': x_sym, 'p': cs.vertcat(e_sym, Ex_sym.reshape((-1, 1))), 'ode': ode, }, { 'tf': 2000, 'regularity_check': True, }) p = np.hstack([e_hat, Ex.reshape((-1, 1), order='F').squeeze()]) xs = np.array(integrator(x0=sc.x_star, p=p)['xf']).flatten() return xs
def getWind(): if 'wind_model' not in conf: return 0 if conf['wind_model']['name'] == 'wind_shear': # use a logarithmic wind shear model # wind(z) = w0 * log((altitude+zt)/zt) / log(z0/zt) # where w0 is wind at z0 altitude # zt is surface roughness characteristic length # altitude is -z - altitude0, where altitude0 is a user parameter z0 = conf['wind_model']['z0'] zt_roughness = conf['wind_model']['zt_roughness'] altitude = -z - conf['wind_model']['altitude0'] return dae['w0']*C.log((altitude+zt_roughness)/zt_roughness)/C.log(z0/zt_roughness) elif conf['wind_model']['name'] in ['constant','hardcoded']: # constant wind return dae['w0']
def get_wind(dae, conf): ''' return the wind at current altitude based on configuration ''' if conf['wind_model']['name'] == 'wind_shear': # use a logarithmic wind shear model # wind(z) = w0 * log((z+zt)/zt) / log(z0/zt) # where w0 is wind at z0 altitude # zt is surface roughness characteristic length z = dae['r_n2b_n_z'] z0 = conf['wind_model']['z0'] zt_roughness = conf['wind_model']['zt_roughness'] return dae['w0']*C.log((-z+zt_roughness)/zt_roughness) / \ C.log(z0/zt_roughness) elif conf['wind_model']['name'] == 'constant': # constant wind return dae['w0']
def solve_casadi(): opti = Opti() x = [[opti.variable() for j in range(nFac)] for i in range(nIndiv)] # nIndiv X nFac y = [opti.variable() for j in range(nFac)] r = [opti.variable() for i in range(nIndiv)] u = [opti.variable() for i in range(nIndiv)] discrete = [] discrete += [False for j in range(nFac) for i in range(nIndiv) ] #x variables - will be binary without integer constraint discrete += [True for j in range(nFac)] #y variables discrete += [False for i in range(nIndiv)] #r variables discrete += [False for i in range(nIndiv)] #u variables opti.minimize(-sum(u)) #maximize sum u opti.subject_to([ u[i] == -log(1 + exp(-beta[0] - beta[1] * theta[i] - beta[2] * r[i])) for i in range(nIndiv) ]) #log prob(success) # opti.subject_to([u[i] == 1/(1+exp(-beta[0] - beta[1]*theta[i] - beta[2]*r[i])) for i in range(nIndiv)]) #prob(success) opti.subject_to([ r[i] >= sum([dist[i, j] * x[i][j] for j in range(nFac)]) for i in range(nIndiv) ]) opti.subject_to([sum(x[i]) == 1 for i in range(nIndiv)]) opti.subject_to( [x[i][j] <= y[j] for i in range(nIndiv) for j in range(nFac)]) opti.subject_to(sum(y) <= nSelectedFac) opti.subject_to([opti.bounded(0, y[j], 1) for j in range(nFac)]) opti.subject_to([ opti.bounded(0, x[i][j], 1) for i in range(nIndiv) for j in range(nFac) ]) p_options = {"discrete": discrete, "expand": True} s_options = {"max_iter": 100, 'tol': 100} opti.solver('bonmin', p_options, s_options) sol = opti.solve() # possibilities for tolerance in s_options (https://web.casadi.org/python-api/): #only 'tol' works... # for key in ['tol','boundTolerance','epsIterRef','terminationTolerance','abstol','opttol']: # try: # s_options = {"max_iter": 100,key: .1} # opti.solver('bonmin',p_options,s_options) # sol = opti.solve() # print(f"NOTE: '{key}' works in s_options!!") # except Exception as e: # print(e) # print(f"NOTE: '{key}' is not a valid s_option!") xvals = np.round( np.array([[sol.value(x[i][j]) for j in range(nFac)] for i in range(nIndiv)])).astype(int) yvals = np.array([sol.value(y[j]) for j in range(nFac)]).astype(int) rvals = np.array([sol.value(r[i]) for i in range(nIndiv)]) uvals = np.array([sol.value(u[i]) for i in range(nIndiv)]) # prob_success = np.array([1/(1+exp(-beta[0] - beta[1]*theta[i] - beta[2]*rvals[i])) for i in range(nIndiv)]) prob_success = np.exp(uvals) fstar = sol.value(opti.f) print(f"Solved using CasADI") return xvals, yvals, rvals, uvals, prob_success, fstar
def get_wind(dae, conf): ''' return the wind at current altitude based on configuration ''' if conf['wind_model']['name'] == 'wind_shear': # use a logarithmic wind shear model # wind(z) = w0 * log((altitude+zt)/zt) / log(z0/zt) # where w0 is wind at z0 altitude # zt is surface roughness characteristic length # altitude is -z - altitude0, where altitude0 is a user parameter z = dae['r_n2b_n_z'] z0 = conf['wind_model']['z0'] zt_roughness = conf['wind_model']['zt_roughness'] altitude = -z - conf['wind_model']['altitude0'] return dae['w0']*C.log((altitude+zt_roughness)/zt_roughness) / \ C.log(z0/zt_roughness) elif conf['wind_model']['name'] == 'constant': # constant wind return dae['w0']
def prod(x, axis: int = None): """ Return the product of array elements over a given axis. See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.prod.html """ if not is_casadi_type(x): return _onp.prod(x, axis=axis) else: return _cas.exp(sum(_cas.log(x), axis=axis))
def SSE_objective(params): """ Given some parameters for the model, what is the "badness" of the corresponding fit. Args: params Returns: A scalar representing the "badness" of the fit. """ y_model = model(x_data, params) if y_model is None: raise TypeError( "model(x, param_guesses) returned None, when it should've returned a 1D ndarray." ) if put_residuals_in_logspace: residuals = cas.log(y_model) - cas.log(y_data) else: residuals = y_model - y_data return cas.sum1(weights * residuals**2)
def getWind(): if 'wind_model' not in conf: return C.veccat([0, 0, 0]) if conf['wind_model']['name'] == 'wind_shear': # use a logarithmic wind shear model # wind(z) = w0 * log((altitude+zt)/zt) / log(z0/zt) # where w0 is wind at z0 altitude # zt is surface roughness characteristic length # altitude is -z - altitude0, where altitude0 is a user parameter z0 = conf['wind_model']['z0'] zt_roughness = conf['wind_model']['zt_roughness'] altitude = -z - conf['wind_model']['altitude0'] wind = dae['w0']*C.log((altitude+zt_roughness)/zt_roughness)/C.log(z0/zt_roughness) dae['wind_at_altitude'] = wind return C.mul([R_g2c, C.veccat([wind, 0, 0])]) elif conf['wind_model']['name'] in ['constant','hardcoded']: # constant wind dae['wind_at_altitude'] = dae['w0'] return C.mul([R_g2c, C.veccat([dae['w0'], 0, 0])]) elif conf['wind_model']['name'] == 'random_walk': dae.addU('delta_wind_x') dae.addU('delta_wind_y') dae.addU('delta_wind_z') wind_x = dae.addX('wind_x') wind_y = dae.addX('wind_y') wind_z = dae.addX('wind_z') dae['wind_at_altitude'] = wind_x return C.veccat([wind_x, wind_y, wind_z])
def sample_parameter_log_normal_distribution_with_sobol( mean, covariance, n_samples=1): """Sample parameter using Sobol sampling with a log-normal distribution. :param mean: :param covariance: :param n_samples: :return: """ if isinstance(mean, list): mean = vertcat(*mean) mean_log = log(mean) log_samples = sample_parameter_normal_distribution_with_sobol( mean_log, covariance, n_samples) samples = exp(log_samples) return samples
def smoothmax(value1, value2, hardness): """ A smooth maximum between two functions. Useful because it's differentiable and convex! Great writeup by John D Cook here: https://www.johndcook.com/soft_maximum.pdf :param value1: Value of function 1. :param value2: Value of function 2. :param hardness: Hardness parameter. Higher values make this closer to max(x1, x2). :return: Soft maximum of the two supplied values. """ value1 = value1 * hardness value2 = value2 * hardness max = cas.fmax(value1, value2) min = cas.fmin(value1, value2) out = max + cas.log(1 + cas.exp(min - max)) out /= hardness return out
def _process_expr(expr, var_dict): if expr.is_constant(): return expr.value from pyomo.core.base.var import _GeneralVarData if isinstance(expr, _GeneralVarData): # create a new CasADi variable if one doesn't already exist pyo_var, cas_var = var_dict.get(expr.local_name, (expr, None)) if cas_var is None: cas_var = SX.sym(expr.local_name) var_dict[pyo_var.local_name] = (pyo_var, cas_var) return cas_var from pyomo.core.base.expr import _SumExpression, _ProductExpression, _PowExpression, _IntrinsicFunctionExpression if isinstance(expr, _SumExpression): return sum( _process_expr(expr._args[i], var_dict) * expr._coef[i] for i in range(len(expr._args))) + expr._const if isinstance(expr, _ProductExpression): prod = expr._coef for num in expr._numerator: prod *= _process_expr(num, var_dict) for denom in expr._denominator: prod /= _process_expr(denom, var_dict) return prod if isinstance(expr, _PowExpression): return _process_expr(expr._args[0], var_dict)**_process_expr(expr._args[1], var_dict) if isinstance(expr, _IntrinsicFunctionExpression): if expr._name == 'log': return casadi.log(_process_expr(expr._args[0], var_dict)) if expr._name == 'exp': return casadi.exp(_process_expr(expr._args[0], var_dict)) if expr._name == 'sqrt': return casadi.sqrt(_process_expr(expr._args[0], var_dict)) # else: (We don't recognize the function) raise NotImplementedError('Unrecognized function: ' + expr._name) # else: (We don't recognize the expression) raise NotImplementedError('Unrecognized expression: ' + str(expr))
def h_ISA(p): """Compute ISA altitude for a given pressure. Args: p (float or ndarray): Pressure (in Pa). Returns: float or ndarray: altitude (m). """ # Lower altitude regions if p >= 22630: T = T0 * (p0 / p)**((-0.0065 * R) / g0) h = (T - T0) / -0.0065 elif p < 22630 and p >= 5470: T1 = T0 - 0.0065 * (11000) p1 = 22630 h = -R * T1 / g0 * ca.log(p / p1) + 11000 else: raise ValueError( "The given pressure is too low, you are above 20 kilometers altitude" ) return h
def _convert(self, symbol, t, y, y_dot, inputs): """ See :meth:`CasadiConverter.convert()`. """ if isinstance( symbol, ( pybamm.Scalar, pybamm.Array, pybamm.Time, pybamm.InputParameter, pybamm.ExternalVariable, ), ): return casadi.MX(symbol.evaluate(t, y, y_dot, inputs)) elif isinstance(symbol, pybamm.StateVector): if y is None: raise ValueError("Must provide a 'y' for converting state vectors") return casadi.vertcat(*[y[y_slice] for y_slice in symbol.y_slices]) elif isinstance(symbol, pybamm.StateVectorDot): if y_dot is None: raise ValueError("Must provide a 'y_dot' for converting state vectors") return casadi.vertcat(*[y_dot[y_slice] for y_slice in symbol.y_slices]) elif isinstance(symbol, pybamm.BinaryOperator): left, right = symbol.children # process children converted_left = self.convert(left, t, y, y_dot, inputs) converted_right = self.convert(right, t, y, y_dot, inputs) if isinstance(symbol, pybamm.Minimum): return casadi.fmin(converted_left, converted_right) if isinstance(symbol, pybamm.Maximum): return casadi.fmax(converted_left, converted_right) # _binary_evaluate defined in derived classes for specific rules return symbol._binary_evaluate(converted_left, converted_right) elif isinstance(symbol, pybamm.UnaryOperator): converted_child = self.convert(symbol.child, t, y, y_dot, inputs) if isinstance(symbol, pybamm.AbsoluteValue): return casadi.fabs(converted_child) return symbol._unary_evaluate(converted_child) elif isinstance(symbol, pybamm.Function): converted_children = [ self.convert(child, t, y, y_dot, inputs) for child in symbol.children ] # Special functions if symbol.function == np.min: return casadi.mmin(*converted_children) elif symbol.function == np.max: return casadi.mmax(*converted_children) elif symbol.function == np.abs: return casadi.fabs(*converted_children) elif symbol.function == np.sqrt: return casadi.sqrt(*converted_children) elif symbol.function == np.sin: return casadi.sin(*converted_children) elif symbol.function == np.arcsinh: return casadi.arcsinh(*converted_children) elif symbol.function == np.arccosh: return casadi.arccosh(*converted_children) elif symbol.function == np.tanh: return casadi.tanh(*converted_children) elif symbol.function == np.cosh: return casadi.cosh(*converted_children) elif symbol.function == np.sinh: return casadi.sinh(*converted_children) elif symbol.function == np.cos: return casadi.cos(*converted_children) elif symbol.function == np.exp: return casadi.exp(*converted_children) elif symbol.function == np.log: return casadi.log(*converted_children) elif symbol.function == np.sign: return casadi.sign(*converted_children) elif isinstance(symbol.function, (PchipInterpolator, CubicSpline)): return casadi.interpolant("LUT", "bspline", [symbol.x], symbol.y)( *converted_children ) elif symbol.function.__name__.startswith("elementwise_grad_of_"): differentiating_child_idx = int(symbol.function.__name__[-1]) # Create dummy symbolic variables in order to differentiate using CasADi dummy_vars = [ casadi.MX.sym("y_" + str(i)) for i in range(len(converted_children)) ] func_diff = casadi.gradient( symbol.differentiated_function(*dummy_vars), dummy_vars[differentiating_child_idx], ) # Create function and evaluate it using the children casadi_func_diff = casadi.Function("func_diff", dummy_vars, [func_diff]) return casadi_func_diff(*converted_children) # Other functions else: return symbol._function_evaluate(converted_children) elif isinstance(symbol, pybamm.Concatenation): converted_children = [ self.convert(child, t, y, y_dot, inputs) for child in symbol.children ] if isinstance(symbol, (pybamm.NumpyConcatenation, pybamm.SparseStack)): return casadi.vertcat(*converted_children) # DomainConcatenation specifies a particular ordering for the concatenation, # which we must follow elif isinstance(symbol, pybamm.DomainConcatenation): slice_starts = [] all_child_vectors = [] for i in range(symbol.secondary_dimensions_npts): child_vectors = [] for child_var, slices in zip( converted_children, symbol._children_slices ): for child_dom, child_slice in slices.items(): slice_starts.append(symbol._slices[child_dom][i].start) child_vectors.append( child_var[child_slice[i].start : child_slice[i].stop] ) all_child_vectors.extend( [v for _, v in sorted(zip(slice_starts, child_vectors))] ) return casadi.vertcat(*all_child_vectors) else: raise TypeError( """ Cannot convert symbol of type '{}' to CasADi. Symbols must all be 'linear algebra' at this stage. """.format( type(symbol) ) )
def setupModel(dae, conf): # PARAMETERS OF THE KITE : # ############## m = conf['mass'] # mass of the kite # [ kg ] # PHYSICAL CONSTANTS : # ############## g = conf['g'] # gravitational constant # [ m /s^2] # PARAMETERS OF THE CABLE : # ############## #INERTIA MATRIX (Kurt's direct measurements) j1 = conf['j1'] j31 = conf['j31'] j2 = conf['j2'] j3 = conf['j3'] #Carousel Friction & inertia jCarousel = conf['jCarousel'] cfric = conf['cfric'] zt = conf['zt'] rA = conf['rArm'] ########### model integ ################### e11 = dae['e11'] e12 = dae['e12'] e13 = dae['e13'] e21 = dae['e21'] e22 = dae['e22'] e23 = dae['e23'] e31 = dae['e31'] e32 = dae['e32'] e33 = dae['e33'] x = dae['x'] y = dae['y'] z = dae['z'] dx = dae['dx'] dy = dae['dy'] dz = dae['dz'] w1 = dae['w1'] w2 = dae['w2'] w3 = dae['w3'] ddelta = dae['ddelta'] r = dae['r'] dr = dae['dr'] ddr = dae['ddr'] tc = dae['motor_torque'] #Carousel motor torque # wind if 'w0' in dae: z0 = conf['z0'] zt_roughness = conf['zt_roughness'] zsat = 0.5*(z+C.sqrt(z*z)) wind_x = dae['w0']*C.log((zsat+zt_roughness+2)/zt_roughness)/C.log(z0/zt_roughness) else: wind_x = 0 dae['wind at altitude'] = wind_x dp_carousel_frame = C.veccat( [ dx - ddelta*y , dy + ddelta*(rA + x) , dz ]) - C.veccat([dae['cos_delta']*wind_x, dae['sin_delta']*wind_x, 0]) R_c2b = C.veccat( [dae[n] for n in ['e11', 'e12', 'e13', 'e21', 'e22', 'e23', 'e31', 'e32', 'e33']] ).reshape((3,3)) # Aircraft velocity w.r.t. inertial frame, given in its own reference frame # (needed to compute the aero forces and torques !) dpE = C.mul( R_c2b, dp_carousel_frame ) (f1, f2, f3, t1, t2, t3) = aeroForcesTorques(dae, conf, dp_carousel_frame, dpE, (dae['w1'], dae['w2'], dae['w3']), (dae['e21'], dae['e22'], dae['e23']), (dae['aileron'],dae['elevator']) ) # mass matrix mm = C.SXMatrix(8, 8) mm[0,0] = jCarousel + m*rA*rA + m*x*x + m*y*y + 2*m*rA*x mm[0,1] = -m*y mm[0,2] = m*(rA + x) mm[0,3] = 0 mm[0,4] = 0 mm[0,5] = 0 mm[0,6] = 0 mm[0,7] = 0 mm[1,0] = -m*y mm[1,1] = m mm[1,2] = 0 mm[1,3] = 0 mm[1,4] = 0 mm[1,5] = 0 mm[1,6] = 0 mm[1,7] = x + zt*e31 mm[2,0] = m*(rA + x) mm[2,1] = 0 mm[2,2] = m mm[2,3] = 0 mm[2,4] = 0 mm[2,5] = 0 mm[2,6] = 0 mm[2,7] = y + zt*e32 mm[3,0] = 0 mm[3,1] = 0 mm[3,2] = 0 mm[3,3] = m mm[3,4] = 0 mm[3,5] = 0 mm[3,6] = 0 mm[3,7] = z + zt*e33 mm[4,0] = 0 mm[4,1] = 0 mm[4,2] = 0 mm[4,3] = 0 mm[4,4] = j1 mm[4,5] = 0 mm[4,6] = j31 mm[4,7] = -zt*(e21*x + e22*y + e23*z + zt*e21*e31 + zt*e22*e32 + zt*e23*e33) mm[5,0] = 0 mm[5,1] = 0 mm[5,2] = 0 mm[5,3] = 0 mm[5,4] = 0 mm[5,5] = j2 mm[5,6] = 0 mm[5,7] = zt*(e11*x + e12*y + e13*z + zt*e11*e31 + zt*e12*e32 + zt*e13*e33) mm[6,0] = 0 mm[6,1] = 0 mm[6,2] = 0 mm[6,3] = 0 mm[6,4] = j31 mm[6,5] = 0 mm[6,6] = j3 mm[6,7] = 0 mm[7,0] = -zt*(e11*e23*x - e13*e21*x + e12*e23*y - e13*e22*y + zt*e11*e23*e31 - zt*e13*e21*e31 + zt*e12*e23*e32 - zt*e13*e22*e32) mm[7,1] = x + zt*e31 mm[7,2] = y + zt*e32 mm[7,3] = z + zt*e33 mm[7,4] = -zt*(e21*x + e22*y + e23*z + zt*e21*e31 + zt*e22*e32 + zt*e23*e33) mm[7,5] = zt*(e11*x + e12*y + e13*z + zt*e11*e31 + zt*e12*e32 + zt*e13*e33) mm[7,6] = 0 mm[7,7] = 0 # right hand side zt2 = zt*zt rhs = C.veccat( [ tc - cfric*ddelta - f1*y + f2*(rA + x) + dy*m*(dx - 2*ddelta*y) - dx*m*(dy + 2*ddelta*rA + 2*ddelta*x) , f1 + ddelta*m*(dy + ddelta*rA + ddelta*x) + ddelta*dy*m , f2 - ddelta*m*(dx - ddelta*y) - ddelta*dx*m , f3 - g*m , t1 - w2*(j3*w3 + j31*w1) + j2*w2*w3 , t2 + w1*(j3*w3 + j31*w1) - w3*(j1*w1 + j31*w3) , t3 + w2*(j1*w1 + j31*w3) - j2*w1*w2 , ddr*r-(zt*w1*(e11*x+e12*y+e13*z+zt*e11*e31+zt*e12*e32+zt*e13*e33)+zt*w2*(e21*x+e22*y+e23*z+zt*e21*e31+zt*e22*e32+zt*e23*e33))*(w3-ddelta*e33)-dx*(dx-zt*e21*(w1-ddelta*e13)+zt*e11*(w2-ddelta*e23))-dy*(dy-zt*e22*(w1-ddelta*e13)+zt*e12*(w2-ddelta*e23))-dz*(dz-zt*e23*(w1-ddelta*e13)+zt*e13*(w2-ddelta*e23))+dr*dr+(w1-ddelta*e13)*(e21*(zt*dx-zt2*e21*(w1-ddelta*e13)+zt2*e11*(w2-ddelta*e23))+e22*(zt*dy-zt2*e22*(w1-ddelta*e13)+zt2*e12*(w2-ddelta*e23))+zt*e23*(dz+zt*e13*w2-zt*e23*w1)+zt*e33*(w1*z+zt*e33*w1+ddelta*e11*x+ddelta*e12*y+zt*ddelta*e11*e31+zt*ddelta*e12*e32)+zt*e31*(x+zt*e31)*(w1-ddelta*e13)+zt*e32*(y+zt*e32)*(w1-ddelta*e13))-(w2-ddelta*e23)*(e11*(zt*dx-zt2*e21*(w1-ddelta*e13)+zt2*e11*(w2-ddelta*e23))+e12*(zt*dy-zt2*e22*(w1-ddelta*e13)+zt2*e12*(w2-ddelta*e23))+zt*e13*(dz+zt*e13*w2-zt*e23*w1)-zt*e33*(w2*z+zt*e33*w2+ddelta*e21*x+ddelta*e22*y+zt*ddelta*e21*e31+zt*ddelta*e22*e32)-zt*e31*(x+zt*e31)*(w2-ddelta*e23)-zt*e32*(y+zt*e32)*(w2-ddelta*e23)) ] ) dRexp = C.SXMatrix(3,3) dRexp[0,0] = e21*(w3 - ddelta*e33) - e31*(w2 - ddelta*e23) dRexp[0,1] = e31*(w1 - ddelta*e13) - e11*(w3 - ddelta*e33) dRexp[0,2] = e11*(w2 - ddelta*e23) - e21*(w1 - ddelta*e13) dRexp[1,0] = e22*(w3 - ddelta*e33) - e32*(w2 - ddelta*e23) dRexp[1,1] = e32*(w1 - ddelta*e13) - e12*(w3 - ddelta*e33) dRexp[1,2] = e12*(w2 - ddelta*e23) - e22*(w1 - ddelta*e13) dRexp[2,0] = e23*w3 - e33*w2 dRexp[2,1] = e33*w1 - e13*w3 dRexp[2,2] = e13*w2 - e23*w1 c =(x + zt*e31)**2/2 + (y + zt*e32)**2/2 + (z + zt*e33)**2/2 - r**2/2 cdot =dx*(x + zt*e31) + dy*(y + zt*e32) + dz*(z + zt*e33) + zt*(w2 - ddelta*e23)*(e11*x + e12*y + e13*z + zt*e11*e31 + zt*e12*e32 + zt*e13*e33) - zt*(w1 - ddelta*e13)*(e21*x + e22*y + e23*z + zt*e21*e31 + zt*e22*e32 + zt*e23*e33) - r*dr # ddx = dae['ddx'] # ddy = dae['ddy'] # ddz = dae['ddz'] # dw1 = dae['dw1'] # dw2 = dae['dw2'] # dddelta = dae['dddelta'] ddx = dae.ddt('dx') ddy = dae.ddt('dy') ddz = dae.ddt('dz') dw1 = dae.ddt('w1') dw2 = dae.ddt('w2') dddelta = dae.ddt('ddelta') cddot = -(w1-ddelta*e13)*(zt*e23*(dz+zt*e13*w2-zt*e23*w1)+zt*e33*(w1*z+zt*e33*w1+ddelta*e11*x+ddelta*e12*y+zt*ddelta*e11*e31+zt*ddelta*e12*e32)+zt*e21*(dx+zt*e11*w2-zt*e21*w1-zt*ddelta*e11*e23+zt*ddelta*e13*e21)+zt*e22*(dy+zt*e12*w2-zt*e22*w1-zt*ddelta*e12*e23+zt*ddelta*e13*e22)+zt*e31*(x+zt*e31)*(w1-ddelta*e13)+zt*e32*(y+zt*e32)*(w1-ddelta*e13))+(w2-ddelta*e23)*(zt*e13*(dz+zt*e13*w2-zt*e23*w1)-zt*e33*(w2*z+zt*e33*w2+ddelta*e21*x+ddelta*e22*y+zt*ddelta*e21*e31+zt*ddelta*e22*e32)+zt*e11*(dx+zt*e11*w2-zt*e21*w1-zt*ddelta*e11*e23+zt*ddelta*e13*e21)+zt*e12*(dy+zt*e12*w2-zt*e22*w1-zt*ddelta*e12*e23+zt*ddelta*e13*e22)-zt*e31*(x+zt*e31)*(w2-ddelta*e23)-zt*e32*(y+zt*e32)*(w2-ddelta*e23))-ddr*r+(zt*w1*(e11*x+e12*y+e13*z+zt*e11*e31+zt*e12*e32+zt*e13*e33)+zt*w2*(e21*x+e22*y+e23*z+zt*e21*e31+zt*e22*e32+zt*e23*e33))*(w3-ddelta*e33)+dx*(dx+zt*e11*w2-zt*e21*w1-zt*ddelta*e11*e23+zt*ddelta*e13*e21)+dy*(dy+zt*e12*w2-zt*e22*w1-zt*ddelta*e12*e23+zt*ddelta*e13*e22)+dz*(dz+zt*e13*w2-zt*e23*w1)+ddx*(x+zt*e31)+ddy*(y+zt*e32)+ddz*(z+zt*e33)-dr*dr+zt*(dw2-dddelta*e23)*(e11*x+e12*y+e13*z+zt*e11*e31+zt*e12*e32+zt*e13*e33)-zt*(dw1-dddelta*e13)*(e21*x+e22*y+e23*z+zt*e21*e31+zt*e22*e32+zt*e23*e33)-zt*dddelta*(e11*e23*x-e13*e21*x+e12*e23*y-e13*e22*y+zt*e11*e23*e31-zt*e13*e21*e31+zt*e12*e23*e32-zt*e13*e22*e32) # cddot = (zt*w1*(e11*x + e12*y + e13*z + zt*e11*e31 + zt*e12*e32 + zt*e13*e33) + zt*w2*(e21*x + e22*y + e23*z + zt*e21*e31 + zt*e22*e32 + zt*e23*e33))*(w3 - ddelta*e33) + dx*(dx + zt*e11*w2 - zt*e21*w1 - zt*ddelta*e11*e23 + zt*ddelta*e13*e21) + dy*(dy + zt*e12*w2 - zt*e22*w1 - zt*ddelta*e12*e23 + zt*ddelta*e13*e22) + dz*(dz + zt*e13*w2 - zt*e23*w1) + ddx*(x + zt*e31) + ddy*(y + zt*e32) + ddz*(z + zt*e33) - (w1 - ddelta*e13)*(e21*(zt*dx - zt**2*e21*(w1 - ddelta*e13) + zt**2*e11*(w2 - ddelta*e23)) + e22*(zt*dy - zt**2*e22*(w1 - ddelta*e13) + zt**2*e12*(w2 - ddelta*e23)) + zt*e33*(z*w1 + ddelta*e11*x + ddelta*e12*y + zt*e33*w1 + zt*ddelta*e11*e31 + zt*ddelta*e12*e32) + zt*e23*(dz + zt*e13*w2 - zt*e23*w1) + zt*e31*(w1 - ddelta*e13)*(x + zt*e31) + zt*e32*(w1 - ddelta*e13)*(y + zt*e32)) + (w2 - ddelta*e23)*(e11*(zt*dx - zt**2*e21*(w1 - ddelta*e13) + zt**2*e11*(w2 - ddelta*e23)) + e12*(zt*dy - zt**2*e22*(w1 - ddelta*e13) + zt**2*e12*(w2 - ddelta*e23)) - zt*e33*(z*w2 + ddelta*e21*x + ddelta*e22*y + zt*e33*w2 + zt*ddelta*e21*e31 + zt*ddelta*e22*e32) + zt*e13*(dz + zt*e13*w2 - zt*e23*w1) - zt*e31*(w2 - ddelta*e23)*(x + zt*e31) - zt*e32*(w2 - ddelta*e23)*(y + zt*e32)) + zt*(dw2 - dddelta*e23)*(e11*x + e12*y + e13*z + zt*e11*e31 + zt*e12*e32 + zt*e13*e33) - zt*(dw1 - dddelta*e13)*(e21*x + e22*y + e23*z + zt*e21*e31 + zt*e22*e32 + zt*e23*e33) - zt*dddelta*(e11*e23*x - e13*e21*x + e12*e23*y - e13*e22*y + zt*e11*e23*e31 - zt*e13*e21*e31 + zt*e12*e23*e32 - zt*e13*e22*e32) # where # dw1 = dw @> 0 # dw2 = dw @> 1 # {- # dw3 = dw @> 2 # -} # ddx = ddX @> 0 # ddy = ddX @> 1 # ddz = ddX @> 2 # dddelta = dddelta' @> 0 dae['c'] = c dae['cdot'] = cdot dae['cddot'] = cddot return (mm, rhs, dRexp)
FIM1_maxeigv = [] for i in range(np.shape(xp_opt)[1] - 1): xp_r = np.reshape(xp_opt[:, i + 1], (2, 4)) # vv = np.zeros([ntheta[0], ntheta[0], 1 + N]) # for i in range(0, 1 + N): FIM_t += [xp_r.T @ np.linalg.inv(np.array([[0.01, 0], [0, 0.05]])) @ xp_r] obsFIM = [] for i in range(np.shape(FIM_t)[0]): obsFIM += [ np.linalg.inv((((10.0 - 0.001)**2) / 12) * np.identity(n_theta)) + sum(FIM_t[:i + 1]) ] for i in range(np.shape(xp_opt)[1] - 1): FIM1_det += [2 * cad.sum1(cad.log(cad.diag(cad.chol(obsFIM[i]))))] FIM1_trace += [cad.trace(obsFIM[i])] FIM_det += [2 * np.sum(np.log(np.diag(np.linalg.cholesky(obsFIM[i]))))] FIM_trace += [np.trace(obsFIM[i])] FIM1_mineigv += [min(np.linalg.eig(obsFIM[i])[0])] FIM1_maxeigv += [max(np.linalg.eig(obsFIM[i])[0])] V_theta = np.linalg.inv(sum(FIM_t[i] for i in range(len(FIM_t)))) theta1 = w_opt[n_x + n_x * n_theta:n_x + n_x * n_theta + n_theta] t_value = np.zeros(n_theta) for i in range(n_theta): t_value[i] = theta1[i] / np.sqrt(V_theta[i, i]) FIM1_trace_array = np.array(FIM1_trace) FIM1_det_array = np.array(FIM1_det)
#################################################################################################### # SET UP MODEL #################################################################################################### #define input and parameters x = cs.SX.sym('x', 1) xnames = ['Light'] p = cs.SX.sym('p', 5) pnames = ['alpha0', 'alpha', 'n', 'K', 'gamma'] #define steady state gfp_mean = cs.exp(p[0]) + cs.exp(p[1]) * x[0]**cs.exp( p[2]) / (cs.exp(p[3])**cs.exp(p[2]) + x[0]**cs.exp(p[2])) gfp_var = cs.exp(p[4]) * gfp_mean geo_mean = cs.log(gfp_mean**2 / cs.sqrt(gfp_mean**2 + gfp_var)) geo_var = cs.log(1 + gfp_var / gfp_mean**2) #geo_mean = 2/3 * cs.log(gfp_mean) - 1/2 * cs.log(cs.exp(p[4]) + gfp_mean) #2 * cs.log(gfp_mean) - 1/2 * cs.log(p[4]*gfp_mean + gfp_mean**2) #geo_var = cs.log(cs.exp(p[4]) + gfp_mean) - cs.log(gfp_mean) #link the deterministic model to the sampling statistics (here normal mean and variance) lognorm_stats = cs.vertcat(geo_mean, geo_var) #create a casadi function mapping input and parameters to sampling statistics (mean and var) y = cs.Function('GFP', [x, p], [lognorm_stats]) # enter the function as a tuple with label indicating normal error, into observation list observ_list = [(y, 'Lognormal')] #instantiate nloed model class
def setupModel(dae, conf): # PARAMETERS OF THE KITE : # ############## m = conf["kite"]["mass"] # mass of the kite # [ kg ] # PHYSICAL CONSTANTS : # ############## g = conf["env"]["g"] # gravitational constant # [ m /s^2] # PARAMETERS OF THE CABLE : # ############## # INERTIA MATRIX (Kurt's direct measurements) j1 = conf["kite"]["j1"] j31 = conf["kite"]["j31"] j2 = conf["kite"]["j2"] j3 = conf["kite"]["j3"] # Carousel Friction & inertia jCarousel = conf["carousel"]["jCarousel"] cfric = conf["carousel"]["cfric"] zt = conf["kite"]["zt"] rA = conf["carousel"]["rArm"] ########### model integ ################### e11 = dae.x("e11") e12 = dae.x("e12") e13 = dae.x("e13") e21 = dae.x("e21") e22 = dae.x("e22") e23 = dae.x("e23") e31 = dae.x("e31") e32 = dae.x("e32") e33 = dae.x("e33") x = dae.x("x") y = dae.x("y") z = dae.x("z") dx = dae.x("dx") dy = dae.x("dy") dz = dae.x("dz") w1 = dae.x("w1") w2 = dae.x("w2") w3 = dae.x("w3") delta = 0 ddelta = 0 r = dae.x("r") dr = dae.x("dr") ddr = dae.u("ddr") # wind z0 = conf["wind shear"]["z0"] zt_roughness = conf["wind shear"]["zt_roughness"] zsat = 0.5 * (z + C.sqrt(z * z)) wind_x = dae.p("w0") * C.log((zsat + zt_roughness + 2) / zt_roughness) / C.log(z0 / zt_roughness) dae.addOutput("wind at altitude", wind_x) dae.addOutput("w0", dae.p("w0")) dp_carousel_frame = C.veccat([dx - ddelta * y, dy + ddelta * (rA + x), dz]) - C.veccat( [C.cos(delta) * wind_x, C.sin(delta) * wind_x, 0] ) R_c2b = C.veccat(dae.x(["e11", "e12", "e13", "e21", "e22", "e23", "e31", "e32", "e33"])).reshape((3, 3)) # Aircraft velocity w.r.t. inertial frame, given in its own reference frame # (needed to compute the aero forces and torques !) dpE = C.mul(R_c2b, dp_carousel_frame) (f1, f2, f3, t1, t2, t3) = aeroForcesTorques( dae, conf, dp_carousel_frame, dpE, dae.x(("w1", "w2", "w3")), dae.x(("e21", "e22", "e23")), dae.u(("aileron", "elevator")), ) # mass matrix mm = C.SXMatrix(7, 7) mm[0, 0] = m mm[0, 1] = 0 mm[0, 2] = 0 mm[0, 3] = 0 mm[0, 4] = 0 mm[0, 5] = 0 mm[0, 6] = x + zt * e31 mm[1, 0] = 0 mm[1, 1] = m mm[1, 2] = 0 mm[1, 3] = 0 mm[1, 4] = 0 mm[1, 5] = 0 mm[1, 6] = y + zt * e32 mm[2, 0] = 0 mm[2, 1] = 0 mm[2, 2] = m mm[2, 3] = 0 mm[2, 4] = 0 mm[2, 5] = 0 mm[2, 6] = z + zt * e33 mm[3, 0] = 0 mm[3, 1] = 0 mm[3, 2] = 0 mm[3, 3] = j1 mm[3, 4] = 0 mm[3, 5] = j31 mm[3, 6] = -zt * (e21 * x + e22 * y + e23 * z + zt * e21 * e31 + zt * e22 * e32 + zt * e23 * e33) mm[4, 0] = 0 mm[4, 1] = 0 mm[4, 2] = 0 mm[4, 3] = 0 mm[4, 4] = j2 mm[4, 5] = 0 mm[4, 6] = zt * (e11 * x + e12 * y + e13 * z + zt * e11 * e31 + zt * e12 * e32 + zt * e13 * e33) mm[5, 0] = 0 mm[5, 1] = 0 mm[5, 2] = 0 mm[5, 3] = j31 mm[5, 4] = 0 mm[5, 5] = j3 mm[5, 6] = 0 mm[6, 0] = x + zt * e31 mm[6, 1] = y + zt * e32 mm[6, 2] = z + zt * e33 mm[6, 3] = -zt * (e21 * x + e22 * y + e23 * z + zt * e21 * e31 + zt * e22 * e32 + zt * e23 * e33) mm[6, 4] = zt * (e11 * x + e12 * y + e13 * z + zt * e11 * e31 + zt * e12 * e32 + zt * e13 * e33) mm[6, 5] = 0 mm[6, 6] = 0 # right hand side zt2 = zt * zt rhs = C.veccat( [ f1 + ddelta * m * (dy + ddelta * rA + ddelta * x) + ddelta * dy * m, f2 - ddelta * m * (dx - ddelta * y) - ddelta * dx * m, f3 - g * m, t1 - w2 * (j3 * w3 + j31 * w1) + j2 * w2 * w3, t2 + w1 * (j3 * w3 + j31 * w1) - w3 * (j1 * w1 + j31 * w3), t3 + w2 * (j1 * w1 + j31 * w3) - j2 * w1 * w2, ddr * r - ( zt * w1 * (e11 * x + e12 * y + e13 * z + zt * e11 * e31 + zt * e12 * e32 + zt * e13 * e33) + zt * w2 * (e21 * x + e22 * y + e23 * z + zt * e21 * e31 + zt * e22 * e32 + zt * e23 * e33) ) * (w3 - ddelta * e33) - dx * (dx - zt * e21 * (w1 - ddelta * e13) + zt * e11 * (w2 - ddelta * e23)) - dy * (dy - zt * e22 * (w1 - ddelta * e13) + zt * e12 * (w2 - ddelta * e23)) - dz * (dz - zt * e23 * (w1 - ddelta * e13) + zt * e13 * (w2 - ddelta * e23)) + dr * dr + (w1 - ddelta * e13) * ( e21 * (zt * dx - zt2 * e21 * (w1 - ddelta * e13) + zt2 * e11 * (w2 - ddelta * e23)) + e22 * (zt * dy - zt2 * e22 * (w1 - ddelta * e13) + zt2 * e12 * (w2 - ddelta * e23)) + zt * e23 * (dz + zt * e13 * w2 - zt * e23 * w1) + zt * e33 * ( w1 * z + zt * e33 * w1 + ddelta * e11 * x + ddelta * e12 * y + zt * ddelta * e11 * e31 + zt * ddelta * e12 * e32 ) + zt * e31 * (x + zt * e31) * (w1 - ddelta * e13) + zt * e32 * (y + zt * e32) * (w1 - ddelta * e13) ) - (w2 - ddelta * e23) * ( e11 * (zt * dx - zt2 * e21 * (w1 - ddelta * e13) + zt2 * e11 * (w2 - ddelta * e23)) + e12 * (zt * dy - zt2 * e22 * (w1 - ddelta * e13) + zt2 * e12 * (w2 - ddelta * e23)) + zt * e13 * (dz + zt * e13 * w2 - zt * e23 * w1) - zt * e33 * ( w2 * z + zt * e33 * w2 + ddelta * e21 * x + ddelta * e22 * y + zt * ddelta * e21 * e31 + zt * ddelta * e22 * e32 ) - zt * e31 * (x + zt * e31) * (w2 - ddelta * e23) - zt * e32 * (y + zt * e32) * (w2 - ddelta * e23) ), ] ) dRexp = C.SXMatrix(3, 3) dRexp[0, 0] = e21 * (w3 - ddelta * e33) - e31 * (w2 - ddelta * e23) dRexp[0, 1] = e31 * (w1 - ddelta * e13) - e11 * (w3 - ddelta * e33) dRexp[0, 2] = e11 * (w2 - ddelta * e23) - e21 * (w1 - ddelta * e13) dRexp[1, 0] = e22 * (w3 - ddelta * e33) - e32 * (w2 - ddelta * e23) dRexp[1, 1] = e32 * (w1 - ddelta * e13) - e12 * (w3 - ddelta * e33) dRexp[1, 2] = e12 * (w2 - ddelta * e23) - e22 * (w1 - ddelta * e13) dRexp[2, 0] = e23 * w3 - e33 * w2 dRexp[2, 1] = e33 * w1 - e13 * w3 dRexp[2, 2] = e13 * w2 - e23 * w1 c = (x + zt * e31) ** 2 / 2 + (y + zt * e32) ** 2 / 2 + (z + zt * e33) ** 2 / 2 - r ** 2 / 2 cdot = ( dx * (x + zt * e31) + dy * (y + zt * e32) + dz * (z + zt * e33) + zt * (w2 - ddelta * e23) * (e11 * x + e12 * y + e13 * z + zt * e11 * e31 + zt * e12 * e32 + zt * e13 * e33) - zt * (w1 - ddelta * e13) * (e21 * x + e22 * y + e23 * z + zt * e21 * e31 + zt * e22 * e32 + zt * e23 * e33) - r * dr ) ddx = dae.z("ddx") ddy = dae.z("ddy") ddz = dae.z("ddz") dw1 = dae.z("dw1") dw2 = dae.z("dw2") dddelta = 0 cddot = ( -(w1 - ddelta * e13) * ( zt * e23 * (dz + zt * e13 * w2 - zt * e23 * w1) + zt * e33 * ( w1 * z + zt * e33 * w1 + ddelta * e11 * x + ddelta * e12 * y + zt * ddelta * e11 * e31 + zt * ddelta * e12 * e32 ) + zt * e21 * (dx + zt * e11 * w2 - zt * e21 * w1 - zt * ddelta * e11 * e23 + zt * ddelta * e13 * e21) + zt * e22 * (dy + zt * e12 * w2 - zt * e22 * w1 - zt * ddelta * e12 * e23 + zt * ddelta * e13 * e22) + zt * e31 * (x + zt * e31) * (w1 - ddelta * e13) + zt * e32 * (y + zt * e32) * (w1 - ddelta * e13) ) + (w2 - ddelta * e23) * ( zt * e13 * (dz + zt * e13 * w2 - zt * e23 * w1) - zt * e33 * ( w2 * z + zt * e33 * w2 + ddelta * e21 * x + ddelta * e22 * y + zt * ddelta * e21 * e31 + zt * ddelta * e22 * e32 ) + zt * e11 * (dx + zt * e11 * w2 - zt * e21 * w1 - zt * ddelta * e11 * e23 + zt * ddelta * e13 * e21) + zt * e12 * (dy + zt * e12 * w2 - zt * e22 * w1 - zt * ddelta * e12 * e23 + zt * ddelta * e13 * e22) - zt * e31 * (x + zt * e31) * (w2 - ddelta * e23) - zt * e32 * (y + zt * e32) * (w2 - ddelta * e23) ) - ddr * r + ( zt * w1 * (e11 * x + e12 * y + e13 * z + zt * e11 * e31 + zt * e12 * e32 + zt * e13 * e33) + zt * w2 * (e21 * x + e22 * y + e23 * z + zt * e21 * e31 + zt * e22 * e32 + zt * e23 * e33) ) * (w3 - ddelta * e33) + dx * (dx + zt * e11 * w2 - zt * e21 * w1 - zt * ddelta * e11 * e23 + zt * ddelta * e13 * e21) + dy * (dy + zt * e12 * w2 - zt * e22 * w1 - zt * ddelta * e12 * e23 + zt * ddelta * e13 * e22) + dz * (dz + zt * e13 * w2 - zt * e23 * w1) + ddx * (x + zt * e31) + ddy * (y + zt * e32) + ddz * (z + zt * e33) - dr * dr + zt * (dw2 - dddelta * e23) * (e11 * x + e12 * y + e13 * z + zt * e11 * e31 + zt * e12 * e32 + zt * e13 * e33) - zt * (dw1 - dddelta * e13) * (e21 * x + e22 * y + e23 * z + zt * e21 * e31 + zt * e22 * e32 + zt * e23 * e33) - zt * dddelta * ( e11 * e23 * x - e13 * e21 * x + e12 * e23 * y - e13 * e22 * y + zt * e11 * e23 * e31 - zt * e13 * e21 * e31 + zt * e12 * e23 * e32 - zt * e13 * e22 * e32 ) ) # cddot = (zt*w1*(e11*x + e12*y + e13*z + zt*e11*e31 + zt*e12*e32 + zt*e13*e33) + zt*w2*(e21*x + e22*y + e23*z + zt*e21*e31 + zt*e22*e32 + zt*e23*e33))*(w3 - ddelta*e33) + dx*(dx + zt*e11*w2 - zt*e21*w1 - zt*ddelta*e11*e23 + zt*ddelta*e13*e21) + dy*(dy + zt*e12*w2 - zt*e22*w1 - zt*ddelta*e12*e23 + zt*ddelta*e13*e22) + dz*(dz + zt*e13*w2 - zt*e23*w1) + ddx*(x + zt*e31) + ddy*(y + zt*e32) + ddz*(z + zt*e33) - (w1 - ddelta*e13)*(e21*(zt*dx - zt**2*e21*(w1 - ddelta*e13) + zt**2*e11*(w2 - ddelta*e23)) + e22*(zt*dy - zt**2*e22*(w1 - ddelta*e13) + zt**2*e12*(w2 - ddelta*e23)) + zt*e33*(z*w1 + ddelta*e11*x + ddelta*e12*y + zt*e33*w1 + zt*ddelta*e11*e31 + zt*ddelta*e12*e32) + zt*e23*(dz + zt*e13*w2 - zt*e23*w1) + zt*e31*(w1 - ddelta*e13)*(x + zt*e31) + zt*e32*(w1 - ddelta*e13)*(y + zt*e32)) + (w2 - ddelta*e23)*(e11*(zt*dx - zt**2*e21*(w1 - ddelta*e13) + zt**2*e11*(w2 - ddelta*e23)) + e12*(zt*dy - zt**2*e22*(w1 - ddelta*e13) + zt**2*e12*(w2 - ddelta*e23)) - zt*e33*(z*w2 + ddelta*e21*x + ddelta*e22*y + zt*e33*w2 + zt*ddelta*e21*e31 + zt*ddelta*e22*e32) + zt*e13*(dz + zt*e13*w2 - zt*e23*w1) - zt*e31*(w2 - ddelta*e23)*(x + zt*e31) - zt*e32*(w2 - ddelta*e23)*(y + zt*e32)) + zt*(dw2 - dddelta*e23)*(e11*x + e12*y + e13*z + zt*e11*e31 + zt*e12*e32 + zt*e13*e33) - zt*(dw1 - dddelta*e13)*(e21*x + e22*y + e23*z + zt*e21*e31 + zt*e22*e32 + zt*e23*e33) - zt*dddelta*(e11*e23*x - e13*e21*x + e12*e23*y - e13*e22*y + zt*e11*e23*e31 - zt*e13*e21*e31 + zt*e12*e23*e32 - zt*e13*e22*e32) # where # dw1 = dw @> 0 # dw2 = dw @> 1 # {- # dw3 = dw @> 2 # -} # ddx = ddX @> 0 # ddy = ddX @> 1 # ddz = ddX @> 2 # dddelta = dddelta' @> 0 dae.addOutput("c", c) dae.addOutput("cdot", cdot) dae.addOutput("cddot", cddot) return (mm, rhs, dRexp)
def variable( self, n_vars: int = 1, init_guess: Union[float, np.ndarray] = None, scale: float = None, log_transform: bool = False, category: str = "Uncategorized", freeze: bool = False, ) -> cas.MX: """ Initializes a new decision variable (or vector of decision variables, if n_vars != 1). It is recommended that you provide an initial guess (`init_guess`) and scale (`scale`) for each variable, although these are not strictly required. Args: n_vars: [Optional] Number of variables to initialize (used to initialize a vector of variables). If you are initializing a scalar variable (the most typical case), leave this equal to 1. When using vector variables, individual components of this vector of variables can be accessed via normal indexing. Example: >>> opti = asb.Opti() >>> my_var = opti.variable(n_vars = 5) >>> opti.subject_to(my_var[3] >= my_var[2]) # This is a valid way of indexing >>> my_sum = asb.cas.sum1(my_var) # This will sum up all elements of `my_var` init_guess: [Optional] Initial guess for the variable being initialized. For scalar variables, this should be a float. For vector variables (see `n_vars`), you can provide either a float (in which case all elements of the vector will be initialized to the given value) or an iterable of equal length (in which case each element will be initialized to the corresponding value in the given iterable). In the case where the variable is to be log-transformed (see `log_transform`), the initial guess should not be log-transformed as well; this happens under the hood. The initial guess must, of course, be a positive number in this case. If not specified, initial guess defaults to 0 for non-log-transformed variables and 1 for log-transformed variables. scale: [Optional] Approximate scale of the variable. If not specified, defaults to the supplied initial guess if one exists; otherwise, defaults to 1. log_transform: [Optional] Advanced use only. A flag of whether to internally-log-transform this variable before passing it to the optimizer. Good for known positive engineering quantities that become nonsensical if negative (e.g. mass). Log-transforming these variables can help maintain convexity. category: [Optional] What category of variables does this belong to Returns: The variable itself as a symbolic CasADi variable (MX type). """ # Validate the inputs if log_transform and init_guess is not None: if np.any(init_guess <= 0): raise ValueError( "If you are initializing a log-transformed variable, the initial guess(es) must be positive." ) # Set defaults if init_guess is None: init_guess = 1 if log_transform else 0 if scale is None: scale = init_guess if log_transform else 1 # Validate the inputs if np.any(scale <= 0): raise ValueError("The 'scale' argument must be a positive number.") # If the variable is in a category to be frozen, fix the variable at the initial guess. is_manually_frozen = freeze if category in self.variable_categories_to_freeze: freeze = True # If the variable is to be frozen, return the initial guess. Otherwise, define the variable using CasADi symbolics. if freeze: # var = init_guess * np.ones(n_vars) var = self.parameter(n_params=n_vars, value=init_guess) else: if not log_transform: var = scale * super().variable(n_vars) self.set_initial(var, init_guess) else: log_scale = scale / init_guess log_var = log_scale * super().variable(n_vars) var = cas.exp(log_var) self.set_initial(log_var, cas.log(init_guess)) # Track the variable if category not in self.variables_categorized: # Add a category if it does not exist self.variables_categorized[category] = [] self.variables_categorized[category].append(var) var.is_manually_frozen = is_manually_frozen return var
import numpy as np import casadi as cas opti = cas.Opti() # Initialize a SAND environment # Define Assumptions L = 34.1376 / 2 n = 200 x = cas.linspace(0, L, n) dx = cas.diff(x) E = 228e9 # Pa, modulus of CF G = E / 2 / (1 + 0.5) # TODO fix this!!! CFRP is not isotropic! max_allowable_stress = 570e6 / 1.75 log_nominal_diameter = opti.variable(n) opti.set_initial(log_nominal_diameter, cas.log(200e-3)) nominal_diameter = cas.exp(log_nominal_diameter) thickness = 0.14e-3 * 5 opti.subject_to([ nominal_diameter > thickness, ]) # Bending loads I = cas.pi / 64 * ((nominal_diameter + thickness)**4 - (nominal_diameter - thickness)**4) EI = E * I total_lift_force = 9.81 * 103.873 / 2 lift_distribution = "elliptical" if lift_distribution == "rectangular":
def logPredProb(rr): u = [ -log(1 + exp(-beta[0] - beta[1] * theta[i] - beta[2] * rr[i])) for i in range(nIndiv) ] return u
def __init__(self, op, options, measurements, inputs, time, costType="integral", hs=False): """ """ self.op = op self.options = options self.measurements = measurements self.inputs = inputs self.time = time self.costType = costType self.prefix = "GreyBox_" self.free_parameters = set() # if non-constant sample period for measurements if hs: diffTimePoints = np.diff(time) sumTimePoints = np.sum(diffTimePoints) self.options['hs'] = diffTimePoints / sumTimePoints # create time parameters N_meas = len(time) self.tf = time[-1] self.t0 = time[0] # set start and final time startTime = self._add_real_parameter('startTime') self.op.set('startTime', self.t0) finalTime = self._add_real_parameter('finalTime') self.op.set('finalTime', self.tf) op.setStartTime(MX(self.t0)) op.setFinalTime(MX(self.tf)) # Check if free parameters already in model for par in self.op.getVariables(self.op.REAL_PARAMETER_INDEPENDENT): if par.hasAttributeSet('free'): if par.getAttribute('free'): self.free_parameters.add(par.getName()) for par in self.op.getVariables(self.op.REAL_PARAMETER_DEPENDENT): if par.hasAttributeSet('free'): if par.getAttribute('free'): self.free_parameters.add(par.getName()) # set number of collocation elements so their endpoint coincide with measurement points self.options['n_e'] = (N_meas - 1) # add parameters for noise convariance of measured variables # add input real for measured signals if costType == "integral": self.options['n_cp'] = 1 self.weight = options['n_e'] / (self.tf - self.t0) for var in measurements.keys(): # Add parameter for noise convariance, set initial guess to base nominal squared r = self._add_real_parameter(self.prefix + 'r_' + var) base_var = op.getVariable(var) value = base_var.getAttribute('nominal').getValue() self.op.set(self.prefix + 'r_' + var, value**2) r.setAttribute('initialGuess', value**2) r.setAttribute('min', 0) # Create real input for measurement data meas = self._add_real_input(self.prefix + 'measured_' + var) # Add w*(y-y_meas)²/r to Objective Integrand oi = self.op.getObjectiveIntegrand() self.op.setObjectiveIntegrand( oi + self.weight * (base_var.getVar() - meas.getVar())**2 / r.getVar()) # Add log term and first measurement to objective timed_var = self._add_timed_variable(var, time[0]) obj = self.op.getObjective() self.op.setObjective(obj + (N_meas) * casadi.log(r.getVar()) + (timed_var.getVar() - measurements[var][0])**2 / r.getVar()) elif costType == "sum": # add parameters for noise convariance of measured variables # add timed variable for each variable and measurementpoint for var in measurements.keys(): # Add parameter for noise convariance, set initial guess to base nominal squared r = self._add_real_parameter(self.prefix + 'r_' + var) base_var = op.getVariable(var) value = base_var.getAttribute('nominal').getValue() self.op.set(self.prefix + 'r_' + var, value**2) r.setAttribute('initialGuess', value**2) r.setAttribute('min', 0) for i in range(0, len(self.time)): # Add timed variable timed_var = self._add_timed_variable(var, time[i]) obj = self.op.getObjective() self.op.setObjective( obj + (timed_var.getVar() - measurements[var][i])**2 / r.getVar()) # add logterm obj = self.op.getObjective() self.op.setObjective(obj + (N_meas) * casadi.log(r.getVar())) else: warning("costType not implemented") self._create_external_data()
sorted(np.random.choice(range(nFac), nEdgePerIndiv, replace=False)) for i in range(nIndiv) ] edges = [(i, e) for i in range(nIndiv) for e in edges_list_of_lists[i]] # edges = [(i,e) for i in range(nIndiv) for e in sorted(np.random.choice(range(nFac),nEdgePerIndiv,replace=False))] fac_vals = sorted([np.random.rand() for i in range(nFac)]) theta = [theta_low for i in range(nIndiv // 2) ] + [theta_high for i in range(nIndiv - (nIndiv // 2))] edge_weights = [ edge_val(theta[indiv_ind], fac_vals[fac_ind]) for (indiv_ind, fac_ind) in edges ] weights_mat = sparse((edge_weights, list(zip(*edges)))).toarray() edge_index = {edge: ind for ind, edge in enumerate(edges)} used_fac = sorted(list(set(e for (i, e) in edges))) MMM = nIndiv * max([abs(log(ew)) for ew in edge_weights]) + 1000 # @setmeta(name="$P(Success)$",axes_inset=[0.7,0.05,0.25,0.25]) # def probSuccess(ttheta,rr): # return 1/(1+exp(-beta[0] - beta[1]*ttheta-beta[2]*rr)) # @setmeta(name="$\\log \\left(P(Success)\\right)$",axes_inset=[0.7,0.05,0.25,0.25]) # def logProbSuccess(ttheta,rr): # return -log(1+exp(-beta[0] - beta[1]*ttheta-beta[2]*rr)) def solve_casadi(): all_xvals = {} all_edgeVals = {} all_indVals = {} all_edgeUtility = {} all_indUtility = {}
def log_utility(utility): return log(utility)
def get_h_i_t(): w_i, alpha_i, beta_i, b_i, c_i, mu_i, v_i, h_tm1_agg_i, delta_t_agg_i = casadi.SX.sym('w_i'), casadi.SX.sym('alpha_i'), casadi.SX.sym('beta_i'), casadi.SX.sym('b_i'), casadi.SX.sym('c_i'), casadi.SX.sym('mu_i'), casadi.SX.sym('v_i'), casadi.SX.sym('h_tm1_agg_i'), casadi.SX.sym('delta_t_agg_i'), boolM = mu_i > 0 sqrthtpowmu = casadi.sqrt(h_tm1_agg_i) ** mu_i zTrue = (w_i + alpha_i * sqrthtpowmu * f_i(delta_t_agg_i, b_i, c_i) ** v_i + beta_i * sqrthtpowmu) ** (2./mu_i) sqrtht = casadi.sqrt(h_tm1_agg_i) zFalse= (casadi.exp(w_i + alpha_i * f_i(delta_t_agg_i, b_i, c_i) ** v_i + beta_i * casadi.log(sqrtht)) ** (2.)) z = casadi.if_else(boolM, zTrue, zFalse) return casadi.Function('h_i_t', [w_i, alpha_i, beta_i, b_i, c_i, mu_i, v_i, h_tm1_agg_i, delta_t_agg_i], [z])
def setup(self, bending_BC_type="cantilevered" ): """ Sets up the problem. Run this last. :return: None (in-place) """ ### Discretize and assign loads # Discretize point_load_locations = [load["location"] for load in self.point_loads] point_load_locations.insert(0, 0) point_load_locations.append(self.length) self.x = cas.vertcat(*[ cas.linspace( point_load_locations[i], point_load_locations[i + 1], self.points_per_point_load) for i in range(len(point_load_locations) - 1) ]) # Post-process the discretization self.n = self.x.shape[0] dx = cas.diff(self.x) # Add point forces self.point_forces = cas.GenMX_zeros(self.n - 1) for i in range(len(self.point_loads)): load = self.point_loads[i] self.point_forces[self.points_per_point_load * (i + 1) - 1] = load["force"] # Add distributed loads self.force_per_unit_length = cas.GenMX_zeros(self.n) self.moment_per_unit_length = cas.GenMX_zeros(self.n) for load in self.distributed_loads: if load["type"] == "uniform": self.force_per_unit_length += load["force"] / self.length elif load["type"] == "elliptical": load_to_add = load["force"] / self.length * ( 4 / cas.pi * cas.sqrt(1 - (self.x / self.length) ** 2) ) self.force_per_unit_length += load_to_add else: raise ValueError("Bad value of \"type\" for a load within beam.distributed_loads!") # Initialize optimization variables log_nominal_diameter = self.opti.variable(self.n) self.opti.set_initial(log_nominal_diameter, cas.log(self.diameter_guess)) self.nominal_diameter = cas.exp(log_nominal_diameter) self.opti.subject_to([ log_nominal_diameter > cas.log(self.thickness) ]) def trapz(x): out = (x[:-1] + x[1:]) / 2 # out[0] += x[0] / 2 # out[-1] += x[-1] / 2 return out # Mass self.volume = cas.sum1( cas.pi / 4 * trapz( (self.nominal_diameter + self.thickness) ** 2 - (self.nominal_diameter - self.thickness) ** 2 ) * dx ) self.mass = self.volume * self.density # Mass proxy self.volume_proxy = cas.sum1( cas.pi * trapz( self.nominal_diameter ) * dx * self.thickness ) self.mass_proxy = self.volume_proxy * self.density # Find moments of inertia self.I = cas.pi / 64 * ( # bending (self.nominal_diameter + self.thickness) ** 4 - (self.nominal_diameter - self.thickness) ** 4 ) self.J = cas.pi / 32 * ( # torsion (self.nominal_diameter + self.thickness) ** 4 - (self.nominal_diameter - self.thickness) ** 4 ) if self.bending: # Set up derivatives self.u = 1 * self.opti.variable(self.n) self.du = 0.1 * self.opti.variable(self.n) self.ddu = 0.01 * self.opti.variable(self.n) self.dEIddu = 1 * self.opti.variable(self.n) self.opti.set_initial(self.u, 0) self.opti.set_initial(self.du, 0) self.opti.set_initial(self.ddu, 0) self.opti.set_initial(self.dEIddu, 0) # Define derivatives self.opti.subject_to([ cas.diff(self.u) == trapz(self.du) * dx, cas.diff(self.du) == trapz(self.ddu) * dx, cas.diff(self.E * self.I * self.ddu) == trapz(self.dEIddu) * dx, cas.diff(self.dEIddu) == trapz(self.force_per_unit_length) * dx + self.point_forces, ]) # Add BCs if bending_BC_type == "cantilevered": self.opti.subject_to([ self.u[0] == 0, self.du[0] == 0, self.ddu[-1] == 0, # No tip moment self.dEIddu[-1] == 0, # No tip higher order stuff ]) else: raise ValueError("Bad value of bending_BC_type!") # Stress self.stress_axial = (self.nominal_diameter + self.thickness) / 2 * self.E * self.ddu if self.torsion: # Set up derivatives phi = 0.1 * self.opti.variable(self.n) dphi = 0.01 * self.opti.variable(self.n) # Add forcing term ddphi = -self.moment_per_unit_length / (self.G * self.J) self.stress = self.stress_axial self.opti.subject_to([ self.stress / self.max_allowable_stress < 1, self.stress / self.max_allowable_stress > -1, ])