예제 #1
0
def kv_valve_dp(pObj, Kv=1.0, wdotPPS=0.5, TdegR=530.0, Ppsia=1000.0):
    """
    Calculate valve pressure drop for a valve with a known metric flow coefficient, Kv.
    
    Metric flow coefficient (Kv) is the amount of water (in m**3/hr) at 4 degC
    that will flow through a fully open valve with a difference of 1 bar between 
    the inlet and the outlet.
    
    :param pObj: propellant object
    :param Kv: valve flow coefficient
    :param wdotPPS: propellant mass flow rate in line, lbm/sec
    :param TdegR: propellant temperature of propellant, degR
    :param Ppsia: propellant inlet pressure to valve, psia
    :type pObj: Propellant
    :type Kv: float
    :type wdotPPS: float
    :type TdegR: float
    :type Ppsia: float
    :return: propellant pressure drop , psid
    :rtype: float    
    """
    # Note, could have converted Kv into Cv
    #Cv = 1.1560992283526375 * Kv
    #return cv_valve_dp( pObj, Cv=Cv, wdotPPS=wdotPPS, TdegR=TdegR, Ppsia=Ppsia)

    SG = pObj.SG_compressed(TdegR, Ppsia)
    rho = get_value(SG, 'SG', 'lbm/in**3')

    Qm3h = get_value(wdotPPS / rho, 'inch**3/s', 'm**3/hr')

    dPbar = SG * (Qm3h / Kv)**2
    deltaP = get_value(dPbar, 'bar', 'psid')
    #print('Qm3h=%g'%Qm3h, '  SG=%g'%SG, '  dPbar=%g'%dPbar, '   Kv=%g'%Kv, '  deltaP=%g'%deltaP)
    return deltaP
예제 #2
0
def cv_valve_dp(pObj, Cv=1.0, wdotPPS=0.5, TdegR=530.0, Ppsia=1000.0):
    """
    Calculate valve pressure drop for a valve with a known imperial flow coefficient, Cv.
    
    Imperial flow coefficient (Cv) is the amount of water (in gallons per minute) at 60 degF 
    that will flow through a fully open valve with a difference of 1 psi between 
    the inlet and the outlet.
    
    :param pObj: propellant object
    :param Cv: valve flow coefficient
    :param wdotPPS: propellant mass flow rate in line, lbm/sec
    :param TdegR: propellant temperature of propellant, degR
    :param Ppsia: propellant inlet pressure to valve, psia
    :type pObj: Propellant
    :type Cv: float
    :type wdotPPS: float
    :type TdegR: float
    :type Ppsia: float
    :return: propellant pressure drop , psid
    :rtype: float    
    """
    SG = pObj.SG_compressed(TdegR, Ppsia)
    rho = get_value(SG, 'SG', 'lbm/in**3')

    Qgpm = get_value(wdotPPS / rho, 'inch**3/s', 'gpm')

    deltaP = SG * (Qgpm / Cv)**2
    #print('Qgpm=%g'%Qgpm, '  SG=%g'%SG, '  deltaP=%g'%deltaP, '   Cv=%g'%Cv)
    return deltaP
예제 #3
0
    def Visc_compressed(self, TdegR, Ppsia):
        r'''Adjusts viscosity of a liquid for high pressure  using an empirical
        formula developed by Lucas.

        This code is modified from thermo package: https://thermo.readthedocs.io/en/latest/index.html
        also see: equation 9-9.1  in 5th Ed. of Gases and Liquids.

        :param TdegR: temperature in degR
        :param Ppsia: pressure in psia
        :type TdegR: float
        :type Ppsia: float
        :return: viscosity at (TdegR, Ppsia) in poise
        '''
        # need to use thermo internal units of degK, Pa
        T = get_value(TdegR, 'degR', 'degK')
        Tc = get_value(self.Tc, 'degR', 'degK')
        P = get_value(Ppsia, 'psia', 'Pa')
        Pc = get_value(self.Pc, 'psia', 'Pa')
        P_sat = get_value(self.PvapAtTdegR(TdegR), 'psia', 'Pa')

        Tr = T / Tc
        mu_sat = self.ViscAtTr(Tr)
        if P <= P_sat:
            return mu_sat

        C = -0.07921+2.1616*Tr - 13.4040*Tr**2 + 44.1706*Tr**3 - 84.8291*Tr**4 \
            + 96.1209*Tr**5-59.8127*Tr**6+15.6719*Tr**7
        D = 0.3257 / ((1.0039 - Tr**2.573)**0.2906) - 0.2086
        A = 0.9991 - 4.674E-4 / (1.0523 * Tr**-0.03877 - 1.0513)
        dPr = (P - P_sat) / Pc
        if dPr < 0:
            dPr = 0
        return (1. + D *
                (dPr / 2.118)**A) / (1. + C * self.omega * dPr) * mu_sat
예제 #4
0
    def SG_compressedCZ1(self, TdegR, Ppsia):
        r'''Calculates compressed-liquid specific gravity, using the Chang Zhao method.

        This code is derived from equation 4-12.3 in 5th Ed. of Gases and Liquids.

        :param TdegR: temperature in degR
        :param Ppsia: pressure in psia
        :type TdegR: float
        :type Ppsia: float
        :return: specific gravity at (TdegR, Ppsia) in g/ml
        '''
        a0 = -170.335
        a1 = -28.578
        a2 = 124.809
        a3 = -55.5393
        a4 = 130.01
        b0 = 0.164813
        b1 = -0.0914427
        C = exp(1)
        D = 1.00588

        # convert to internal units from thermo
        T = get_value(TdegR, 'degR', 'degK')
        Tc = get_value(self.Tc, 'degR', 'degK')
        P = get_value(Ppsia, 'psia', 'bar')
        Pc = get_value(self.Pc, 'psia', 'bar')
        Psat = get_value(self.PvapAtTdegR(TdegR), 'psia', 'bar')

        SGsat = self.SGLiqAtTdegR(TdegR)
        if P < Psat:
            print(
                'Warning in SG_compressed... Pressure below Psat for T=%g degR, P=%g psia'
                % (TdegR, Ppsia))
            return SGsat

        Vs = self.MolWt / SGsat  # [cm^3/mol]

        Tr = T / Tc
        if Tr > 0.94:
            print(
                'Warning in SG_compressed... Reduced Temperature > 0.95 Tr=%g '
                % Tr)

        A = a0 + a1 * Tr + a2 * Tr**3 + a3 * Tr**6 + a4 / Tr
        B = b0 + self.omega * b1

        numer = A * Pc + C**((D - Tr)**B) * (P - Psat)
        denom = A * Pc + C * (P - Psat)

        try:
            V_dense = Vs * numer / denom  # [cm^3/mol]

            # convert to SG
            SG_dense = self.MolWt / V_dense  # g/cm^3
        except:
            print('WARNING... SG_compressed has error at T=%g R, P=%g psia' %
                  (TdegR, Ppsia))
            return None
        return SG_dense
