def setup(self, aircraft, state, **kwargs):
        #make submodels
        self.aircraft = aircraft
        self.wingP = aircraft.wing.dynamic(state)
        self.fuseP = aircraft.fuse.dynamic(state)
        self.engineP = aircraft.engine.dynamic(state)

        self.Pmodels = [self.wingP, self.fuseP, self.engineP]

        #variable definitions
        Vstall = Variable('V_{stall}', 'knots', 'Aircraft Stall Speed')
        D = Variable('D', 'N', 'Total Aircraft Drag')
        W_avg = Variable('W_{avg}', 'N',
                         'Geometric Average of Segment Start and End Weight')
        W_start = Variable('W_{start}', 'N', 'Segment Start Weight')
        W_end = Variable('W_{end}', 'N', 'Segment End Weight')
        W_burn = Variable('W_{burn}', 'N', 'Segment Fuel Burn Weight')
        WLoadmax = Variable('W_{Load_{max}}', 'N/m^2', 'Max Wing Loading')
        WLoad = Variable('W_{Load}', 'N/m^2', 'Wing Loading')
        t = Variable('tmin', 'min', 'Segment Flight Time in Minutes')
        thours = Variable('thr', 'hour', 'Segment Flight Time in Hours')

        constraints = []

        constraints.extend([
            #speed must be greater than stall speed
            state['V'] >= Vstall,

            #Figure out how to delete
            Vstall == 120 * units('kts'),
            WLoadmax == 6664 * units('N/m^2'),

            #compute the drag
            TCS([D >= self.wingP['D_{wing}'] + self.fuseP['D_{fuse}']]),

            #constraint CL and compute the wing loading
            W_avg == .5 * self.wingP['C_{L}'] * self.aircraft['S'] *
            state.atm['\\rho'] * state['V']**2,
            WLoad == .5 * self.wingP['C_{L}'] * self.aircraft['S'] *
            state.atm['\\rho'] * state['V']**2 / self.aircraft.wing['S'],

            #set average weight equal to the geometric avg of start and end weight
            W_avg == (W_start * W_end)**.5,

            #constrain the max wing loading
            WLoad <= WLoadmax,

            #compute fuel burn from TSFC
            W_burn == aircraft['numeng'] * self.engineP['TSFC'] * thours *
            self.engineP['thrust'],

            #time unit conversion
            t == thours,

            #make lift equal weight --> small angle approx in climb
            self.wingP['L_{wing}'] == W_avg,
        ])

        return constraints, self.wingP, self.engineP, self.fuseP
Esempio n. 2
0
    def setup(self):
        fs = FlightState()
        Propulsor.prop_flight_model = BladeElementProp
        p = Propulsor()
        pp = p.flight_model(p,fs)
        pp.substitutions[pp.prop.T] = 100
        self.cost = pp.motor.Pelec/(1000*units('W')) + p.W/(1000*units('lbf'))

        return fs,p,pp
Esempio n. 3
0
 def test_constraint_creation_units(self):
     v = VectorVariable(2, "v", "m/s")
     c = (v >= 40*gpkit.units("ft/s"))
     c2 = (v >= [20, 30]*gpkit.units("ft/s"))
     if gpkit.units:
         self.assertTrue(c.right.units)
         self.assertTrue(c2.right.units)
     else:
         self.assertEqual(type(c.right), int)
         self.assertEqual(type(c2.right), list)
Esempio n. 4
0
 def test_constraint_creation_units(self):
     v = VectorVariable(2, "v", "m/s")
     c = (v >= 40*gpkit.units("ft/s"))
     c2 = (v >= np.array([20, 30])*gpkit.units("ft/s"))
     if gpkit.units:
         self.assertTrue(c.right.units)
         self.assertTrue(NomialArray(c2.right).units)
     else:
         self.assertEqual(type(c.right), int)
         self.assertEqual(type(c2.right), np.ndarray)
Esempio n. 5
0
 def test_constraint_creation_units(self):
     v = VectorVariable(2, "v", "m/s")
     c = (v >= 40*gpkit.units("ft/s"))
     c2 = (v >= np.array([20, 30])*gpkit.units("ft/s"))
     if gpkit.units:
         self.assertTrue(c.right.units)
         self.assertTrue(NomialArray(c2.right).units)
     else:
         self.assertEqual(type(c.right), int)
         self.assertEqual(type(c2.right), np.ndarray)
Esempio n. 6
0
 def test_constraint_creation_units(self):
     v = VectorVariable(2, "v", "m/s")
     c = (v >= 40 * gpkit.units("ft/s"))
     c2 = (v >= [20, 30] * gpkit.units("ft/s"))
     if gpkit.units:
         self.assertTrue(c.right.units)
         self.assertTrue(c2.right.units)
     else:
         self.assertEqual(type(c.right), int)
         self.assertEqual(type(c2.right), list)
Esempio n. 7
0
 def test_united_sub_sweep(self):
     A = Variable("A", "USD")
     h = Variable("h", "USD/count")
     Q = Variable("Q", "count")
     Y = Variable("Y", "USD")
     m = Model(Y, [Y >= h*Q + A/Q])
     m.substitutions.update({A: 500*gpkit.units("USD"),
                             h: 35*gpkit.units("USD"),
                             Q: ("sweep", [50, 100, 500])})
     firstcost = m.solve(verbosity=0)["cost"][0]
     self.assertAlmostEqual(1760*gpkit.ureg("USD")/firstcost, 1, 5)
Esempio n. 8
0
 def test_united_sub_sweep(self):
     A = Variable("A", "USD")
     h = Variable("h", "USD/count")
     Q = Variable("Q", "count")
     Y = Variable("Y", "USD")
     m = Model(Y, [Y >= h*Q + A/Q])
     m.substitutions.update({A: 500*gpkit.units("USD"),
                             h: 35*gpkit.units("USD"),
                             Q: ("sweep", [50, 100, 500])})
     firstcost = m.solve(verbosity=0)["cost"][0]
     self.assertAlmostEqual(firstcost, 1760, 3)
Esempio n. 9
0
def test_Nozzle():
    print "Testing Nozzle..."
    m = Rocket(1)
    m.substitutions.update({
        'k_A': 5,
        'T_t': 1800 * units('K'),
        'P_t': 5e8 * units('Pa'),
        # 'mdot':        150*units('kg/s'),
    })
    m.cost = 1 / sum(m.nozzlePerformance.T)
    sol = m.localsolve(verbosity=0)
    print sol.table()
