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 __cost_saturation_l(self, x, x_ref, covar_x, u, covar_u, delta_u, Q, R, S): """ Stage Cost function: Expected Value of Saturating Cost """ Nx = ca.MX.size1(Q) Nu = ca.MX.size1(R) # Create symbols Q_s = ca.SX.sym('Q', Nx, Nx) R_s = ca.SX.sym('Q', Nu, Nu) x_s = ca.SX.sym('x', Nx) u_s = ca.SX.sym('x', Nu) covar_x_s = ca.SX.sym('covar_z', Nx, Nx) covar_u_s = ca.SX.sym('covar_u', ca.MX.size(R)) Z_x = ca.SX.eye(Nx) + 2 * covar_x_s @ Q_s Z_u = ca.SX.eye(Nu) + 2 * covar_u_s @ R_s cost_x = ca.Function('cost_x', [x_s, Q_s, covar_x_s], [ 1 - ca.exp(-(x_s.T @ ca.solve(Z_x.T, Q_s.T).T @ x_s)) / ca.sqrt(ca.det(Z_x)) ]) cost_u = ca.Function('cost_u', [u_s, R_s, covar_u_s], [ 1 - ca.exp(-(u_s.T @ ca.solve(Z_u.T, R_s.T).T @ u_s)) / ca.sqrt(ca.det(Z_u)) ]) return cost_x(x - x_ref, Q, covar_x) + cost_u(u, R, covar_u)
def RBF(n): if n == 1: sX = 1 sY = n n_features = self.n_features X = cs.SX.sym('X', sX, n_features) Y = cs.SX.sym('Y', sY, n_features) length_scale = cs.SX.sym('l', 1, n_features) X_ = X / cs.repmat(length_scale, sX, 1) Y_ = Y / cs.repmat(length_scale, sY, 1) dist = cs.SX.zeros((sX, sY)) for i in xrange(0, sX): for j in xrange(0, sY): dist[i, j] = cs.sum2((X_[i, :] - Y_[j, :])**2) K = cs.exp(-.5 * dist) self.RBF1 = cs.Function('RBF1', [X, Y, length_scale], [K]) else: sX = 1 sY = n n_features = self.n_features X = cs.SX.sym('X', sX, n_features) Y = self.model.X_train_ length_scale = cs.SX.sym('l', 1, n_features) X_ = X / cs.repmat(length_scale, sX, 1) Y_ = Y / cs.repmat(length_scale, sY, 1) dist = cs.SX.zeros((sX, sY)) for i in xrange(0, sX): for j in xrange(0, sY): dist[i, j] = cs.sum2((X_[i, :] - Y_[j, :])**2) K = cs.exp(-.5 * dist) self.RBFn = cs.Function('RBFn', [X, length_scale], [K])
def obstacle_cost(U_var, T): U_tot = casadi.reshape(U_var, 2, T) X_tot = find_X_tot(U_var, T) obs = env_setup() obs = casadi.DM(obs) cost = 0 for i in range(T): x = X_tot[0, i] y = X_tot[1, i] x0 = obs[0, 0] y0 = obs[0, 1] r0 = obs[0, 2] x1 = obs[1, 0] y1 = obs[1, 1] r1 = obs[1, 2] x2 = obs[2, 0] y2 = obs[2, 1] r2 = obs[2, 2] cost = cost + r0 * 5000 * casadi.exp(-((x - x0)**2 + (y - y0)**2 - r0**2)) cost = cost + r1 * 5000 * casadi.exp(-((x - x1)**2 + (y - y1)**2 - r1**2)) cost = cost + r2 * 5000 * casadi.exp(-((x - x2)**2 + (y - y2)**2 - r2**2)) return cost
def cost_func_SSP(self, robot, U, X0): cost = 0 U = c.reshape(U, robot.nu, self.T) X = c.MX(robot.nx, self.T + 1) X[:, 0] = X0 for i in range(self.T): cost = (cost + c.mtimes(c.mtimes(U[:, i].T, self.R), U[:, i]) + c.mtimes(c.mtimes((self.Xg - X[:, i]).T, self.Q), (self.Xg - X[:, i]))) X_temp = X[0:2, i] if params.OBSTACLES: obstacle_cost = params.M*(c.exp(-(c.mtimes(c.mtimes((params.c_obs_1 - X_temp).T, params.E_obs_1),(params.c_obs_1 - X_temp))))+ \ c.exp(-(c.mtimes(c.mtimes((params.c_obs_2 - X_temp).T, params.E_obs_2),(params.c_obs_2 - X_temp)))) + \ c.exp(-(c.mtimes(c.mtimes((params.c_obs_3 - X_temp).T, params.E_obs_3),(params.c_obs_3 - X_temp)))) + \ c.exp(-(c.mtimes(c.mtimes((params.c_obs_4 - X_temp).T, params.E_obs_4),(params.c_obs_4 - X_temp))))) cost = cost + obstacle_cost X[:, i + 1] = robot.kinematics(X[:, i], U[:, i]) cost = cost + c.mtimes(c.mtimes((self.Xg - X[:, self.T]).T, self.Qf), (self.Xg - X[:, self.T])) return cost
def Cl_rae2822(alpha, Re_c): # A curve fit I did to a RAE2822 airfoil, 2D XFoil data. Incompressible flow. # Within -2 < alpha < 12 and 10^4 < Re_c < 10^6, has R^2 = 0.9857 # Likely valid from -6 < alpha < 12 and 10^4 < Re_c < 10^6. # See: C:\Projects\GitHub\firefly_aerodynamics\Gists and Ideas\XFoil Drag Fitting\rae2822 Re_c = cas.fmax(Re_c, 1) log10_Re = cas.log10(Re_c) # Coeffs a1l = 5.5686866813855172e-02 a1t = 9.7472055628494134e-02 a4l = -7.2145733312046152e-09 a4t = -3.6886704372829236e-06 atr = 8.3723547264375520e-01 atr2 = -8.3128119739031697e-02 c0l = -4.9103908291438701e-02 c0t = 2.3903424824298553e-01 ctr = 1.3082854754897108e+01 rtr = 2.6963082864300731e+00 a = alpha r = log10_Re Cl = (c0t + a1t * a + a4t * a**4) * 1 / ( 1 + cas.exp(ctr - rtr * r - atr * a - atr2 * a**2)) + ( c0l + a1l * a + a4l * a**4) * ( 1 - 1 / (1 + cas.exp(ctr - rtr * r - atr * a - atr2 * a**2))) return Cl
def Cl_e216(alpha, Re_c): # A curve fit I did to a Eppler 216 (e216) airfoil, 2D XFoil data. Incompressible flow. # Within -2 < alpha < 12 and 10^4 < Re_c < 10^6, has R^2 = 0.9994 # Likely valid from -6 < alpha < 12 and 10^4 < Re_c < Inf. # See: C:\Projects\GitHub\firefly_aerodynamics\Gists and Ideas\XFoil Drag Fitting\e216 Re_c = cas.fmax(Re_c, 1) log10_Re = cas.log10(Re_c) # Coeffs a1l = 3.0904412662858878e-02 a1t = 9.6452654383488254e-02 a4t = -2.5633334023068302e-05 asl = 6.4175433185427011e-01 atr = 3.6775107602844948e-01 c0l = -2.5909363461176749e-01 c0t = 8.3824440586718862e-01 ctr = 1.1431810545735890e+02 ksl = 5.3416670116733611e-01 rtr = 3.9713338634462829e+01 rtr2 = -3.3634858542657771e+00 xsl = -1.2220899840236835e-01 a = alpha r = log10_Re Cl = (c0t + a1t * a + a4t * a**4) * 1 / ( 1 + cas.exp(ctr - rtr * r - atr * a - rtr2 * r**2)) + ( c0l + a1l * a + asl / (1 + cas.exp(-ksl * (a - xsl)))) * ( 1 - 1 / (1 + cas.exp(ctr - rtr * r - atr * a - rtr2 * r**2))) return Cl
def Cd_profile_e216(alpha, Re_c): # A curve fit I did to a Eppler 216 (e216) airfoil, 2D XFoil data. Incompressible flow. # Within -2 < alpha < 12 and 10^4 < Re_c < 10^6, has R^2 = 0.9995 # Likely valid from -6 < alpha < 12 and 10^4 < Re_c < 10^6. # see: C:\Projects\GitHub\firefly_aerodynamics\Gists and Ideas\XFoil Drag Fitting\e216 Re_c = cas.fmax(Re_c, 1) log10_Re = cas.log10(Re_c) # Coeffs a1l = 4.7167470806940448e-02 a1t = 7.5663005080888857e-02 a2l = 8.7552076545610764e-04 a4t = 1.1220763679805319e-05 atr = 4.2456038382581129e-01 c0l = -1.4099657419753771e+00 c0t = -2.3855286371940609e+00 ctr = 9.1474872611212135e+01 rtr = 3.0218483612170434e+01 rtr2 = -2.4515094313899279e+00 a = alpha r = log10_Re log10_Cd = (c0t + a1t * a + a4t * a**4) * 1 / ( 1 + cas.exp(ctr - rtr * r - atr * a - rtr2 * r**2)) + ( c0l + a1l * a + a2l * a**2) * ( 1 - 1 / (1 + cas.exp(ctr - rtr * r - atr * a - rtr2 * r**2))) Cd = 10**log10_Cd return Cd
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 Cd_profile_rae2822(alpha, Re_c): # A curve fit I did to a RAE2822 airfoil, 2D XFoil data. Incompressible flow. # Within -2 < alpha < 12 and 10^4 < Re_c < 10^6, has R^2 = 0.9995 # Likely valid from -6 < alpha < 12 and 10^4 < Re_c < Inf. # see: C:\Projects\GitHub\firefly_aerodynamics\Gists and Ideas\XFoil Drag Fitting\e216 Re_c = cas.fmax(Re_c, 1) log10_Re = cas.log10(Re_c) # Coeffs at = 8.1034027621509015e+00 c0l = -8.4296746456429639e-01 c0t = -1.3700609138855402e+00 kart = -4.1609994062600880e-01 kat = 5.9510959342452441e-01 krt = -7.1938030052506197e-01 r1l = 1.1548628822014631e-01 r1t = -4.9133662875044504e-01 rt = 5.0070459892411696e+00 a = alpha r = log10_Re log10_Cd = (c0t + r1t * (r - 4)) * ( 1 / (1 + cas.exp(kat * (a - at) + krt * (r - rt) + kart * (a - at) * (r - rt)))) + ( c0l + r1l * (r - 4)) * ( 1 - 1 / (1 + cas.exp(kat * (a - at) + krt * (r - rt) + kart * (a - at) * (r - rt)))) Cd = 10 ** log10_Cd return Cd
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 obstacle_cost_func(self, X_temp): cost = params.M*(c.exp(-(c.mtimes(c.mtimes((params.c_obs_1 - X_temp).T, params.E_obs_1),(params.c_obs_1 - X_temp))))+ \ c.exp(-(c.mtimes(c.mtimes((params.c_obs_2 - X_temp).T, params.E_obs_2),(params.c_obs_2 - X_temp)))) + \ c.exp(-(c.mtimes(c.mtimes((params.c_obs_3 - X_temp).T, params.E_obs_3),(params.c_obs_3 - X_temp)))) + \ c.exp(-(c.mtimes(c.mtimes((params.c_obs_4 - X_temp).T, params.E_obs_4),(params.c_obs_4 - X_temp))))) return cost
def trig_prop(m, v, idx, a=1.0): """ Exact moment-matching for trig function with Gaussian input Compute E(a*sin(x)), E(a*cos(x)), V(a*sin(x)), V(a*cos(x)) and cross-covariances for Gaussian inputs x \sim N(m_idx,v_idx) as well as input-output covariances using exact moment-matching Parameters ---------- m : dx1 ndarray[float | casadi.Sym] The mean of the input Gaussian v : dxd ndarray[float | casadi.Sym] idx: int The index to be trigonometrically augmented a: float [optional] A scalar coefficient Returns ------- m_out: 2x1 ndarray[float | casadi.Sym] The mean of the trigonometric output v_out: 2x2 ndarray[float | casadi.Sym] The variance of the trigonometric output c_out: inv(v) times input-output-covariance """ m_out = MX(2, 1) v_out = MX(2, 2) v_exp_0 = exp(-v[idx, idx] / 2) m_sin = v_exp_0 * sin(m[idx, 0]) m_cos = v_exp_0 * cos(m[idx, 0]) m_out[0] = a * m_sin m_out[1] = a * m_cos v_exp_1 = exp(-2 * v[idx, idx]) e_s_sq = (1 - v_exp_1 * cos(2 * m[idx, 0])) / 2 e_c_sq = (1 + v_exp_1 * cos(2 * m[idx, 0])) / 2 e_s_times_c = v_exp_1 * sin(2 * m[idx, 0]) / 2 v_out[0, 0] = e_s_sq - m_sin**2 v_out[1, 1] = e_c_sq - m_cos**2 v_out[1, 0] = e_s_times_c - m_sin * m_cos v_out[0, 1] = v_out[1, 0] v_out = a**2 * v_out d = np.shape(m)[0] c_out = MX(d, 2) c_out[idx, 0] = m_out[1] c_out[idx, 1] = -m_out[0] return m_out, v_out, c_out
def generate_bird(n=2, func_opts={}, data_type=cs.SX): if n != 2: raise ValueError("bird is only defined for n=2") x = data_type.sym("x", n) f = cs.sin(x[0]) * cs.exp((1 - cs.cos(x[1]))**2) f += cs.cos(x[1]) * cs.exp((1 - cs.sin(x[0]))**2) f += (x[0] - x[1])**2 func = cs.Function("bird", [x], [f], ["x"], ["f"], func_opts) glob_min = [[4.70104, 3.15294], [-1.58214, -3.13024]] return func, [[-2 * cs.np.pi, 2 * cs.np.pi]] * n, glob_min
def generate_ackley(n=2, a=20, b=0.2, c=2 * cs.np.pi, func_opts={}, data_type=cs.SX): x = data_type.sym("x", n) sum1 = cs.sumsqrt(x) sum2 = cs.sum1(cs.cos(x)) f = -a * cs.exp(-b * cs.sqrt((1. / n) * sum1)) - cs.exp( (1. / n) * sum2) + a + cs.exp(1) func = cs.Function("ackley", [x], [f], ["x"], ["f"], func_opts) return func, [[-32., 32.]] * n, [[0.] * n]
def generate_ackleyn3(n=2, a=200, b=0.02, c=5., d=3., func_opts={}, data_type=cs.SX): if n != 2: raise ValueError("ackleyn3 is only defined for n=2") x = data_type.sym("x", n) f = -a * cs.exp(-b * cs.sqrt(x[0]**2 + x[1]**2)) f += c * cs.exp(cs.cos(d * x[0]) + cs.sin(d * x[1])) func = cs.Function("ackleyn3", [x], [f], ["x"], ["f"], func_opts) glob_min = [[0.682584587365898, -0.36075325513719], [-0.682584587365898, -0.36075325513719]] return func, [[-32., 32.]] * n, glob_min
def generate_ackleyn2(n=2, a=200, b=0.02, func_opts={}, data_type=cs.SX): if n != 2: raise ValueError("ackleyn2 is only defined for n=2") x = data_type.sym("x", n) f = -a * cs.exp(-b * cs.sqrt(x[0]**2 + x[1]**2)) func = cs.Function("ackleyn2", [x], [f], ["x"], ["f"], func_opts) return func, [[-32., 32.]] * n, [[0.] * n]
def solve_enumerative(obj_fn): 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 = obj_fn(r) print(f"Obj is {sum(u)}") if sum(u) > sum(uvals): uvals = u rvals = r yvals = np.zeros((nFac), dtype=int) yvals[gp] = 1 print(f"Best obj is {sum(uvals)}") fstar = sum(uvals) prob_success = [ 1 / (1 + exp(-beta[0] - beta[1] * theta[i] - beta[2] * rvals[i])) for i in range(nIndiv) ] print(f"Solved enumeratively") return yvals, rvals, uvals, prob_success, fstar, obj_fn.extra_info
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 _k_mat52(x, y=None, variance=1., lengthscale=None, diag_only=False, ARD=False): """ Evaluate the Matern52 kernel function symbolically using Casadi""" n_x, dim_x = x.shape if diag_only: ret = SX(n_x, ) ret[:] = variance return ret if y is None: y = x n_y, _ = np.shape(y) if lengthscale is None: if ARD: lengthscale = np.ones((dim_x, )) else: lengthscale = 1. if ARD is False: lengthscale = lengthscale * np.ones((dim_x, )) lens_x = repmat(lengthscale.reshape(1, -1), n_x) lens_y = repmat(lengthscale.reshape(1, -1), n_y) r = _unscaled_dist(x / lens_x, y / lens_y) # GPY: self.variance*(1+np.sqrt(5.)*r+5./3*r**2)*np.exp(-np.sqrt(5.)*r) return variance * (1. + sqrt(5.) * r + 5. / 3 * r**2) * exp(-sqrt(5.) * r)
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 cal(self, x, style="casadi"): # return self.f(x) if (style == "casadi"): exp_x = csd.exp(x) elif (style == "numpy"): exp_x = np.exp(x) return exp_x / (1 + exp_x)
def generate_brent(n=2, a=10., b=10., func_opts={}, data_type=cs.SX): if n != 2: raise ValueError("brent is only defined for n=2") x = data_type.sym("x", n) f = (x[0] + a)**2 + (x[1] + b)**2 + cs.exp(-cs.sumsqr(x)) func = cs.Function("brent", [x], [f], ["x"], ["f"], func_opts) return func, [[-20., 0.]] * n, [[-10.] * n]
def generate_easom(n=2, func_opts={}, data_type=cs.SX): if n != 2: raise ValueError("easom is only defined for n=2") x = data_type.sym("x", n) exponential = cs.exp(-(x[0] - cs.pi)**2 - (x[1] - cs.pi)**2) f = -cs.cos(x[0]) * cs.cos(x[1]) * exponential func = cs.Function("easom", [x], [f], ["x"], ["f"], func_opts) return func, [[-100., 100.]] * n, [[cs.pi, cs.pi]]
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 mvg_mgf(t, mu, sigma): """Multivariate Gaussian Moment Generating Function. Args: t (1D array): mu (1D array): sigma (2D array): """ return casadi.exp(mu.T @ t + 0.5 * t.T @ sigma @ t)
def incidence_angle_function(latitude, day_of_year, time, scattering=False): """ What is the fraction of insolation that a horizontal surface will receive as a function of sun position in the sky? :param latitude: Latitude [degrees] :param day_of_year: Julian day (1 == Jan. 1, 365 == Dec. 31) :param time: Time since (local) solar noon [seconds] :param scattering: Boolean: include scattering effects at very low angles? """ # Old description: # To first-order, this is true. In class, Kevin Uleck claimed that you have higher-than-cosine losses at extreme angles, # since you get reflection losses. However, an experiment by Sharma appears to not reproduce this finding, showing only a # 0.4-percentage-point drop in cell efficiency from 0 to 60 degrees. So, for now, we'll just say it's a cosine loss. # Sharma: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6611928/ elevation_angle = solar_elevation_angle(latitude, day_of_year, time) theta = 90 - elevation_angle # Angle between panel normal and the sun, in degrees cosine_factor = cosd(theta) if not scattering: return cosine_factor else: # Calculate scattering knockdown (See C:\Users\User\Google Drive\School\Grad School\2020 Spring\16-885\Solar Panel Scattering Rough Fit) theta_rad = theta * cas.pi / 180 # Model 1 c = (0.27891510500505767300438719757949, -0.015994330894744987481281839336589, -19.707332432605799255043166340329, -0.66260979582573353852126274432521) scattering_factor = c[0] + c[3] * theta_rad + cas.exp( c[1] * (cas.tan(theta_rad - 1e-8) + c[2] * theta_rad)) # Model 2 # c = ( # -0.04636, # -0.3171 # ) # scattering_factor = cas.exp( # c[0] * ( # cas.tan(theta_rad-1e-8) + c[1] * theta_rad # ) # ) # Model 3 # p1 = -21.74 # p2 = 282.6 # p3 = -1538 # p4 = 1786 # q1 = -923.2 # q2 = 1456 # x = theta_rad # scattering_factor = ((p1*x**3 + p2*x**2 + p3*x + p4) / # (x**2 + q1*x + q2)) # scattering_factor = cas.fmin(cas.fmax(scattering_factor, 0), 1) return cosine_factor * scattering_factor
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 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 fermination_ode(t, x, u, p, z): """ Fermination model """ k_dc = p[0] k_dm = p[1] s_i = p[2] T = u[0] x_lag = x[0] x_active = x[1] x_bottom = x[2] s = x[3] e = x[4] acet = x[5] diac = x[6] mu_x0 = ca.exp(108.31 - 31934.09 / (T+273.15)) mu_eas = ca.exp(89.92 - 26589 / (T+273.15)) mu_s0 = ca.exp( -41.92 + 11654.64/ (T+273.15)) mu_lag = ca.exp(30.72 - 9501.54 / (T+273.15)) k_dc = 0.000127672 k_m = ca.exp( 130.16 - 38313 / (T+273.15)) mu_D0 = ca.exp( 33.82 - 10033.28/ (T+273.15)) mu_a0 = ca.exp(3.72 - 1267.24 / (T+273.15)) k_s = ca.exp(-119.63 + 34203.95 / (T + 273.15)) k_dm = 0.00113864 mu_x = mu_x0 * s / (0.5 * s_i + e) mu_D = 0.5 * s_i * mu_D0 / (0.5 * s_i + e) mu_s = mu_s0 * s / (k_s + s) mu_a = mu_a0 * s / (k_s + s) f = 1 - e / (0.5 * s_i) dx_lag = - mu_lag * x_lag dx_active = mu_x * x_active - k_m * x_active + mu_lag * x_lag dx_bottom = k_m * x_active - mu_D * x_bottom ds = - mu_s * x_active de = mu_a * f * x_active dacet = - mu_eas * mu_s * x_active ddiac = k_dc * s * x_active - k_dm * diac * e rhs = [dx_lag, dx_active, dx_bottom, ds, de, dacet, ddiac ] return ca.vertcat(*rhs)
def CasadiRBF(X, Y, model): """ RBF kernel in CasADi """ sX = X.shape[0] sY = Y.shape[0] length_scale = model.kernel_.get_params()['k1__k2__length_scale'].reshape(1,-1) constant = model.kernel_.get_params()['k1__k1__constant_value'] X = X / cs.repmat(length_scale, sX , 1) Y = Y / cs.repmat(length_scale, sY , 1) dist = cs.repmat(cs.sum1(X.T**2).T,1,sY) + cs.repmat(cs.sum1(Y.T**2),sX,1) - 2*cs.mtimes(X,Y.T) K = constant*cs.exp(-.5 * dist) return K
def get_f(): r_t, h_i_tm1, lambda_i, gamma_i = casadi.SX.sym('r_t'), casadi.SX.sym('h_i_tm1'), casadi.SX.sym('lambda_i'), casadi.SX.sym('gamma_i') z = 1/casadi.sqrt(2*numpy.pi * h_i_tm1) * casadi.exp(-((r_t - (lambda_i + gamma_i * casadi.sqrt(h_i_tm1))) ** 2.) / (2 * h_i_tm1)) return casadi.Function('f', [r_t, h_i_tm1, lambda_i, gamma_i], [z])