Beispiel #1
0
    def __init__(self):

        Afloor   = Variable('A_{floor}', 'm^2', 'Floor beam x-sectional area')
        Afuse    = Variable('A_{fuse}', 'm^2', 'Fuselage x-sectional area')
        Ahold    = Variable('A_{hold}', 'm^2', 'Cargo hold x-sectional area')
        Askin    = Variable('A_{skin}', 'm^2', 'Skin cross sectional area')
        Dfuse    = Variable('D_{fuse}', 'N', 'Total drag in cruise')
        Dfrict   = Variable('D_{friction}', 'N', 'Friction drag')
        Dupswp   = Variable('D_{upsweep}', 'N', 'Drag due to fuse upsweep')
        FF       = Variable('FF', '-','Fuselage form factor')
        LF       = Variable('LF', '-', 'Load factor')
        Lvmax    = Variable('L_{v_{max}}', 'N', 'Max vertical tail load')
        Mfloor   = Variable('M_{floor}', 'N*m',
                            'Max bending moment in floor beams')
        Nland    = Variable('N_{land}', '-', 'Emergency landing load factor')
        Pfloor   = Variable('P_{floor}', 'N', 'Distributed floor load')
        Qv       = Variable('Q_v', 'N*m', 'Torsion moment imparted by tail')
        R        = Variable('R', 287, 'J/(kg*K)', 'Universal gas constant')
        Rfuse    = Variable('R_{fuse}', 'm', 'Fuselage radius')
        SPR      = Variable('SPR', '-', 'Number of seats per row')
        Sbulk    = Variable('S_{bulk}', 'm^2', 'Bulkhead surface area')
        Sfloor   = Variable('S_{floor}', 'N', 'Maximum shear in floor beams')
        Snose    = Variable('S_{nose}', 'm^2', 'Nose surface area')
        Tcabin   = Variable('T_{cabin}', 'K', 'Cabin temperature')
        Vbulk    = Variable('V_{bulk}', 'm^3', 'Bulkhead skin volume')
        Vcabin   = Variable('V_{cabin}', 'm^3', 'Cabin volume')
        Vcargo   = Variable('V_{cargo}', 'm^3', 'Cargo volume')
        Vcone    = Variable('V_{cone}', 'm^3', 'Cone skin volume')
        Vcyl     = Variable('V_{cyl}', 'm^3', 'Cylinder skin volume')
        Vfloor   = Variable('V_{floor}', 'm^3', 'Floor volume')
        Vhold    = Variable('V_{hold}', 'm^3', 'Hold volume')
        Vinf     = Variable('V_{\\infty}', 'm/s', 'Cruise velocity')
        Vlugg    = Variable('V_{lugg}', 'm^3', 'Luggage volume')
        Vnose    = Variable('V_{nose}', 'm^3', 'Nose skin volume')
        Wapu     = Variable('W_{apu}', 'N', 'APU weight')
        Wavgpass = Variable('W_{avg. pass}', 'lbf', 'Average passenger weight')
        Wbuoy    = Variable('W_{buoy}', 'N', 'Buoyancy weight')
        Wcargo   = Variable('W_{cargo}', 'N', 'Cargo weight')
        Wcarryon = Variable('W_{carry on}', 'lbf', 'Ave. carry-on weight')
        Wchecked = Variable('W_{checked}', 'lbf', 'Ave. checked bag weight')
        Wcone    = Variable('W_{cone}', 'N', 'Cone weight')
        Wfix     = Variable('W_{fix}', 'lbf',
                            'Fixed weights (pilots, cockpit seats, navcom)')
        Wfloor   = Variable('W_{floor}', 'N', 'Floor weight')
        Wfuse    = Variable('W_{fuse}', 'N', 'Fuselage weight')
        Winsul   = Variable('W_{insul}', 'N', 'Insulation material weight')
        Wlugg    = Variable('W_{lugg}', 'N', 'Passenger luggage weight')
        Wpadd    = Variable('W_{padd}', 'N',
                            'Misc weights (galley, toilets, doors etc.)')
        Wpass    = Variable('W_{pass}', 'N', 'Passenger weight')
        Wpay     = Variable('W_{pay}', 'N', 'Payload weight')
        Wppfloor = Variable('W\'\'_{floor}', 'N/m^2',
                            'Floor weight/area density')
        Wppinsul = Variable('W\'\'_{insul}', 'N/m^2',
                            'Weight/area density of insulation material')
        Wpseat   = Variable('W\'_{seat}', 'N', 'Weight per seat')
        Wpwindow = Variable('W\'_{window}', 'N/m',
                            'Weight/length density of windows')
        Wseat    = Variable('W_{seat}', 'N', 'Seating weight')
        Wshell   = Variable('W_{shell}', 'N', 'Shell weight')
        Wskin    = Variable('W_{skin}', 'N', 'Skin weight')
        Wwindow  = Variable('W_{window}', 'N', 'Window weight')
        bvt      = Variable('b_{vt}', 'm', 'Vertical tail span')
        cvt      = Variable('c_{vt}', 'm', 'Vertical tail root chord')
        dh       = Variable('\\Delta h', 'm',
                            'Distance from floor to widest part of fuselage')
        dp       = Variable('\\Delta p', 'Pa',
                            'Pressure difference across fuselage skin')
        f        = Variable('f', '-', 'Fineness ratio')
        fapu     = Variable('f_{apu}', '-',
                            'APU weight as fraction of payload weight')
        ffadd    = Variable('f_{fadd}', '-',
                            'Fractional added weight of local reinforcements')
        fframe   = Variable('f_{frame}', '-', 'Fractional frame weight')
        flugg1   = Variable('f_{lugg,1}', '-',
                            'Proportion of passengers with one suitcase')
        flugg2   = Variable('f_{lugg,2}', '-',
                            'Proportion of passengers with two suitcases')
        fpadd    = Variable('f_{padd}', '-',
                            'Other misc weight as fraction of payload weight')
        fstring  = Variable('f_{string}', '-','Fractional weight of stringers')
        g        = Variable('g', 9.81, 'm/s^2', 'Gravitational acceleration')
        hfloor   = Variable('h_{floor}', 'm', 'Floor beam height')
        hhold    = Variable('h_{hold}', 'm', 'Height of the cargo hold')
        lamcone  = Variable('\\lambda_{cone}', '-',
                            'Tailcone radius taper ratio (xshell2->xtail)')
        lcone    = Variable('l_{cone}', 'm', 'Cone length')
        lfloor   = Variable('l_{floor}', 'm', 'Floor length')
        lfuse    = Variable('l_{fuse}', 'm', 'Fuselage length')
        lnose    = Variable('l_{nose}', 'm', 'Nose length')
        lshell   = Variable('l_{shell}', 'm', 'Shell length')
        mu       = Variable('\\mu', 'N*s/m^2', 'Dynamic viscosity (35,000 ft)')
        npass    = Variable('n_{pass}', '-', 'Number of passengers')
        nrows    = Variable('n_{rows}', '-', 'Number of rows')
        nseat    = Variable('n_{seat}', '-',' Number of seats')
        pcabin   = Variable('p_{cabin}', 'Pa','Cabin air pressure (8,000ft)')
        phi      = Variable('\\phi', '-', 'Upsweep angle')
        pitch    = Variable('p_s', 'in', 'Seat pitch')
        plamv    = Variable('p_{\\lambda_v}', '-', '1 + 2*Tail taper ratio')
        rE       = Variable('r_E', '-', 'Ratio of stringer/skin moduli')
        rho      = Variable('\\rho', 'kg/m^3', 'Air density (cruise)')
        rhobend  = Variable('\\rho_{bend}', 'kg/m^3', 'Stringer density')
        rhocabin = Variable('\\rho_{cabin}', 'kg/m^3', 'Air density in cabin')
        rhocargo = Variable('\\rho_{cargo}', 'kg/m^3', 'Cargo density')
        rhocone  = Variable('\\rho_{cone}', 'kg/m^3',
                            'Cone material density')
        rhofloor = Variable('\\rho_{floor}', 'kg/m^3',
                            'Floor material density')
        rholugg  = Variable('\\rho_{lugg}', 'kg/m^3', 'Luggage density')
        rhoskin  = Variable('\\rho_{skin}', 'kg/m^3', 'Skin density')
        sigfloor = Variable('\\sigma_{floor}', 'N/m^2',
                            'Max allowable cap stress')
        sigskin  = Variable('\\sigma_{skin}', 'N/m^2',
                            'Max allowable skin stress')
        sigth    = Variable('\\sigma_{\\theta}', 'N/m^2', 'Skin hoop stress')
        sigx     = Variable('\\sigma_x', 'N/m^2', 'Axial stress in skin')
        taucone  = Variable('\\tau_{cone}', 'N/m^2', 'Shear stress in cone')
        taufloor = Variable('\\tau_{floor}', 'N/m^2',
                            'Max allowable shear web stress')
        tcone    = Variable('t_{cone}', 'm', 'Cone thickness')
        tshell   = Variable('t_{shell}', 'm', 'Shell thickness')
        tskin    = Variable('t_{skin}', 'm', 'Skin thickness')
        waisle   = Variable('w_{aisle}', 'm', 'Aisle width')
        wfloor   = Variable('w_{floor}', 'm', 'Floor width')
        wfuse    = Variable('w_{fuse}', 'm', 'Fuselage width')
        wseat    = Variable('w_{seat}', 'm', 'Seat width')
        wsys     = Variable('w_{sys}', 'm',
                            'Width between cabin and skin for systems')
        xCGfu    = Variable('x_{CG_{fu}}', 'm', 'x-location of fuselage CG')
        xVbulk   = Variable('xVbulk', 'm^4', 'Volume moment of bulkhead')
        xVcyl    = Variable('xVcyl', 'm^4', 'Volume moment of cylinder')
        xVnose   = Variable('xVnose', 'm^4', 'Volume moment of nose')
        xWapu    = Variable('xWapu', 'N*m', 'Moment of APU')
        xWcone   = Variable('xWcone', 'N*m', 'Moment of cone')
        xWfix    = Variable('xWfix', 'N*m', 'Moment of fixed weights')
        xWfloor  = Variable('xWfloor', 'N*m', 'Moment of floor weight')
        xWfuse   = Variable('xWfuse', 'N*m', 'Fuselage moment')
        xWinsul  = Variable('xWinsul', 'N*m', 'Moment of insulation material')
        xWpadd   = Variable('xWpadd', 'N*m', 'Moment of misc weights')
        xWseat   = Variable('xWseat', 'N*m', 'Moment of seats')
        xWshell  = Variable('xWshell', 'N*m', 'Mass moment of shell')
        xWskin   = Variable('xWskin', 'N*m', 'Mass moment of skin')
        xWwindow = Variable('xWwindow', 'N*m', 'Mass moment of windows')
        x_upswp  = Variable('x_{up}', 'm', 'Fuselage upsweep point')
        xapu     = Variable('xapu', 'ft', 'x-location of APU')
        xconend  = Variable('xconend', 'm', 'x-location of cone end')
        xfix     = Variable('xfix', 'm', 'x-location of fixed weight')
        xshell1  = Variable('x_{shell1}', 'm', 'Start of cylinder section')
        xshell2  = Variable('x_{shell2}', 'm', 'End of cylinder section')

        with SignomialsEnabled():
            objective = Dfuse + 0.5*Wfuse

            constraints = [
                            # Geometry relations
                            lnose == xshell1,

                            # Cross section relations
                            wfuse == 2*Rfuse,
                            wfuse >= SPR*wseat + waisle + 2*wsys,
                            Askin >= 2*np.pi*Rfuse*tskin, # simplified
                            Afuse >= np.pi*Rfuse**2, # simplified
                            tshell >= tskin*(1 + rE*fstring*rhoskin/rhobend),

                            # TODO: Bending loads

                            # Pressure shell loads
                            sigx == dp/2*Rfuse/tshell,
                            sigth == dp*Rfuse/tskin,
                            sigskin >= sigth,
                            sigskin >= sigx,
                            Snose**(8./5) >= (2*np.pi*Rfuse**2)**(8./5) *
                                             (1./3 + (2./3)*(lnose/Rfuse)
                                             **(8./5)),
                            Sbulk == 2*np.pi*Rfuse**2,
                            Vcyl == Askin*lshell,
                            Vnose == Snose*tskin,
                            Vbulk == Sbulk*tskin,
                            Wskin >= rhoskin*g*(Vcyl + Vnose + Vbulk),
                            Wshell >= Wskin*(1 + fstring + fframe + ffadd),

                            # Cabin volume and buoyancy weight
                            rhocabin == (1/(R*Tcabin))*pcabin,
                            Vcabin >= Afuse*(lshell + 0.67*lnose + 0.67*Rfuse),
                            TCS([Wbuoy >= (rhocabin - rho)*g*Vcabin], reltol=1E-3), # [SP]

                            # Windows and insulation
                            Wwindow == Wpwindow * lshell,
                            Winsul >= Wppinsul*(1.1*np.pi*Rfuse*lshell
                                      + 0.55*(Snose + Sbulk)),

                            # Payload-proportional weights
                            Wapu == Wpay*fapu,
                            Wseat == Wpseat*nseat,
                            Wpadd == Wpay*fpadd,

                            # Floor
                            Pfloor >= Nland*(Wpay + Wseat),
                            Sfloor == 0.5*Pfloor, # without support
                            Mfloor == 0.25*Pfloor*wfloor/2,
                            lnose >= 5.2*units.m, # TODO less arbitrary
                            Afloor >= 2*Mfloor/(sigfloor*hfloor)
                                      + 1.5*Sfloor/taufloor,
                            Vfloor >= wfloor*Afloor,
                            lfloor >= lshell + 2*Rfuse,
                            lshell >= nrows*pitch,
                            (wfloor/2)**2 + dh**2 >= Rfuse**2, # [SP]
                            Wfloor >= rhofloor*g*Vfloor
                                      + wfloor*lfloor*Wppfloor,

                            # Tail cone
                            Rfuse*taucone*(1+plamv)*Vcone*(1+lamcone)/(4*lcone)
                                >= Lvmax*bvt*plamv/3, # [SP]
                            plamv >= 1.6,
                            taucone == sigskin,
                            lamcone == 0.4, # TODO remove
                            lamcone == cvt/lcone,
                            Wcone >= rhocone*g*Vcone*(1 + fstring + fframe
                                                      + ffadd),

                            # Payload weight breakdown
                            npass == nseat*LF,
                            nseat == nrows*SPR,
                            Wpass == npass*Wavgpass,
                            Wlugg >= flugg2*npass*2*Wchecked
                                     + flugg1*npass*Wchecked + Wcarryon,
                            Wlugg == Vlugg*g*rholugg,
                            Wcargo == Vcargo*g*rhocargo,
                            Vhold >= Vcargo + Vlugg,
                            Vhold == Ahold*lshell,
                            TCS([Ahold <= (2./3)*wfloor*hhold + hhold**3/(2*wfloor)], reltol=1E-5),
                            # [SP] Harris stocker 1998 (wolfram)
                            TCS([dh + hhold + hfloor <= Rfuse]),
                            Wpay >= Wpass + Wlugg + Wcargo,

                            # Total fuselage weight
                            Wfuse >= Wfix + Wapu + Wpadd + Wseat + Wshell
                                   + Wwindow + Winsul + Wcone + Wfloor + Wbuoy,

                            # Drag
                            # sources: Raymer (p285), kfid 325 notes (p180)
                            lfuse >= lnose+lshell+lcone,
                            f == lfuse/((4/np.pi*Afuse)**0.5), # fineness ratio
                            FF >= 1 + 60/f**3 + f/400, # form factor
                            Dfrict >= FF * np.pi*Rfuse * mu*Vinf
                                      * 0.074*(rho*Vinf*lfuse/mu)**0.8,

                            # Drag due to fuselage upsweep (Raymer p286)
                            xshell2 >= xshell1 + lshell,
                            xshell2 == x_upswp,
                            x_upswp + lcone <= lfuse,
                            1.13226*phi**1.03759 == Rfuse/lcone, # monomial fit
                                                                 # of tan(phi)
                            Dupswp >= 3.83*phi**2.5*Afuse * 0.5*rho*Vinf**2,
                            Dfuse >= Dfrict + Dupswp
                          ]

        CG_constraints = [
                          xVcyl >= 0.5*(xshell1+xshell2)*Vcyl,
                          xVnose >= 0.5*(xshell1)*Vnose,
                          xVbulk >= xshell2*Vbulk, # simplified
                          xWskin >= rhoskin*g*(xVcyl + xVnose + xVbulk),
                          xWshell >= xWskin*(1 + fstring + fframe + ffadd),
                          xWwindow >= 0.5* (xshell1+xshell2)*Wwindow,
                          xWinsul >= 0.5*(xshell1 + xshell2)*Winsul,
                          xWapu == xapu*Wapu,
                          xWseat >= 0.5*(xshell1 + xshell2)*Wseat,
                          xWpadd >= 0.5*(xshell1 + xshell2)*Wpadd,
                          xWfix == xfix*Wfix,
                          xWfloor >= 0.5*(xshell1 + xshell2)*Wfloor,
                          xWcone >= 0.5*(xshell2 + lfuse) * Wcone,
                          xWfuse >= xWfix + xWapu + xWpadd + xWseat + xWshell
                                  + xWcone + xWwindow + xWinsul + xWfloor,
                          xCGfu == xWfuse/Wfuse,
                         ]
        self.CG_constraints = CG_constraints

        CostedConstraintSet.__init__(self, objective, constraints)