Esempio n. 10
0
    def setup(self, engine):
        self.engine = engine
        M2 = .6
        M25 = .6
        M0 = .8025

        toclimb = [
            engine['F'][0] == 94.971 * units('kN'),
            engine['F'][1] == 30.109 * units('kN'),
            engine['F'][2] == 22.182 * units('kN'),
            engine.state['P_{atm}'][1] == 23.84 * units('kPa'),  #36K feet
            engine.state["T_{atm}"][1] == 218 * units('K'),
            engine.state['M'][1] == M0,
            engine.engineP['M_2'][1] == M2,
            engine.engineP['M_{2.5}'][1] == M25,
            engine.engineP['hold_{2}'][1] == 1 + .5 * (1.398 - 1) * M2**2,
            engine.engineP['hold_{2.5}'][1] == 1 + .5 * (1.354 - 1) * M25**2,
            engine.engineP['c1'][1] == 1 + .5 * (.401) * M0**2,
        ]

        M2 = .6
        M25 = .6
        M0 = .8

        cruise = [
            engine.state['P_{atm}'][2] == 23.92 * units('kPa'),  #36K feet
            engine.state["T_{atm}"][2] == 219.4 * units('K'),
            engine.state['M'][2] == M0,
            engine.engineP['M_2'][2] == M2,
            engine.engineP['M_{2.5}'][2] == M25,
            engine.engineP['hold_{2}'][2] == 1 + .5 * (1.398 - 1) * M2**2,
            engine.engineP['hold_{2.5}'][2] == 1 + .5 * (1.354 - 1) * M25**2,
            engine.engineP['c1'][2] == 1 + .5 * (.401) * M0**2,
        ]

        M2 = .6
        M25 = .6
        M0 = .2201

        rotation = [
            engine.state['P_{atm}'][0] == 101.325 * units('kPa'),
            engine.state["T_{atm}"][0] == 288 * units('K'),
            engine.state['M'][0] == M0,
            engine.engineP['M_2'][0] == M2,
            engine.engineP['M_{2.5}'][0] == M25,
            engine.engineP['hold_{2}'][0] == 1 + .5 * (1.401 - 1) * M2**2,
            engine.engineP['hold_{2.5}'][0] == 1 + .5 * (1.401 - 1) * M25**2,
            engine.engineP['c1'][0] == 1 + .5 * (.401) * M0**2,
            engine['W_{engine}'] <= 1.1 * 7870.7 * units('lbf'),
        ]

        return rotation, toclimb, cruise
Esempio n. 11
0
def run_M072_737(objective, fixedBPR, pRatOpt, mutategparg):
    # User definitions
    Nclimb = 3
    Ncruise = 2
    Nmission = 1
    aircraft = 'M072_737'

    m = Mission(Nclimb, Ncruise, objective, aircraft, Nmission)

    substitutions = get_M072_737_subs()

    if Nmission > 1:
        substitutions.update({
            'R_{req}': [3000. * units('nmi'), 2500. * units('nmi')],
            'n_{pass}': [180., 180.],
        })
    else:
        substitutions.update({
            'R_{req}': 3000. * units('nmi'),
            'n_{pass}': 180.,
        })

    if fixedBPR:
        substitutions.update({
            '\\alpha_{max}': 6.97,
        })

    if pRatOpt:
        del substitutions['\pi_{f_D}']


##        del substitutions['\pi_{lc_D}']
##        del substitutions['\pi_{hc_D}']

    m.substitutions.update(substitutions)

    m = Model(m.cost, BCS(m))
    m_relax = relaxed_constants(m, None, ['M_{takeoff}', '\\theta_{db}'])

    sol = m_relax.localsolve(verbosity=4,
                             iteration_limit=200,
                             reltol=0.01,
                             mutategp=mutategparg)
    post_process(sol)

    percent_diff(sol, aircraft, Nclimb)

    post_compute(sol, Nclimb)

    return sol
Esempio n. 12
0
    def test_mul(self):
        "Test monomial multiplication"
        x = Monomial({'x': 1, 'y': -1}, 4)
        # test integer division
        self.assertEqual(x / 5, Monomial({'x': 1, 'y': -1}, 0.8))
        # divide by scalar
        self.assertEqual(x * 9, Monomial({'x': 1, 'y': -1}, 36))
        # divide by Monomial
        y = x * Variable('z')
        self.assertEqual(y, Monomial({'x': 1, 'y': -1, 'z': 1}, 4))
        # make sure x unchanged
        self.assertEqual(x, Monomial({'x': 1, 'y': -1}, 4))
        # mixed new and old vars
        z = x * Monomial({'x': -1, 't': 2}, .5)
        self.assertEqual(z, Monomial({'x': 0, 'y': -1, 't': 2}, 2))

        x0 = Variable('x0')
        self.assertEqual(0.0, 0.0 * x0)
        x1 = Variable('x1')
        n_hat = [1, 0]
        p = n_hat[0] * x0 + n_hat[1] * x1
        self.assertEqual(p, x0)

        if gpkit.units:
            self.assertNotEqual((x + 1), (x + 1) * gpkit.units("m"))
Esempio n. 13
0
def test():
    Nclimb = 3 # number of climb segments
    Ncruise = 2 # number of cruise segments
    Nmission = 1 # number of missions
    config = 'optimalD8' # String describing configuration:
    # currently one of: 'D8_eng_wing', 'optimal737', 'optimal777', 'optimalD8', 'D8_no_BLI', 'M072_737'
    m = Mission(Nclimb, Ncruise, config, Nmission)

    # Objective
    m.cost = m['W_{f_{total}}'].sum()

    # Inputs to the model
    substitutions = get_optimalD8_subs()
    substitutions.update({'R_{req}': 3000.*units('nmi'), #6000*units('nmi'),
                         'n_{pass}': 180.})              #450.,)

    # Additional options
    fixedBPR = False
    pRatOpt = True
    sol = optimize_aircraft(m, substitutions, fixedBPR, pRatOpt)

    percent_diff(sol, config, Nclimb)
    post_compute(sol, Nclimb)
    sol.savetxt()
    return sol
