def setup(self): constraints = [] components = self.components = [] ######### components ########## ox_assembly = self.ox_assembly = EngineOxAssembly() valve_assembly = self.valve_assembly = EngineValveAssembly() fuel_assembly = self.fuel_assembly = EngineFuelAssembly() nozzle_assembly = self.nozzle_assembly = EngineNozzleAssembly() components += [ ox_assembly, valve_assembly, fuel_assembly, nozzle_assembly ] m = self.m = Variable("m", "kg", "Mass of Engine") if len(components) > 0: constraints += [Tight([m >= sum(comp.m for comp in components)])] ######### constraints ######### # constraints += [m >= 6 * ureg.kg] # define m_prop m_prop = self.m_prop = Variable("m_{prop}", "kg", "Propellant Mass") constraints += [ Tight([m_prop >= ox_assembly.ox.m + fuel_assembly.fuel.m]) ] # define by mass fraction # constraints += [m >= m_prop/0.3] c = Variable("c", 2000, "m/s", "Main engine effective exhaust speed") return [constraints, components]
def setup(self): constraints = [] components = self.components = [] ######### components ########## m = self.m = Variable("m", "kg", "Mass of Boosters") if len(components) > 0: constraints += [Tight([m >= sum(comp.m for comp in components)])] ######### constraints ######### constraints += [Loose([m >= 0.1 * ureg.kg])] F = self.F = Variable("F", "N", "Boosters cumulative thrust") t_burn = self.t_burn = Variable("t_{burn}", "s", "Booster burn time") c = self.c = Variable("c", 2000, "m/s", "boosters exhaust speed") m_prop = self.m_prop = Variable("m_{prop}", "kg", "Propellant mass of boosters") m_dry = self.m_dry = Variable("m_{dry}", "kg", "Dry mass of boosters") dmf = self.dmf = Variable("DMF", 0.7, "", "Dry mass fraction of boosters") constraints += [Tight([m >= m_prop + m_dry])] constraints += [m_dry >= dmf * m] # constraints += [m_prop >= F*t_burn/c] return [constraints, components]
def setup(self, N): edgeCost = VectorVariable([N, N], 'edgeCost') edgeMaxFlow = VectorVariable([N, N], 'edgeMaxFlow') slackCost = Variable('slackCost', 1000) connect = VectorVariable([N, N], 'connectivity') flow = VectorVariable([N, N], 'flow') source = VectorVariable(N, 'source') sink = VectorVariable(N, 'sink') slack = VectorVariable(N, 'slack') constraints = [] with SignomialsEnabled(): for i in range(0, N): constraints.extend([ Tight([ sink[i] + sum(flow[i, :]) <= slack[i] * (source[i] + sum(flow[:, i])) ]), Tight([slack[i] >= 1]) ]) for j in range(0, N): constraints += [ flow[i, j] <= connect[i, j] * edgeMaxFlow[i, j], connect[i, j] <= 1., flow[i, j] >= 1e-20 ] for i in range(0, N): for j in range(i + 1, N): constraints.extend( [connect[i, j] * connect[j, i] <= 1e-20]) return constraints
def test_posyconstr_in_gp(self): """Tests tight constraint set with solve()""" x = Variable('x') x_min = Variable('x_{min}', 2) m = Model(x, [Tight([x >= 1], raiseerror=True), x >= x_min]) with self.assertRaises(ValueError): m.solve(verbosity=0) m.substitutions[x_min] = 0.5 self.assertAlmostEqual(m.solve(verbosity=0)["cost"], 1)
def setup(self, nt, nx): exec parse_variables(Rocket.__doc__) self.nt = nt self.nx = nx self.nozzle = Nozzle() with Vectorize(nt): self.nozzlePerformance = NozzlePerformance(self.nozzle) self.section = SRM(nx) constraints = [ # Limiting nozzle size to cross-sectional area # self.nozzle.A_e <= np.pi*r**2, # Equal time segments self.section.dt == t_T/nt, # All fuel is consumed self.section.A_p_out[:,-1] == 1e-20*np.ones(nx)*np.pi*r**2, A_fuel == self.section.A_p_in[:,0], T_target == self.nozzlePerformance.T, c_T == self.nozzlePerformance.c_T, # Fuel parameters self.section.k_comb_p == k_comb_p, self.section.rho_p == rho_p, ] for i in range(nt-1): constraints += [ # Decreasing fuel self.section.A_p_out[:, i] == self.section.A_p_in[:, i+1], # Decreasing sectional area self.section.A_in[:,i] <= self.section.A_in[:,i+1], self.section.A_out[:,i] <= self.section.A_out[:,i+1], ] for i in range(nt): constraints += [ # Rocket length is section length, self.section.radius[i] == r, self.section.l[i] == l, # Matching nozzle and section conditions self.nozzlePerformance.mdot[i] == self.section.mdot_out[i], self.nozzlePerformance.T_t[i] == self.section.T_t_out[i], # Maximum chamber pressure self.section.P_chamb[:, i] <= P_max, self.nozzlePerformance.P_star[i] <= P_max, ] with SignomialsEnabled(): constraints += [ # Matching nozzle stagnation pressure Tight([self.nozzlePerformance.P_t[i] <= s[i]*(self.section.P_out[i] + 0.5*self.section.rho_out[i]*self.section.u_out[i]**2)], name='PtNozzle', printwarning=True), s[i]*self.nozzlePerformance.P_t[i] >= self.section.P_out[i] + 0.5*self.section.rho_out[i]*self.section.u_out[i]**2, s[i] >= 1 ] return constraints, self.nozzle, self.nozzlePerformance, self.section
def setup(self, nPoints): r_i = Variable('r_i', 'm', 'internal radius') r_o = Variable('r_o', 'm', 'outer radius') r_ii = Variable('r_{ii}', 'm', 'radius of biggest internal circle') A = Variable('A', 'm^2', 'total internal area') C = Variable('C', 'm', 'total circumference') S_e = Variable('S', 'm', 'semi-perimeter of outer triangles') l_e = Variable('l_e', 'm', 'internal polyhedron edge length') h_e = Variable('h_e', 'm', 'external polyhedron height') e = Variable('e', 'm', 'external triangle external edge length') A_e = Variable('A_e', 'm^2', 'area of external triangle') cos_ai = Variable('cos(a_i)', np.cos(np.pi / nPoints), '-', 'cosine of internal triangle half angle') sin_ai = Variable('sin(a_i)', np.sin(np.pi / nPoints), '-', 'sine of internal triangle half angle') slack = Variable('slack', '-') with SignomialsEnabled(): constraints = [ slack >= 1, r_ii / r_i == cos_ai, l_e / (2 * r_i) == sin_ai, Tight([r_o >= r_ii + h_e], printwarning=True), Tight([ slack * A >= 0.5 * nPoints * (r_ii * l_e) + nPoints * A_e ], printwarning=True), Tight([ A <= slack * (0.5 * nPoints * (r_ii * l_e) + nPoints * A_e) ], printwarning=True), # SignomialEquality(A, 0.5*nPoints*(r_ii*l_e) + nPoints*A_e), # Tight([A_e >= 0.5*(h_e*l_e)], printwarning=True), A_e == 0.5 * (h_e * l_e), # Heron's formula for outer triangle outer edge Tight([S_e <= 0.5 * (l_e + 2 * e)], printwarning=True), Tight( [A_e**2 <= S_e * (0.5 * l_e) * (0.5 * l_e) * (S_e - l_e)], printwarning=True), C == 2. * nPoints * e, ] return constraints
def test_posyconstr_in_sp(self): x = Variable('x') y = Variable('y') with SignomialsEnabled(): sig_constraint = (x + y >= 0.1) m = Model(x*y, [Tight([x >= y], raiseerror=True), x >= 2, y >= 1, sig_constraint]) with self.assertRaises(ValueError): m.localsolve(verbosity=0) m.pop(1) self.assertAlmostEqual(m.localsolve(verbosity=0)["cost"], 1, 5)
def test_posyconstr_in_gp(self): "Tests tight constraint set with solve()" x = Variable('x') x_min = Variable('x_{min}', 2) m = Model(x, [Tight([x >= 1]), x >= x_min]) sol = m.solve(verbosity=0) self.assertIs(sol["warnings"]["Unexpectedly Loose Constraints"][0][1], m[0][0]) self.assertAlmostEqual(m[0][0].rel_diff, 1, 3) m.substitutions[x_min] = 0.5 self.assertAlmostEqual(m.solve(verbosity=0)["cost"], 1)
def test_posyconstr_in_sp(self): x = Variable('x') y = Variable('y') with SignomialsEnabled(): sig_constraint = (x + y >= 0.1) m = Model(x * y, [Tight([x >= y]), x >= 2, y >= 1, sig_constraint]) sol = m.localsolve(verbosity=0) self.assertIs(sol["warnings"]["Unexpectedly Loose Constraints"][0][1], m[0][0]) self.assertAlmostEqual(m[0][0].rel_diff, 1, 3) m.pop(1) self.assertAlmostEqual(m.localsolve(verbosity=0)["cost"], 1, 5)
def test_sigconstr_in_sp(self): "Tests tight constraint set with localsolve()" x = Variable('x') y = Variable('y') x_min = Variable('x_{min}', 2) y_max = Variable('y_{max}', 0.5) with SignomialsEnabled(): m = Model(x, [Tight([x + y >= 1]), x >= x_min, y <= y_max]) sol = m.localsolve(verbosity=0) self.assertIs(sol["warnings"]["Unexpectedly Loose Constraints"][0][1], m[0][0]) self.assertGreater(m[0][0].rel_diff, 0.5) m.substitutions[x_min] = 0.5 self.assertAlmostEqual(m.localsolve(verbosity=0)["cost"], 0.5, 5)
def test_sigconstr_in_sp(self): """Tests tight constraint set with localsolve()""" x = Variable('x') y = Variable('y') x_min = Variable('x_{min}', 2) y_max = Variable('y_{max}', 0.5) with SignomialsEnabled(): m = Model( x, [Tight([x + y >= 1], raiseerror=True), x >= x_min, y <= y_max]) with self.assertRaises(ValueError): m.localsolve(verbosity=0) m.substitutions[x_min] = 0.5 self.assertAlmostEqual(m.localsolve(verbosity=0)["cost"], 0.5)
def setup(self): constraints = [] components = self.components = [] ####### components ###### m = self.m = Variable("m", "kg", "Mass of Engine Tank") if len(components) > 0: constraints += [Tight([m >= sum(comp.m for comp in components)])] ####### constraints += [m >= 2 * ureg.kg] return [components, constraints]
def setup(self): exec parse_variables(Section.__doc__) constraints = [ # Taking averages, A_in * A_out == A_avg**2, # Volume of chamber V_chamb == A_avg * l, # Area ratio A_in / A_out == k_A, # Mass flow rate rho_in * u_in * A_in == mdot_in, rho_out * u_out * A_out == mdot_out, # Chamber pressure P_chamb**2 == P_in * P_out, # Product generation rate q == rho_p * A_b * r, A_b == l_b * l, A_p_out + r * l_b * dt <= A_p_in, # Stagnation quantities P_t_in >= P_in + 0.5 * rho_in * u_in**2, T_t_in >= T_in + u_in**2 / (2 * c_p), # Ideal gas law P_out == rho_out * R * T_out, # Pressure increase P_out + dP <= P_in, # Making sure burn surface length is feasible l_b >= 2 * np.pi**0.5 * (A_avg)**0.5, l_b <= l_b_max * 2 * np.pi**0.5 * (A_avg)**0.5, # Constraining areas Tight([A_avg + A_p_in <= np.pi * radius**2]), ] with SignomialsEnabled(): constraints += [ # Flow acceleration (conservation of momentum) # Note: assumes constant rate of burn through the chamber dP + rho_in * u_in**2 >= q * u_out / V_chamb * (2. / 3. * l) + rho_in * u_in * u_out, # Burn rate (Saint-Robert's Law, coefficients taken for Space Shuttle SRM) Tight([ r >= r_c * (P_chamb / 1e6 * units('1/Pa'))**0.35 * (1 + 0.5 * r_k * (u_in + u_out)) ]), # Mass flows Tight([mdot_in + q >= mdot_out]), mdot_out >= mdot_in, # Temperatures Tight([ T_t_out * mdot_out <= mdot_in * T_t_in + q * T_amb + q * k_comb_p / c_p ]), # Stagnation quantities Tight([P_t_out <= P_out + 0.5 * rho_out * u_out**2]), Tight([T_t_out <= T_out + u_out**2 / (2 * c_p)]), ] return constraints
def setup(self, nozzle): exec parse_variables(NozzlePerformance.__doc__) constraints = [ # Gas constants c_p == g / gm1 * R, c_v == 1. / gm1 * R, # Mass flow rate mdot == rho_star * u_star * nozzle.A_star, mdot == rho_e * u_e * nozzle.A_e, # Characteristic velocity c_star == P_t * nozzle.A_star / mdot, # Thrust coefficient T == mdot * c_star * c_T, c_T >= 1, # Universal gas law P_e == rho_e * R * T_e, P_star == rho_star * R * T_star, # Stagnation pressure and static pressure at throat (P_t / P_star) == (2.4 / 2.)**(1.4 / 0.4), T_t / T_star == (2.4 / 2.), # Choked throat relations mdot * c_p**0.5 * T_t**0.5 / nozzle.A_star / P_t == chokeConstant, u_star / a_star == 1., # Stagnation temperature 2. * c_p * T_e + u_e**2. <= 2. * c_p * T_t, Tight([T_star + u_star**2. / (2. * c_p) <= T_t], name='TtThroat', printwarning=True), # Exit Mach number M_e == u_e / a_e, M_e >= 1., # Speed of sound a_e**2. == g * R * T_e, a_star**2. == g * R * T_star, # Exit pressure (T_e / T_t)**(1.4 / .4) == P_e / P_t, ] with SignomialsEnabled(): constraints += [ # Thrust T <= mdot * u_e + (P_e - P_atm) * nozzle.A_e, ] return constraints
def setup(self): constraints = [] components = self.components = [] ####### components ###### fuel = self.fuel = EngineFuel() enclosure = self.enclosure = EngineFuelEnclosure() components += [fuel, enclosure] m = self.m = Variable("m", "kg", "Mass of Engine Tank") if len(components) > 0: constraints += [Tight([m >= sum(comp.m for comp in components)])] ####### constraints += [m >= 2 * ureg.kg] return [components, constraints]
def setup(self): # define the structures of the rocket. # includes upper rocket airframe, nosecone, fins constraints = [] components = self.components = [] ######### components ########## m = self.m = Variable("m", 4.6, "kg", "Mass of Structures") if len(components) > 0: constraints += [Tight([m >= sum(comp.m for comp in components)])] ######### constraints ######### #m_fins = self.m_fins = Variable("m_{fins}", 1.2, "kg", "Mass of fins and mounting of fins") #m_nc = self.m_nc = Variable("m_{nc}", 0.5, "kg", "Mass of nose cone") #m_tube = self.m_tube = Variable("m_{tube}", 4, "kg") #m_booster_struc = self.m_booster_struc = Variable("m_{booster_struc}", 0.3, "kg", "Mass needed to mount boosters") #constraints += [m >= m_fins + m_nc + m_tube + m_booster_struc] #constraints += [m >= 4.6*u.kg] return [constraints, components]
def setup(self): constraints = [] components = self.components = [] ####### components ######### # payload payload = self.payload = Payload() # avionics avionics = self.avionics = Avionics() # recovery recovery = self.recovery = Recovery() # main engine engine = self.engine = SimpleEngine() # boosters boosters = self.boosters = Boosters() # structures structures = self.structures = Structures() components += [ payload, avionics, recovery, engine, boosters, structures ] m = self.m = Variable("m", "kg", "Mass of Rocket") constraints += [Tight([m >= sum(comp.m for comp in components)])] ########## constraints ###### # total impulse of main engine # main_impulse = Variable("I_t", 20000, "N s", "Total impulse of main engine") # constraints += [engine.c * engine.m_prop >= main_impulse] pmf = self.pmf = Variable('PMF', 0.20, '', 'Propellant Mass Fraction required') constraints += [engine.m_prop >= pmf * m] # launch rail requirements launch_accel = Variable("a_{launch}", "m/s^2", "Acceleration off launch rail") g = Variable("g", 9.81, "m/s^2", "Acceleration due to gravity") min_a = Variable("min_a", "m/s^2", "minimum launch acceleration") launch_rail_v = Variable("v_{launch}", 30, "m/s", "Velocity off launch rail") launch_rail_l = Variable("L_{launch}", 5, "m", "Length of launch rail") constraints += [min_a >= launch_rail_v**2 / (2 * launch_rail_l)] constraints += [ Tight([launch_accel <= (engine.F + boosters.F - m * g) / m]) ] constraints += [Tight([launch_accel >= min_a])] constraints += [ 0.5 * launch_accel * boosters.t_burn**2 >= launch_rail_l ] constraints += [Loose([boosters.m_prop >= 0.2 * ureg.kg]) ] # from estimate of propellant mass required constraints += [ boosters.m_prop * boosters.c >= boosters.F * boosters.t_burn ] # from estimate of propellant mass required constraints += [Loose([m <= 100 * ureg.kg, m >= 10 * ureg.kg])] TW_main = self.TW_main = Variable( "TW_{main, min}", 2, "", "Main engine thrust to take off weight") constraints += [Loose([engine.F >= TW_main * m * g])] return [components, constraints]
"Example Tight ConstraintSet usage" from gpkit import Variable, Model from gpkit.constraints.tight import Tight Tight.reltol = 1e-2 # set the global tolerance of Tight x = Variable('x') x_min = Variable('x_{min}', 2) m = Model(x, [Tight([x >= 1], reltol=1e-3), # set the specific tolerance x >= x_min]) m.solve(verbosity=0) # prints warning
def setup(self, N, topology_dict, friction='DW', penalty=10.): n_p = len(topology_dict) # number of pipes H = VectorVariable(N, "H", "m", "Head") H_min = VectorVariable(N, "H_{min}", "m", "Minimal Head Required") source = VectorVariable(N, "\dot{V}_+", "m^3/s", "Source", pr=20) sink = VectorVariable(N, "\dot{V}_-", "m^3/s", "Sink", pr=20) rough = VectorVariable(n_p, "\\epsilon", "m", "Pipe Roughness") pipeCost = VectorVariable(n_p, "c_p", "-", "Pipe Cost") L = VectorVariable(n_p, "L", "m", "Pipe Length") D = VectorVariable(n_p, "D", "m", "Pipe Diameter") flow = VectorVariable(n_p, "q", "m^3/s", "Flow Rate") V = VectorVariable(n_p, "v_f", "m/s", "Flow Velocity") maxV = VectorVariable(n_p, "v_{max}", 1e20 * np.ones(n_p), "m/s", 'Maximum Flow Velocity') H_loss = VectorVariable(n_p, "H_L", "m", "Head Loss") slack_out = VectorVariable(N, "S_{out}", "-", "Outflow Slack") slack_in = VectorVariable(N, "S_{in}", "-", "Inflow Slack") slack_h = VectorVariable(n_p, "S_h", "-", "Head Slack") totalCost = Variable("C", "-", "Total Cost") D_max = Variable("D_{max}", "m", "Maximum Diameter") D_min = Variable("D_{min}", "m", "Minimum Diameter") rho = Variable("\\rho", 1000, "kg/m^3", "Density") mu = Variable("\\mu", 8.9e-4, "kg/m/s", "Viscosity") g = Variable("g", 9.81, "m/s^2", "Gravity") if friction == 'DW': relRough = VectorVariable(n_p, "\\bar{\\epsilon}", "-", "Relative Pipe Roughness") Re = VectorVariable(n_p, "Re", "-", "Reynold's Number") f = VectorVariable(n_p, "f", "-", "Friction Factor") constraints = [] with SignomialsEnabled(): for i in range(0, N): flow_in = sink[i] flow_out = source[i] for pipe_index, node in list(topology_dict.items()): if node[0] == i: flow_in += flow[pipe_index] if node[1] == i: flow_out += flow[pipe_index] constraints.extend([ Tight([flow_in <= slack_out[i] * flow_out]), Tight([flow_out <= slack_in[i] * flow_in]), Tight([slack_in[i] >= 1]), Tight([slack_out[i] >= 1]), H[i] >= H_min[i] ]) # Head loss constraints for pipe_index, node in list(topology_dict.items()): if node[0] == i: constraints.extend([ Tight([ H[node[0]] >= H_loss[pipe_index] + H[node[1]] ]), Tight([ H[node[0]] <= slack_h[pipe_index] * (H_loss[pipe_index] + H[node[1]]) ]), Tight([slack_h[pipe_index] >= 1]), ]) for pipe_index in range(n_p): constraints += [ V[pipe_index] <= maxV, pipeCost[pipe_index] == 1.1 * D[pipe_index]**1.5 * L[pipe_index] / units.m**2.5, V[pipe_index] == 4 * flow[pipe_index] / (np.pi * D[pipe_index]**2), D[pipe_index] <= D_max, D[pipe_index] >= D_min ] if friction == "HW": constraints += [ H_loss[pipe_index] == 10.67 * L[pipe_index] * (flow[pipe_index] / units('m^3/s'))**1.852 / ((rough[pipe_index] / units('m'))**1.852 * (D[pipe_index] / units('m'))**4.8704) ] # S (hydraulic slope H/L) = 10.67*Q^1.852 (volumetric flow rate) / # C^1.852 (pipe roughness) /d^4.8704 (pipe diameter) if friction == 'DW': constraints += [ H_loss[pipe_index] == f[pipe_index] * L[pipe_index] * V[pipe_index]**2 / (2 * D[pipe_index] * g), relRough[pipe_index] == rough[pipe_index] / D[pipe_index], Re[pipe_index] == rho * V[pipe_index] * D[pipe_index] / mu, # From frictionFactorFitting.py f[pipe_index]**2.39794 >= 3.26853e-06 * Re[pipe_index]**0.0574443 * relRough[pipe_index]**0.364794 + 0.0001773 * Re[pipe_index]**-0.529499 * relRough[pipe_index]**-0.0810121 + 0.00301918 * Re[pipe_index]**-0.0220498 * relRough[pipe_index]**1.73526 + 0.0734922 * Re[pipe_index]**-1.13629 * relRough[pipe_index]**0.0574655 + 0.000214297 * Re[pipe_index]**0.00035242 * relRough[pipe_index]**0.823896, f[pipe_index] <= 1 ] constraints += [ totalCost >= np.sum(pipeCost) * (np.prod(slack_out) * np.prod(slack_in) * np.prod(slack_h)**penalty) ] return constraints
# Optimization variables sigma1a = Variable("sigma1a") sigma1b = Variable("sigma1b") sigma2a = Variable("sigma2a") sigma2b = Variable("sigma2b") sigma3a = Variable("sigma3a") sigma3b = Variable("sigma3b") p1 = Variable("p1") p2 = Variable("p2") p3 = Variable("p3") # Constraints constraints = [ p1 <= 0.429 * delta + 0.25 * (1 - delta), Tight([ sigma1a + sigma1b <= 1, sigma2a + sigma2b <= 1, sigma3a + sigma3b <= 1 ]), p3 == 1, (sigma1a * 0.3 + sigma1b * 0.2 + (sigma1a * 0.3 + sigma1b * 0.2) * p1) / p1 <= 1 ] # Objective function objective = 1 / sigma1a + 1 / sigma1b + 1 / sigma2a + 1 / sigma2b + 1 / sigma3a + 1 / sigma3b # Formulate the Model m = Model(objective, constraints) # Solve the Model and print the results table print(m.solve(verbosity=0).table())
"Demonstrates manual and auto sweeping and plotting" import matplotlib as mpl mpl.use('Agg') # comment out the lines above to show figures in a window import numpy as np from gpkit import Model, Variable, units from gpkit.constraints.tight import Tight x = Variable("x", "m", "Swept Variable") y = Variable("y", "m^2", "Cost") m = Model(y, [ y >= (x / 2)**-0.5 * units.m**2.5 + 1 * units.m**2, Tight([y >= (x / 2)**2]) ]) # arguments are: model, swept: values, posnomial for y-axis sol = m.sweep({x: np.linspace(1, 3, 20)}, verbosity=0) f, ax = sol.plot(y) ax.set_title("Manually swept (20 points)") f.show() f.savefig("plot_sweep1d.png") sol.save() # arguments are: model, swept: (min, max, optional logtol), posnomial for y-axis sol = m.autosweep({x: (1, 3)}, tol=0.001, verbosity=0) f, ax = sol.plot(y) ax.set_title("Autoswept (7 points)\nGuaranteed to be in blue region") f.show() f.savefig("plot_autosweep1d.png")
def SimPleAC(): "Creates SimpleAC model" # Env. constants g = Variable("g", 9.81, "m/s^2", "gravitational acceleration") mu = Variable("\\mu", 1.775e-5, "kg/m/s", "viscosity of air") rho = Variable("\\rho", 1.23, "kg/m^3", "density of air") rho_f = Variable("\\rho_f", 817, "kg/m^3", "density of fuel") # Non-dimensional constants C_Lmax = Variable("C_{L,max}", 1.6, "-", "max CL with flaps down") e = Variable("e", 0.92, "-", "Oswald efficiency factor") k = Variable("k", 1.17, "-", "form factor") N_ult = Variable("N_{ult}", 3.3, "-", "ultimate load factor") S_wetratio = Variable("(\\frac{S}{S_{wet}})", 2.075, "-", "wetted area ratio") tau = Variable("\\tau", 0.12, "-", "airfoil thickness to chord ratio") W_W_coeff1 = Variable("W_{W_{coeff1}}", 2e-5, "1/m", "wing weight coefficent 1") # 12e-5 originally W_W_coeff2 = Variable("W_{W_{coeff2}}", 60., "Pa", "wing weight coefficent 2") # Dimensional constants Range = Variable("Range", 3000, "km", "aircraft range") TSFC = Variable("TSFC", 0.6, "1/hr", "thrust specific fuel consumption") V_min = Variable("V_{min}", 25, "m/s", "takeoff speed") W_0 = Variable("W_0", 6250, "N", "aircraft weight excluding wing") # Free Variables LoD = Variable("L/D", "-", "lift-to-drag ratio") D = Variable("D", "N", "total drag force") V = Variable("V", "m/s", "cruising speed") W = Variable("W", "N", "total aircraft weight") Re = Variable("Re", "-", "Reynold's number") CDA0 = Variable("(CDA0)", "m^2", "fuselage drag area") # 0.035 originally C_D = Variable("C_D", "-", "drag coefficient") C_L = Variable("C_L", "-", "lift coefficient of wing") C_f = Variable("C_f", "-", "skin friction coefficient") W_f = Variable("W_f", "N", "fuel weight") V_f = Variable("V_f", "m^3", "fuel volume") V_f_avail = Variable("V_{f_{avail}}", "m^3", "fuel volume available") T_flight = Variable("T_{flight}", "hr", "flight time") # Free variables (fixed for performance eval.) A = Variable("A", "-", "aspect ratio") S = Variable("S", "m^2", "total wing area") W_w = Variable("W_w", "N", "wing weight") W_w_strc = Variable("W_w_strc", "N", "wing structural weight") W_w_surf = Variable("W_w_surf", "N", "wing skin weight") V_f_wing = Variable("V_f_wing", "m^3", "fuel volume in the wing") V_f_fuse = Variable("V_f_fuse", "m^3", "fuel volume in the fuselage") objective = W_f constraints = [] # Weight and lift model constraints += [ W >= W_0 + W_w + W_f, W_0 + W_w + 0.5 * W_f <= 0.5 * rho * S * C_L * V**2, W <= 0.5 * rho * S * C_Lmax * V_min**2, T_flight >= Range / V, LoD == C_L / C_D ] # Thrust and drag model C_D_fuse = CDA0 / S C_D_wpar = k * C_f * S_wetratio C_D_ind = C_L**2 / (np.pi * A * e) constraints += [ W_f >= TSFC * T_flight * D, D >= 0.5 * rho * S * C_D * V**2, C_D >= C_D_fuse + C_D_wpar + C_D_ind, V_f_fuse <= 10 * units("m") * CDA0, Re <= (rho / mu) * V * (S / A)**0.5, C_f >= 0.074 / Re**0.2 ] # Fuel volume model with SignomialsEnabled(): constraints += [ V_f == W_f / g / rho_f, # linear with b and tau, quadratic with chord V_f_wing**2 <= 0.0009 * S**3 / A * tau**2, V_f_avail <= V_f_wing + V_f_fuse, # [SP] Tight([V_f_avail >= V_f]) ] # Wing weight model constraints += [ W_w_surf >= W_W_coeff2 * S, W_w_strc**2. >= W_W_coeff1**2 / tau**2 * N_ult**2 * A**3 * (V_f_fuse * g * rho_f + W_0) * W * S, W_w >= W_w_surf + W_w_strc ] m = Model(objective, constraints) return m
def setup(self): constraints = [] components = [] ######## components ########### m = self.m = Variable("m", "kg", "Mass of Engine") if len(components) > 0: constraints += [Tight([m >= sum(comp.m for comp in components)])] ########## constraints ######### m_prop = self.m_prop = Variable("m_{prop}", "kg", "Mass of Propellant") m_dry = self.m_dry = Variable("m_{dry}", "kg", "Dry mass of engine") # constraints += [m_dry >= 0.7 * m] c = self.c = Variable("c", 2100, "m/s", "effective exhaust speed of engine") F = self.F = Variable("F", 750, "N", "Engine thrust") OF = self.OF = Variable("OF", 6, "", "Ox to fuel ratio") m_ox = self.m_ox = Variable("m_{ox}", "kg", "ox mass") m_fuel = self.m_fuel = Variable("m_{fuel}", "kg", "fuel mass") constraints += [Tight([m_prop >= m_ox + m_fuel])] constraints += [Tight([m_fuel * (OF + 1) >= m_prop])] # constraints += [m_fuel * (OF + 1) <= m_prop] constraints += [Tight([m_ox * (1 / OF + 1) >= m_prop])] # constraints += [m_ox * (1 / OF + 1) <= m_prop] constraints += [Tight([m >= m_prop + m_dry])] # size the ox tank v_ox = self.v_ox = Variable("V_{ox}", "cm^3", "Volume of ox tank") l_ox = self.l_ox = Variable("L_{ox}", "m", "Length of ox tank") t_wall = self.t = Variable("t_{wall}", "mm", "Wall Thickness of ox tank") d = self.d = Variable("d_ox", 15, "cm", "Diameter of ox tank") P_ox = self.P = Variable("Tank P", 80, "bar", "Max Ox Tank pressure") sigma_max = Variable("\sigma_{max}", 430, "MPa", "Max stress of tank, Al-7075-T6") # determine the wall thickness needed SF = Variable("SF", 5, "", "Wall thickness safety factor") constraints += [t_wall >= SF * P_ox * d / (2 * sigma_max)] # determine volume required # R = Variable("R", 8.314, "J/mol/K", "Ideal gas constant") # T = Variable("T", 350, "K", "Tank temperature ") # MM = Variable("MM", 44.1, "g/mol", "Molar mass of Nitrous") rho_ox = Variable("rho_{ox}", 490, "kg/m^3", "density of liquid ox") constraints += [v_ox >= (m_ox / rho_ox)] # determine length of ox tank constraints += [l_ox >= 4 * v_ox / (3.14 * d**2)] m_ox_tank = Variable("m_{ox tank}", "kg", "Mass of ox tank") rho_tank = Variable("rho_{ox, tank}", 2700, "kg/m^3", "Density of ox tank (if al)") constraints += [m_ox_tank >= rho_tank * (3.14 * d * l_ox * t_wall) ] # the 2 is for safety factor and endcaps # grain tank sizing m_grain_tank = Variable("m_{grain tank}", "kg", "Mass of grain tank") rho_fuel = Variable("rho_{wax}", 900, "kg/m^3", "Density of fuel") v_fuel = Variable("v_{fuel}", "cm^3", "Volume of fuel") constraints += [Tight([v_fuel >= m_fuel / rho_fuel])] # estimate port such that the grain area is half the cross section area A_grain = Variable("A_{grain}", "cm^2", "cross section area of grain") constraints += [Tight([A_grain <= 0.5 * 3.14 * (d / 2)**2])] #estimate length l_grain = Variable("L_{grain}", "m", "Length of the grain") constraints += [l_grain >= v_fuel / A_grain] # estimate mass, assuming the thickness is the same as the ox constraints += [ Tight([m_grain_tank >= rho_tank * (3.14 * d * l_grain * t_wall)]) ] m_valves = Variable("m_{valves}", 1, "kg", "Mass of valves and plumbing") m_nozzle = Variable("m_{nozzle}", 1, "kg", "Mass of nozzle assembly") constraints += [ Tight([m_dry >= m_ox_tank + m_valves + m_grain_tank + m_nozzle]) ] # impose bounds constraints += [Loose([l_ox >= 0.5 * ureg.m, l_ox <= 2 * ureg.m])] constraints += [Loose([t_wall >= 1 * ureg.mm, t_wall <= 20 * ureg.mm])] return [components, constraints]
def setup(self, N, topology_list=None): H = VectorVariable(N, "H", "m", "Head") H_min = VectorVariable(N, "H_{min}", "m", "Minimal Head Required") H_s = Variable("H_{s}", "m", "Head Source") source = VectorVariable(N, "Sr", "m^3/s", "Source") sink = VectorVariable(N, "Sk", "m^3/s", "Sink") rough = VectorVariable([N, N], "\\epsilon", "m", "Pipe Roughness") relRough = VectorVariable([N, N], "\\epsilon/D", "-", "Relative Pipe Roughness") pipeCost = VectorVariable([N, N], "C_f", "s/m^3", "Pipe Flow Cost") L = VectorVariable([N, N], "L", "m", "Pipe Length") D = VectorVariable([N, N], "D", "m", "Pipe Diameter") maxFlow = VectorVariable([N, N], "F_{max}", "m^3/s", 'Maximum Flow Rate') connect = VectorVariable([N, N], "x", "-", "connectivity") # Integer Variable flow = VectorVariable([N, N], "q", "m^3/s", "Flow Rate") V = VectorVariable([N, N], "v_f", "m/s", "Flow Velocity") H_loss = VectorVariable([N, N], "H_L", "m", "Head Loss") Re = VectorVariable([N, N], "Re", "-", "Reynold's Number") f = VectorVariable([N, N], "f", "-", "Friction Factor") slack_1 = VectorVariable(N, "S_1", "-", "First Slack") slack_2 = VectorVariable(N, "S_2", "-", "Second Slack") slack_h = VectorVariable([N, N], "S_h", "-", "Head Slack") udr = Variable("Udr", "-", "Undirected Topology") slackCost = Variable("C_s", "-", "Slack Cost") totalCost = Variable("C", "-", "Total Cost") D_max = Variable("D_{max}", "m", "Maximum Diameter") D_min = Variable("D_{min}", "m", "Minimum Diameter") rho = Variable("\\rho", "kg/m^3", "Density") mu = Variable("\\mu", "kg/m/s", "Viscosity") g = Variable("g", "m/s^2", "Gravity") constraints = [] # Allowing for solution of known topologies as well if topology_list: for i in range(N): for j in range(N): if [i, j] in topology_list: constraints += [connect[i, j] == 1] else: constraints += [connect[i, j] == 1e-20] with SignomialsEnabled(): for i in range(0, N): # conservation of mass constraints constraints.extend([ Tight([ sink[i] + sum(flow[i, :]) <= slack_1[i] * (source[i] + sum(flow[:, i])) ]), Tight([ source[i] + sum(flow[:, i]) <= slack_2[i] * (sink[i] + sum(flow[i, :])) ]), Tight([slack_2[i] >= 1]), Tight([slack_1[i] >= 1]), ]) # head constraints constraints.extend([ H[i] >= H_min[i], ]) for j in range(0, N): if i != j: constraints.extend([ Tight([ H[i] * slack_h[i, j] >= (H_loss[i, j] + H[j]) * connect[i, j] ]), Tight([ H[i] * connect[i, j] <= slack_h[i, j] * (H_loss[i, j] + H[j]) ]), Tight([slack_h[i, j] >= 1]), ]) # topology constraints constraints += [ connect[i, j] <= 1, connect[i, j] >= udr, connect[i, j] * connect[j, i] <= udr, flow[i, j] <= maxFlow[i, j], D[i, j] <= D_max, D[i, j] >= D_min * (connect[i, j] + connect[j, i]), # flow cost pipeCost[i, j] == 1.1 * D[i, j]**1.5 * L[i, j] * units.s / units.m**5.5, # Darcy-Weisbach Equations H_loss[i, j] == f[i, j] * L[i, j] * V[i, j]**2 / (2 * D[i, j] * g), V[i, j] == 4 * flow[i, j] / (np.pi * D[i, j]**2), relRough[i, j] == rough[i, j] / D[i, j], Re[i, j] == rho * V[i, j] * D[i, j] / mu, # friction factor posynomial approximation f[i, j]**2.39794 >= 3.26853e-06 * Re[i, j]**0.0574443 * relRough[i, j]**0.364794 + 0.0001773 * Re[i, j]**-0.529499 * relRough[i, j]**-0.0810121 + 0.00301918 * Re[i, j]**-0.0220498 * relRough[i, j]**1.73526 + 0.0734922 * Re[i, j]**-1.13629 * relRough[i, j]**0.0574655 + 0.000214297 * Re[i, j]**0.00035242 * relRough[i, j]**0.823896, f[i, j] <= 1, ] else: constraints.extend([ slack_h[i, j] == 1, connect[i, j] == udr, D[i, j] == udr * D[i, j].units, pipeCost[i, j] == udr * pipeCost[i, j].units, H_loss[i, j] == udr * H_loss[i, j].units, f[i, j] == udr, ]) for j in range(i + 1, N): constraints.extend([ D[i, j] == D[j, i], ]) constraints += [ totalCost >= np.sum(flow * pipeCost) * (1 + slackCost * np.prod(slack_1) * np.prod(slack_2) * np.prod(slack_h)) ] return constraints