Beispiel #2
0
    def __init__(self):
        B       = Variable('B', 'm', 'Landing gear base')
        E       = Variable('E', 'GPa', 'Modulus of elasticity, 4340 steel')
        Eland   = Variable('E_{land}', 'J', 'Max KE to be absorbed in landing')
        Fwm     = Variable('F_{w_m}', '-', 'Weight factor (main)')
        Fwn     = Variable('F_{w_n}', '-', 'Weight factor (nose)')
        I_m     = Variable('I_m', 'm^4', 'Area moment of inertia (main strut)')
        I_n     = Variable('I_n', 'm^4', 'Area moment of inertia (nose strut)')
        K       = Variable('K', '-', 'Column effective length factor')
        L_m     = Variable('L_m', 'N', 'Max static load through main gear')
        L_n     = Variable('L_n', 'N', 'Min static load through nose gear')
        L_n_dyn = Variable('L_{n_{dyn}}', 'N', 'Dyn. braking load, nose gear')
        Lwm     = Variable('L_{w_m}', 'N', 'Static load per wheel (main)')
        Lwn     = Variable('L_{w_n}', 'N', 'Static load per wheel (nose)')
        N_s     = Variable('N_s', '-', 'Factor of safety')
        S_sa    = Variable('S_{sa}', 'm', 'Stroke of the shock absorber')
        S_t     = Variable('S_t', 'm', 'Tire deflection')
        T       = Variable('T', 'm', 'Main landing gear track')
        W       = Variable('W', 'N', 'Total aircraft weight')
        WAWm    = Variable('W_{wa,m}', 'lbf',
                           'Wheel assembly weight for single main gear wheel')
        WAWn    = Variable('W_{wa,n}', 'lbf',
                           'Wheel assembly weight for single nose gear wheel')
        W_0     = Variable('W_{0_{lg}}', 'N',
                           'Weight of aircraft excluding landing gear')
        W_lg    = Variable('W_{lg}', 'N', 'Weight of landing gear')
        W_mg    = Variable('W_{mg}', 'N', 'Weight of main gear')
        W_ms    = Variable('W_{ms}', 'N', 'Weight of main struts')
        W_mw    = Variable('W_{mw}', 'N', 'Weight of main wheels (per strut)')
        W_ng    = Variable('W_{ng}', 'N', 'Weight of nose gear')
        W_ns    = Variable('W_{ns}', 'N', 'Weight of nose strut')
        W_nw    = Variable('W_{nw}', 'N', 'Weight of nose wheels (total)')
        d_fan   = Variable('d_{fan}', 'm', 'Fan diameter')
        d_nac   = Variable('d_{nacelle}', 'm', 'Nacelle diameter')
        d_oleo  = Variable('d_{oleo}', 'm', 'Diameter of oleo shock absorber')
        dtm     = Variable('d_{t_m}', 'in', 'Diameter of main gear tires')
        dtn     = Variable('d_{t_n}', 'in', 'Diameter of nose gear tires')
        dxm     = Variable('\\Delta x_m', 'm', 'Distance b/w main gear and CG')
        dxn     = Variable('\\Delta x_n', 'm', 'Distance b/w nose gear and CG')
        eta_s   = Variable('\\eta_s', '-', 'Shock absorber efficiency')
        faddm   = Variable('f_{add,m}', '-', 'Proportional added weight, main')
        faddn   = Variable('f_{add,n}', '-', 'Proportional added weight, nose')
        g       = Variable('g', 9.81, 'm/s^2', 'Gravitational acceleration')
        h_nac   = Variable('h_{nacelle}', 'm', 'Min. nacelle clearance')
        hhold   = Variable('h_{hold}', 'm', 'Hold height')
        l_m     = Variable('l_m', 'm', 'Length of main gear')
        l_n     = Variable('l_n', 'm', 'Length of nose gear')
        l_oleo  = Variable('l_{oleo}', 'm', 'Length of oleo shock absorber')
        lam     = Variable('\\lambda_{LG}', '-',
                           'Ratio of max to static load') # Torenbeek p360
        n_mg    = Variable('n_{mg}', '-', 'Number of main gear struts')
        nwps    = Variable('n_{wps}', '-', 'Number of wheels per strut')
        p_oleo  = Variable('p_{oleo}', 'lbf/in^2', 'Oleo pressure')
       #p_t     = Variable('p_t', 170, 'lbf/in^2', 'Tyre pressure')
        r_m     = Variable('r_m', 'm', 'Radius of main gear struts')
        r_n     = Variable('r_n', 'm', 'Radius of nose gear struts')
        rho_st  = Variable('\\rho_{st}', 'kg/m^3', 'Density of 4340 Steel')
        sig_y_c = Variable('\\sigma_{y_c}', 'Pa',
                           'Compressive yield strength 4340 steel') #  AZOM
        t_m     = Variable('t_m', 'm', 'Thickness of main gear strut wall')
        t_n     = Variable('t_n', 'm', 'Thickness of nose gear strut wall')
        t_nac   = Variable('t_{nacelle}', 'm', 'Nacelle thickness')
        tan_15  = Variable('\\tan(\\phi_{min})', '-', 'Lower bound on phi')
        tan_63  = Variable('\\tan(\\psi_{max})', '-', 'Upper bound on psi')
        tan_gam = Variable('\\tan(\\gamma)', '-', 'Dihedral angle')
        tan_phi = Variable('\\tan(\\phi)', '-', 'Angle b/w main gear and CG')
        tan_psi = Variable('\\tan(\\psi)', '-', 'Tip over angle')
        tan_th  = Variable('\\tan(\\theta_{max})', '-', 'Max rotation angle')
        w_ult   = Variable('w_{ult}', 'ft/s', 'Ultimate velocity of descent')
        wtm     = Variable('w_{t_m}', 'm', 'Width of main tires')
        wtn     = Variable('w_{t_n}', 'm', 'Width of nose tires')
        x_m     = Variable('x_m', 'm', 'x-location of main gear')
        x_n     = Variable('x_n', 'm', 'x-location of nose gear')
        x_upswp = Variable('x_{up}', 'm', 'Fuselage upsweep point')
        xcg     = Variable('x_{CG}', 'm', 'x-location of CG incl. LG')
        xcglg   = Variable('x_{CG_{lg}}', 'm', 'Landing gear CG')
        xcg0    = Variable('x_{CG_0}', 'm', 'x-location of CG excl. LG')
        y_eng   = Variable('y_{eng}', 'm', 'Spanwise loc. of engines')
        y_m     = Variable('y_m', 'm', 'y-location of main gear (symmetric)')
        z_CG_0  = Variable('z_{CG}', 'm',
                           'CG height relative to bottom of fuselage')
        zwing   = Variable('z_{wing}', 'm',
                           'Height of wing relative to base of fuselage')


        with SignomialsEnabled():

            objective = W_lg

            constraints = [
                           # Track and Base geometry definitions
                           TCS([l_n+zwing+y_m*tan_gam>=l_m], reltol=1E-3), #[SP]
                           T == 2*y_m,
                           TCS([x_n + B <= x_m]),
                           x_n >= 5*units.m, # nose gear after nose

                           # Geometric constraints relating gear placement with
                           # fore/aft CG locations
                           TCS([dxn + x_n >= xcg], reltol=1E-3), # [SP]
                           TCS([dxm + xcg >= x_m], reltol=1E-4), # [SP]
                           # TODO forward and aft CG

                           # Maximum static loads through main and nose gears
                           L_n == W*dxm/B,
                           L_m == W*dxn/B,

                           # Dynamic braking load through nose gear
                           # (assumes deceleration of 10 ft/s^2)
                           L_n_dyn >= 0.31*((z_CG_0+l_m)/B)*W,

                           # For steering don't want too much or too little
                           # load on nose gear
                           L_n/W >= 0.05,
                           L_n/W <= 0.20,

                           # Longitudinal tip over (static)
                           x_m >= tan_phi*(z_CG_0+l_m) + xcg,
                           tan_phi >= tan_15,

                           # Lateral tip over in turn (dynamic)
                           # www.dept.aoe.vt.edu/~mason/Mason_f/M96SC03.pdf
                           # stricter constraint uses forward CG
                           # cos(arctan(y/x))) = x/sqrt(x^2 + y^2)
                           1 >= (z_CG_0 + l_m)**2 * (y_m**2 + B**2) /
                                (dxn * y_m * tan_psi)**2,
                           tan_psi <= tan_63,

                           # Tail strike: Longitudinal ground clearance in
                           # takeoff, landing (Raymer says 10-15 degrees)
                           # TODO?: 2 cases:(i) upsweep angle > rotation angle,
                           # (ii) upsweep angle < rotation ang
                           x_upswp - x_m <= l_m/tan_th, # [SP]

                           # Engine ground clearance
                           d_nac >= d_fan + 2*t_nac,
                           d_nac + h_nac <= l_m + (y_eng-y_m)*tan_gam, # [SP]

                           # Size/Volume for retraction
                           y_m >= l_m,

                           # Constrains/is constrained by engine location
                           y_m <= y_eng,

                           # Brake sizing for stopping aircraft

                           # Hard landing
                           # http://www.boeing.com/commercial/aeromagazine/...
                           # articles/qtr_3_07/AERO_Q307_article3.pdf
                           # sink rate of 10 feet per second at the maximum
                           # design landing weight
                           # Landing condition from Torenbeek p360
                           Eland >= W/(2*g)*w_ult**2, # Torenbeek (10-26)
                           # S_t == 0.5*lam*Lwm/(p*(dtm*bt)**0.5), # (10-30)
                           S_sa == (1/eta_s)*(Eland/(L_m*lam)),# - eta_t*S_t),
                           # [SP] Torenbeek (10-28)

                           l_oleo == 2.5*S_sa, # Raymer 244
                           d_oleo == 1.3*(4*lam*L_m/n_mg/(np.pi*p_oleo))**0.5,
                           l_m >= l_oleo + dtm/2,

                           # Wheel weights
                           Fwm == Lwm*dtm/(1000*Lwm.units*dtm.units),
                           WAWm == 1.2*Fwm**0.609*units.lbf,# Currey p145
                           Fwn == Lwn*dtn/(1000*units.lbf*units.inches),
                           WAWn == 1.2*Fwn**0.609*units.lbf,# Currey p145
                           Lwm == L_m/(n_mg*nwps),
                           Lwn == L_n/nwps,

                           # Main wheel diameter/width (Raymer p233)
                           dtm == 1.63*(Lwm/(4.44*units.N))**0.315*units.inch,
                           wtm == 0.1043*(Lwm/(4.44*units.N))**0.48*units.inch,
                           dtn == 0.8*dtm,
                           wtn == 0.8*wtm,

                           # TODO: Beam sizing and max bending (limits track,
                           # downward pressure on y_m)

                           # Weight is a function of height and load through
                           # each strut as well as tyre size (and obviously
                           # number of struts)
                           # Main gear strut weight (for a single strut) is a
                           # function of length and load passing through strut
                           W_ms >= 2*np.pi*r_m*t_m*l_m * rho_st * g,
                           # Compressive yield in hard landing condition
                           N_s * lam * L_m/n_mg <= sig_y_c * (2*np.pi*r_m*t_m),
                           W_mw == nwps*WAWm,

                           # Nose gear strut weight is a function of length and
                           # load passing through strut
                           W_ns >= 2*np.pi*r_n*t_n*l_n * rho_st * g,
                           # find cross sectional area based on compressive yield
                           N_s * (L_n + L_n_dyn) <= sig_y_c*(2*np.pi*r_n*t_n),
                           W_nw >= nwps*WAWn,

                           # Buckling constraint on main gear
                           L_m <= np.pi**2*E*I_m/(K*l_m)**2,
                           I_m == np.pi*r_m**3*t_m,

                           # Buckling constraint on nose gear
                           # source: https://en.wikipedia.org/wiki/Buckling
                           L_n <= np.pi**2*E*I_n/(K*l_n)**2,
                           I_n == np.pi*r_n**3*t_n,

                           # Machining constraint # p89 Mason
                           # www.dept.aoe.vt.edu/~mason/Mason_f/M96SC08.pdf
                           2*r_m/t_m <= 40,
                           2*r_m/t_n <= 40,

                           # Retraction constraint on strut diameter
                           2*wtm + 2*r_m <= hhold,
                           2*wtn + 2*r_n <= 0.8*units.m, #TODO improve this

                           # Weight accounting
                           W_mg >= n_mg*(W_ms + W_mw*(1 + faddm)),# Currey p264
                           W_ng >= W_ns + W_nw*(1 + faddn),
                           W_lg >= W_mg + W_ng,
                          ]

            standaloneCG = [
                           # CG location affected by landing gear position
                           TCS([xcg*W <= W_0*xcg0 + W_ng*x_n + W_mg*x_m]),
                           W >= W_0 + W_lg,
                           ]

            coupledCG = [
                         TCS([W_lg*xcglg >= W_ng*x_n + W_mg*x_m], reltol=1E-2,
                             raiseerror=False),
                         x_m >= xcglg,
                        ]

            self.standaloneCG = standaloneCG
            self.coupledCG = coupledCG

        CostedConstraintSet.__init__(self, objective, constraints)