Esempio n. 14
0
    def setup(self, tailboom, htail, state):
        N = self.N = tailboom.N
        self.state = state
        self.htail = htail
        self.tailboom = tailboom
        exec parse_variables(TailBoomBending.__doc__)

        Beam.qbarFun = [1e-10] * N
        Beam.SbarFun = [1.] * N
        beam = self.beam = Beam(N)

        I = tailboom.I
        tailboom.I0 = I[0]
        l = tailboom.l
        S = htail.planform.S
        E = tailboom.material.E
        Sy = tailboom.Sy
        qne = state.qne
        CLmax = htail.planform.CLmax
        deta = tailboom.deta
        sigma = tailboom.material.sigma

        constraints = [
            beam.dx == deta, F >= qne * S,
            beam["\\bar{EI}"] <= E * I / F / l**2 / 2,
            Mr >= beam["\\bar{M}"][:-1] * F * l, sigma >= Mr / Sy,
            th == beam["\\theta"][-1],
            beam["\\bar{\\delta}"][-1] * CLmax * Nsafety <= kappa
        ]

        self.tailboomJ = hasattr(tailboom, "J")
        if self.tailboomJ:
            constraints.append(tailboom.J >= 1e-10 * units("m^4"))

        return constraints, beam
Esempio n. 15
0
def map_relaxations(groupedDict, nt, nx, decimals = 3):
    strkeys = groupedDict.keys()
    relaxDict = {i:None for i in strkeys}
    for i in strkeys:
        dim = len(groupedDict[i])
        nd = groupedDict[i]
        # Mapping relaxations in time and space
        dim1, dim2 = [0,0]
        if dim == nx*nt:
            [dim1,dim2] = [nt,nx]
        elif dim == nt:
            [dim1,dim2] = [nt, 1]
        elif dim == nx:
            [dim1,dim2] = [1, nx]
        # Special cases where monomials (always tight) replace posys
        # in the first section
        elif dim == (nx-1)*nt and i == 'massCons':
            [dim1,dim2] = [nt, nx]
            a = np.array(nd)[:,0].reshape((nt, nx-1))
            nd = np.concatenate((np.zeros((nt,1))*units(''), a), axis=1)
            nd = nd.reshape((nx*nt,1))
        else:
            print 'Warning: tight constraint that does not' \
                  ' obey the specified relaxations detected.'
        nd = [mag(j) for j in np.array(nd)[:,0]]
        nd = np.array(nd).reshape((dim2, dim1))
        relaxDict[i] = np.round(nd, decimals=decimals)
    return relaxDict
Esempio n. 16
0
    def setup(self, aircraft, state, **kwargs):
        #submodels
        self.aircraft = aircraft
        self.aircraftP = AircraftP(aircraft, state)
        self.wingP = self.aircraftP.wingP
        self.fuseP = self.aircraftP.fuseP

        #variable definitions
        theta = Variable('\\theta', '-', 'Aircraft Climb Angle')
        excessP = Variable('P_{excess}', 'W', 'Excess Power During Climb')
        RC = Variable('RC', 'feet/min', 'Rate of Climb/Decent')
        dhft = Variable('dhft', 'feet',
                        'Change in Altitude Per Climb Segment [feet]')
        RngClimb = Variable('R_{climb}', 'nautical_miles',
                            'Down Range Covered in Each Climb Segment')

        #constraints
        constraints = []

        constraints.extend([
            RC == excessP / self.aircraftP['W_{avg}'],
            RC >= 500 * units('ft/min'),

            #make the small angle approximation and compute theta
            theta * state['V'] == RC,
            dhft == self.aircraftP['tmin'] * RC,

            #makes a small angle assumption during climb
            RngClimb == self.aircraftP['thr'] * state['V'],
            self.aircraftP['W_{burn}'] == self.aircraft.engine['TSFC'][:2] *
            self.aircraft.engine['F'][:2] * self.aircraftP['thr']
        ])

        return constraints, self.aircraftP
Esempio n. 17
0
    def setup(self):
        fs = FlightState()
        p = Propulsor()
        pp = p.flight_model(p,fs)
        pp.substitutions[pp.prop.T] = 100
        self.cost = 1./pp.motor.etam + p.W/(1000*units('lbf')) + 1./pp.prop.eta

        return fs,p,pp
def test():
    Nmissions = 2
    Nsegments = 4
    aircraft = SimPleAC()
    m = Multimission(aircraft,Nmissions,Nsegments)
    m.substitutions.update({
        'h_{cruise_{mm}}':[5000*units('m'), 5000*units('m')],
        'Range_{mm}'     :[3000*units('km'), 2000*units('km')],
        'W_{p_{mm}}'     :[6250*units('N'),   8000*units('N')],
        'C_{mm}'         :[120*units('1/hr'), 360*units('1/hr')],
    })
    #m.cost = m['W_{f_{mm}}']*units('1/N') + sum(m.missions[i]['C_m']*m.missions[i]['t_m'] for i in range(0,Nmissions))
    m.cost = (m.missions[0]['W_{f_m}']*units('1/N') + m.missions[1]['C_m']*m.missions[1]['t_m'])
    sol = m.localsolve(verbosity = 2)
Esempio n. 19
0
    def setup(self, engine):
        self.engine = engine
        M2 = .6
        M25 = .6
        M0 = .5

        engineclimb = [
            engine['F'][1] == 13.798 * units('kN'),
            engine['F'][0] == 11.949 * units('kN'),
            engine.state['P_{atm}'][1] == 23.84 * units('kPa'),  #36K feet
            engine.state["T_{atm}"][1] == 218 * units('K'),
            engine.state['M'][1] == M0,
            engine.engineP['M_{2.5}'][1] == M25,
            engine.engineP['hold_{2}'][1] == 1 + .5 * (1.398 - 1) * M2**2,
            engine.engineP['hold_{2.5}'][1] == 1 + .5 * (1.354 - 1) * M25**2,
            engine.engineP['c1'][1] == 1 + .5 * (.401) * M0**2,
        ]

        M2 = .6
        M25 = .6
        M0 = .72

        enginecruise = [
            engine.state['P_{atm}'][0] == 23.84 * units('kPa'),  #36K feet
            engine.state["T_{atm}"][0] == 218 * units('K'),
            engine.state['M'][0] == M0,
            engine.engineP['M_2'][0] == M2,
            engine.engineP['M_{2.5}'][0] == M25,
            engine.engineP['hold_{2}'][0] == 1 + .5 * (1.398 - 1) * M2**2,
            engine.engineP['hold_{2.5}'][0] == 1 + .5 * (1.354 - 1) * M25**2,
            engine.engineP['c1'][0] == 1 + .5 * (.401) * M0**2,
            engine['W_{engine}'] <= 10502.8 * units('lbf'),
        ]

        return engineclimb, enginecruise