예제 #5
0
    def SG_compressedCOSTALD(self, TdegR, Ppsia):
        r'''Calculates compressed-liquid specific gravity, using the COSTALD  CSP method.

        This code is modified from thermo package: https://thermo.readthedocs.io/en/latest/index.html

        :param TdegR: temperature in degR
        :param Ppsia: pressure in psia
        :type TdegR: float
        :type Ppsia: float
        :return: specific gravity at (TdegR, Ppsia) in g/ml
        '''
        a = -9.070217
        b = 62.45326
        d = -135.1102
        f = 4.79594
        g = 0.250047
        h = 1.14188
        j = 0.0861488
        k = 0.0344483

        # convert to internal units from thermo
        T = get_value(TdegR, 'degR', 'degK')
        Tc = get_value(self.Tc, 'degR', 'degK')
        P = get_value(Ppsia, 'psia', 'Pa')
        Pc = get_value(self.Pc, 'psia', 'Pa')
        Psat = get_value(self.PvapAtTdegR(TdegR), 'psia', 'Pa')

        SGsat = self.SGLiqAtTdegR(TdegR)
        if P < Psat:
            print(
                'Warning... Pressure below saturation pressure for T=%g degR, P=%g psia'
                % (TdegR, Ppsia))
            return SGsat

        Vs = self.MolWt / SGsat  # [cm^3/mol]

        tau = 1 - T / Tc
        e = exp(f + g * self.omega + h * self.omega**2)
        C = j + k * self.omega
        B = Pc * (-1 + a * tau**(1 / 3.) + b * tau**(2 / 3.) + d * tau +
                  e * tau**(4 / 3.))

        try:
            V_dense = Vs * (1 - C * log((B + P) / (B + Psat)))  # [cm^3/mol]

            # convert to SG
            SG_dense = self.MolWt / V_dense  # g/cm^3
        except:
            print('WARNING... SG_compressed has error at T=%g R, P=%g psia' %
                  (TdegR, Ppsia))
            return None
        return SG_dense
예제 #6
0
def calc_tank_volume( pObj, kg_expelled=50.0,
                      TmaxC=50.0, expPcent=98.0, ullPcent=3.0):
    """
    Calculate the volume of a propellant tank given operating requirements.
    
    :param pObj: propellant object
    :param kg_expelled: mass of expelled propellant in kg
    :param TmaxC: max operating/storage/transport temperature in deg C
    :param expPcent: expulsion efficiency in percent
    :param ullPcent: percent of total tank volume that is ullage at TmaxC
    :type pObj: Propellant
    :type kg_expelled: float
    :type TmaxC: float
    :type expPcent: float
    :type ullPcent: float
    :return: (volume of tank (ml), loaded propellant mass (kg), residual propellant mass (kg))
    :rtype: (float, float, float)
    """

    # put temperature units into degR
    Thot  = get_value( TmaxC, 'degC', 'degR' )
    
    SGhot = pObj.SGLiqAtTdegR( Thot )
    cc_expelled = kg_expelled * 1000.0 / SGhot

    # residual and ullage fractions apply to entire tank volume, not just propellant volume
    expulsionEff = expPcent / 100.0 
    residualFraction = 1.0 - expulsionEff
    ullageFraction = ullPcent / 100.0

    cc_Total = cc_expelled / (1.0 - residualFraction - ullageFraction)
    kg_loaded = cc_Total * (1.0 - ullageFraction) * SGhot / 1000.0
    kg_residual = kg_loaded - kg_expelled

    return cc_Total, kg_loaded, kg_residual
예제 #7
0
def calib_valve_dp(pObj,
                   wdotPPS=0.5,
                   TdegR=530.0,
                   Ppsia=1000.0,
                   refWaterWdot=0.214,
                   refWaterDP=30.0):
    """
    Calculate valve pressure drop for a valve that has been calibrated
    with a water flow test.

    :param pObj: propellant object
    :param wdotPPS: propellant mass flow rate in line, lbm/sec
    :param TdegR: propellant temperature of propellant, degR
    :param Ppsia: propellant inlet pressure to valve, psia
    :param refWaterWdot: reference water flow rate, lbm/sec
    :param refWaterDP: reference water pressure drop, psid
    :type pObj: Propellant
    :type wdotPPS: float
    :type TdegR: float
    :type Ppsia: float
    :type refWaterWdot: float
    :type refWaterDP: float
    :return: propellant pressure drop , psid
    :rtype: float
    """

    SG = pObj.SG_compressed(TdegR, Ppsia)
    Dens = get_value(SG, 'SG', 'lbm/ft**3')

    Kw = sqrt(refWaterWdot**2 / refWaterDP)

    # calculate pressure drop
    deltaP = wdotPPS**2 * 62.4 / Dens / Kw**2

    return deltaP