Beispiel #3
0
    def __init__(self, **kwargs):
        ARh     = Variable('AR_h', '-', 'Horizontal tail aspect ratio')
        ARw     = Variable('AR_w', '-', 'Wing aspect ratio')
        CD0h    = Variable('C_{D_{0_h}}', '-',
                           'Horizontal tail parasitic drag coefficient')
        CDh     = Variable('C_{D_h}', '-', 'Horizontal tail drag coefficient')
        CLah    = Variable('C_{L_{ah}}', '-', 'Lift curve slope (htail)')
        CLah0   = Variable('C_{L_{ah_0}}', '-',
                           'Isolated lift curve slope (htail)')
        CLaw    = Variable('C_{L_{aw}}', '-', 'Lift curve slope (wing)')
        CLh     = Variable('C_{L_h}', '-', 'Lift coefficient (htail)')
        CLhmax  = Variable('C_{L_{hmax}}', '-', 'Max lift coefficient')
        CLw     = Variable('C_{L_w}', '-', 'Lift coefficient (wing)')
        Cmac    = Variable('|C_{m_{ac}}|', '-', # Absolute value of CMwing
                           'Moment coefficient about aerodynamic centre (wing)')
        Cmfu    = Variable('C_{m_{fuse}}', '-', 'Moment coefficient (fuselage)')
        D       = Variable('D_{ht}', 'N', 'Horizontal tail drag')
        Kf      = Variable('K_f', '-',
                           'Empirical factor for fuselage-wing interference')
        Lh      = Variable('L_h', 'N', 'Horizontal tail downforce')
        Lmax    = Variable('L_{{max}_h}', 'N', 'Maximum load')
        M       = Variable('M', '-', 'Cruise Mach number')
        Rec     = Variable('Re_{c_h}', '-',
                           'Cruise Reynolds number (Horizontal tail)')
        SM      = Variable('S.M.', '-', 'Stability margin')
        SMmin   = Variable('S.M._{min}', '-', 'Minimum stability margin')
        Sh      = Variable('S_h', 'm^2', 'Horizontal tail area')
        Sw      = Variable('S_w', 'm^2', 'Wing area')
        Vinf    = Variable('V_{\\infty}', 'm/s', 'Freestream velocity')
        Vne     = Variable('V_{ne}', 'm/s', 'Never exceed velocity')
        W       = Variable('W_{ht}', 'N', 'Horizontal tail weight')
        a       = Variable('a', 'm/s', 'Speed of sound (35,000 ft)')
        alpha   = Variable('\\alpha', '-', 'Horizontal tail angle of attack')
        amax    = Variable('\\alpha_{max,h}', '-', 'Max angle of attack, htail')
        bht     = Variable('b_{ht}', 'm', 'Horizontal tail span')
        chma    = Variable('\\bar{c}_{ht}', 'm', 'Mean aerodynamic chord (ht)')
        croot   = Variable('c_{root_h}', 'm', 'Horizontal tail root chord')
        ctip    = Variable('c_{tip_h}', 'm', 'Horizontal tail tip chord')
        cwma    = Variable('\\bar{c}_w', 'm',
                           'Mean aerodynamic chord (wing)')
        dxlead  = Variable('\\Delta x_{{lead}_h}', 'm',
                           'Distance from CG to horizontal tail leading edge')
        dxtrail = Variable('\\Delta x_{{trail}_h}', 'm',
                           'Distance from CG to horizontal tail trailing edge')
        dxw     = Variable('\\Delta x_w', 'm',
                           'Distance from aerodynamic centre to CG')
        e       = Variable('e_h', '-', 'Oswald efficiency factor')
        eta     = Variable('\\eta_h', '-',
                           ("Lift efficiency (diff between sectional and "
                            "actual lift)"))
        etaht   = Variable('\\eta_{ht}', '-', 'Tail efficiency')
        fl      = Variable(r"f(\lambda_h)", '-',
                           'Empirical efficiency function of taper')
        lfuse   = Variable('l_{fuse}', 'm', 'Fuselage length')
        lht     = Variable('l_{ht}', 'm', 'Horizontal tail moment arm')
        mu      = Variable(r'\mu', 'N*s/m^2', 'Dynamic viscosity (35,000 ft)')
        p       = Variable('p_{ht}', '-', 'Substituted variable = 1 + 2*taper')
        q       = Variable('q_{ht}', '-', 'Substituted variable = 1 + taper')
        rho     = Variable(r'\rho', 'kg/m^3', 'Air density (cruise)')
        rho0    = Variable(r'\rho_0', 'kg/m^3', 'Air density (0 ft)')
        tanLh   = Variable(r'\tan(\Lambda_{ht})', '-',
                           'tangent of horizontal tail sweep')
        taper   = Variable(r'\lambda_h', '-', 'Horizontal tail taper ratio')
        tau     = Variable(r'\tau_h', '-',
                           'Horizontal tail thickness/chord ratio')
        wf      = Variable('w_{fuse}', 'm', 'Fuselage width')
        xcg     = Variable('x_{CG}', 'm', 'CG location')
        xcght   = Variable('x_{CG_{ht}}', 'm', 'Horizontal tail CG location')
        xw      = Variable('x_w', 'm', 'Position of wing aerodynamic center')
        ymac    = Variable('y_{\\bar{c}_{ht}}', 'm',
                           'Spanwise location of mean aerodynamic chord')

        objective = D + 0.1*W

        with SignomialsEnabled():
                           # Stability from UMich AE-481 course notes
            constraints = [TCS([SM + dxw/cwma + Kf*wf**2*lfuse/(CLaw*Sw*cwma)
                                <= CLah*Sh*lht/(CLaw*Sw*cwma)]),
                           SM >= SMmin,

                           # Trim from UMich AE-481 course notes
                           TCS([CLh*Sh*lht/(Sw*cwma) + Cmac >=
                                CLw*dxw/cwma + Cmfu], reltol=0.02),
                           Lh == 0.5*rho*Vinf**2*Sh*CLh,

                           # Moment arm and geometry -- same as for vtail
                           TCS([dxlead + croot <= dxtrail]),
                           TCS([xcg + dxtrail <= lfuse], reltol=0.002),
                           TCS([dxlead + ymac*tanLh + 0.25*chma >= lht],
                               reltol=1e-2), # [SP]
                           p >= 1 + 2*taper,
                           2*q >= 1 + p,
                           ymac == (bht/3)*q/p,
                           TCS([(2./3)*(1 + taper + taper**2)*croot/q >=
                                chma]), # [SP]
                           taper == ctip/croot,
                           TCS([Sh <= bht*(croot + ctip)/2]), # [SP]

                           # DATCOM formula (Mach number makes it SP)
                           TCS([(ARh/eta)**2*(1+tanLh**2-M**2) + 8*pi*ARh/CLah0
                                <= (2*pi*ARh/CLah0)**2]),
                           # Loss of tail effectiveness due to wing downwash
                           CLah + (2*CLaw/(pi*ARw))*etaht*CLah0 <= CLah0*etaht,
                           CLh == CLah*alpha,
                           alpha <= amax,

                           # K_f as f(wing position) -- (fitted posynomial)
                           # from from UMich AE-481 course notes Table 9.1
                           Kf >= (1.5012*(xw/lfuse)**2 +
                                  0.538*(xw/lfuse) +
                                  0.0331),
                           TCS([xw >= xcg + dxw]),

                           # Drag
                           D == 0.5*rho*Vinf**2*Sh*CDh,
                           CDh >= CD0h + CLh**2/(pi*e*ARh),
                           # same drag model as vtail
                           CD0h**0.125 >= 0.19*(tau)**0.0075 *(Rec)**0.0017
                                        + 1.83e+04*(tau)**3.54*(Rec)**-0.494
                                        + 0.118*(tau)**0.0082 *(Rec)**0.00165
                                        + 0.198*(tau)**0.00774*(Rec)**0.00168,
                           Rec == rho*Vinf*chma/mu,

                           # Oswald efficiency
                           # Nita, Scholz,
                           # "Estimating the Oswald factor from basic
                           # aircraft geometrical parameters"
                           TCS([fl >= (0.0524*taper**4 - 0.15*taper**3
                                       + 0.1659*taper**2
                                       - 0.0706*taper + 0.0119)], reltol=0.2),
                           # NOTE: slightly slack
                           TCS([e*(1 + fl*ARh) <= 1]),
                           taper >= 0.2, # TODO: make less arbitrary

                           Lmax == 0.5*rho0*Vne**2*Sh*CLhmax,
                          ]

        standalone_constraints = [M == Vinf/a,
                                 ]

        CG_constraint = [TCS([xcght >= xcg+(dxlead+dxtrail)/2]),
                         xcght <= lfuse
                        ]

        self.standalone_constraints = standalone_constraints
        self.CG_constraint = CG_constraint

        wb = WingBox()
        wb.subinplace({'A': ARh,
                       'b': bht,
                       'L_{max}': Lmax,
                       'p': p,
                       'q': q,
                       'S': Sh,
                       'taper': taper,
                       r'\tau': tau,
                       'W_{struct}': W})

        lc = LinkedConstraintSet([constraints, wb])

        CostedConstraintSet.__init__(self, objective, lc, **kwargs)