Esempio n. 20
0
    def setup(self):
        # Free Variables
        CDA0 = Variable("(CDA0)", "m^2",
                        "fuselage drag area")  #0.035 originally
        C_D_fuse = Variable('C_{D_{fuse}}', '-', 'fuselage drag coefficient')
        # Free variables (fixed for performance eval.)
        V_f_fuse = Variable('V_{f_{fuse}}',
                            'm^3',
                            'fuel volume in the fuselage',
                            fix=True)

        constraints = []
        constraints += [
            V_f_fuse == 10 * units('m') * CDA0,
            V_f_fuse >= 1 * 10**-5 * units('m^3')
        ]

        return constraints
Esempio n. 21
0
 def setup(self):
     fs = FlightState()
     m  = Motor()
     mp = MotorPerf(m,fs)
     self.mp = mp
     mp.substitutions[m.Qmax] = 100
     mp.substitutions[mp.Q]    = 10
     self.cost = 1./mp.etam + m.W/(100.*units('lbf'))
     return self.mp, fs, m
Esempio n. 22
0
 def setup(self):
     exec parse_variables(Section.__doc__)
     constraints = [
         # Taking averages,
         A_in * A_out == A_avg**2,
         # Volume of chamber
         V_chamb == A_avg * l,
         # Area ratio
         A_in / A_out == k_A,
         # Mass flow rate
         rho_in * u_in * A_in == mdot_in,
         rho_out * u_out * A_out == mdot_out,
         # Chamber pressure
         P_chamb**2 == P_in * P_out,
         # Product generation rate
         q == rho_p * A_b * r,
         A_b == l_b * l,
         A_p_out + r * l_b * dt <= A_p_in,
         # Stagnation quantities
         P_t_in >= P_in + 0.5 * rho_in * u_in**2,
         T_t_in >= T_in + u_in**2 / (2 * c_p),
         # Ideal gas law
         P_out == rho_out * R * T_out,
         # Pressure increase
         P_out + dP <= P_in,
         # Making sure burn surface length is feasible
         l_b >= 2 * np.pi**0.5 * (A_avg)**0.5,
         l_b <= l_b_max * 2 * np.pi**0.5 * (A_avg)**0.5,
         # Constraining areas
         Tight([A_avg + A_p_in <= np.pi * radius**2]),
     ]
     with SignomialsEnabled():
         constraints += [
             # Flow acceleration (conservation of momentum)
             # Note: assumes constant rate of burn through the chamber
             dP + rho_in * u_in**2 >= q * u_out / V_chamb *
             (2. / 3. * l) + rho_in * u_in * u_out,
             # Burn rate (Saint-Robert's Law, coefficients taken for Space Shuttle SRM)
             Tight([
                 r >= r_c * (P_chamb / 1e6 * units('1/Pa'))**0.35 *
                 (1 + 0.5 * r_k * (u_in + u_out))
             ]),
             # Mass flows
             Tight([mdot_in + q >= mdot_out]),
             mdot_out >= mdot_in,
             # Temperatures
             Tight([
                 T_t_out * mdot_out <=
                 mdot_in * T_t_in + q * T_amb + q * k_comb_p / c_p
             ]),
             # Stagnation quantities
             Tight([P_t_out <= P_out + 0.5 * rho_out * u_out**2]),
             Tight([T_t_out <= T_out + u_out**2 / (2 * c_p)]),
         ]
     return constraints
Esempio n. 23
0
    def setup(self, engine):
        self.engine = engine
        M2 = .6
        M25 = .6
        M0 = .8

        climb = [
            engine['F'][0] == 5496.4 * 4.4 * units('N'),
            engine['F'][1] == 5961.9 * 4.4 * units('N'),
            engine.state["T_{atm}"] == 218 * units('K'),
            engine.state['P_{atm}'][0] == 23.84 * units('kPa'),  #36K feet
            engine.state['M'][0] == M0,
            engine.engineP['M_2'][0] == M2,
            engine.engineP['M_{2.5}'][0] == M25,
            engine.engineP['hold_{2}'] == 1 + .5 * (1.398 - 1) * M2**2,
            engine.engineP['hold_{2.5}'] == 1 + .5 * (1.354 - 1) * M25**2,
            engine.engineP['c1'] == 1 + .5 * (.401) * M0**2,
        ]

        M2 = .6
        M25 = .6
        M0 = .8

        cruise = [
            engine.state['P_{atm}'][1] == 23.84 * units('kPa'),  #36K feet
            engine.state['M'][1] == M0,
            engine.engineP['M_2'][1] == M2,
            engine.engineP['M_{2.5}'][1] == M25,
            engine['W_{engine}'] <= 5216 * units('lbf'),
        ]

        return climb, cruise
Esempio n. 24
0
 def test_quantity_sub(self):
     if gpkit.units:
         x = Variable("x", 1, "cm")
         y = Variable("y", 1)
         self.assertEqual(x.sub({x: 1*gpkit.units.m}).c.magnitude, 100)
         # NOTE: uncomment the below if requiring Quantity substitutions
         # self.assertRaises(ValueError, x.sub, x, 1)
         self.assertRaises(ValueError, x.sub, {x: 1*gpkit.ureg.N})
         self.assertRaises(ValueError, y.sub, {y: 1*gpkit.ureg.N})
         v = gpkit.VectorVariable(3, "v", "cm")
         subbed = v.sub({v: [1, 2, 3]*gpkit.ureg.m})
         self.assertEqual([z.c.magnitude for z in subbed], [100, 200, 300])
         v = VectorVariable(1, "v", "km")
         v_min = VectorVariable(1, "v_min", "km")
         m = Model(v.prod(), [v >= v_min],
                   {v_min: [2*gpkit.units("nmi")]})
         cost = m.solve(verbosity=0)["cost"]
         self.assertAlmostEqual(cost/(3.704*gpkit.ureg("km")), 1.0)
         m = Model(v.prod(), [v >= v_min],
                   {v_min: np.array([2])*gpkit.units("nmi")})
         cost = m.solve(verbosity=0)["cost"]
         self.assertAlmostEqual(cost/(3.704*gpkit.ureg("km")), 1.0)
Esempio n. 25
0
 def test_quantity_sub(self):
     if gpkit.units:
         x = Variable("x", 1, "cm")
         y = Variable("y", 1)
         self.assertEqual(x.sub({x: 1 * gpkit.units.m}).c.magnitude, 100)
         # NOTE: uncomment the below if requiring Quantity substitutions
         # self.assertRaises(ValueError, x.sub, x, 1)
         self.assertRaises(ValueError, x.sub, {x: 1 * gpkit.ureg.N})
         self.assertRaises(ValueError, y.sub, {y: 1 * gpkit.ureg.N})
         v = gpkit.VectorVariable(3, "v", "cm")
         subbed = v.sub({v: [1, 2, 3] * gpkit.ureg.m})
         self.assertEqual([z.c.magnitude for z in subbed], [100, 200, 300])
         v = VectorVariable(1, "v", "km")
         v_min = VectorVariable(1, "v_min", "km")
         m = Model(v.prod(), [v >= v_min],
                   {v_min: [2 * gpkit.units("nmi")]})
         cost = m.solve(verbosity=0)["cost"]
         self.assertAlmostEqual(cost / (3.704 * gpkit.ureg("km")), 1.0)
         m = Model(v.prod(), [v >= v_min],
                   {v_min: np.array([2]) * gpkit.units("nmi")})
         cost = m.solve(verbosity=0)["cost"]
         self.assertAlmostEqual(cost / (3.704 * gpkit.ureg("km")), 1.0)
Esempio n. 26
0
def test():
    m = Mission(SimPleAC(),4)
    m.substitutions.update({
        'h_{cruise_m}'   :5000*units('m'),
        'Range_m'        :3000*units('km'),
        'W_{p_m}'        :3000*units('N'),
        '\\rho_{p_m}'    :1500*units('kg/m^3'),
        'C_m'            :120*units('1/hr'),
        'V_{min_m}'      :35*units('m/s'),
        'T/O factor_m'   :2,
    })
    m.cost = m['W_{f_m}']*units('1/N') + m['C_m']*m['t_m']
    sol = m.localsolve(verbosity = 2)
Esempio n. 27
0
 def test_vector(self):
     v = VectorVariable(3, "v")
     kd = KeyDict()
     kd[v] = np.array([2, 3, 4])
     self.assertTrue(all(kd[v] == kd[v.key]))
     self.assertTrue(all(kd["v"] == np.array([2, 3, 4])))
     self.assertEqual(v[0].key.idx, (0,))
     self.assertEqual(kd[v][0], kd[v[0]])
     self.assertEqual(kd[v][0], 2)
     kd[v[0]] = 6
     self.assertEqual(kd[v][0], kd[v[0]])
     self.assertEqual(kd[v][0], 6)
     self.assertTrue(all(kd[v] == np.array([6, 3, 4])))
     v = VectorVariable(3, "v", "m")
     kd[v] = np.array([2, 3, 4])
     if gpkit.units:
         kd[v[0]] = gpkit.units("inch")
Esempio n. 28
0
 def test_vector(self):
     v = VectorVariable(3, "v")
     kd = KeyDict()
     kd[v] = np.array([2, 3, 4])
     self.assertTrue(all(kd[v] == kd[v.key]))
     self.assertTrue(all(kd["v"] == np.array([2, 3, 4])))
     self.assertEqual(v[0].key.idx, (0, ))
     self.assertEqual(kd[v][0], kd[v[0]])
     self.assertEqual(kd[v][0], 2)
     kd[v[0]] = 6
     self.assertEqual(kd[v][0], kd[v[0]])
     self.assertEqual(kd[v][0], 6)
     self.assertTrue(all(kd[v] == np.array([6, 3, 4])))
     v = VectorVariable(3, "v", "m")
     kd[v] = np.array([2, 3, 4])
     if gpkit.units:
         kd[v[0]] = gpkit.units("inch")
    def setup(self, alt, **kwargs):
        p_sl = Variable("p_{sl}", 101325, "Pa", "Pressure at sea level")
        T_sl = Variable("T_{sl}", 288.15, "K", "Temperature at sea level")
        L_atm = Variable("L_{atm}", .0065, "K/m", "Temperature lapse rate")
        M_atm = Variable("M_{atm}", .0289644, "kg/mol",
                         "Molar mass of dry air")
        p_atm = Variable("P_{atm}", "Pa", "air pressure")
        R_atm = Variable("R_{atm}", 8.31447, "J/mol/K",
                         "air specific heating value")
        TH = 5.257386998354459  #(g*M_atm/R_atm/L_atm).value
        rho = self.rho = Variable('\\rho', 'kg/m^3', 'Density of air')
        T_atm = self.T_atm = Variable("T_{atm}", "K", "air temperature")

        h = self.h = alt['h']
        """
        Dynamic viscosity (mu) as a function of temperature
        References:
        http://www-mdp.eng.cam.ac.uk/web/library/enginfo/aerothermal_dvd_only/aero/
            atmos/atmos.html
        http://www.cfd-online.com/Wiki/Sutherland's_law
        """
        mu = Variable('\\mu', 'kg/(m*s)', 'Dynamic viscosity')

        T_s = Variable('T_s', 110.4, "K", "Sutherland Temperature")
        C_1 = Variable('C_1', 1.458E-6, "kg/(m*s*K^0.5)",
                       'Sutherland coefficient')

        with SignomialsEnabled():
            constraints = [
                # Pressure-altitude relation
                (p_atm / p_sl)**(1 / 5.257) == T_atm / T_sl,

                # Ideal gas law
                rho == p_atm / (R_atm / M_atm * T_atm),

                #temperature equation
                SignomialEquality(T_sl, T_atm + L_atm * h),

                #constraint on mu
                mu == C_1 * T_atm**1.5 / (6.64 * units('K^.28') * T_s**0.72),
            ]

        #like to use a local subs here in the future
        subs = None

        return constraints
Esempio n. 30
0
    def setup(self, aircraft, state, **kwargs):
        #submodels
        self.aircraft = aircraft
        self.aircraftP = AircraftP(aircraft, state)
        self.wingP = self.aircraftP.wingP
        self.fuseP = self.aircraftP.fuseP
        self.engineP = self.aircraftP.engineP
                                  
        #variable definitions
        theta = Variable('\\theta', '-', 'Aircraft Climb Angle')
        excessP = Variable('P_{excess}', 'W', 'Excess Power During Climb')
        RC = Variable('RC', 'feet/min', 'Rate of Climb/Decent')
        dhft = Variable('dhft', 'feet', 'Change in Altitude Per Climb Segment [feet]')
        RngClimb = Variable('R_{climb}', 'nautical_miles', 'Down Range Distance Covered in Each Climb Segment')
        TotRngClimb = Variable('TotRngClimb', 'nautical_miles', 'Down Range Distance Covered in Climb')

        #constraints
        constraints = []
        
        constraints.extend([
           #constraint on drag and thrust
            self.aircraft['numeng']*self.engineP['thrust'] >= self.aircraftP['D'] + self.aircraftP['W_{avg}'] * theta,
            
            #climb rate constraints
            TCS([excessP + state['V'] * self.aircraftP['D'] <=  state['V'] * aircraft['numeng'] * self.engineP['thrust']]),
            
            RC == excessP/self.aircraftP['W_{avg}'],
            RC >= 500*units('ft/min'),
            
            #make the small angle approximation and compute theta
            theta * state['V']  == RC,
           
            dhft == self.aircraftP['tmin'] * RC,
        
            #makes a small angle assumption during climb
##            RngClimb == self.aircraftP['thr']*state['V'],
            ])

        with SignomialsEnabled():
            constraints.extend([
                #time
                TCS([self.aircraftP['thr'] * state['V'] >= RngClimb + (.5*theta**2)*self.aircraftP['thr'] * state['V']]),
                ])

        return constraints, self.aircraftP
Esempio n. 31
0
def SimPleAC_setup():
    a = SimPleAC()
    m = Mission(a, 4)
    subs = {
        'h_{cruise_m}': 5000 * units('m'),
        'Range_m': 3000 * units('km'),
        'W_{p_m}': 3000 * units('N'),
        '\\rho_{p_m}': 1500 * units('kg/m^3'),
        'C_m': 120 * units('1/hr'),
        'V_{min_m}': 35 * units('m/s'),
        'T/O factor_m': 2,
    }
    m.substitutions.update(subs)
    m.cost = m['W_{f_m}']  #+m['C_m']*m['t_m']*units('N')
    return m, subs
Esempio n. 32
0
    def setup(self):
        # Free Variables
        S         = Variable('S_{fuse}', 'm^2', 'fuselage surface area')
        l         = Variable('l_{fuse}', 'm', 'fuselage length')
        r         = Variable('r_{fuse}', 'm', 'fuselage minor radius')
        f         = Variable('f_{fuse}', '-', 'fuselage fineness ratio', fix = True)
        k         = Variable('k_{fuse}', '-', 'fuselage form factor')
        # Free variables (fixed for performance eval.)
        V         = Variable('V_{fuse}', 'm^3', 'total volume in the fuselage', fix = True)
        V_f_fuse  = Variable('V_{f_{fuse}}','m^3','fuel volume in the fuselage')
        W_fuse    = Variable('W_{fuse}', 'N', 'fuselage weight')
        p = 1.6075

        constraints = [f == l/r/2,
                       f <= 6,
                       k >= 1 + 60/f**3 + f/400,
                        3*(S/np.pi)**p >= 2*(l*2*r)**p + (2*r)**(2*p),
                        V == 4./6.*np.pi*r**2*l,
                        V_f_fuse >= 1*10**-10*units('m^3'),
                       ]

        return constraints
    def setup(self,aircraft,Nmissions,Nsegments):
        self.aircraft = aircraft
        self.missions = []
        for i in range(0,Nmissions):
            self.missions.append(Mission(self.aircraft,Nsegments))

        # Multimission objective variables
        W_f_mm = Variable('W_{f_{mm}}','N','multimission fuel weight')

        with Vectorize(Nmissions):
            # Mission variables
            hcruise    = Variable('h_{cruise_{mm}}', 'm', 'minimum cruise altitude')
            Range      = Variable("Range_{mm}", "km", "aircraft range")
            W_p        = Variable("W_{p_{mm}}", "N", "payload weight", pr=20.)
            V_min      = Variable("V_{min_{mm}}", 25, "m/s", "takeoff speed", pr=20.)
            cost_index = Variable("C_{mm}", '1/hr','hourly cost index')
            TOfac      = Variable('T/O factor_{mm}', 2.,'-','takeoff thrust factor')

        constraints = []

        # Setting up the missions
        for i in range(0,Nmissions):
            constraints += [
            self.missions[i]['h_{cruise_m}'] == hcruise[i],
            self.missions[i]['Range_m']      == Range[i],
            self.missions[i]['W_{p_m}']        == W_p[i],
            self.missions[i]['V_{min_m}']    == V_min[i],
            self.missions[i]['C_m']          == cost_index[i],
            self.missions[i]['T/O factor_m'] == TOfac[i],
            # Upper bounding relevant variables
            W_f_mm <= 1e11*units('N'),
            ]

        # Multimission constraints
        constraints += [W_f_mm >= sum(self.missions[i]['W_{f_m}'] for i in range(0,Nmissions))]



        return constraints, self.aircraft, self.missions
Esempio n. 34
0
    def setup(self, DF70=False):

        self.DF70 = DF70

        W = Variable("W", "lbf", "Installed/Total engine weight")
        mfac = Variable("m_{fac}", 1.0, "-", "Engine weight margin factor")
        bsfc_min = Variable("BSFC_{min}", 0.3162, "kg/kW/hr", "minimum BSFC")
        Pref = Variable("P_{ref}", 10.0, "hp", "Reference shaft power")
        Wengref = Variable("W_{eng-ref}", 10.0, "lbf",
                           "Reference engine weight")
        Weng = Variable("W_{eng}", "lbf", "engine weight")
        Pslmax = Variable("P_{sl-max}", "hp",
                          "Max shaft power at sea level")

        path = os.path.dirname(__file__)
        df = pd.read_csv(path + os.sep + "power_lawfit.csv").to_dict(
            orient="records")[0]

        constraints = [
            FitCS(df, Weng/Wengref, [Pslmax/Pref]),
            W/mfac >= 2.572*Weng**0.922*units("lbf")**0.078]

        return constraints
Esempio n. 35
0
    def test_mul(self):
        "Test monomial multiplication"
        x = Monomial({"x": 1, "y": -1}, 4)
        # test integer division
        self.assertEqual(x / 5, Monomial({"x": 1, "y": -1}, 0.8))
        # divide by scalar
        self.assertEqual(x * 9, Monomial({"x": 1, "y": -1}, 36))
        # divide by Monomial
        y = x * Variable("z")
        self.assertEqual(y, Monomial({"x": 1, "y": -1, "z": 1}, 4))
        # make sure x unchanged
        self.assertEqual(x, Monomial({"x": 1, "y": -1}, 4))
        # mixed new and old vars
        z = x * Monomial({"x": -1, "t": 2}, .5)
        self.assertEqual(z, Monomial({"x": 0, "y": -1, "t": 2}, 2))

        x0 = Variable("x0")
        self.assertEqual(0.0, 0.0 * x0)
        x1 = Variable("x1")
        n_hat = [1, 0]
        p = n_hat[0] * x0 + n_hat[1] * x1
        self.assertEqual(p, x0)

        self.assertNotEqual((x + 1), (x + 1) * gpkit.units("m"))
Esempio n. 36
0
    def setup(self):
        constraints = []

        # Steady level flight relations
        CD = Variable('C_D', '-', 'Drag coefficient')
        CL = Variable('C_L', '-', 'Lift coefficient')
        P_shaft = Variable('P_{shaft}', 'W', 'Shaft power')
        S = Variable('S', 'm^2', 'Wing reference area')
        V = Variable('V', 'm/s', 'Cruise velocity')
        W = Variable('W', 'lbf', 'Aircraft weight')

        eta_prop = Variable(r'\eta_{prop}', 0.7, '-', 'Propulsive efficiency')
        rho = Variable(r'\rho', 'kg/m^3')

        constraints.extend([P_shaft == V*W*CD/CL/eta_prop,   # eta*P = D*V
                            W == 0.5*rho*V**2*CL*S])

        # Aerodynamics model
        Cd0 = Variable('C_{d0}', 0.01, '-', "non-wing drag coefficient")
        CLmax = Variable('C_{L-max}', 1.5, '-', 'maximum lift coefficient')
        e = Variable('e', 0.9, '-', "spanwise efficiency")
        A = Variable('A', 20, '-', "aspect ratio")
        b = Variable('b', 'ft', 'span')
        mu = Variable(r'\mu', 1.5e-5, 'N*s/m^2', "dynamic viscosity")
        Re = Variable("Re", '-', "Reynolds number")
        Cf = Variable("C_f", "-", "wing skin friction coefficient")
        Kwing = Variable("K_{wing}", 1.3, "-", "wing form factor")
        cl_16 = Variable("cl_{16}", 0.0001, "-", "profile stall coefficient")
        constraints.extend([CD >= Cd0 + 2*Cf*Kwing + CL**2/(pi*e*A) + cl_16*CL**16,
                            b**2 == S*A,
                            CL <= CLmax,
                            Re == rho*V/mu*(S/A)**0.5,
                            Cf >= 0.074/Re**0.2])


        # Engine Weight Model
        W_eng = Variable('W_{eng}', 'lbf', 'Engine weight')
        W_engmin = Variable('W_{min}', 1.3, 'lbf', 'min engine weight')
        W_engmax = Variable('W_{max}', 275, 'lbf', 'max engine weight')
        eta_t = Variable('\\eta_t', 0.75, '-', 'percent throttle')
        eng_cnst = Variable('eng_{cnst}', 0.0011, '-',
                            'engine constant based off of power weight model')
        constraints.extend([W_eng >= W_engmin,
                            W_eng <= W_engmax,
                            W_eng >= P_shaft*eng_cnst/eta_t * units('lbf/watt')])

        # Weight model
        W_airframe = Variable('W_{airframe}', 'lbf', 'Airframe weight')
        W_pay = Variable(r'W_{pay}', 4, 'lbf', 'Payload weight')
        W_fuel = Variable('W_{fuel}', 'lbf', 'Fuel Weight')
        W_zfw = Variable('W_{zfw}', 'lbf', 'Zero fuel weight')
        wl = Variable('wl', 'lbf/ft^2', 'wing loading')

        f_airframe = Variable('f_{airframe}', 0.3, '-',
                              'Airframe weight fraction')
        g = Variable('g', 9.81, 'm/s^2', 'Gravitational acceleration')

        constraints.extend([W_airframe >= W*f_airframe,
                            W_zfw >= W_airframe + W_eng + W_pay,
                            wl == W/S,
                            W >= W_pay + W_eng + W_airframe + W_fuel])

        # Breguet Range
        z_bre = Variable("z_bre", "-", "breguet coefficient")
        h_fuel = Variable("h_{fuel}", 42e6, "J/kg", "heat of combustion")
        eta_0 = Variable("\\eta_0", 0.2, "-", "overall efficiency")
        t = Variable('t', 7, 'days', 'time on station')

        constraints.extend([z_bre >= g*t*V*CD/(h_fuel*eta_0*CL),
                            W_fuel/W_zfw >= te_exp_minus1(z_bre, 3)])

        # Atmosphere model
        h = Variable("h", "ft", "Altitude")
        p_sl = Variable("p_{sl}", 101325, "Pa", "Pressure at sea level")
        T_sl = Variable("T_{sl}", 288.15, "K", "Temperature at sea level")
        L_atm = Variable("L_{atm}", 0.0065, "K/m", "Temperature lapse rate")
        T_atm = Variable("T_{atm}", "K", "air temperature")
        M_atm = Variable("M_{atm}", 0.0289644, "kg/mol",
                         "Molar mass of dry air")
        R_atm = Variable("R_{atm}", 8.31447, "J/mol/K")
        TH = (g*M_atm/R_atm/L_atm).value.magnitude  # dimensionless
        constraints.extend([h <= 20000*units.m,  # Model valid to top of troposphere
                            T_sl >= T_atm + L_atm*h,     # Temp decreases w/ altitude
                            rho <= p_sl*T_atm**(TH-1)*M_atm/R_atm/(T_sl**TH)])
            # http://en.wikipedia.org/wiki/Density_of_air#Altitude

        # station keeping requirement
        footprint = Variable("d_{footprint}", 100, 'km',
                             "station keeping footprint diameter")
        lu = Variable(r"\theta_{look-up}", 5, '-', "look up angle")
        R_earth = Variable("R_{earth}", 6371, "km", "Radius of earth")
        tan_lu = lu*pi/180. + (lu*pi/180.)**3/3.  # Taylor series expansion
        # approximate earth curvature penalty as distance^2/(2*Re)
        constraints.extend([
            h >= tan_lu*0.5*footprint + footprint**2/8./R_earth])

        # wind speed model
        V_wind = Variable('V_{wind}', 'm/s', 'wind speed')
        wd_cnst = Variable('wd_{cnst}', [0.002, 0.0015], 'm/s/ft',
                           'wind speed constant predited by model')
        wd_ln = Variable('wd_{ln}', [13.009, 8.845], 'm/s',
                         'linear wind speed variable')
        h_min = Variable('h_{min}', 11800, 'ft', 'minimum height')
        h_max = Variable('h_{max}', 20800, 'ft', 'maximum height')
        constraints.extend([V_wind >= wd_cnst*h + wd_ln, # model predicting worse case scenario at 45 deg latitude
                            V >= V_wind,
                            h >= h_min,
                            h <= h_max])

        objective = W

        return objective, constraints
Esempio n. 37
0
"Debug examples"

from gpkit import Variable, Model, units

x = Variable("x", "ft")
x_min = Variable("x_min", 2, "ft")
x_max = Variable("x_max", 1, "ft")
y = Variable("y", "volts")

m = Model(x/y, [x <= x_max, x >= x_min])
m.debug()

print "# Now let's try a model unsolvable with relaxed constants\n"

Model(x, [x <= units("inch"), x >= units("yard")]).debug()

print "# And one that's only unbounded\n"

# the value of x_min was used up in the previous model!
x_min = Variable("x_min", 2, "ft")
Model(x/y, [x >= x_min]).debug()
Esempio n. 38
0
def SimPleAC():
    "Creates SimpleAC model"
    # Env. constants
    g = Variable("g", 9.81, "m/s^2", "gravitational acceleration")
    mu = Variable("\\mu", 1.775e-5, "kg/m/s", "viscosity of air")
    rho = Variable("\\rho", 1.23, "kg/m^3", "density of air")
    rho_f = Variable("\\rho_f", 817, "kg/m^3", "density of fuel")

    # Non-dimensional constants
    C_Lmax = Variable("C_{L,max}", 1.6, "-", "max CL with flaps down")
    e = Variable("e", 0.92, "-", "Oswald efficiency factor")
    k = Variable("k", 1.17, "-", "form factor")
    N_ult = Variable("N_{ult}", 3.3, "-", "ultimate load factor")
    S_wetratio = Variable("(\\frac{S}{S_{wet}})", 2.075, "-",
                          "wetted area ratio")
    tau = Variable("\\tau", 0.12, "-", "airfoil thickness to chord ratio")
    W_W_coeff1 = Variable("W_{W_{coeff1}}", 2e-5, "1/m",
                          "wing weight coefficent 1")  # 12e-5 originally
    W_W_coeff2 = Variable("W_{W_{coeff2}}", 60., "Pa",
                          "wing weight coefficent 2")

    # Dimensional constants
    Range = Variable("Range", 3000, "km", "aircraft range")
    TSFC = Variable("TSFC", 0.6, "1/hr", "thrust specific fuel consumption")
    V_min = Variable("V_{min}", 25, "m/s", "takeoff speed")
    W_0 = Variable("W_0", 6250, "N", "aircraft weight excluding wing")

    # Free Variables
    LoD = Variable("L/D", "-", "lift-to-drag ratio")
    D = Variable("D", "N", "total drag force")
    V = Variable("V", "m/s", "cruising speed")
    W = Variable("W", "N", "total aircraft weight")
    Re = Variable("Re", "-", "Reynold's number")
    CDA0 = Variable("(CDA0)", "m^2", "fuselage drag area")  # 0.035 originally
    C_D = Variable("C_D", "-", "drag coefficient")
    C_L = Variable("C_L", "-", "lift coefficient of wing")
    C_f = Variable("C_f", "-", "skin friction coefficient")
    W_f = Variable("W_f", "N", "fuel weight")
    V_f = Variable("V_f", "m^3", "fuel volume")
    V_f_avail = Variable("V_{f_{avail}}", "m^3", "fuel volume available")
    T_flight = Variable("T_{flight}", "hr", "flight time")

    # Free variables (fixed for performance eval.)
    A = Variable("A", "-", "aspect ratio")
    S = Variable("S", "m^2", "total wing area")
    W_w = Variable("W_w", "N", "wing weight")
    W_w_strc = Variable("W_w_strc", "N", "wing structural weight")
    W_w_surf = Variable("W_w_surf", "N", "wing skin weight")
    V_f_wing = Variable("V_f_wing", "m^3", "fuel volume in the wing")
    V_f_fuse = Variable("V_f_fuse", "m^3", "fuel volume in the fuselage")

    objective = W_f

    constraints = []

    # Weight and lift model
    constraints += [
        W >= W_0 + W_w + W_f,
        W_0 + W_w + 0.5 * W_f <= 0.5 * rho * S * C_L * V ** 2,
        W <= 0.5 * rho * S * C_Lmax * V_min ** 2,
        T_flight >= Range / V,
        LoD == C_L/C_D]

    # Thrust and drag model
    C_D_fuse = CDA0 / S
    C_D_wpar = k * C_f * S_wetratio
    C_D_ind = C_L ** 2 / (np.pi * A * e)
    constraints += [
        W_f >= TSFC * T_flight * D,
        D >= 0.5 * rho * S * C_D * V ** 2,
        C_D >= C_D_fuse + C_D_wpar + C_D_ind,
        V_f_fuse <= 10*units("m")*CDA0,
        Re <= (rho / mu) * V * (S / A) ** 0.5,
        C_f >= 0.074 / Re ** 0.2]

    # Fuel volume model
    with SignomialsEnabled():
        constraints += [
            V_f == W_f / g / rho_f,
            # linear with b and tau, quadratic with chord
            V_f_wing**2 <= 0.0009*S**3/A*tau**2,
            V_f_avail <= V_f_wing + V_f_fuse,  # [SP]
            Tight([V_f_avail >= V_f])]

    # Wing weight model
    constraints += [
        W_w_surf >= W_W_coeff2 * S,
        W_w_strc**2. >= W_W_coeff1**2/tau**2 * N_ult**2*A**3*(V_f_fuse*g*rho_f
                                                              + W_0)*W*S,
        W_w >= W_w_surf + W_w_strc]

    m = Model(objective, constraints)

    return m
Esempio n. 39
0
 def test_pint_366(self):
     # test for https://github.com/hgrecco/pint/issues/366
     if gpkit.units:
         self.assertIn(unitstr(gpkit.units("nautical_mile")),
                       ("nmi", "nautical_mile"))
         self.assertEqual(gpkit.units("nautical_mile"), gpkit.units("nmi"))