예제 #8
0
def calc_inj_velocity(pObj, dPpsia=50.0, TdegR=530.0, Ppsia=1000.0):
    """
    Calculate the injection velocity of a propellant.

    :param pObj: propellant object
    :param dPpsia: pressure drop across orifice, psid
    :param TdegR: temperature of propellant, degR
    :param Ppsia: inlet pressure to orifice, psia
    :type pObj: Propellant
    :type dPpsia: float
    :type TdegR: float
    :type Ppsia: float
    :return: injection velocity, ft/sec
    :rtype: float
    """

    Pave = Ppsia - dPpsia / 2.0
    SGave = pObj.SG_compressed(TdegR, Pave)

    rho = get_value(SGave, 'SG', 'lbm/in**3')

    in_per_sec = sqrt(24.0 * 32.174 * dPpsia / rho)  # in/sec
    ft_per_sec = in_per_sec / 12.0

    return ft_per_sec
예제 #9
0
def calc_orifice_flow_rate(pObj,
                           CdOrf=0.75,
                           DiamInches=0.01,
                           dPpsia=50.0,
                           TdegR=530.0,
                           Ppsia=1000.0):
    """        
    Calculate mass flow rate through a single injector orifice.

    :param pObj: propellant object
    :param CdOrf: discharge coefficient of orifice
    :param DiamInches: diameter of orifice, inch
    :param dPpsia: pressure drop across orifice, psid
    :param TdegR: temperature of propellant, degR
    :param Ppsia: inlet pressure to orifice, psia
    :type pObj: Propellant
    :type CdOrf: float
    :type DiamInches: float
    :type dPpsia: float
    :type TdegR: float
    :type Ppsia: float
    :return: mass flow rate of single orifice, lbm/sec
    :rtype: float
    """

    Pave = Ppsia - dPpsia / 2.0
    SGave = pObj.SG_compressed(TdegR, Pave)

    rho = get_value(SGave, 'SG', 'lbm/in**3')

    in_per_sec = sqrt(24.0 * 32.174 * dPpsia / rho)  # in/sec

    wdotOrif = in_per_sec * rho * CdOrf * DiamInches**2 * pi / 4.0

    return wdotOrif  # lbm/sec
예제 #10
0
def calc_line_id_dp( pObj, TdegR=530.0, Ppsia=1000.0,
                     wdotPPS=0.5, velFPS=13.0, 
                     roughness=5.0E-6,  Kfactors=2.0, len_inches=50.0):
    """
    Calculate the inner diameter and pressure drop in propellant line.

    :param pObj: propellant object
    :param TdegR: temperature of propellant, degR
    :param Ppsia: inlet pressure to orifice, psia
    :param wdotPPS: mass flow rate in line, lbm/sec
    :param velFPS: velocity of liquid in line, ft/sec
    :param roughness: line roughness, inches
    :param Kfactors: number of velocity heads lost due to bends, valves, etc.
    :param len_inches: length of line, inches
    :type pObj: Propellant
    :type TdegR: float
    :type Ppsia: float
    :type wdotPPS: float
    :type velFPS: float
    :type roughness: float
    :type Kfactors: float
    :type len_inches: float
    :return: tuple of inside diameter and pressure drop (dinsid, deltaP), (inch, psid)
    :rtype: (float, float)
    """

    SG = pObj.SG_compressed( TdegR, Ppsia )
    rho = get_value( SG, 'SG', 'lbm/in**3' )
    Dens = get_value( SG, 'SG', 'lbm/ft**3' )
    
    Q = wdotPPS / rho
    Ac = Q / (velFPS * 12.0)
    
    rinsid = sqrt( Ac / pi )
    dinsid = rinsid * 2.0

    # calculate pressure drop
    visc = pObj.Visc_compressed(TdegR, Ppsia)
    mu = get_value( visc, 'poise', 'lbm/s/ft')
    ReNum= 144.0 * rho * velFPS * dinsid / mu
    
    ff = colebrook_ffact(roughness, dinsid, ReNum)

    deltaP = (ff * len_inches/dinsid + Kfactors) * wdotPPS**2 / (dinsid**4 * 0.27622 * Dens)

    return dinsid, deltaP
예제 #11
0
def calc_line_vel_dp( pObj, TdegR=530.0, Ppsia=1000.0,
                     wdotPPS=0.5, IDinches=0.335, 
                     roughness=5.0E-6,  Kfactors=2.0, len_inches=50.0):
    """
    Calculate the line velocity and pressure drop in propellant line.

    :param pObj: propellant object
    :param TdegR: temperature of propellant, degR
    :param Ppsia: inlet pressure to orifice, psia
    :param wdotPPS: mass flow rate in line, lbm/sec
    :param IDinches: inside diameter of line, in
    :param roughness: line roughness, inches
    :param Kfactors: number of velocity heads lost due to bends, valves, etc.
    :param len_inches: length of line, inches
    :type pObj: Propellant
    :type TdegR: float
    :type Ppsia: float
    :type wdotPPS: float
    :type velFPS: float
    :type roughness: float
    :type Kfactors: float
    :type len_inches: float
    :return: tuple of velocity and pressure drop (velFPS, deltaP), (ft/s, psid)
    :rtype: (float, float)
    """

    SG = pObj.SG_compressed( TdegR, Ppsia )
    rho = get_value( SG, 'SG', 'lbm/in**3' )
    Dens = get_value( SG, 'SG', 'lbm/ft**3' )
    
    Q = wdotPPS / rho            # in**3/s
    Ac = pi * IDinches**2 / 4.0  # in**2
    velFPS = Q / (Ac * 12.0)     # ft/sec

    # calculate pressure drop
    visc = pObj.Visc_compressed(TdegR, Ppsia)   # poise
    mu = get_value( visc, 'poise', 'lbm/s/ft')  # lbm/s-ft
    ReNum= 144.0 * rho * velFPS * IDinches / mu
    
    ff = colebrook_ffact(roughness, IDinches, ReNum)

    deltaP = (ff * len_inches/IDinches + Kfactors) * wdotPPS**2 / (IDinches**4 * 0.27622 * Dens)

    return velFPS, deltaP