Beispiel #4
0
    def __init__(self, **kwargs):
        Afuel   = Variable('\\bar{A}_{fuel, max}', '-', 'Non-dim. fuel area')
        AR      = Variable('AR_w', '-', 'Wing aspect ratio')
        CDp     = Variable('C_{D_{p_w}}', '-',
                           'Wing parasitic drag coefficient')
        CDw     = Variable('C_{D_w}', '-', 'Drag coefficient, wing')
        CLaw    = Variable('C_{L_{aw}}', '-', 'Lift curve slope, wing')
        CLw     = Variable('C_{L_w}', '-', 'Lift coefficient, wing')
        CLwmax  = Variable('C_{L_{wmax}}', '-', 'Max lift coefficient, wing')
        D       = Variable('D_{wing}', 'N', 'Wing drag')
        Lmax    = Variable('L_{max_{w}}', 'N', 'Maximum load')
        Lw      = Variable('L_w', 'N', 'Wing lift')
        M       = Variable('M', '-', 'Cruise Mach number')
        Re      = Variable('Re_w', '-', 'Cruise Reynolds number (wing)')
        Sw      = Variable('S_w', 'm^2', 'Wing area')
        Vinf    = Variable('V_{\\infty}', 'm/s', 'Freestream velocity')
        Vfuel   = Variable('V_{fuel, max}', 'm^3', 'Available fuel volume')
        Vne     = Variable('V_{ne}', 'm/s', 'Never exceed velocity')
        W       = Variable('W', 'N', 'Aircraft weight')
        W0      = Variable('W_0', 'N', 'Weight excluding wing')
        Wfuel   = Variable('W_{fuel}', 'N', 'Fuel weight')
        Wfuelmax= Variable('W_{fuel,max}', 'N', 'Max fuel weight')
        Ww      = Variable('W_{wing}', 'N', 'Wing weight')
        a       = Variable('a', 'm/s', 'Speed of sound (35,000 ft)')
        alpha   = Variable('\\alpha_w', '-', 'Wing angle of attack')
        amax    = Variable('\\alpha_{max,w}', '-', 'Max angle of attack')
        b       = Variable('b_w', 'm', 'Wing span')
        cosL    = Variable('\\cos(\\Lambda)', '-',
                           'Cosine of quarter-chord sweep angle')
        croot   = Variable('c_{root}', 'm', 'Wing root chord')
        ctip    = Variable('c_{tip}', 'm', 'Wing tip chord')
        cwma    = Variable('\\bar{c}_w', 'm',
                           'Mean aerodynamic chord (wing)')
        e       = Variable('e', '-', 'Oswald efficiency factor')
        eta     = Variable('\\eta_w', '-',
                           'Lift efficiency (diff b/w sectional, actual lift)')
        fl      = Variable('f(\\lambda_w)', '-',
                           'Empirical efficiency function of taper')
        g       = Variable('g', 'm/s^2', 'Gravitational acceleration')
        mu      = Variable('\\mu', 'N*s/m^2', 'Dynamic viscosity (35,000 ft)')
        p       = Variable('p_w', '-', 'Substituted variable = 1 + 2*taper')
        q       = Variable('q_w', '-', 'Substituted variable = 1 + taper')
        rho     = Variable('\\rho', 'kg/m^3', 'Air density (cruise)')
        rho0    = Variable('\\rho_0', 'kg/m^3', 'Air density (0 ft)')
        rhofuel = Variable('\\rho_{fuel}', 'kg/m^3', 'Density of fuel')
        tanL    = Variable('\\tan(\\Lambda)', '-',
                           'Tangent of quarter-chord sweep angle')
        taper   = Variable('\\lambda', '-', 'Wing taper ratio')
        tau     = Variable('\\tau_w', '-', 'Wing thickness/chord ratio')
        tcap    = Variable('t_{cap}' ,'-', 'Non-dim. spar cap thickness')
        tweb    = Variable('t_{web}', '-', 'Non-dim. shear web thickness')
        w       = Variable('w', 0.5, '-', 'Wingbox-width-to-chord ratio')
        #xw     = Variable('x_w', 'm', 'Position of wing aerodynamic center')
        ymac    = Variable('y_{\\bar{c}_w}', 'm',
                           'Spanwise location of mean aerodynamic chord')


        objective = D

        with SignomialsEnabled():
            constraints = [
                           Lw == 0.5*rho*Vinf**2*Sw*CLw,

                           p >= 1 + 2*taper,
                           2*q >= 1 + p,
                           ymac == (b/3)*q/p,
                           TCS([(2./3)*(1+taper+taper**2)*croot/q <= cwma],
                               reltol=1E-2),
                           taper == ctip/croot,
                           TCS([Sw <= b*(croot + ctip)/2], reltol=1E-2), # [SP]

                           # DATCOM formula (Mach number makes it SP)
                           TCS([(AR/eta)**2*(1 + tanL**2 - M**2) + 8*pi*AR/CLaw
                                <= (2*pi*AR/CLaw)**2]),
                           CLw == CLaw*alpha,
                           alpha <= amax,

                           # Drag
                           D == 0.5*rho*Vinf**2*Sw*CDw,
                           CDw >= CDp + CLw**2/(pi*e*AR),
                           Re == rho*Vinf*cwma/mu,
                           1 >= (2.56*CLw**5.88/(Re**1.54*tau**3.32*CDp**2.62)
                              + 3.8e-9*tau**6.23/(CLw**0.92*Re**1.38*CDp**9.57)
                              + 2.2e-3*Re**0.14*tau**0.033/(CLw**0.01*CDp**0.73)
                              + 6.14e-6*CLw**6.53/(Re**0.99*tau**0.52*CDp**5.19)
                              + 1.19e4*CLw**9.78*tau**1.76/(Re*CDp**0.91)),

                           # Oswald efficiency
                           # Nita, Scholz, "Estimating the Oswald factor from
                           # basic aircraft geometrical parameters"
                           TCS([fl >= 0.0524*taper**4 - 0.15*taper**3
                                    + 0.1659*taper**2 - 0.0706*taper + 0.0119],
                               reltol=1E-2),
                           TCS([e*(1 + fl*AR) <= 1]),
                           taper >= 0.2, # TODO

                           Lmax == 0.5*rho0*Vne**2*Sw*CLwmax,

                           # Fuel volume [TASOPT doc]
                           Afuel <= w*0.92*tau,
                           # GP approx of the signomial constraint:
                           # Afuel <= (w - 2*tweb)*(0.92*tau - 2*tcap),
                           Vfuel <= croot**2 * (b/6) * (1+taper+taper**2)*cosL,
                           Wfuel <= rhofuel*Afuel*Vfuel*g,
                          ]

            standalone_constraints = [W >= W0 + Ww + Wfuel,
                                      Lw == W,
                                      M == Vinf/a,
                                      ]

            self.standalone_constraints = standalone_constraints

        wb = WingBox()
        wb.subinplace({'A': AR,
                       'b': b,
                       'L_{max}': Lmax,
                       'p': p,
                       'q': q,
                       'S': Sw,
                       'taper': taper,
                       '\\tau': tau,
                       'W_{struct}': Ww})

        lc = LinkedConstraintSet([constraints, wb])

        CostedConstraintSet.__init__(self, objective, lc, **kwargs)
Beispiel #5
0
 def test_vector_cost(self):
     x = VectorVariable(2, "x")
     self.assertRaises(ValueError, CostedConstraintSet, x, [])
     _ = CostedConstraintSet(np.array(x[0]), [])
Beispiel #6
0
    def __init__(self, **kwargs):

        Afan   = Variable('A_{fan}', 'm^2', 'Engine reference area')
        Avt    = Variable('A_{vt}', '-', 'Vertical tail aspect ratio')
        CDvis  = Variable('C_{D_{vis}}', '-', 'Viscous drag coefficient')
        CDwm   = Variable('C_{D_{wm}}', '-', 'Windmill drag coefficient')
        CLvmax = Variable('C_{L_{vmax}}', '-', 'Max lift coefficient')
        CLvt   = Variable('C_{L_{vt}}', '-', 'Vertical tail lift coefficient')
        Dvt    = Variable('D_{vt}', 'N', 'Vertical tail viscous drag, cruise')
        Dwm    = Variable('D_{wm}', 'N', 'Engine out windmill drag')
        Lmax   = Variable('L_{max_{vt}}', 'N',
                          'Maximum load for structural sizing') # fuselage
        Lvmax  = Variable('L_{v_{max}}', 'N',
                          'Maximum load for structural sizing')
        Lvt    = Variable('L_{vt}', 'N', 'Vertical tail lift in engine out')
        Rec    = Variable('Re_{vt}', '-', 'Vertical tail reynolds number, cruise')
        S      = Variable('S', 'm^2', 'Vertical tail reference area (full)')
        Svt    = Variable('S_{vt}', 'm^2', 'Vertical tail reference area (half)')
        Te     = Variable('T_e', 'N', 'Thrust per engine at takeoff')
        V1     = Variable('V_1', 'm/s', 'Minimum takeoff velocity')
        Vinf   = Variable('V_{\\infty}', 'm/s', 'Cruise velocity')
        Vne    = Variable('V_{ne}', 'm/s', 'Never exceed velocity')
        Wstruct= Variable('W_{struct}', 'N', 'Full span weight')
        Wvt    = Variable('W_{vt}', 'N', 'Vertical tail weight')
        b      = Variable('b', 'm', 'Vertical tail full span')
        bvt    = Variable('b_{vt}', 'm', 'Vertical tail half span')
        clvt   = Variable('c_{l_{vt}}', '-',
                          'Sectional lift force coefficient (engine out)')
        cma    = Variable('\\bar{c}_{vt}', 'm', 'Vertical tail mean aero chord')
        croot  = Variable('c_{root_{vt}}', 'm', 'Vertical tail root chord')
        ctip   = Variable('c_{tip_{vt}}', 'm', 'Vertical tail tip chord')
        cvt    = Variable('c_{vt}', 'm', 'Vertical tail root chord') # fuselage
        dfan   = Variable('d_{fan}', 'm', 'Fan diameter')
        dxlead = Variable('\\Delta x_{lead_v}', 'm',
                          'Distance from CG to vertical tail leading edge')
        dxtrail= Variable('\\Delta x_{trail_v}', 'm',
                          'Distance from CG to vertical tail trailing edge')
        e      = Variable('e_v', '-', 'Span efficiency of vertical tail')
        lfuse  = Variable('l_{fuse}', 'm', 'Length of fuselage')
        lvt    = Variable('l_{vt}', 'm', 'Vertical tail moment arm')
        mu     = Variable('\\mu', 'N*s/m^2', 'Dynamic viscosity (35,000 ft)')
        mu0    = Variable('\\mu_0', 1.8E-5, 'N*s/m^2', 'Dynamic viscosity (SL)')
        p      = Variable('p_{vt}', '-', 'Substituted variable = 1 + 2*taper')
        plamv  = Variable('p_{\\lambda_v}', '-',
                          'Dummy variable = 1 + 2\\lambda') # fuselage
        q      = Variable('q_{vt}', '-', 'Substituted variable = 1 + taper')
        rho0   = Variable('\\rho_{TO}', 'kg/m^3', 'Air density (SL))')
        rho    = Variable('\\rho', 'kg/m^3', 'Air density (cruise)')
        tanL   = Variable('\\tan(\\Lambda_{vt})', '-',
                          'Tangent of leading edge sweep (40 deg)')
        taper  = Variable('\\lambda_{vt}', '-', 'Vertical tail taper ratio')
        tau    = Variable('\\tau_{vt}', '-', 'Vertical tail thickness/chord ratio')
        xCG    = Variable('x_{CG}', 'm', 'x-location of CG')
        xCGvt  = Variable('x_{CG_{vt}}', 'm', 'x-location of tail CG')
        y_eng  = Variable('y_{eng}', 'm', 'Engine moment arm')
        zmac   = Variable('z_{\\bar{c}_{vt}}', 'm',
                          'Vertical location of mean aerodynamic chord')


        with SignomialsEnabled():
            objective = Dvt + 0.05*Wvt
            constraints = [
                           Lvt*lvt >= Te*y_eng + Dwm*y_eng,
                           # Force moment balance for one engine out condition
                           # TASOPT 2.0 p45

                           TCS([dxlead + zmac*tanL + 0.25*cma >= lvt]), # [SP]
                           # Tail moment arm

                           Lvt == 0.5*rho0*V1**2*Svt*CLvt,
                           # Vertical tail force (y-direction) for engine out 

                           Avt == bvt**2/Svt,
                           TCS([CLvt*(1 + clvt/(np.pi*e*Avt)) <= clvt]),
                           # Finite wing theory
                           # people.clarkson.edu/~pmarzocc/AE429/AE-429-4.pdf
                           # Valid because tail is untwisted and uncambered
                           # (lift curve slope passes through origin)

                           Dwm >= 0.5*rho0*V1**2*Afan*CDwm,
                           Afan >= np.pi*(dfan/2)**2,
                           # Drag of a windmilling engine

                           Svt <= bvt*(croot + ctip)/2, # [SP]
                           # Tail geometry relationship

                           TCS([dxtrail >= croot + dxlead]),
                           # Tail geometry constraint

                           lfuse >= dxtrail + xCG,
                           # Fuselage length constrains the tail trailing edge

                           p >= 1 + 2*taper,
                           2*q >= 1 + p,
                           zmac == (bvt/3)*q/p,
                           TCS([(2./3)*(1 + taper + taper**2)*croot/q >= cma]), # [SP]
                           taper == ctip/croot,
                           # Define vertical tail geometry

                           taper >= 0.27,
                           # TODO: Constrain taper by tip Reynolds number
                           # source: b737.org.uk

                           Dvt >= 0.5*rho*Vinf**2*Svt*CDvis,
                           CDvis**0.125 >= 0.19*(tau)**0.0075 *(Rec)**0.0017
                                        + 1.83e+04*(tau)**3.54*(Rec)**-0.494
                                        + 0.118*(tau)**0.0082 *(Rec)**0.00165
                                        + 0.198*(tau)**0.00774*(Rec)**0.00168,
                           # Vertical tail viscous drag in cruise
                           # Data fit from Xfoil

                           Rec == rho*Vinf*cma/mu,
                           # Cruise Reynolds number

                           S == Svt*2,
                           b == bvt*2,
                           Wvt == Wstruct/2,
                           Lmax == 2*Lvmax,
                           # Relate vertical tail geometry/weight to generic
                           # wing used in structural model

                           Lvmax == 0.5*rho0*Vne**2*Svt*CLvmax,
                           # Max load for structural sizing
                          ]

            # For linking to other models
            linking_constraints = [plamv == p,
                                   cvt == croot]

            CG_constraint = [TCS([xCGvt >= xCG+(dxlead+dxtrail)/2],
                                 raiseerror=False),
                             xCGvt <= lfuse]

            self.linking_constraints = linking_constraints
            self.CG_constraint = CG_constraint


        # Incorporate the structural model
        wb = WingBox()
        wb.subinplace({'b': b,
                       'L_{max}': Lmax,
                       'p': p,
                       'q': q,
                       'S': S,
                       'taper': taper,
                       '\\tau': tau})
        lc = LinkedConstraintSet([constraints, wb])

        CostedConstraintSet.__init__(self, objective, lc)