diff --git a/gpkitmodels/GP/aircraft/tail/empennage.py b/gpkitmodels/GP/aircraft/tail/empennage.py index 0ba09422..8e70c170 100644 --- a/gpkitmodels/GP/aircraft/tail/empennage.py +++ b/gpkitmodels/GP/aircraft/tail/empennage.py @@ -1,33 +1,58 @@ " empennage.py " -from gpkit import Variable, Model +from gpkit import Model, parse_variables from .horizontal_tail import HorizontalTail from .vertical_tail import VerticalTail from .tail_boom import TailBoom, TailBoomState -#pylint: disable=attribute-defined-outside-init +#pylint: disable=attribute-defined-outside-init, no-member, exec-used +#pylint: disable=too-many-instance-attributes, invalid-name, undefined-variable class Empennage(Model): - "empennage model, consisting of vertical, horizontal and tailboom" + """empennage model, consisting of vertical, horizontal and tailboom + + Variables + --------- + mfac 1.0 [-] tail weight margin factor + W [lbf] empennage weight + + Upper Unbounded + --------------- + W, Vv, Vh + + Lower Unbounded + --------------- + lv, lh, Vv, Vh, bv, bh, mh + + LaTex Strings + ------------- + mfac m_{\\mathrm{fac}} + + """ def setup(self): - mfac = Variable("m_{fac}", 1.0, "-", "Tail weight margin factor") - W = Variable("W", "lbf", "empennage weight") + exec parse_variables(Empennage.__doc__) self.htail = HorizontalTail() - self.htail.substitutions.update({"m_{fac}": 1.1}) + self.htail.substitutions.update({self.htail.mfac: 1.1}) + lh = self.lh = self.htail.lh + self.Vh = self.htail.Vh + self.bh = self.htail.b + self.mh = self.htail.mh self.vtail = VerticalTail() - self.vtail.substitutions.update({"m_{fac}": 1.1}) + self.vtail.substitutions.update({self.vtail.mfac: 1.1}) + lv = self.lv = self.vtail.lv + self.Vv = self.vtail.Vv + self.bv = self.vtail.b self.tailboom = TailBoom() self.components = [self.htail, self.vtail, self.tailboom] + l = self.l = self.tailboom.l state = TailBoomState() - loading = [self.tailboom.horizontalbending(self.htail, state), - self.tailboom.verticalbending(self.vtail, state), - self.tailboom.verticaltorsion(self.vtail, state)] + loading = [self.tailboom.hbending(self.tailboom, self.htail, state), + self.tailboom.vbending(self.tailboom, self.vtail, state), + self.tailboom.vtorsion(self.tailboom, self.vtail, state)] constraints = [ - W/mfac >= (self.htail.topvar("W") + self.vtail.topvar("W") - + self.tailboom["W"]), - self.tailboom["l"] >= self.htail["l_h"], - self.tailboom["l"] >= self.vtail["l_v"], + W/mfac >= sum(c.W for c in self.components), + l >= lh, l >= lv, ] return self.components, constraints, loading diff --git a/gpkitmodels/GP/aircraft/tail/horizontal_tail.py b/gpkitmodels/GP/aircraft/tail/horizontal_tail.py index 5fe5c34c..538476a6 100644 --- a/gpkitmodels/GP/aircraft/tail/horizontal_tail.py +++ b/gpkitmodels/GP/aircraft/tail/horizontal_tail.py @@ -1,30 +1,52 @@ " horizontal tail " import numpy as np -from gpkit import Variable +from gpkit import parse_variables from .tail_aero import TailAero from gpkitmodels.GP.aircraft.wing.wing import Wing -from gpkitmodels.GP.aircraft.wing.wing_interior import WingInterior +from gpkitmodels.GP.aircraft.wing.wing_core import WingCore -#pylint: disable=attribute-defined-outside-init, unused-variable +#pylint: disable=attribute-defined-outside-init, no-member +#pylint: disable=exec-used, undefined-variable class HorizontalTail(Wing): - "horizontal tail model" + """ Horizontal Tail Model + + Variables + --------- + Vh [-] horizontal tail volume coefficient + lh [ft] horizontal tail moment arm + CLhmin 0.75 [-] max downlift coefficient + mh [-] horizontal tail span effectiveness + + Upper Unbounded + --------------- + lh, Vh, W + + Lower Unbounded + --------------- + lh, Vh, b, mh + + LaTex Strings + ------------- + Vh V_{\\mathrm{h}} + lh l_{\\mathrm{h}} + CLmin C_{L_{\\mathrm{min}}} + mh m_{\\mathrm{h}} + + """ flight_model = TailAero - fillModel = WingInterior + fillModel = WingCore sparModel = None - def setup(self, N=3, lam=0.8): + def setup(self, N=3): + exec parse_variables(HorizontalTail.__doc__) + self.ascs = Wing.setup(self, N) - self.planform.substitutions.update({"AR": 4, "\\tau": 0.08, - "\\lambda": 0.8}) - self.skin.substitutions.update({"\\rho_{CFRP}": 0.049}) - self.foam.substitutions.update({"\\bar{A}_{jh01}": 0.0548, - "\\rho_{foam}": 0.024}) - Vh = Variable("V_h", "-", "horizontal tail volume coefficient") - lh = Variable("l_h", "ft", "horizontal tail moment arm") - CLhmin = Variable("(C_{L_h})_{min}", 0.75, "-", - "max downlift coefficient") - mh = Variable("m_h", "-", "horizontal tail span effectiveness") + self.planform.substitutions.update( + {self.planform.AR: 4, self.planform.tau: 0.08, + self.planform.lam: 0.8}) + self.skin.substitutions.update({self.skin.rhocfrp: 0.049}) + self.foam.substitutions.update({self.foam.Abar: 0.0548, + self.foam.rhocore: 0.024}) return self.ascs, mh*(1+2.0/self.planform["AR"]) <= 2*np.pi - diff --git a/gpkitmodels/GP/aircraft/tail/tail_aero.py b/gpkitmodels/GP/aircraft/tail/tail_aero.py index 049490e3..5239c41b 100644 --- a/gpkitmodels/GP/aircraft/tail/tail_aero.py +++ b/gpkitmodels/GP/aircraft/tail/tail_aero.py @@ -1,36 +1,46 @@ " tail aerodynamics " -from gpkit import Variable, Model import os -from gpfit.fit_constraintset import XfoilFit import pandas as pd +from gpkit import Model, parse_variables +from gpfit.fit_constraintset import XfoilFit + +#pylint: disable=exec-used, attribute-defined-outside-init, undefined-variable +#pylint: disable=no-member class TailAero(Model): - "horizontal tail aero model" - def setup(self, static, state): + """Tail Aero Model + + Variables + --------- + Re [-] Reynolds number + Cd [-] drag coefficient - name = get_lowername(static.__class__.__name__) - Re = Variable("Re", "-", "%s reynolds number" % name) - Cd = Variable("C_d", "-", "%s drag coefficient" % name) + Upper Unbounded + --------------- + Cd, Re + LaTex Strings + ------------- + Cd C_d + + """ + def setup(self, static, state): + exec parse_variables(TailAero.__doc__) + + cmac = self.cmac = static.planform.cmac + b = self.b = static.planform.b + S = self.S = static.planform.S path = os.path.dirname(__file__) fd = pd.read_csv(path + os.sep + "tail_dragfit.csv").to_dict( orient="records")[0] constraints = [ - Re == (state["V"]*state["\\rho"]*static["S"]/static["b"] + Re == (state["V"]*state["\\rho"]*S/b / state["\\mu"]), # XfoilFit(fd, Cd, [Re, static["\\tau"]], # err_margin="RMS", airfoil="naca 0008") - XfoilFit(fd, Cd, [Re, static["\\tau"]], err_margin="RMS") + XfoilFit(fd, Cd, [Re, static.planform.tau], err_margin="RMS") ] return constraints -def get_lowername(classname): - start = [c for c in classname if c.isupper()] - name = [classname] - for t in start: - name = name[-1].split(t) - - n = " ".join([t.lower()+n for n, t in zip(name, start)]) - return n diff --git a/gpkitmodels/GP/aircraft/tail/tail_boom.py b/gpkitmodels/GP/aircraft/tail/tail_boom.py index 71c891a5..6591e557 100644 --- a/gpkitmodels/GP/aircraft/tail/tail_boom.py +++ b/gpkitmodels/GP/aircraft/tail/tail_boom.py @@ -1,126 +1,223 @@ " tail boom model " import numpy as np -from gpkit import Variable, Model +from gpkit import Model, parse_variables -class TailBoom(Model): - "tail boom model" - def setup(self): - - l = Variable("l", "ft", "tail boom length") - E = Variable("E", 150e9, "N/m^2", "young's modulus carbon fiber") - k = Variable("k", 0.8, "-", "tail boom inertia value") - kfac = Variable("(1-k/2)", 1-k.value/2, "-", "(1-k/2)") - I0 = Variable("I_0", "m^4", "tail boom moment of inertia") - d0 = Variable("d_0", "in", "tail boom diameter") - t0 = Variable("t_0", "mm", "tail boom thickness") - tmin = Variable("t_{min}", 0.25, "mm", "minimum tail boom thickness") - rhocfrp = Variable("\\rho_{CFRP}", 1.6, "g/cm^3", "density of CFRP") - g = Variable("g", 9.81, "m/s^2", "Gravitational acceleration") - W = Variable("W", "lbf", "tail boom weight") - J = Variable("J", "m^4", "tail boom polar moment of inertia") - S = Variable("S", "ft**2", "tail boom surface area") - mfac = Variable("m_{fac}", 1.0, "-", "tail boom margin factor") - - constraints = [ - I0 <= np.pi*t0*d0**3/8.0, - W/mfac >= np.pi*g*rhocfrp*d0*l*t0*kfac, - t0 >= tmin, - J <= np.pi/8.0*d0**3*t0, - S == l*np.pi*d0, - k == k, - E == E - ] - - return constraints - - def flight_model(self, state): - return TailBoomAero(self, state) - - def horizontalbending(self, htail, state): - return HorizontalBoomBending(self, htail, state) - - def verticalbending(self, vtail, state): - return VerticalBoomBending(self, vtail, state) - - def verticaltorsion(self, vtail, state): - return VerticalBoomTorsion(self, vtail, state) +#pylint: disable=exec-used, undefined-variable, invalid-name +#pylint: disable=attribute-defined-outside-init class TailBoomAero(Model): - "horizontal tail aero model" - def setup(self, static, state): + """ Tail Boom Aero Model - Cf = Variable("C_f", "-", "fuselage skin friction coefficient") - Re = Variable("Re", "-", "fuselage reynolds number") + Variables + --------- + Cf [-] tail boom skin friction coefficient + Re [-] tail boom reynolds number + + Upper Unbounded + --------------- + Re, l, Cf + + LaTex Strings + ------------- + Cf C_f + + """ + def setup(self, static, state): + exec parse_variables(TailBoomAero.__doc__) - constraints = [ - Re == (state["V"]*state["\\rho"]*static["l"]/state["\\mu"]), - Cf >= 0.455/Re**0.3, - ] + l = self.l = static.l - return constraints + return [Re == (state["V"]*state["\\rho"]*l/state["\\mu"]), + Cf >= 0.455/Re**0.3, + ] class TailBoomState(Model): - "tail boom design state" - def setup(self): + """ Tail Boom Loading State + + Variables + --------- + rhosl 1.225 [kg/m^3] air density at sea level + Vne 40 [m/s] never exceed vehicle speed - rhosl = Variable("\\rho_{sl}", 1.225, "kg/m^3", - "air density at sea level") - Vne = Variable("V_{NE}", 40, "m/s", "never exceed vehicle speed") + LaTex Strings + ------------- + rhosl \\rho_{\\mathrm{sl}} + Vne V_{\\mathrm{NE}} - constraints = [rhosl == rhosl, - Vne == Vne] + """ + def setup(self): + exec parse_variables(TailBoomState.__doc__) - return constraints class VerticalBoomTorsion(Model): - "tail boom torison case" - def setup(self, tailboom, vtail, state): + """ Tail Boom Torsion from Vertical Tail - T = Variable("T", "N*m", "vertical tail moment") - taucfrp = Variable("\\tau_{CFRP}", 210, "MPa", "torsional stress limit") + Variables + --------- + T [N*m] vertical tail moment + taucfrp 210 [MPa] torsional stress limit of carbon - constraints = [ - T >= (0.5*state["\\rho_{sl}"]*state["V_{NE}"]**2*vtail["S"] - * vtail["C_{L_{max}}"]*vtail["b"]), - taucfrp >= T*tailboom["d_0"]/2/tailboom["J"] - ] + Upper Unbounded + --------------- + J - return constraints + Lower Unbounded + --------------- + d0, b, S -class VerticalBoomBending(Model): - "tail boom bending loading case" + LaTex Strings + ------------- + taucfrp \\tau_{\\mathrm{CFRP}} + + """ def setup(self, tailboom, vtail, state): + exec parse_variables(VerticalBoomTorsion.__doc__) - F = Variable("F", "N", "vertical tail force") - th = Variable("\\theta", "-", "tail boom deflection angle") - thmax = Variable("\\theta_{max}", 0.1, "-", - "max tail boom deflection angle") + J = self.J = tailboom.J + d0 = self.d0 = tailboom.d0 + b = self.b = vtail.planform.b + S = self.S = vtail.planform.S + rhosl = self.rhosl = state.rhosl + Vne = self.Vne = state.Vne + CLmax = vtail.planform.CLmax - constraints = [ - F >= (0.5*state["\\rho_{sl}"]*state["V_{NE}"]**2*vtail["S"] - * vtail["C_{L_{max}}"]), - th >= (F*tailboom["l"]**2/tailboom["E"]/tailboom["I_0"] - * (1+tailboom["k"])/2), - th <= thmax, - ] + return [T >= 0.5*rhosl*Vne**2*S*CLmax*b, + taucfrp >= T*d0/2/J + ] - return constraints +class VerticalBoomBending(Model): + """ Tail Boom Bending from Vtail Deflection + + Variables + --------- + F [N] vertical tail force + th [-] tail boom deflection angle + thmax 0.1 [-] max tail boom deflection angle + + Upper Unbounded + --------------- + I0 + + Lower Unbounded + --------------- + S, l + + LaTex Strings + ------------- + th \\theta + thmax \\theta_{\\mathrm{max}} + + """ + def setup(self, tailboom, vtail, state): + exec parse_variables(VerticalBoomBending.__doc__) + + I0 = self.I0 = tailboom.I0 + l = self.l = tailboom.l + S = self.S = vtail.planform.S + E = self.E = tailboom.E + k = self.k = tailboom.k + rhosl = self.rhosl = state.rhosl + Vne = self.Vne = state.Vne + CLmax = vtail.planform.CLmax + + return [F >= 0.5*rhosl*Vne**2*S*CLmax, + th >= F*l**2/E/I0*(1+k)/2, + th <= thmax, + ] class HorizontalBoomBending(Model): - "tail boom bending loading case" + """ Tail Boom Bending from Htail Deflection + + Variables + --------- + F [N] horizontal tail force + th [-] tail boom deflection angle + thmax 0.1 [-] max tail boom deflection angle + + Upper Unbounded + --------------- + I0 + + Lower Unbounded + --------------- + S, l + + LaTex Strings + ------------- + th \\theta + thmax \\theta_{\\mathrm{max}} + + """ def setup(self, tailboom, htail, state): + exec parse_variables(HorizontalBoomBending.__doc__) + + I0 = self.I0 = tailboom.I0 + l = self.l = tailboom.l + S = self.S = htail.planform.S + E = self.E = tailboom.E + k = self.k = tailboom.k + rhosl = self.rhosl = state.rhosl + Vne = self.Vne = state.Vne + CLmax = htail.planform.CLmax + + return [F >= 0.5*rhosl*Vne**2*S*CLmax, + th >= F*l**2/E/I0*(1+k)/2, + th <= thmax, + ] - F = Variable("F", "N", "horizontal tail force") - th = Variable("\\theta", "-", "tail boom deflection angle") - thmax = Variable("\\theta_{max}", 0.1, "-", - "max tail boom deflection angle") +class TailBoom(Model): + """ Tail Boom Model + + Variables + --------- + l [ft] tail boom length + E 150e9 [N/m^2] Youngs modulus for carbon fiber + k 0.8 [-] tail boom taper index + kfac self.minusk2 [-] (1-k/2) + I0 [m^4] tail boom moment of inertia + d0 [in] tail boom diameter + t0 [in] tail boom thickness + tmin 0.25 [mm] minimum tail boom thickness + rhocfrp 1.6 [g/cm^3] density of CFRP + g 9.81 [m/s^2] gravitational acceleration + W [lbf] tail boom weight + J [m^4] tail boom polar moment of inertia + S [ft^2] tail boom surface area + mfac 1.0 [-] tail boom margin factor + + Upper Unbounded + --------------- + W + + Lower Unbounded + --------------- + S, J, l, I0 + + LaTex Strings + ------------- + kfac (1-k/2) + I0 I_0 + d0 d_0 + t0 t_0 + tmin t_{\\mathrm{min}} + rhocfrp \\rho_{\\mathrm{CFRP}} + mfac m_{\\mathrm{fac}} + + """ + + minusk2 = lambda self, c: 1-c[self.k]/2. + flight_model = TailBoomAero + hbending = HorizontalBoomBending + vbending = VerticalBoomBending + vtorsion = VerticalBoomTorsion + + def setup(self): + exec parse_variables(TailBoom.__doc__) - constraints = [ - F >= (0.5*state["\\rho_{sl}"]*state["V_{NE}"]**2*htail["S"] - * htail["C_{L_{max}}"]), - th >= (F*tailboom["l"]**2/tailboom["E"]/tailboom["I_0"] - * (1+tailboom["k"])/2), - th <= thmax, - ] + return [I0 <= np.pi*t0*d0**3/8.0, + W/mfac >= np.pi*g*rhocfrp*d0*l*t0*kfac, + t0 >= tmin, + J <= np.pi/8.0*d0**3*t0, + S == l*np.pi*d0, + ] - return constraints diff --git a/gpkitmodels/GP/aircraft/tail/tail_tests.py b/gpkitmodels/GP/aircraft/tail/tail_tests.py index d102cc5e..7c8693a0 100644 --- a/gpkitmodels/GP/aircraft/tail/tail_tests.py +++ b/gpkitmodels/GP/aircraft/tail/tail_tests.py @@ -3,47 +3,64 @@ from gpkitmodels.GP.aircraft.tail.vertical_tail import VerticalTail from gpkitmodels.GP.aircraft.tail.empennage import Empennage from gpkitmodels.GP.aircraft.wing.wing_test import FlightState -from gpkit import Model +from gpkit import Model, Variable, units + +#pylint: disable=no-member def test_htail(): + Sw = Variable("S_w", 50, "ft**2", "wing area") + cmac = Variable("cmac", 15, "in", "wing MAC") ht = HorizontalTail() fs = FlightState() - ht.substitutions.update({ht.topvar("W"): 5, "m_h": 0.01, "AR": 4}) + ht.substitutions.update({ht.W: 5, ht.mh: 0.01, ht.planform.AR: 4, + ht.Vh: 0.5, ht.lh: 10}) perf = ht.flight_model(ht, fs) - m = Model(perf["C_d"], [ht, perf]) + m = Model(perf.Cd, [ht.Vh <= ht.planform.S*ht.lh/Sw/cmac, ht, perf]) m.solve(verbosity=0) def test_vtail(): - ht = VerticalTail() + Sw = Variable("S_w", 50, "ft**2", "wing area") + bw = Variable("b_w", 20, "ft", "wing span") + vt = VerticalTail() fs = FlightState() - ht.substitutions.update({ht.topvar("W"): 5, "AR": 3}) - perf = ht.flight_model(ht, fs) + vt.substitutions.update({vt.W: 5, vt.planform.AR: 3, vt.Vv: 0.04, + vt.lv: 10}) + perf = vt.flight_model(vt, fs) - m = Model(perf["C_d"], [ht, perf]) + m = Model(perf.Cd, [vt.Vv <= vt.planform.S*vt.lv/Sw/bw, vt, perf]) m.solve(verbosity=0) -# def test_emp(): -# -# emp = Empennage() -# fs = FlightState() -# emp.substitutions.update({emp.topvar("W"): 10, "l": 5, -# emp.htail.planform["AR"]: 4, -# emp.vtail.planform["AR"]: 4}) -# htperf = emp.htail.flight_model(emp.htail, fs) -# vtperf = emp.vtail.flight_model(emp.vtail, fs) -# tbperf = emp.tailboom.flight_model(fs) -# -# m = Model(htperf["C_d"] + vtperf["C_d"] + tbperf["C_f"], -# [emp, fs, htperf, vtperf, tbperf]) -# m.solve(verbosity=0) +def test_emp(): + + Sw = Variable("S_w", 50, "ft**2", "wing area") + bw = Variable("b_w", 20, "ft", "wing span") + cmac = Variable("cmac", 15, "in", "wing MAC") + emp = Empennage() + fs = FlightState() + emp.substitutions.update({emp.W: 10, emp.tailboom.l: 5, + emp.htail.planform.AR: 4, + emp.vtail.planform.AR: 4, + emp.vtail.Vv: 0.04, + emp.htail.Vh: 0.4, + emp.htail.mh: 0.01}) + htperf = emp.htail.flight_model(emp.htail, fs) + vtperf = emp.vtail.flight_model(emp.vtail, fs) + tbperf = emp.tailboom.flight_model(emp.tailboom, fs) + + m = Model(htperf.Cd + vtperf.Cd + tbperf.Cf, + [emp.vtail.lv == emp.tailboom.l, emp.htail.lh == emp.tailboom.l, + emp.htail.Vh <= emp.htail.planform.S*emp.htail.lh/Sw/cmac, + emp.vtail.Vv <= emp.vtail.planform.S*emp.vtail.lv/Sw/bw, + emp, fs, htperf, vtperf, tbperf]) + m.solve(verbosity=0) def test(): test_htail() test_vtail() - # test_emp() + test_emp() if __name__ == "__main__": test() diff --git a/gpkitmodels/GP/aircraft/tail/vertical_tail.py b/gpkitmodels/GP/aircraft/tail/vertical_tail.py index b409507f..90ed2b1d 100644 --- a/gpkitmodels/GP/aircraft/tail/vertical_tail.py +++ b/gpkitmodels/GP/aircraft/tail/vertical_tail.py @@ -1,26 +1,44 @@ " vertical tail " -from gpkit import Variable +from gpkit import parse_variables from .tail_aero import TailAero from gpkitmodels.GP.aircraft.wing.wing import Wing -from gpkitmodels.GP.aircraft.wing.wing_interior import WingInterior +from gpkitmodels.GP.aircraft.wing.wing_core import WingCore -#pylint: disable=attribute-defined-outside-init, unused-variable +#pylint: disable=attribute-defined-outside-init, no-member, exec-used class VerticalTail(Wing): - "vertical tail model" + """ Vertical Tail Model + + Variables + --------- + Vv [-] vertical tail volume coefficient + lv [ft] vertical tail moment arm + + Upper Unbounded + --------------- + lv, Vv, W + + Lower Unbounded + --------------- + lv, Vv, b + + LaTex Strings + ------------- + Vv V_{\\mathrm{v}} + lv l_{\\mathrm{v}} + + """ flight_model = TailAero - fillModel = WingInterior + fillModel = WingCore sparModel = None - def setup(self, N=3, lam=0.8): + def setup(self, N=3): + exec parse_variables(VerticalTail.__doc__) self.ascs = Wing.setup(self, N) - self.planform.substitutions.update({"\\tau": 0.08, "\\lambda": 0.8}) - self.skin.substitutions.update({"\\rho_{CFRP}": 0.049}) - self.foam.substitutions.update({"\\bar{A}_{jh01}": 0.0548, - "\\rho_{foam}": 0.024}) - - Vv = Variable("V_v", "-", "vertical tail volume coefficient") - lv = Variable("l_v", "ft", "vertical tail moment arm") + self.planform.substitutions.update( + {self.planform.tau: 0.08, self.planform.lam: 0.8}) + self.skin.substitutions.update({self.skin.rhocfrp: 0.049}) + self.foam.substitutions.update({self.foam.Abar: 0.0548, + self.foam.rhocore: 0.024}) return self.ascs, self.components - diff --git a/gpkitmodels/GP/aircraft/wing/boxspar.py b/gpkitmodels/GP/aircraft/wing/boxspar.py index db99f961..048a7a1a 100644 --- a/gpkitmodels/GP/aircraft/wing/boxspar.py +++ b/gpkitmodels/GP/aircraft/wing/boxspar.py @@ -1,48 +1,79 @@ -" cap spar " -from gpkit import Model, Variable, Vectorize -from sparloading import SparLoading -from gustloading import GustL +" box spar " +from gpkit import Model, parse_variables +from .sparloading import SparLoading +from .gustloading import GustL + +#pylint: disable=exec-used, undefined-variable, unused-argument, invalid-name class BoxSpar(Model): - "cap spar model" + """ Box Spar Model + + Scalar Variables + ---------------- + rhocfrp 1.6 [g/cm^3] density of CFRP + E 2e7 [psi] Young modulus of CFRP + W [lbf] spar weight + wlim 0.15 [-] spar width to chord ratio + tshearmin 0.012 [in] min gauge shear web thickness + g 9.81 [m/s^2] gravitational acceleration + mfac 0.97 [-] curvature knockdown factor + rhocore 0.036 [g/cm^3] foam core density + tcoret 0.02 [-] core to thickness ratio + + Variables of length N-1 + ----------------------- + hin [in] height between caps + I [m^4] spar x moment of inertia + Sy [m^3] section modulus + dm [kg] segment spar mass + w [in] spar width + t [in] spar cap thickness + tshear [in] shear web thickness + tcore [in] core thickness + + Upper Unbounded + --------------- + W + + Lower Unbounded + --------------- + Sy, b + + LaTex Strings + ------------- + rhocfrp \\rho_{\\mathrm{CFRP}} + wlim w_{\\mathrm{lim}} + tshearmin t_{\\mathrm{shear-min}} + mfac m_{\\mathrm{fac}} + rhocore \\rho_{\\mathrm{core}} + hin h_{\\mathrm{in}_i} + I I_i + Sy S_{y_i} + dm \\Delta{m} + w w_i + t t_i + tshear t_{\\mathrm{shear}_i} + tcoret (t_{\\mathrm{core}}/t) + + """ + loading = SparLoading + gustloading = GustL + def setup(self, N, surface): + exec parse_variables(BoxSpar.__doc__) + + b = self.b = surface.b + cave = surface.cave + tau = surface.tau + deta = surface.deta - # phyiscal properties - rhocfrp = Variable("\\rho_{CFRP}", 1.6, "g/cm^3", "density of CFRP") - E = Variable("E", 2e7, "psi", "Youngs modulus of CFRP") - - with Vectorize(N-1): - hin = Variable("h_{in}", "in", "inner spar height") - I = Variable("I", "m^4", "spar x moment of inertia") - Sy = Variable("S_y", "m**3", "section modulus") - dm = Variable("dm", "kg", "segment spar mass") - w = Variable("w", "in", "spar width") - t = Variable("t", "in", "spar cap thickness") - tshear = Variable("t_{shear}", "in", "shear web thickness") - tcore = Variable("t_{core}", "in", "core thickness") - - W = Variable("W", "lbf", "spar weight") - tcoret = Variable("(t_{core})/t", 0.02, "-", "core to thickness ratio") - wlim = Variable("w_{lim}", 0.15, "-", "spar width to chord ratio") - tshearmin = Variable("t_{shear-min}", 0.012, "in", - "min shear web thickness") - g = Variable("g", 9.81, "m/s^2", "gravitational acceleration") - mfac = Variable("m_{fac}", 0.97, "-", "curvature knockdown factor") - rhofoam = Variable("\\rho_{foam}", 0.036, "g/cm^3", "foam density") - - constraints = [ - I/mfac <= w*t*hin**2, - dm >= (rhocfrp*(4*w*t + 2*tshear*(hin + 2*tcore + 4*t)) - + rhofoam*w*tcore*2)*surface["b"]/2*surface["d\\eta"], - w <= wlim*surface["c_{ave}"], - surface["c_{ave}"]*surface["\\tau"] >= hin + 4*t + 2*tcore, - W >= 2*dm.sum()*g, - Sy*(hin/2 + 2*t + tcore) <= I, - tshear >= tshearmin, - tcore >= tcoret*surface["c_{ave}"]*surface["\\tau"] - ] - - self.loading = SparLoading - self.gustloading = GustL - - return constraints + return [I/mfac <= w*t*hin**2, + dm >= (rhocfrp*(4*w*t + 2*tshear*(hin + 2*tcore + 4*t)) + + rhocore*w*tcore*2)*b/2*deta, + w <= wlim*cave, + cave*tau >= hin + 4*t + 2*tcore, + W >= 2*dm.sum()*g, + Sy*(hin/2 + 2*t + tcore) <= I, + tshear >= tshearmin, + tcore >= tcoret*cave*tau + ] diff --git a/gpkitmodels/GP/aircraft/wing/capspar.py b/gpkitmodels/GP/aircraft/wing/capspar.py index 83493ed6..019c493a 100644 --- a/gpkitmodels/GP/aircraft/wing/capspar.py +++ b/gpkitmodels/GP/aircraft/wing/capspar.py @@ -1,45 +1,75 @@ " cap spar " -from gpkit import Model, Variable, Vectorize -from sparloading import SparLoading -from gustloading import GustL +from gpkit import Model, parse_variables +from .sparloading import SparLoading +from .gustloading import GustL + +#pylint: disable=exec-used, undefined-variable, unused-argument, invalid-name class CapSpar(Model): - "cap spar model" + """ Cap Spar Model + + Scalar Variables + ---------------- + rhocfrp 1.6 [g/cm^3] density of CFRP + E 2e7 [psi] Young modulus of CFRP + W [lbf] spar weight + wlim 0.15 [-] spar width to chord ratio + tshearmin 0.012 [in] min gauge shear web thickness + g 9.81 [m/s^2] gravitational acceleration + mfac 0.97 [-] curvature knockdown factor + rhocore 0.036 [g/cm^3] foam core density + + Variables of length N-1 + ----------------------- + hin [in] height between caps + I [m^4] spar x moment of inertia + Sy [m^3] section modulus + dm [kg] segment spar mass + w [in] spar width + t [in] spar cap thickness + tshear [in] shear web thickness + + Upper Unbounded + --------------- + W, cave + + Lower Unbounded + --------------- + Sy, b + + LaTex Strings + ------------- + rhocfrp \\rho_{\\mathrm{CFRP}} + wlim w_{\\mathrm{lim}} + tshearmin t_{\\mathrm{shear-min}} + mfac m_{\\mathrm{fac}} + rhocore \\rho_{\\mathrm{core}} + hin h_{\\mathrm{in}_i} + I I_i + Sy S_{y_i} + dm \\Delta{m} + w w_i + t t_i + tshear t_{\\mathrm{shear}_i} + + """ + loading = SparLoading + gustloading = GustL + def setup(self, N, surface): + exec parse_variables(CapSpar.__doc__) + + cave = self.cave = surface.cave + b = self.b = surface.b + deta = surface.deta + tau = surface.tau - # phyiscal properties - rhocfrp = Variable("\\rho_{CFRP}", 1.6, "g/cm^3", "density of CFRP") - E = Variable("E", 2e7, "psi", "Youngs modulus of CFRP") - - with Vectorize(N-1): - hin = Variable("h_{in}", "in", "inner spar height") - I = Variable("I", "m^4", "spar x moment of inertia") - Sy = Variable("S_y", "m**3", "section modulus") - dm = Variable("dm", "kg", "segment spar mass") - w = Variable("w", "in", "spar width") - t = Variable("t", "in", "spar cap thickness") - tshear = Variable("t_{shear}", "in", "shear web thickness") - - W = Variable("W", "lbf", "spar weight") - wlim = Variable("w_{lim}", 0.15, "-", "spar width to chord ratio") - tshearmin = Variable("t_{shear-min}", 0.012, "in", - "min shear web thickness") - g = Variable("g", 9.81, "m/s^2", "gravitational acceleration") - mfac = Variable("m_{fac}", 0.97, "-", "curvature knockdown factor") - rhofoam = Variable("\\rho_{foam}", 0.036, "g/cm^3", "foam density") - - constraints = [ - I/mfac <= 2*w*t*(hin/2)**2, - dm >= (rhocfrp*(2*w*t + 2*tshear*(hin + 2*t)) - + rhofoam*w*hin)*surface["b"]/2*surface["d\\eta"], - W >= 2*dm.sum()*g, - w <= wlim*surface["c_{ave}"], - surface["c_{ave}"]*surface["\\tau"] >= hin + 2*t, - Sy*(hin/2 + t) <= I, - tshear >= tshearmin - ] - - self.loading = SparLoading - self.gustloading = GustL - - return constraints + return [I/mfac <= 2*w*t*(hin/2)**2, + dm >= (rhocfrp*(2*w*t + 2*tshear*(hin + 2*t)) + + rhocore*w*hin)*b/2*deta, + W >= 2*dm.sum()*g, + w <= wlim*cave, + cave*tau >= hin + 2*t, + Sy*(hin/2 + t) <= I, + tshear >= tshearmin + ] diff --git a/gpkitmodels/GP/aircraft/wing/gustloading.py b/gpkitmodels/GP/aircraft/wing/gustloading.py index 5d4bf386..af62d018 100644 --- a/gpkitmodels/GP/aircraft/wing/gustloading.py +++ b/gpkitmodels/GP/aircraft/wing/gustloading.py @@ -2,32 +2,60 @@ import os from numpy import pi, hstack, cos import pandas as pd -from gpkit import Variable, Vectorize +from gpkit import parse_variables from gpfit.fit_constraintset import FitCS from .sparloading import SparLoading -#pylint: disable=invalid-name, no-member, arguments-differ -#pylint: disable=attribute-defined-outside-init +#pylint: disable=invalid-name, no-member, arguments-differ, exec-used +#pylint: disable=attribute-defined-outside-init, undefined-variable class GustL(SparLoading): - "spar loading model" + """ Gust Loading Model + + Variables + --------- + vgust 10 [m/s] gust velocity + Ww [lbf] wing weight + v [m/s] vehicle speed + cl [-] wing lift coefficient + + Variables of length wing.N + -------------------------- + agust [-] gust angle of attack + cosminus1 self.return_cosm1 [-] 1 minus cosine factor + + Upper Unbounded + --------------- + v, cl, I, tshear, Sy, cave + + Lower Unbounded + --------------- + Ww, b + + LaTex Strings + ------------- + vgust V_{\\mathrm{gust}} + Ww W_{\\mathrm{w}} + cl c_l + agust \\alpha_{\\mathrm{gust}} + cosminus1 (cos(x)-1) + + """ new_qbarFun = None new_SbarFun = None - def setup(self, static): + return_cosm1 = lambda self, c: hstack( + [1e-10, 1-cos(c[self.wing.planform.eta][1:]*pi/2)]) - self.load = SparLoading.setup(self, static) - vgust = Variable("V_{gust}", 10, "m/s", "gust velocity") - Ww = Variable("W_w", "lbf", "wing weight") - v = Variable("V", "m/s", "speed") - cl = Variable("c_l", "-", "wing lift coefficient") + def setup(self, wing): + exec parse_variables(GustL.__doc__) + self.load = SparLoading.setup(self, wing) - with Vectorize(static.N): - agust = Variable("\\alpha_{gust}", "-", "gust angle of attack") - return_cosm1 = lambda c: hstack( - [1e-10, 1-cos(c[static["\\eta"]][1:]*pi/2)]) - cosminus1 = Variable("1-cos(\\eta)", return_cosm1, - "-", "1 minus cosine factor") + self.b = self.wing.planform.b + self.I = self.wing.spar.I + self.Sy = self.wing.spar.Sy + self.cave = self.wing.planform.cave + self.tshear = self.wing.spar.tshear path = os.path.dirname(os.path.abspath(__file__)) df = pd.read_csv(path + os.sep + "arctan_fit.csv").to_dict( @@ -36,7 +64,7 @@ def setup(self, static): constraints = [ # fit for arctan from 0 to 1, RMS = 0.044 FitCS(df, agust, [cosminus1*vgust/v]), - self.beam["\\bar{q}"] >= self.static["\\bar{c}"]*( + self.beam["\\bar{q}"] >= self.wing.planform.cbar*( 1 + 2*pi*agust/cl*(1+Ww/self.W)), ] diff --git a/gpkitmodels/GP/aircraft/wing/sparloading.py b/gpkitmodels/GP/aircraft/wing/sparloading.py index 2837a5e8..b4b06932 100644 --- a/gpkitmodels/GP/aircraft/wing/sparloading.py +++ b/gpkitmodels/GP/aircraft/wing/sparloading.py @@ -1,46 +1,70 @@ -" cap spar " -from numpy import flip -from gpkit import Model, Variable, Vectorize +" spar loading " +from gpkit import Model, parse_variables from gpkitmodels.GP.beam.beam import Beam -#pylint: disable=invalid-name +#pylint: disable=no-member, unused-argument, exec-used, invalid-name +#pylint: disable=undefined-variable, attribute-defined-outside-init class SparLoading(Model): - "spar loading model" + """ Spar Loading Model - def new_qbarFun(self, c): - " define qbar model for chord loading " - barc = self.static["\\bar{c}"] - return [f(c) for f in self.static.substitutions[barc]] + Variables + --------- + Nmax 5 [-] max loading + sigmacfrp 1700e6 [Pa] CFRP max stress + taucfrp 450e6 [Pa] CFRP fabric stress + kappa 0.2 [-] max tip deflection ratio + W [lbf] loading weight + + Variables of length wing.N-1 + ---------------------------- + Mr [N*m] wing section root moment - def setup(self, static): + Upper Unbounded + --------------- + I, tshear, Sy, cave - self.static = static - Nmax = Variable("N_{max}", 5, "-", "max loading") + Lower Unbounded + --------------- + b, W - sigmacfrp = Variable("\\sigma_{CFRP}", 1700e6, "Pa", "CFRP max stress") - taucfrp = Variable("\\tau_{CFRP}", 450e6, "Pa", "CFRP fabric stress") - kappa = Variable("\\kappa", 0.2, "-", "max tip deflection ratio") - self.W = Variable("W", "lbf", "loading weight") + LaTex Strings + ------------- + Nmax N_{\\mathrm{max}} + sigmacfrp \\sigma_{\\mathrm{CFRP}} + taucfrp \\tau_{\\mathrm{CFRP}} + kappa \\kappa + Mr M_r - with Vectorize(self.static.N-1): - Mr = Variable("M_r", "N*m", "wing section root moment") + """ + def new_qbarFun(self, c): + " define qbar model for chord loading " + barc = self.wing.planform.cbar + return [f(c) for f in self.wing.substitutions[barc]] + def setup(self, wing): + self.wing = wing + exec parse_variables(SparLoading.__doc__) Beam.qbarFun = self.new_qbarFun - self.beam = Beam(self.static.N) + self.beam = Beam(self.wing.N) + + b = self.b = self.wing.planform.b + I = self.I = self.wing.spar.I + Sy = self.Sy = self.wing.spar.Sy + cave = self.cave = self.wing.planform.cave + tshear = self.tshear = self.wing.spar.tshear + E = self.wing.spar.E + tau = self.wing.planform.tau constraints = [ # dimensionalize moment of inertia and young's modulus - self.beam["dx"] == self.static["d\\eta"], - self.beam["\\bar{EI}"] <= (8*self.static["E"]*self.static["I"]/Nmax - / self.W/self.static["b"]**2), - Mr == (self.beam["\\bar{M}"][:-1]*self.W*Nmax*self.static["b"]/4), - sigmacfrp >= Mr/self.static["S_y"], + self.beam["dx"] == self.wing.planform.deta, + self.beam["\\bar{EI}"] <= 8*E*I/Nmax/W/b**2, + Mr >= self.beam["\\bar{M}"][:-1]*W*Nmax*b/4, + sigmacfrp >= Mr/Sy, self.beam["\\bar{\\delta}"][-1] <= kappa, - taucfrp >= (self.beam["\\bar{S}"][-1]*self.W*Nmax/4 - / self.static["t_{shear}"]/self.static["c_{ave}"] - / self.static["\\tau"]) + taucfrp >= self.beam["\\bar{S}"][-1]*W*Nmax/4/tshear/cave/tau ] return self.beam, constraints diff --git a/gpkitmodels/GP/aircraft/wing/wing.py b/gpkitmodels/GP/aircraft/wing/wing.py index 0d3ce5ab..21f105e2 100644 --- a/gpkitmodels/GP/aircraft/wing/wing.py +++ b/gpkitmodels/GP/aircraft/wing/wing.py @@ -3,17 +3,62 @@ from os.path import abspath, dirname import numpy as np import pandas as pd -from gpkit import Variable, Model, Vectorize -from .wing_interior import WingInterior +from gpkit import Model, parse_variables +from .wing_core import WingCore from .wing_skin import WingSkin from .capspar import CapSpar from gpfit.fit_constraintset import XfoilFit -#pylint: disable=invalid-name, attribute-defined-outside-init, unused-variable -#pylint: disable=too-many-instance-attributes, too-many-locals, no-member +#pylint: disable=no-member, invalid-name, unused-argument, exec-used +#pylint: disable=undefined-variable, attribute-defined-outside-init +#pylint: disable=too-many-instance-attributes class Planform(Model): - "The thing that creates the lift" + """ Planform Area Definition + + Scalar Variables + --------- + S [ft^2] surface area + AR [-] aspect ratio + b [ft] span + tau 0.115 [-] airfoil thickness ratio + CLmax 1.39 [-] maximum lift coefficient + CM 0.14 [-] wing moment coefficient + croot [ft] root chord + cmac [ft] mean aerodynamic chord + lam 0.5 [-] taper ratio + cbarmac self.return_cmac [-] non-dim MAC + + Variables of length N + --------------------- + eta np.linspace(0,1,N) [-] (2y/b) + cbar self.return_c [-] non-dim chord at nodes + + Variables of length N-1 + ----------------------- + cave [ft] mid section chord + cbave self.return_avg [-] non-dim mid section chord + deta self.return_deta [-] \\Delta (2y/b) + + Upper Unbounded + --------------- # bounding any pair of variables will work + cave, b + + Lower Unbounded + --------------- + cave, b + + LaTex Strings + ------------- + tau \\tau + CLmax C_{L_{\\mathrm{max}}} + CM C_M + croot c_{\\mathrm{root}} + cmac c_{\\mathrm{MAC}} + lam \\lambda + cbarmac \\bar{c}_{\\mathrm{MAC}} + + """ def return_c(self, c): " return normalized chord distribution " return np.array([2./(1+c[self.lam])*(1+(c[self.lam]-1)*e) for e @@ -30,30 +75,12 @@ def return_cmac(self, c): den = sum([(cbar[i] + cbar[i+1])/2*deta[i] for i in range(len(deta))]) return num/den/cbar[0] - def setup(self, N): + return_avg = lambda self, c: (self.return_c(c)[:-1] + + self.return_c(c)[1:])/2. + return_deta = lambda self, c: np.diff(c[self.eta]) - S = Variable("S", "ft^2", "surface area") - AR = Variable("AR", "-", "aspect ratio") - b = Variable("b", "ft", "wing span") - tau = Variable("\\tau", 0.115, "-", "airfoil thickness ratio") - CLmax = Variable("C_{L_{max}}", 1.39, "-", "maximum CL of JHO1") - CM = Variable("C_M", 0.14, "-", "wing moment coefficient") - croot = Variable("c_{root}", "ft", "root chord") - cmac = Variable("c_{MAC}", "ft", "mean aerodynamic chord") - self.lam = Variable("\\lambda", 0.5, "-", "wing taper ratio") - with Vectorize(N): - self.eta = Variable("\\eta", np.linspace(0, 1, N), "-", "(2y/b)") - cbar = Variable("\\bar{c}", self.return_c, "-", "non-dim chord at nodes") - - with Vectorize(N-1): - cave = Variable("c_{ave}", "ft", "mid section chord") - return_avg = lambda c: (self.return_c(c)[:-1] + self.return_c(c)[1:])/2. - cbave = Variable("\\bar{c}_{ave}", return_avg, "-", - "non-dim mid section chord") - return_deta = lambda c: np.diff(c[self.eta]) - deta = Variable("d\\eta", return_deta, "-", "\\Delta (2y/b)") - cbarmac = Variable("\\bar{c}_{MAC}", self.return_cmac, "-", - "non-dim MAC") + def setup(self, N): + exec parse_variables(Planform.__doc__) return [b**2 == S*AR, cave == cbave*S/b, @@ -61,64 +88,92 @@ def setup(self, N): cmac == croot*cbarmac] class WingAero(Model): - "wing aerodynamic model with profile and induced drag" + """ Wing Aero Model + + Variables + --------- + Cd [-] wing drag coefficient + CL [-] lift coefficient + CLstall 1.3 [-] stall CL + e 0.9 [-] span efficiency + Re [-] reynolds number + cdp [-] wing profile drag coefficient + + Upper Unbounded + --------------- + Cd, Re, AR + + LaTex Strings + ------------- + Cd C_d + CL C_L + CLstall C_{L_{\\mathrm{stall}}} + cdp c_{d_p} + + """ def setup(self, static, state, fitdata=dirname(abspath(__file__)) + sep + "jho_fitdata.csv"): - "wing drag model" - Cd = Variable("C_d", "-", "wing drag coefficient") - CL = Variable("C_L", "-", "lift coefficient") - CLstall = Variable("C_{L_{stall}}", 1.3, "-", "stall CL") - e = Variable("e", 0.9, "-", "span efficiency") - Re = Variable("Re", "-", "Reynold's number") - cdp = Variable("c_{dp}", "-", "wing profile drag coeff") + exec parse_variables(WingAero.__doc__) df = pd.read_csv(fitdata) fd = df.to_dict(orient="records")[0] + AR = self.AR = static.planform.AR + cmac = static.planform.cmac + if fd["d"] == 2: - independentvars = [CL, Re] + independentvars = [self.CL, self.Re] elif fd["d"] == 3: - independentvars = [CL, Re, static["\\tau"]] + independentvars = [self.CL, self.Re, static.planform.tau] - constraints = [ - Cd >= cdp + CL**2/np.pi/static["AR"]/e, - Re == state["\\rho"]*state["V"]*static["c_{MAC}"]/state["\\mu"], - # XfoilFit(fd, cdp, [CL, Re], airfoil="jho1.dat"), - XfoilFit(fd, cdp, independentvars), - CL <= CLstall - ] - - return constraints + return [Cd >= cdp + CL**2/np.pi/AR/e, + Re == (state["\\rho"]*state["V"]*cmac/state["\\mu"]), + # XfoilFit(fd, cdp, [CL, Re], airfoil="jho1.dat"), + XfoilFit(fd, cdp, independentvars), + CL <= CLstall + ] class Wing(Model): """ - Aicraft wing model for constant tapered wing - INPUTS - ------ - N : int number of sections - lam : float taper ratio - hollow: boolean True if wing is not hollow (filled with foam) + Wing Model + + Variables + --------- + W [lbf] wing weight + mfac 1.2 [-] wing weight margin factor + + Upper Unbounded + --------------- + W + + Lower Unbounded + --------------- + b, Sy + + LaTex Strings + ------------- + mfac m_{\\mathrm{fac}} + """ sparModel = CapSpar - fillModel = WingInterior + fillModel = WingCore flight_model = WingAero - def setup(self, N=5, lam=0.5): - # TODO: phase out lam in later version + def setup(self, N=5): + exec parse_variables(Wing.__doc__) self.N = N - W = Variable("W", "lbf", "wing weight") - mfac = Variable("m_{fac}", 1.2, "-", "wing weight margin factor") - self.planform = Planform(N) + self.b = self.planform.b self.skin = WingSkin(self.planform) self.components = [self.skin] if self.sparModel: self.spar = self.sparModel(N, self.planform) self.components.extend([self.spar]) + self.Sy = self.spar.Sy if self.fillModel: self.foam = self.fillModel(self.planform) self.components.extend([self.foam]) diff --git a/gpkitmodels/GP/aircraft/wing/wing_core.py b/gpkitmodels/GP/aircraft/wing/wing_core.py new file mode 100644 index 00000000..4fe1f496 --- /dev/null +++ b/gpkitmodels/GP/aircraft/wing/wing_core.py @@ -0,0 +1,37 @@ +" wing interior " +from gpkit import Model, parse_variables + +#pylint: disable=exec-used, no-member, undefined-variable + +class WingCore(Model): + """ Wing Core Model + + Variables + --------- + W [lbf] wing core weight + rhocore 0.036 [g/cm^3] core density + Abar 0.0753449 [-] normalized cross section area + g 9.81 [m/s^2] graviataional constant + + Upper Unbounded + --------------- + W + + Lower Unbounded + --------------- + cave, b + + LaTex Strings + ------------- + rhocore \\rho_{\\mathrm{core}} + Abar \\bar{A} + + """ + def setup(self, surface): + exec parse_variables(WingCore.__doc__) + + cave = self.cave = surface.cave + b = self.b = surface.b + deta = surface.deta + + return [W >= 2*(g*rhocore*Abar*cave**2*b/2*deta).sum()] diff --git a/gpkitmodels/GP/aircraft/wing/wing_interior.py b/gpkitmodels/GP/aircraft/wing/wing_interior.py deleted file mode 100644 index 532a7999..00000000 --- a/gpkitmodels/GP/aircraft/wing/wing_interior.py +++ /dev/null @@ -1,17 +0,0 @@ -" wing interior " -from gpkit import Model, Variable - -class WingInterior(Model): - "wing interior model" - def setup(self, surface): - - W = Variable("W", "lbf", "interior mass of wing") - rhofoam = Variable("\\rho_{foam}", 0.036, "g/cm^3", "foam density") - Abar = Variable("\\bar{A}_{jh01}", 0.0753449, "-", - "jh01 non dimensional area") - g = Variable("g", 9.81, "m/s^2", "gravitational acceleration") - - constraints = [W >= 2*(g*rhofoam*Abar*surface["c_{ave}"]**2 - * surface["b"]/2* surface["d\\eta"]).sum()] - - return constraints diff --git a/gpkitmodels/GP/aircraft/wing/wing_skin.py b/gpkitmodels/GP/aircraft/wing/wing_skin.py index 083b5837..619175c9 100644 --- a/gpkitmodels/GP/aircraft/wing/wing_skin.py +++ b/gpkitmodels/GP/aircraft/wing/wing_skin.py @@ -1,24 +1,53 @@ " wing skin " -from gpkit import Model, Variable +from gpkit import Model, Variable, parse_variables class WingSkin(Model): - "wing skin model" + """ Wing Skin model + + Variables + --------- + rhocfrp 1.6 [g/cm^3] density of CFRP + W [lbf] wing skin weight + g 9.81 [m/s^2] gravitational acceleration + t [in] wing skin thickness + tmin 0.012 [in] wing skin min gauge + Jtbar 0.01114 [1/mm] torsional moment of inertia + taucfrp 570 [MPa] torsional stress limit + Cmw 0.121 [-] negative wing moment coeff + rhosl 1.225 [kg/m^3] sea level air density + Vne 45 [m/s] never exceed vehicle speed + + Upper Unbounded + --------------- + W, croot + + Lower Unbounded + --------------- + S + + LaTex Strings + ------------- + W W_{\\mathrm{skin}} + t t_{\\mathrm{skin}} + tmin t_{\\mathrm{min}} + Jtbar \\bar{J/t} + taucfrp \\tau_{\\mathrm{CFRP}} + Cmw C_{m_w} + rhosl \\rho_{\\mathrm{SL}} + Vne V_{\\mathrm{NE}} + + """ def setup(self, surface): + exec parse_variables(WingSkin.__doc__) - rhocfrp = Variable("\\rho_{CFRP}", 1.6, "g/cm^3", "density of CFRP") - W = Variable("W", "lbf", "wing skin weight") - g = Variable("g", 9.81, "m/s^2", "gravitational acceleration") - t = Variable("t", "in", "wing skin thickness") - tmin = Variable("t_{min}", 0.012, "in", "wing skin min gauge") - Jtbar = Variable("\\bar{J/t}", 0.01114, "1/mm", - "torsional moment of inertia") - - constraints = [W >= rhocfrp*surface["S"]*2*t*g, - t >= tmin] - + croot = self.croot = surface.croot + S = self.S = surface.S self.loading = WingSkinL - return constraints + return [W >= rhocfrp*surface.S*2*t*g, + t >= tmin, + taucfrp >= 1/Jtbar/croot**2/t*Cmw*S*rhosl*Vne**2 + ] class WingSkinL(Model): "wing skin loading model for torsional loads in skin" @@ -30,8 +59,4 @@ def setup(self, static): "air density at sea level") Vne = Variable("V_{NE}", 45, "m/s", "never exceed vehicle speed") - constraints = [ - taucfrp >= (1/static["\\bar{J/t}"]/(static["c_{root}"])**2 - / static.skin["t"]*Cmw*static["S"]*rhosl*Vne**2)] - - return constraints + return [] diff --git a/gpkitmodels/GP/aircraft/wing/wing_test.py b/gpkitmodels/GP/aircraft/wing/wing_test.py index 28b7e75e..d7460125 100644 --- a/gpkitmodels/GP/aircraft/wing/wing_test.py +++ b/gpkitmodels/GP/aircraft/wing/wing_test.py @@ -1,7 +1,10 @@ " wing test " from gpkitmodels.GP.aircraft.wing.wing import Wing +from gpkitmodels.GP.aircraft.wing.boxspar import BoxSpar from gpkit import Variable, Model +#pylint: disable=no-member + class FlightState(Model): " state variables " def setup(self): @@ -14,14 +17,39 @@ def setup(self): return constraints -def test(): +def wing_test(): " test wing models " - from gpkit import units - Wcent = Variable("W_{cent}", 100, "lbf", "center weight") + W = Wing() + W.substitutions[W.W] = 50 + fs = FlightState() + perf = W.flight_model(W, fs) + loading = [W.spar.loading(W)] + loading[0].substitutions["W"] = 100 + loading.append(W.spar.gustloading(W)) + loading[1].substitutions["W"] = 100 + + from gpkit import settings + if settings["default_solver"] == "cvxopt": + for l in loading: + for v in ["\\bar{M}_{tip}", "\\bar{S}_{tip}", + "\\bar{\\delta}_{root}", "\\theta_{root}"]: + l.substitutions[v] = 1e-3 + + m = Model(perf.Cd, [ + loading[1].v == fs["V"], + loading[1].cl == perf.CL, + loading[1].Ww == W.W, + loading[1].Ww <= 0.5*fs["\\rho"]*fs["V"]**2*perf.CL*W.planform.S, + W, fs, perf, loading]) + m.solve(verbosity=0) +def box_spar(): + " test wing models " + + Wing.sparModel = BoxSpar W = Wing() - W.substitutions[W.topvar("W")] = 50 + W.substitutions[W.W] = 50 fs = FlightState() perf = W.flight_model(W, fs) loading = [W.spar.loading(W)] @@ -29,11 +57,24 @@ def test(): loading.append(W.spar.gustloading(W)) loading[1].substitutions["W"] = 100 - m = Model(perf["C_d"], [loading[1]["V"] == fs["V"], - loading[1]["c_l"] == perf["C_L"], - loading[1]["W_w"] == W.topvar("W"), - W, fs, perf, loading, W["b"] >= 0.01*units("ft")]) - m.solve("mosek") + from gpkit import settings + if settings["default_solver"] == "cvxopt": + for l in loading: + for v in ["\\bar{M}_{tip}", "\\bar{S}_{tip}", + "\\bar{\\delta}_{root}", "\\theta_{root}"]: + l.substitutions[v] = 1e-3 -if __name__ == "__main__": + m = Model(perf.Cd, [ + loading[1].v == fs["V"], + loading[1].cl == perf.CL, + loading[1].Ww == W.W, + loading[1].Ww <= 0.5*fs["\\rho"]*fs["V"]**2*perf.CL*W.planform.S, + W, fs, perf, loading]) + m.solve(verbosity=0) + +def test(): wing_test() + box_spar() + +if __name__ == "__main__": + test() diff --git a/gpkitmodels/GP/beam/beam.py b/gpkitmodels/GP/beam/beam.py index 58537e7b..ae6f467b 100644 --- a/gpkitmodels/GP/beam/beam.py +++ b/gpkitmodels/GP/beam/beam.py @@ -4,7 +4,17 @@ #pylint: disable=invalid-name class Beam(Model): - "discretized beam bending model" + """discretized beam bending model + + Upper Unbounded + --------------- + EIbar, dbar_tip + + Lower Unbounded + --------------- + dx, qbar (if not qbarFun) + + """ qbarFun = None SbarFun = None MbarFun = None @@ -12,15 +22,16 @@ class Beam(Model): def setup(self, N): with Vectorize(N-1): - EIbar = Variable("\\bar{EI}", "-", + EIbar = self.EIbar = Variable("\\bar{EI}", "-", "normalized YM and moment of inertia") - dx = Variable("dx", "-", "normalized length of element") + dx = self.dx = Variable("dx", "-", "normalized length of element") with Vectorize(N): Sbar = Variable("\\bar{S}", self.SbarFun, "-", "normalized shear") Mbar = Variable("\\bar{M}", self.MbarFun, "-", "normalized moment") th = Variable("\\theta", "-", "deflection slope") dbar = Variable("\\bar{\\delta}", "-", "normalized displacement") + self.dbar_tip = dbar[-1] throot = Variable("\\theta_{root}", 1e-10, "-", "Base angle") @@ -30,7 +41,7 @@ def setup(self, N): constraints = [] if self.SbarFun is None: with Vectorize(N): - qbar = Variable("\\bar{q}", self.qbarFun, "-", + qbar = self.qbar = Variable("\\bar{q}", self.qbarFun, "-", "normalized loading") Sbartip = Variable("\\bar{S}_{tip}", 1e-10, "-", "Tip loading") constraints.extend([ @@ -51,4 +62,3 @@ def setup(self, N): ]) return constraints - diff --git a/gpkitmodels/SP/aircraft/tail/tail_boom_flex.py b/gpkitmodels/SP/aircraft/tail/tail_boom_flex.py index 06146b19..91cf00f5 100644 --- a/gpkitmodels/SP/aircraft/tail/tail_boom_flex.py +++ b/gpkitmodels/SP/aircraft/tail/tail_boom_flex.py @@ -15,16 +15,16 @@ def setup(self, htail, tailboom, wing, state): sph2 = Variable("sph2", "-", "second term involving $V_h$") constraints = [ - Fne >= (1 + htail["m_h"]*0.5*state["V_{NE}"]**2*state["\\rho_{sl}"] - * htail["S"]*htail["l_h"]**2/tailboom["E"] - / tailboom["I_0"]*tailboom["(1-k/2)"]), - sph1*(wing["m_w"]*Fne/htail["m_h"]/htail["V_h"]) + deda <= 1, - sph2 <= htail["V_h"]*htail["(C_{L_h})_{min}"]/wing["C_{L_{max}}"], + Fne >= (1 + htail.mh*0.5*state.Vne**2*state.rhosl + * htail["S"]*htail.lh**2/tailboom.E + / tailboom.I0*tailboom.kfac), + sph1*(wing["m_w"]*Fne/htail.mh/htail.Vh) + deda <= 1, + sph2 <= htail.Vh*htail.CLhmin/wing.planform.CLmax, # (sph1 + sph2).mono_lower_bound({"sph1": .48, "sph2": .52}) >= ( # SMcorr + wing["C_M"]/wing["C_{L_{max}}"]), - deda >= wing["m_w"]*wing["S"]/wing["b"]/4/np.pi/htail["l_h"]] + deda >= wing["m_w"]*wing["S"]/wing["b"]/4/np.pi/htail.lh] with SignomialsEnabled(): - constraints.extend([sph1 + sph2 >= SMcorr + wing["C_M"]/wing["C_{L_{max}}"]]) + constraints.extend([sph1 + sph2 >= SMcorr + wing.planform.CM/wing.planform.CLmax]) return constraints diff --git a/gpkitmodels/SP/aircraft/wing/wing.py b/gpkitmodels/SP/aircraft/wing/wing.py index 5619f038..c1fd9801 100644 --- a/gpkitmodels/SP/aircraft/wing/wing.py +++ b/gpkitmodels/SP/aircraft/wing/wing.py @@ -7,9 +7,10 @@ #pylint: disable=attribute-defined-outside-init, invalid-name class Wing(WingGP): - def setup(self, N=5, lam=0.5): - self.wing = WingGP.setup(self, N=N, lam=lam) + def setup(self, N=5): + + self.wing = WingGP.setup(self, N=N) mw = Variable("m_w", "-", "span wise effectiveness") with SignomialsEnabled():