예제 #12
0

if __name__ == "__main__":
    from rocketprops.rocket_prop import get_prop

    print("""
    ...Calculate the propellant injection velocity...""")
    pObj = get_prop('N2O4')
    TdegR = 530.0
    Ppsia = 1000.0
    dPpsia = 50.0
    ft_per_sec = calc_inj_velocity(pObj,
                                   dPpsia=dPpsia,
                                   TdegR=TdegR,
                                   Ppsia=Ppsia)
    print('ft_per_sec =', ft_per_sec, '=', get_value(ft_per_sec, 'ft/s',
                                                     'm/s'), 'm/s')

    # check calc in metric
    Pave = Ppsia - dPpsia / 2.0
    SGave = pObj.SG_compressed(TdegR, Pave)
    gh_m = get_value(dPpsia, 'psia', 'N/m**2') / get_value(
        SGave, 'SG', 'kg/m**3')
    m_per_sec = sqrt(2 * gh_m)
    print('     gh_m=%g' % gh_m, '   m_per_sec =', m_per_sec, 'm/s')

    print("""
    ...Calculate the propellant orifice mass flow rate...""")

    wdot = calc_orifice_flow_rate(pObj,
                                  CdOrf=0.75,
                                  DiamInches=0.01,
예제 #13
0
        log10x = log10(1 + dp / (2.8615834935979536e-06 + psat)
                       )  # Fit Standard Deviation = 0.037367390648883274
        dsg_o_sgL.append(2.340023173056651 * log10x +
                         -3.4531382789431726 * log10x**2 +
                         1.6738282493779768 * log10x**3)

        sgratio_terp = InterpProp(trL, dsg_o_sgL, extrapOK=True)

        SGratio = sgratio_terp(Tr)
        SGsat = self.SGLiqAtTr(Tr)
        SG = SGsat / (1.0 - SGratio)

        return SG


if __name__ == '__main__':
    from rocketprops.unit_conv_data import get_value
    C = Prop()
    print('T = %g R = %g K' % (C.T, C.T / 1.8))
    print('SurfaceTension = %g lbf/in' % C.surf, ' = ',
          get_value(C.surf, 'lbf/in', 'mN/m'), 'mN/m')

    print()
    print(' Tr_data_range =', C.Tr_data_range())
    print('  T_data_range=', C.T_data_range())
    print('  P_data_range=', C.P_data_range())

    print('omega =%s' % C.omega)

    C.plot_sat_props()
예제 #14
0
 def __init__(self, coreObj, # CoreStream object
     Tox=None, Tfuel=None, elemEm=0.8,
     fdPinjOx=0.25, fdPinjFuel=0.25, dpOxInp=None, dpFuelInp=None,
     setNelementsBy='acoustics', # can be "acoustics", "elem_density", "input"
     elemDensInp=5, NelementsInp=100,
     OxOrfPerEl=1.0, FuelOrfPerEl=1.0, 
     lolFuelElem=False, 
     setAcousticFreqBy='mode', # can be "mode" or "freq"
     desAcousMode='3T', desFreqInp=5000, 
     CdOxOrf=0.75, CdFuelOrf=0.75, dropCorrOx=0.33, dropCorrFuel=0.33,
     DorfMin=0.008,
     LfanOvDorfOx=20.0, LfanOvDorfFuel=20.0):
     """
     Injector object holds basic information about the injector.
     Injector design features are calculated
     including chamber losses due to the injector, Em, Mix and Vap.
     """
     self.coreObj        = coreObj
     self.geomObj        = coreObj.geomObj
     
     # build propellant  objects
     self.oxProp   = get_prop( self.coreObj.oxName )
     self.fuelProp = get_prop( self.coreObj.fuelName )
     
     self.TminOx,   self.TmaxOx   = self.oxProp.T_data_range()
     self.TminFuel, self.TmaxFuel = self.fuelProp.T_data_range()
     
     self.Tox_warning = ''
     self.Tfuel_warning = ''
     
     if Tox is None: 
         Tox = min(530.0, self.oxProp.Tnbp)
     else:
         Tox, self.Tox_warning = temperature_clamp(Tox, 'Tox', self.TminOx,   self.TmaxOx)
     self.Tox            = Tox
     
     if Tfuel is None: 
         Tfuel = min(530.0, self.fuelProp.Tnbp)
     else:
         Tfuel,self.Tfuel_warning = temperature_clamp(Tfuel, 'Tfuel', self.TminFuel,   self.TmaxFuel)
     self.Tfuel          = Tfuel
     
     self.elemEm         = min(1.0, elemEm) # intra-element mixing parameter for injector
     self.fdPinjOx       = fdPinjOx
     self.fdPinjFuel     = fdPinjFuel
     self.dpOxInp        = dpOxInp
     self.dpFuelInp      = dpFuelInp
     self.setNelementsBy = setNelementsBy.lower() # just in case user screw up.
     self.used_Nelem_criteria = self.setNelementsBy # assume for now that intention is satisfied
     
     self.elemDensInp    = elemDensInp
     self.NelementsInp   = NelementsInp
     self.OxOrfPerEl     = OxOrfPerEl
     self.FuelOrfPerEl   = FuelOrfPerEl
     
     self.lolFuelElem    = lolFuelElem
     if lolFuelElem:
         self.strouhal_mult = 0.1 # LOL element uses 0.1 strouhal multiplier
     else:
         self.strouhal_mult = 0.2 # unlike element uses 0.2 strouhal multiplier
     
     self.desAcousMode   = desAcousMode
     if desAcousMode in modeSvnD:
         self.desAcousMult = modeSvnD[ desAcousMode ]
     else:
         self.desAcousMult = float( desAcousMode ) # let it raise exception if not a float
     self.desFreqInp     = desFreqInp
     
     self.setAcousticFreqBy = setAcousticFreqBy.lower() # can be "mode" or "freq"
     
     self.CdOxOrf        = CdOxOrf
     self.CdFuelOrf      = CdFuelOrf
     self.dropCorrOx     = dropCorrOx
     self.dropCorrFuel   = dropCorrFuel
     self.DorfMin        = DorfMin
     self.LfanOvDorfOx   = LfanOvDorfOx
     self.LfanOvDorfFuel = LfanOvDorfFuel
     
     # get oxidizer propellant properties
     self.sgOx = self.oxProp.SG_compressed( Tox, self.coreObj.Pc )  # g/ml
     self.dHvapOx = self.oxProp.HvapAtTdegR( Tox )     # BTU/lbm
     self.surfOx = self.oxProp.SurfAtTdegR( Tox )      # lbf/in
     
     self.viscOx = self.oxProp.ViscAtTdegR( Tox )      # poise
     self.viscOx = get_value( self.viscOx, 'poise', 'lbm/s/ft')
     
     self.MolWtOx = self.oxProp.MolWt
     #print('sgOx=',self.sgOx)
     
     # get fuel propellant properties
     self.sgFuel = self.fuelProp.SG_compressed( Tfuel, self.coreObj.Pc )  # g/ml
     self.dHvapFuel = self.fuelProp.HvapAtTdegR( Tfuel )     # BTU/lbm
     self.surfFuel = self.fuelProp.SurfAtTdegR( Tfuel )      # lbf/in
     self.viscFuel = self.fuelProp.ViscAtTdegR( Tfuel )      # poise
     self.viscFuel = get_value( self.viscFuel, 'poise', 'lbm/s/ft')
     
     self.MolWtFuel = self.fuelProp.MolWt
     #print('sgFuel=',self.sgFuel)
     
     # --------- start vaporization calcs --------
     self.rhoOx = rho = get_value( self.sgOx, 'SG', 'lbm/in**3' )
     self.rhoFuel = rho = get_value( self.sgFuel, 'SG', 'lbm/in**3' )
     
     self.calc_element_attr() # e.g. Nelements, injection velocities, elements diam, etc.
     #self.evaluate()
     
     # get input descriptions and units from doc string
     self.inp_descD, self.inp_unitsD, self.is_inputD = get_desc_and_units( self.__doc__ )
예제 #15
0
    def get_model_summ_obj(self):
        """
        return ModelSummary object for current state of Injector instance.
        """
        
        M = ModelSummary( '%s/%s Injector'%(self.coreObj.oxName, self.coreObj.fuelName) )
        M.add_alt_units('psia', ['MPa','atm','bar'])
        M.add_alt_units('psid', ['MPa','atm','bar'])
        M.add_alt_units('lbf',   'N')
        M.add_alt_units('lbm/s', 'kg/s')
        M.add_alt_units('ft/s',  'm/s')
        M.add_alt_units('sec',   ['N-sec/kg', 'km/sec'])
        M.add_alt_units('degR',  ['degK','degC','degF'])
        #M.add_alt_units('Hz',    'kHz')
        M.add_alt_units('elem/in**2', 'elem/cm**2')
        M.add_alt_units('in',    ['mil','mm'])
        M.add_alt_units('mil',    ['micron','mm'])
        
        M.add_alt_units( 'g/ml', ['lbm/inch**3', 'lbm/ft**3'] )
        M.add_alt_units( 'lbf/in', ['N/m', 'mN/m', 'dyne/cm'] )
        M.add_alt_units('poise', ['cpoise', 'Pa*s', 'lbm/hr/ft'])
        M.add_alt_units( 'BTU/lbm', ['cal/g',  'J/g'] )
        M.add_alt_units('in**2', 'cm**2')
        
        category_setD = {} # index=category name, value=set of parameter names in category
        category_setD['Ox Properties'] = set()
        category_setD['Fuel Properties'] = set()
        M.add_inp_category( '' ) # show unlabeled category 1st
        M.add_out_category( '' ) # show unlabeled category 1st
        
        for name in self.is_inputD.keys():
            if name.lower().find('ox') >= 0:
                category_setD['Ox Properties'].add( name )
            if name.lower().find('fuel') >= 0:
                category_setD['Fuel Properties'].add( name )
        
        # dpOx dpFuel
        def get_cat( name ):
            for cn, nameset in category_setD.items():
                if name in nameset:
                    return cn
            return ''
        
        specialFmtD = {'DorfFuel':'%.4f', 'DorfOx':'%.4f', 'DorfMin':'%.4f'}
        # function to add parameters from __doc__ string to ModelSummary
        def add_param( name, desc='', fmt='', units='', value=None):
            
            if name in self.inp_unitsD:
                units = self.inp_unitsD[name]
                
            if desc=='' and name in self.inp_descD:
                desc = self.inp_descD[name]
            
            if value is None:
                try:
                    value = getattr( self, name )
                except:
                    return
            
            if fmt=='':
                fmt = specialFmtD.get( name, '' )
            
            if self.is_inputD.get(name, False):
                M.add_inp_param( name, value, units, desc, fmt=fmt, category=get_cat(name))
            else:
                M.add_out_param( name, value, units, desc, fmt=fmt, category=get_cat(name))
        
        # build a list of __doc__ parameters that should be ignored by ModelSummary
        ignoreL = ['coreObj', 'geomObj', 'effObj']
        
        # ignore some Nelemens inputs if they do not apply
        if self.setNelementsBy == "acoustics":
            
            ignoreL.extend( ['elemDensInp', 'NelementsInp'] )
            if self.setAcousticFreqBy == "mode":
                ignoreL.append( 'desFreqInp' )
            else:
                ignoreL.append( 'desAcousMode' )
        else:
            ignoreL.extend( ['desAcousMode', 'desFreqInp', 'DorfFlForHzLim'] )
        
        # ignore delta P inputs if they do not apply
        if self.dpFuelInp is None:
            ignoreL.append( 'dpFuelInp' )
        else:
            ignoreL.append( 'fdPinjFuel' )

        if self.dpOxInp is None:
            ignoreL.append( 'dpOxInp' )
        else:
            ignoreL.append( 'fdPinjOx' )
        
        # iterate through __doc__ parameters and add them to ModelSummary
        for name in self.is_inputD.keys():
            if name not in ignoreL:
                add_param( name )
        
        # some conditional output NOT in :ivar xxx: section
        #if self.calc_effVap:
        if hasattr(self, 'rDropOx'):
            # only print internal vaporization values if calc'd
            #M.add_out_param( name, value, units, desc, fmt=fmt, category=get_cat(name))
            M.add_out_param('rDropOx', get_value(self.rDropOx,'inch','mil'), 'mil', 'median ox droplet radius', 
            fmt='%.4f', category='Vaporization') 
            M.add_out_param('rDropFuel', get_value(self.rDropFuel,'inch','mil'), 'mil', 'median fuel droplet radius', 
            fmt='%.4f', category='Vaporization') 
            
            M.add_out_param('chamShapeFact', self.ShapeFact, '', 'chamber shape factor', 
            fmt='%.4f', category='Vaporization') 
            
            M.add_out_param('genVapLenOx', self.genVapLenOx, '', 'Priem generalized vaporization length of oxidizer', 
            fmt='%.2f', category='Vaporization')
            M.add_out_param('genVapLenFuel', self.genVapLenFuel, '', 'Priem generalized vaporization length of fuel', 
            fmt='%.2f', category='Vaporization')
            M.add_out_param('fracVapOx', self.fracVapOx, '', 'fraction of vaporized oxidizer', 
            fmt='%.4f', category='Vaporization')
            M.add_out_param('fracVapFuel', self.fracVapFuel, '', 'fraction of vaporized fuel', 
            fmt='%.4f', category='Vaporization')
            
            M.add_out_param('mrVap', self.mrVap,'', 'vaporized mixture ratio', fmt='%.4f', category='Vaporization')
        
        # some stability parameters
        #M.add_out_param( name, value, units, desc, fmt=fmt, category=get_cat(name))
        M.add_out_param('tauOx',         self.tauOx*1000.0   , 'ms','oxidizer lag time (tau/tResid=%g)'%self.tauOvResOx, category='Combustion Stability')
        M.add_out_param('tauFuel',       self.tauFuel*1000.0 , 'ms','fuel lag time (tau/tResid=%g)'%self.tauOvResFuel, category='Combustion Stability')
        M.add_out_param('tResid',        self.tResid*1000.0  , 'ms','residual time in chamber', 
        fmt='%.4f', category='Combustion Stability')
        
        M.add_out_param('fdPinjOxReqd',  self.fdPinjOxReqd,    '', 'minimum required oxidizer dP/Pc', category='Combustion Stability')
        M.add_out_param('fdPinjFuelReqd', self.fdPinjFuelReqd, '', 'minimum required fuel dP/Pc', category='Combustion Stability')
        
        M.add_out_param(' cham sonicVel', self.sonicVel, 'ft/s', 'approximate gas sonic velocity in chamber', category='Combustion Stability') 
        
        # show the acoustic modes in chamber
        # calc 3T and 1L for printout only
        f3T = modeSvnD['3T'] * self.sonicVel / pi / (self.geomObj.Dinj/12.0)
        freq1L = self.sonicVel * 12.0 / 2.0 / self.geomObj.Lcham
        
        modeL = [(freq1L,'1L')] # list of (freq, name)
        modeL.append( ( 0.8 * modeSvnD['1T'] * self.sonicVel / pi / (self.geomObj.Dinj/12.0), '80% of 1T') )
        modeL.append( ( 0.8 * modeSvnD['1R'] * self.sonicVel / pi / (self.geomObj.Dinj/12.0), '80% of 1R') )
        modeL.append( ( 0.8 * modeSvnD['3T'] * self.sonicVel / pi / (self.geomObj.Dinj/12.0), '80% of 3T') )
        modeL.append( ( 0.999999 * modeSvnD['3T'] * self.sonicVel / pi / (self.geomObj.Dinj/12.0), ' 3T') )
        
        modeL.append( (self.des_freq, '=====> DESIGN') )
        
        for name, mult in modeSvnD.items():
            modeL.append( (mult * self.sonicVel / pi / (self.geomObj.Dinj/12.0), name) )
        modeL.sort()
        
        M.add_out_category('Acoustic Modes', allowsort=False)
        for (freq, name) in modeL:
            comment = modeCommentD.get( name, '')
            M.add_out_param(name, '%i'%int(freq), 'Hz', comment, category='Acoustic Modes')
            #M.add_out_param( name, value, units, desc, fmt=fmt, category=get_cat(name))
        
        
        
        # -------------------- WARNING AND ASSUMPTION ADDITIONS --------------------------
        # maybe add some warnings and assumptions
            
        mode, mode_freq, mode_msg = self.get_closest_mode()
        
        if self.coreObj.add_barrier:
            M.add_assumption( 'NOTE: Injector elements are designed by Initial Core Flow ONLY.' )
            M.add_assumption( '      Fuel Film Cooling orifices must be designed separately.' )
        
        M.add_assumption( 'NOTE: number of elements set by '+ self.setNelementsBy )

        # parameters that are NOT attributes OR are conditional
        if self.setNelementsBy == "acoustics":
            if self.setAcousticFreqBy == "mode":
                if self.desAcousMode in modeSvnD:
                    msg = self.desAcousMode #+ ' where: Svn mult = %g'%self.desAcousMult
                else:
                    msg = 'Svn multiplier = %g'%self.desAcousMult
            elif self.setAcousticFreqBy == "freq":
                msg = 'freq=%g Hz'%self.desFreqInp
            
            M.add_assumption('      Acoustic frequency set by %s'%msg)
            mil = get_value(self.DorfFlForHzLimit,'inch','mil')
            
            if self.DorfFuel < self.DorfFlForHzLimit * 0.999:
                M.add_warning( 'WARNING... Fuel Orifice Diameter is Less Than D/V Requirement of %.1f mil'%mil )
            else:
                M.add_assumption( 'Fuel Orifice Diameter Meets Stability Requirement of >= %.1f mil'%mil )
            
            
        elif  self.setNelementsBy == "input":
            M.add_assumption('      Number of elements = %g'%self.NelementsInp)
        elif  self.setNelementsBy == "elem_density":
            M.add_assumption('      Element Density = %g elem/in**2'%self.elemDensInp)
        
        
        if self.used_Nelem_criteria != self.setNelementsBy:
            M.add_warning( 'WARNING... Number of elements set by: ' + self.used_Nelem_criteria )
            M.add_warning( '                 original intent was: ' + self.setNelementsBy )
                
        
        M.add_assumption( 'Chamber design frequency set by: ' + self.used_Nelem_criteria +\
                          ' to: %g Hz,'%round(self.des_freq) + mode_msg )
            
        if self.des_freq >  f3T * 1.01:
            M.add_warning( 'WARNING... Design frequency is above recommended 3T limit of %i Hz'%int(f3T) )
            
        if self.DorfOx <  self.DorfMin * 0.999:
            mil = get_value(self.DorfMin,'inch','mil')
            M.add_warning( 'WARNING... Oxidizer Orifice Diameter is Less Than minimum limit of %.1f mil'%mil )
            
        if self.DorfFuel <  self.DorfMin * 0.999:
            mil = get_value(self.DorfMin,'inch','mil')
            M.add_warning( 'WARNING... Fuel Orifice Diameter is Less Than minimum limit of %.1f mil'%mil )

        if self.Tox_warning:
            M.add_warning(  self.Tox_warning )
        if self.Tfuel_warning:
            M.add_warning(  self.Tfuel_warning )

        if self.dpOx/self.coreObj.Pc < self.fdPinjOxReqd:
            M.add_warning('WARNING... Oxidizer pressure drop is below stability requirement')
            M.add_warning('           Oxidizer dP/Pc=%g, should be >= %g'%(self.dpOx/self.coreObj.Pc, self.fdPinjOxReqd) )

        if self.dpFuel/self.coreObj.Pc < self.fdPinjFuelReqd:
            M.add_warning('WARNING... Fuel pressure drop is below stability requirement')
            M.add_warning('           Fuel dP/Pc=%g, should be >= %g'%(self.dpFuel/self.coreObj.Pc, self.fdPinjFuelReqd) )
            


        #if self.dpOxInp is None:
        #    M.add_assumption('dPinjector oxidizer set by fdPinjOx = %g'%self.fdPinjOx)
        #else:
        #    M.add_assumption('dPinjector oxidizer set by  dpOxInp = %.1f psia'%self.dpOxInp)
        
        #if self.dpFuelInp is None:
        #    M.add_assumption('dPinjector fuel set by fdPinjFuel = %g'%self.fdPinjFuel)
        #else:
        #    M.add_assumption('dPinjector fuel set by dpFuelInp = %.1f psia'%self.dpFuelInp)
        
        return M
예제 #16
0
        try:
            self.log10visc_terp = InterpProp(self.trL, self.log10viscL, extrapOK=False)
        except:
            pass
        try:
            self.cond_terp = InterpProp(self.trL, self.condL, extrapOK=False)
        except:
            pass
        self.cp_terp = InterpProp(self.trL, self.cpL, extrapOK=False)
        self.hvap_terp = InterpProp(self.trL, self.hvapL, extrapOK=False)
        self.surf_terp = InterpProp(self.trL, self.surfL, extrapOK=False)
        self.SG_liq_terp = InterpProp(self.trL, self.SG_liqL, extrapOK=False)
        self.log10SG_vap_terp = InterpProp(self.trL, self.log10SG_vapL, extrapOK=False)

if __name__ == '__main__':
    from rocketprops.unit_conv_data import get_value
    C = Prop()
    print('T = %g R = %g K'%( C.T, C.T/1.8 ))
    print('SurfaceTension = %g lbf/in'%C.surf, ' = ', get_value(C.surf, 'lbf/in', 'mN/m'), 'mN/m' )
    
    print()
    print(' Tr_data_range =', C.Tr_data_range())
    print('  T_data_range=',C.T_data_range())
    print('  P_data_range=', C.P_data_range())
    
    print( 'omega =%s'%C.omega )
    
    C.plot_sat_props()

    
예제 #17
0
if __name__ == "__main__":
    from rocketprops.rocket_prop import get_prop
    """
    Calculate the required volume of a Hydrazine (N2H4) tank.
    Assume:
        required usable propellant is 50 kg
        vehicle max operating/storage/transport temperature is 50 deg C.
        minimum ullage volume is 3%.
        expulsion efficiency = 98%.
    """
    pObj = get_prop('hydrazine')
    
    cc_Total, kg_loaded, kg_residual = calc_tank_volume( pObj, kg_expelled=50.0,
                                                         TmaxC=50.0, expPcent=98.0, ullPcent=3.0 )

    print('cc_Total    = %g cc'%cc_Total)
    print('loaded   propellant mass = %g kg'%kg_loaded )
    print('residual propellant mass = %g kg'%kg_residual )
    print('loaded / expelled mass =', kg_loaded / 50.0)

    Thot  = get_value( 50.0, 'degC', 'degR' )
    SGhot = pObj.SGLiqAtTdegR( Thot )
    
    print('kg residual = SGhot * 0.02 * cc_Total / 1000 =', SGhot * 0.02 * cc_Total / 1000, 'kg'  )

    cc_expelled = 50.0 * 1000.0 / SGhot
    print('cc_expelled =',cc_expelled, '  mass expelled = %g g'%(SGhot*cc_expelled,) )
    print('cc_expelled / cc_Total =', cc_expelled / cc_Total)
    
예제 #18
0
    sg_ecL = []
    errL = []
    terrL = []
    
    Tcutoff = p.TdegRAtPsat(P)
    
    for T in range( int(Tmin), int(Tmax), 1 ):
        if T < Tcutoff:
            
            #sg_rp = p.SG_compressedCOSTALD( T, P)
            #sg_rp = p.SG_compressed( T, P)
            #sg_rp = p.SG_compressedCZ2( T, P )
            sg_rp = p.SG_compressedNasrfar(T, P)
            
            ec.setTP( T=T, P=P )
            sg_ec = get_value( ec.rho, 'lbm/in**3', 'SG' )
            
            if sg_rp is not None and sg_ec is not None:
                sg_rpL.append( sg_rp )
                sg_ecL.append( sg_ec )
                tL.append( T / p.Tc )
                terrL.append( T / p.Tc )
                errL.append( 100.0*(sg_rp - sg_ec)/ sg_ec  )
        
    plt.plot( tL, sg_rpL, '-', label='RocketProps P=%g'%P, color=COLORL[i%len(COLORL)])
    plt.plot( tL, sg_ecL, '--', label='CoolProp P=%g'%P, color=COLORL[i%len(COLORL)])
    i += 1
    errLL.append( (terrL, errL, P) )

plt.legend()
plt.grid()
예제 #19
0
    def SG_compressedNasrfar(self, TdegR, Ppsia):
        r'''Calculates compressed-liquid specific gravity, using the Nasrfar Moshfeghian method
        from Journal of Molecular Liquids 160 (2011) 94-102

        :param TdegR: temperature in degR
        :param Ppsia: pressure in psia
        :type TdegR: float
        :type Ppsia: float
        :return: specific gravity at (TdegR, Ppsia) in g/ml
        '''

        Pr = Ppsia / self.Pc
        Tr = TdegR / self.Tc
        Psat = self.PvapAtTdegR(TdegR)
        Psatr = Psat / self.Pc
        SGsat = self.SGLiqAtTdegR(TdegR)
        if Ppsia < Psat:
            print(
                'Warning in SG_compressed... Pressure below Psat for T=%g degR, P=%g psia'
                % (TdegR, Ppsia))
            return SGsat

        Vs = self.MolWt / SGsat  # [cm^3/mol]

        j0 = 1.3168E-3
        j1 = 3.4448E-2
        j2 = 5.4131E-2
        L = 9.6840E-2
        M = 8.6761E-6
        f0 = 48.8756
        G = 0.7185
        I = 3.4031E-5
        c0 = 5.5526
        c1 = -2.7659
        Om0 = 7.9019E-2
        Om1 = -2.8431E-2
        R = 8.3144598  # m^3-Pa / mol-K

        J = j0 + j1 * (1 - Tr)**(1. / 3.) + j2 * (1 - Tr)**(2. / 3.)
        F = f0 * (1 - Tr)
        C = c0 + c1 * self.omega
        TcK = get_value(self.Tc, 'degR', 'degK')
        PcMPa = get_value(self.Pc, 'psia', 'MPa')

        Om = Om0 + Om1 * self.omega
        Vinf = Om * R * TcK / PcMPa  # cm^3/mol

        if Tr > 0.94:
            print(
                'Warning in SG_compressed... Reduced Temperature > 0.95 Tr=%g '
                % Tr)

        dpr = max(0, Pr - Psatr)
        numer = J + L * dpr + M * dpr**3
        denom = F + G * dpr + I * dpr**3

        vrat = C * numer / denom
        V_dense = vrat * (Vinf - Vs) + Vs  # [cm^3/mol]

        SG_dense = self.MolWt / (V_dense)  # g/cm^3

        return SG_dense
예제 #20
0
    sg_p1L  = []
    sg_p2L  = []
    sg_p3L  = []
    sg_p4L  = []
    
    Psat_ec, DliqSat, DgasSat = ec.getSatPandDens( Tr * ec.Tc )
    Psat = p.PvapAtTr( Tr )

    dpL = [dp for dp in range(0,6000, 100)]
    for dp in dpL:
        T = Tr * p.Tc
        P = Psat + dp + 1
        P_ec = Psat_ec + dp + 1
        ec.setTP( T=Tr*ec.Tc, P=P_ec )
        
        sg_ecL.append( get_value( ec.rho, 'lbm/in**3', 'SG' ) )
        
        sg_p1L.append( p.SG_compressedCOSTALD( T, P) )
        sg_p2L.append( p.SG_compressedCZ1( T, P) )
        sg_p3L.append( p.SG_compressedCZ2( T, P ) )
        sg_p4L.append( p.SG_compressedNasrfar(T, P) )

    fig = plt.figure()
    plt.title( p.pname + ' SG Compressed Comparison at Tr=%g'%Tr )

    plt.plot( dpL, sg_ecL, '--', label='CoolProp', linewidth=5)
    plt.plot( dpL, sg_p1L, '--', label='COSTALD-Default', linewidth=3)
    plt.plot( dpL, sg_p2L, '-', label='CZ1')
    plt.plot( dpL, sg_p3L, '-', label='CZ2')
    plt.plot( dpL, sg_p4L, '-', label='Nasrfar')
예제 #21
0
__copyright__ = 'Copyright (c) 2020 Charlie Taylor'
__license__ = 'GPL-3'
exec(open(os.path.join(
    here, '_version.py')).read())  # creates local __version__ variable
__email__ = "*****@*****.**"
__status__ = "4 - Beta"  # "3 - Alpha", "4 - Beta", "5 - Production/Stable"

#
# import statements here. (built-in first, then 3rd party, then yours)
#
from math import exp, log
import importlib
from rocketprops.unit_conv_data import get_value
from rocketprops.prop_names import prop_names

TREF_K = get_value(20.0, 'degC', 'degK')


def get_prop(name, suppress_warning=False):
    """
    Return a Propellant object for the named propellant.

    :param name: name of propellant (for example "N2O4" or "LOX")
    :param suppress_warning: if True, then do not print warnings.
    :type name: string
    :type suppress_warning: boolean
    :return: Propellant object for named propellant
    :rtype: Propellant
    """
    pname = prop_names.get_primary_name(name)
    if pname is None: