Exemple #1
0
class CEA():
    def __init__(self, fuel, oxidiser, chamber_pressure):
        """[summary]
		Calcualtes hot gas properties using CEA and converts to SI units. If errors occur with FORTRAN, resart and try again!
		:param chamber_pressure in [Pa]
		:type fuel = string
		:type oxidiser = string
		"""
        self.chamber_pressure = chamber_pressure
        self.imperial_pressure = 0.000145038 * self.chamber_pressure  #conversion to psia
        self.ispObj = CEA_Obj(oxName=oxidiser, fuelName=fuel)
        self.ispObj.get_full_cea_output()

    def chamber_gas_properties(self, mixture_ratio, expansion_ratio):
        self.Cp, self.visc, self.cond, self.Pr = self.ispObj.get_Chamber_Transport(
            Pc=self.imperial_pressure, MR=mixture_ratio, frozen=1)
        self.MW, self.gamma = self.ispObj.get_Chamber_MolWt_gamma(
            Pc=self.imperial_pressure, MR=mixture_ratio, eps=expansion_ratio)

    def throat_gas_properties(self, mixture_ratio, expansion_ratio):
        self.Cp, self.visc, self.cond, self.Pr = self.ispObj.get_Throat_Transport(
            Pc=self.imperial_pressure, MR=mixture_ratio, frozen=1)
        self.MW, self.gamma = self.ispObj.get_Throat_MolWt_gamma(
            Pc=self.imperial_pressure, MR=mixture_ratio, eps=expansion_ratio)

    def exit_gas_properties(self, mixture_ratio, expansion_ratio):
        self.Cp, self.visc, self.cond, self.Pr = self.ispObj.get_Exit_Transport(
            Pc=self.imperial_pressure, MR=mixture_ratio, frozen=1)
        self.MW, self.gamma = self.ispObj.get_exit_MolWt_gamma(
            Pc=self.imperial_pressure, MR=mixture_ratio, eps=expansion_ratio)

    def metric_cea_output(self, location, mixture_ratio, expansion_ratio):
        if location == 'chamber':
            self.chamber_gas_properties(mixture_ratio, expansion_ratio)
        elif location == 'throat':
            self.throat_gas_properties(mixture_ratio, expansion_ratio)
        elif location == 'exit':
            self.exit_gas_properties(mixture_ratio, expansion_ratio)
        else:
            raise ValueError(
                'Invalid location, use "chamber," "throat" or "exit"')

        self.isp, self.cstar, _ = self.ispObj.getFrozen_IvacCstrTc(
            Pc=self.imperial_pressure, MR=mixture_ratio, eps=expansion_ratio)

        self.cstar = self.cstar * 0.3048  # coversion to m/s
        self.mole_fractions = self.ispObj.get_SpeciesMoleFractions(
            Pc=self.imperial_pressure,
            MR=mixture_ratio,
            eps=expansion_ratio,
            frozen=0,
            frozenAtThroat=0,
            min_fraction=5e-05)
        self.Cp = self.Cp * 4186.8  # coversion to J/gk/K
        self.mu = self.visc * 0.0001  # coversion to Pa*s
        self.k = self.cond * 418.4e-3  # coversion to W/m/K
        self.T_static = self.ispObj.get_Tcomb(
            Pc=self.imperial_pressure,
            MR=mixture_ratio) * 0.555556  # coversion to K
Exemple #2
0
                                                            eps=40.0)
cpFch, visFch, conFch, prFch = ispObj.get_Chamber_Transport(Pc=1000.0,
                                                            MR=6.0,
                                                            eps=40.0,
                                                            frozen=1)

cpEth, visEth, conEth, prEth = ispObj.get_Throat_Transport(Pc=1000.0,
                                                           MR=6.0,
                                                           eps=40.0)
cpFth, visFth, conFth, prFth = ispObj.get_Throat_Transport(Pc=1000.0,
                                                           MR=6.0,
                                                           eps=40.0,
                                                           frozen=1)

cpEex, visEex, conEex, prEex = ispObj.get_Exit_Transport(Pc=1000.0,
                                                         MR=6.0,
                                                         eps=40.0)
cpFex, visFex, conFex, prFex = ispObj.get_Exit_Transport(Pc=1000.0,
                                                         MR=6.0,
                                                         eps=40.0,
                                                         frozen=1)

sOut = """           Calling Transport Functions.
VISC,MILLIPOISE   %6.4f   %6.4f  %6.4f
 VISC,MILLIPOISE   %6.4f   %6.4f  %6.4f
 
  WITH EQUILIBRIUM REACTIONS

 Cp, CAL/(G)(K)    %6.4f   %6.4f   %6.4f
 CONDUCTIVITY      %6.4f   %6.4f   %6.4f
 PRANDTL NUMBER    %6.4f   %6.4f   %6.4f
class CEA_Obj(object):
    """
    RocketCEA wraps the NASA FORTRAN CEA code to calculate Isp, cstar, and Tcomb
    
    This object wraps the English unit version of CEA_Obj to enable desired user units.    
    """
    def __init__(self,
                 propName='',
                 oxName='',
                 fuelName='',
                 useFastLookup=0,
                 makeOutput=0,
                 isp_units='sec',
                 cstar_units='ft/sec',
                 pressure_units='psia',
                 temperature_units='degR',
                 sonic_velocity_units='ft/sec',
                 enthalpy_units='BTU/lbm',
                 density_units='lbm/cuft',
                 specific_heat_units='BTU/lbm degR',
                 viscosity_units='millipoise',
                 thermal_cond_units='mcal/cm-K-s',
                 fac_CR=None,
                 make_debug_prints=False):
        """::
        
        #: RocketCEA wraps the NASA FORTRAN CEA code to calculate Isp, cstar, and Tcomb
        #: This object wraps the English unit version of CEA_Obj to enable desired user units.
        #: Same as CEA_Obj with standard units except, input and output units can be specified.
        #:  parameter             default             options
        #: isp_units            = 'sec',         # N-s/kg, m/s, km/s
        #: cstar_units          = 'ft/sec',      # m/s
        #: pressure_units       = 'psia',        # MPa, KPa, Pa, Bar, Atm, Torr
        #: temperature_units    = 'degR',        # K, C, F
        #: sonic_velocity_units = 'ft/sec',      # m/s
        #: enthalpy_units       = 'BTU/lbm',     # J/g, kJ/kg, J/kg, kcal/kg, cal/g
        #: density_units        = 'lbm/cuft',    # g/cc, sg, kg/m^3
        #: specific_heat_units  = 'BTU/lbm degR' # kJ/kg-K, cal/g-C, J/kg-K (# note: cal/g K == BTU/lbm degR)
        #: viscosity_units      = 'millipoise'   # lbf-sec/sqin, lbf-sec/sqft, lbm/ft-sec, poise, centipoise
        #: thermal_cond_units   = 'mcal/cm-K-s'  # millical/cm-degK-sec, BTU/hr-ft-degF, BTU/s-in-degF, cal/s-cm-degC, W/cm-degC
        #: fac_CR, Contraction Ratio of finite area combustor (None=infinite)
        #: if make_debug_prints is True, print debugging info to terminal.
        """

        self.isp_units = isp_units
        self.cstar_units = cstar_units
        self.pressure_units = pressure_units
        self.temperature_units = temperature_units
        self.sonic_velocity_units = sonic_velocity_units
        self.enthalpy_units = enthalpy_units
        self.density_units = density_units
        self.specific_heat_units = specific_heat_units
        self.viscosity_units = viscosity_units
        self.thermal_cond_units = thermal_cond_units
        self.fac_CR = fac_CR

        # Units objects for input/output (e.g. Pc and Pamb)
        self.Pc_U = get_units_obj('psia', pressure_units)

        # units of output quantities
        self.isp_U = get_units_obj('sec', isp_units)
        self.cstar_U = get_units_obj('ft/sec', cstar_units)
        self.temperature_U = get_units_obj('degR', temperature_units)
        self.sonic_velocity_U = get_units_obj('ft/sec', sonic_velocity_units)
        self.enthalpy_U = get_units_obj('BTU/lbm', enthalpy_units)
        self.density_U = get_units_obj('lbm/cuft', density_units)
        self.specific_heat_U = get_units_obj('BTU/lbm degR',
                                             specific_heat_units)
        self.viscosity_U = get_units_obj('millipoise', viscosity_units)
        self.thermal_cond_U = get_units_obj('mcal/cm-K-s', thermal_cond_units)

        self.cea_obj = CEA_Obj_default(propName=propName,
                                       oxName=oxName,
                                       fuelName=fuelName,
                                       useFastLookup=useFastLookup,
                                       makeOutput=makeOutput,
                                       fac_CR=fac_CR,
                                       make_debug_prints=make_debug_prints)
        self.desc = self.cea_obj.desc

    def get_IvacCstrTc(self, Pc=100.0, MR=1.0, eps=40.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        IspVac, Cstar, Tcomb = self.cea_obj.get_IvacCstrTc(Pc=Pc,
                                                           MR=MR,
                                                           eps=eps)

        IspVac = self.isp_U.dval_to_uval(IspVac)
        Cstar = self.cstar_U.dval_to_uval(Cstar)
        Tcomb = self.temperature_U.dval_to_uval(Tcomb)

        return IspVac, Cstar, Tcomb

    def getFrozen_IvacCstrTc(self,
                             Pc=100.0,
                             MR=1.0,
                             eps=40.0,
                             frozenAtThroat=0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        IspFrozen, Cstar, Tcomb = self.cea_obj.getFrozen_IvacCstrTc(
            Pc=Pc, MR=MR, eps=eps, frozenAtThroat=frozenAtThroat)
        IspFrozen = self.isp_U.dval_to_uval(IspFrozen)
        Cstar = self.cstar_U.dval_to_uval(Cstar)
        Tcomb = self.temperature_U.dval_to_uval(Tcomb)

        return IspFrozen, Cstar, Tcomb

    def get_IvacCstrTc_exitMwGam(self, Pc=100.0, MR=1.0, eps=40.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        IspVac, Cstar, Tcomb, mw, gam = self.cea_obj.get_IvacCstrTc_exitMwGam(
            Pc=Pc, MR=MR, eps=eps)

        IspVac = self.isp_U.dval_to_uval(IspVac)
        Cstar = self.cstar_U.dval_to_uval(Cstar)
        Tcomb = self.temperature_U.dval_to_uval(Tcomb)

        return IspVac, Cstar, Tcomb, mw, gam

    def get_IvacCstrTc_ChmMwGam(self, Pc=100.0, MR=1.0, eps=40.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        IspVac, Cstar, Tcomb, mw, gam = self.cea_obj.get_IvacCstrTc_ChmMwGam(
            Pc=Pc, MR=MR, eps=eps)

        IspVac = self.isp_U.dval_to_uval(IspVac)
        Cstar = self.cstar_U.dval_to_uval(Cstar)
        Tcomb = self.temperature_U.dval_to_uval(Tcomb)

        return IspVac, Cstar, Tcomb, mw, gam

    def get_IvacCstrTc_ThtMwGam(self, Pc=100.0, MR=1.0, eps=40.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        IspVac, Cstar, Tcomb, mw, gam = self.cea_obj.get_IvacCstrTc_ThtMwGam(
            Pc=Pc, MR=MR, eps=eps)

        IspVac = self.isp_U.dval_to_uval(IspVac)
        Cstar = self.cstar_U.dval_to_uval(Cstar)
        Tcomb = self.temperature_U.dval_to_uval(Tcomb)

        return IspVac, Cstar, Tcomb, mw, gam

    def __call__(self, Pc=100.0, MR=1.0, eps=40.0):
        return self.get_Isp(Pc=Pc, MR=MR, eps=eps)

    def get_Isp(self, Pc=100.0, MR=1.0, eps=40.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        IspVac = self.cea_obj.get_Isp(Pc=Pc, MR=MR, eps=eps)
        IspVac = self.isp_U.dval_to_uval(IspVac)

        return IspVac

    def get_Cstar(self, Pc=100.0, MR=1.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        Cstar = self.cea_obj.get_Cstar(Pc=Pc, MR=MR)
        Cstar = self.cstar_U.dval_to_uval(Cstar)
        return Cstar

    def get_Tcomb(self, Pc=100.0, MR=1.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        Tcomb = self.cea_obj.get_Tcomb(Pc=Pc, MR=MR)
        Tcomb = self.temperature_U.dval_to_uval(Tcomb)
        return Tcomb

    def get_PcOvPe(self, Pc=100.0, MR=1.0, eps=40.0):
        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        return self.cea_obj.get_PcOvPe(Pc=Pc, MR=MR, eps=eps)

    def get_eps_at_PcOvPe(self, Pc=100.0, MR=1.0, PcOvPe=1000.0):
        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        return self.cea_obj.get_eps_at_PcOvPe(Pc=Pc, MR=MR, PcOvPe=PcOvPe)

    def get_Throat_PcOvPe(self, Pc=100.0, MR=1.0):
        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        return self.cea_obj.get_Throat_PcOvPe(Pc=Pc, MR=MR)

    def get_MachNumber(self, Pc=100.0, MR=1.0, eps=40.0):
        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        return self.cea_obj.get_MachNumber(Pc=Pc, MR=MR, eps=eps)

    def get_Temperatures(self,
                         Pc=100.0,
                         MR=1.0,
                         eps=40.0,
                         frozen=0,
                         frozenAtThroat=0):
        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        tempList = self.cea_obj.get_Temperatures(Pc=Pc,
                                                 MR=MR,
                                                 eps=eps,
                                                 frozen=frozen,
                                                 frozenAtThroat=frozenAtThroat)

        for i, T in enumerate(tempList):
            tempList[i] = self.temperature_U.dval_to_uval(T)
        return tempList  # Tc, Tthroat, Texit

    def get_SonicVelocities(self, Pc=100.0, MR=1.0, eps=40.0):
        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        sonicList = self.cea_obj.get_SonicVelocities(Pc=Pc, MR=MR, eps=eps)

        for i, S in enumerate(sonicList):
            sonicList[i] = self.sonic_velocity_U.dval_to_uval(S)
        return sonicList  # Chamber, Throat, Exit

    def get_Chamber_SonicVel(self, Pc=100.0, MR=1.0, eps=40.0):
        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        sonicVel = self.cea_obj.get_Chamber_SonicVel(Pc=Pc, MR=MR, eps=eps)

        sonicVel = self.sonic_velocity_U.dval_to_uval(sonicVel)
        return sonicVel

    def get_Enthalpies(self, Pc=100.0, MR=1.0, eps=40.0):
        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia

        hList = self.cea_obj.get_Enthalpies(Pc=Pc, MR=MR, eps=eps)
        for i, H in enumerate(hList):
            hList[i] = self.enthalpy_U.dval_to_uval(H)

        return hList

    def get_SpeciesMassFractions(self,
                                 Pc=100.0,
                                 MR=1.0,
                                 eps=40.0,
                                 frozen=0,
                                 frozenAtThroat=0,
                                 min_fraction=0.000005):
        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia

        molWtD, massFracD = self.cea_obj.get_SpeciesMassFractions(
            Pc=Pc,
            MR=MR,
            eps=eps,
            frozenAtThroat=frozenAtThroat,
            min_fraction=min_fraction)
        return molWtD, massFracD

    def get_SpeciesMoleFractions(self,
                                 Pc=100.0,
                                 MR=1.0,
                                 eps=40.0,
                                 frozen=0,
                                 frozenAtThroat=0,
                                 min_fraction=0.000005):
        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia

        molWtD, moleFracD = self.cea_obj.get_SpeciesMoleFractions(
            Pc=Pc,
            MR=MR,
            eps=eps,
            frozenAtThroat=frozenAtThroat,
            min_fraction=min_fraction)
        return molWtD, moleFracD

    def get_Chamber_H(self, Pc=100.0, MR=1.0, eps=40.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        H = self.cea_obj.get_Chamber_H(Pc=Pc, MR=MR, eps=eps)
        return self.enthalpy_U.dval_to_uval(H)

    def get_Densities(self, Pc=100.0, MR=1.0, eps=40.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        dList = self.cea_obj.get_Densities(Pc=Pc, MR=MR, eps=eps)

        for i, d in enumerate(dList):
            dList[i] = self.density_U.dval_to_uval(d)

        return dList

    def get_Chamber_Density(self, Pc=100.0, MR=1.0, eps=40.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        H = self.cea_obj.get_Chamber_Density(Pc=Pc, MR=MR, eps=eps)
        return self.density_U.dval_to_uval(H)

    def get_HeatCapacities(self, Pc=100.0, MR=1.0, eps=40.0, frozen=0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        cpList = self.cea_obj.get_HeatCapacities(Pc=Pc,
                                                 MR=MR,
                                                 eps=eps,
                                                 frozen=frozen)

        for i, cp in enumerate(cpList):
            cpList[i] = self.specific_heat_U.dval_to_uval(cp)

        return cpList

    def get_Chamber_Cp(self, Pc=100.0, MR=1.0, eps=40.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        Cp = self.cea_obj.get_Chamber_Cp(Pc=Pc, MR=MR, eps=eps)
        return self.specific_heat_U.dval_to_uval(Cp)

    def get_Throat_Isp(self, Pc=100.0, MR=1.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        Isp = self.cea_obj.get_Throat_Isp(Pc=Pc, MR=MR)
        Isp = self.isp_U.dval_to_uval(Isp)

        return Isp

    def get_Chamber_MolWt_gamma(self, Pc=100.0, MR=1.0, eps=40.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        return self.cea_obj.get_Chamber_MolWt_gamma(Pc=Pc, MR=MR, eps=eps)

    def get_Throat_MolWt_gamma(self, Pc=100.0, MR=1.0, eps=40.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        return self.cea_obj.get_Throat_MolWt_gamma(Pc=Pc, MR=MR, eps=eps)

    def get_exit_MolWt_gamma(self, Pc=100.0, MR=1.0, eps=40.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        return self.cea_obj.get_exit_MolWt_gamma(Pc=Pc, MR=MR, eps=eps)

    def get_eqratio(self, Pc=100.0, MR=1.0, eps=40.0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        return self.cea_obj.get_eqratio(Pc=Pc, MR=MR, eps=eps)

    def getMRforER(self, ERphi=None, ERr=None):
        return self.cea_obj.getMRforER(ERphi=ERphi, ERr=ERr)

    def get_description(self):
        return self.cea_obj.get_description()

    def estimate_Ambient_Isp(self,
                             Pc=100.0,
                             MR=1.0,
                             eps=40.0,
                             Pamb=14.7,
                             frozen=0,
                             frozenAtThroat=0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        Pamb = self.Pc_U.uval_to_dval(Pamb)  # convert user units to psia
        IspAmb, mode = self.cea_obj.estimate_Ambient_Isp(
            Pc=Pc,
            MR=MR,
            eps=eps,
            Pamb=Pamb,
            frozen=frozen,
            frozenAtThroat=frozenAtThroat)

        IspAmb = self.isp_U.dval_to_uval(IspAmb)

        return IspAmb, mode

    def get_PambCf(self, Pamb=14.7, Pc=100.0, MR=1.0, eps=40.0):
        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        Pamb = self.Pc_U.uval_to_dval(Pamb)  # convert user units to psia

        CFcea, CF, mode = self.cea_obj.get_PambCf(Pamb=Pamb,
                                                  Pc=Pc,
                                                  MR=MR,
                                                  eps=eps)

        return CFcea, CF, mode

    def getFrozen_PambCf(self,
                         Pamb=0.0,
                         Pc=100.0,
                         MR=1.0,
                         eps=40.0,
                         frozenAtThroat=0):
        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        Pamb = self.Pc_U.uval_to_dval(Pamb)  # convert user units to psia

        CFcea, CFfrozen, mode = self.cea_obj.getFrozen_PambCf(
            Pamb=Pamb, Pc=Pc, MR=MR, eps=eps, frozenAtThroat=frozenAtThroat)

        return CFcea, CFfrozen, mode

    def get_Chamber_Transport(self, Pc=100.0, MR=1.0, eps=40.0, frozen=0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        Cp, visc, cond, Prandtl = self.cea_obj.get_Chamber_Transport(
            Pc=Pc, MR=MR, eps=eps, frozen=frozen)

        #Cp = Cp * 8314.51 / 4184.0  # convert into BTU/lbm degR
        Cp = self.specific_heat_U.dval_to_uval(Cp)
        visc = self.viscosity_U.dval_to_uval(visc)
        cond = self.thermal_cond_U.dval_to_uval(cond)

        return Cp, visc, cond, Prandtl

    def get_Throat_Transport(self, Pc=100.0, MR=1.0, eps=40.0, frozen=0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        Cp, visc, cond, Prandtl = self.cea_obj.get_Throat_Transport(
            Pc=Pc, MR=MR, eps=eps, frozen=frozen)

        #Cp = Cp * 8314.51 / 4184.0  # convert into BTU/lbm degR
        Cp = self.specific_heat_U.dval_to_uval(Cp)
        visc = self.viscosity_U.dval_to_uval(visc)
        cond = self.thermal_cond_U.dval_to_uval(cond)

        return Cp, visc, cond, Prandtl

    def get_Exit_Transport(self, Pc=100.0, MR=1.0, eps=40.0, frozen=0):

        Pc = self.Pc_U.uval_to_dval(Pc)  # convert user units to psia
        Cp, visc, cond, Prandtl = self.cea_obj.get_Exit_Transport(
            Pc=Pc, MR=MR, eps=eps, frozen=frozen)

        Cp = Cp * 8314.51 / 4184.0  # convert into BTU/lbm degR
        Cp = self.specific_heat_U.dval_to_uval(Cp)
        visc = self.viscosity_U.dval_to_uval(visc)
        cond = self.thermal_cond_U.dval_to_uval(cond)

        return Cp, visc, cond, Prandtl
Exemple #4
0
class CEA:
    def __init__(self, oxName, fuelName):
        self.oxName = oxName
        self.fuelName = fuelName
        # dictionary containing the standard heat of formation for all species in [kJ/mol]
        # you can find this data in thermo.inp in the rocketCEA library folder
        self.heatDict = {
            "ABS": 62.719,
            "Acrylic": 382.0,
            "N2O": 82.05,
            "LO2": 0,
            "*CO": -110.53,
            "*CO2": -393.5,
            "*H": 217.998,
            "HCO": 42.397,
            "HO2": 12.02,
            "*H2": 0,
            "C(gr)": 0,
            "H2O": -241.826,
            "*N": 472.680,
            "*NO": 91.271,
            "*N2": 0,
            "*O": 249.175,
            "*OH": 37.278,
            "*O2": 0,
            "COOH": -213,
            "H2O2": -135.88,
            "O3": 141.8,
            "CH3": 146.658,
            "CH4": -74.6,
            "C2H2,acetylene": 228.2,
            "CH2CO,ketene": -49.576,
            "C2H4": 52.5,
            "HCN": 133.082,
            "HNC": 194.378,
            "NH3": -54.752,
            "CH3CN": 31.38,
            "C4H2,butadiyne": 450,
            "C2N2": 283.209,
            "*CN": 438.683,
            "HNCO": -118.056,
            "C3H3,2-propynl": 331.8,
            "HNO": 102.032,
            "NO2": 34.193,
            "C2H6": -103.819,
            "HCHO,formaldehy": -108.58,
            "C3H6,propylene": 20.0
        }
        # Dictionary holding molar masses for reactants [g/mol]
        self.MMDict = {
            "LO2": 15.999,
            "N2O": 44.013,
            "ABS": 57.07,
            "Acrylic": 100.12
        }

        self.addCustomSpecies()
        self.C = CEA_Obj(oxName=oxName, fuelName=fuelName)



    def getOutput(self, Pc, OFRatio, ExpansionRatio, printOutput):
        output = self.C.get_full_cea_output(Pc=Pc, MR=OFRatio, eps=ExpansionRatio, short_output=0, output='siunits')
        if printOutput:
            print(output)

    def getChamberEquilibrium(self, Pc, OFRatio, ExpansionRatio, location):
        # gets all of the properties of the thingy (make sure not to ask for too much, you will upset him)
        # location: 0-injector (not supported) 1-chamber 2-throat 3-exit

        if location == 0:
            print("ERROR: properties at injector not supported")
        elif location == 1:
            self.Isp_Vac, self.C_star, self.T_flame, self.MW, self.gamma = self.C.get_IvacCstrTc_ChmMwGam(Pc=Pc, MR=OFRatio, eps=ExpansionRatio)  # get ISP [s], C* [ft/s], T [R], MW [g/mol], gamma [-]
            self.Cp, self.visc, self.thermCond, self.prandtl = self.C.get_Chamber_Transport(Pc, OFRatio, ExpansionRatio)  # get heat capacity [cal/g*K], viscosity[milliPoise], thermal conductivity [mcal/cm*s*K], Prandtl Number [-]

        elif location == 2:
            self.Isp_Vac, self.C_star, self.T_flame, self.MW, self.gamma = self.C.get_IvacCstrTc_ThtMwGam(Pc=Pc, MR=OFRatio, eps=ExpansionRatio)  # get ISP [s], C* [ft/s], T [R], MW [g/mol], gamma [-]
            self.Cp, self.visc, self.thermCond, self.prandtl = self.C.get_Throat_Transport(Pc, OFRatio, ExpansionRatio)  # get heat capacity [cal/g*K], viscosity[milliPoise], thermal conductivity [mcal/cm*s*K], Prandtl Number [-]
        elif location == 3:
            self.Isp_Vac, self.C_star, self.T_flame, self.MW, self.gamma = self.C.get_IvacCstrTc_exitMwGam(Pc=Pc, MR=OFRatio, eps=ExpansionRatio)  # get ISP [s], C* [ft/s], T [R], MW [g/mol], gamma [-]
            self.Cp, self.visc, self.thermCond, self.prandtl = self.C.get_Exit_Transport(Pc, OFRatio, ExpansionRatio)  # get heat capacity [cal/g*K], viscosity[milliPoise], thermal conductivity [mcal/cm*s*K], Prandtl Number [-]
        else:
            print("ERROR: location index out of bounds")
        self.T_flame = self.T_flame/1.8  # convert to Kelvin
        self.C_star = self.C_star / 3.28084  # convert characteristic velocity to [m/s]
        self.Cp = self.Cp * 4.186798  # get specific heat capacity [j/g*C]
        self.visc = self.visc/1000  # convert from milliPoise to Poise
        self.thermCond = self.thermCond * 418000  # convert to [W/m*K]

        return self.Isp_Vac, self.C_star, self.T_flame, self.MW, self.gamma, self.Cp, self.visc, self.thermCond, self.prandtl

    def getReactionHeat(self, Pc, OFRatio, ExpansionRatio, location):
        h_products = self.getProductsEnthalpy(Pc, OFRatio, ExpansionRatio, location)
        h_fuel = self.findHeatOfFormation(self.fuelName)/self.MMDict[self.fuelName]
        h_ox = self.findHeatOfFormation(self.oxName)/self.MMDict[self.oxName]

        X_fuel = 1/(OFRatio+1)  # fuel mass fraction
        X_ox = OFRatio/(OFRatio+1)  # oxidizer mass fraction

        h_reactants = X_fuel*h_fuel + X_ox*h_ox

        Q_total = h_products - h_reactants  # assuming adiabatic circumstances, Q_total = deltaH
        return Q_total

    def getProductsEnthalpy(self, Pc, OFRatio, ExpansionRatio, location):
        # calculates the enthalpy per gram of products
        # location: 0-injector 1-chamber 2-throat 3-exit

        molarMass, massFraction = self.C.get_SpeciesMassFractions(Pc=Pc, MR=OFRatio, eps=ExpansionRatio)

        # convert molarMass and massFraction into lists with species name in first column, and data in second
        molarMass = list(molarMass), list(molarMass.values())
        massFraction = list(massFraction), list(massFraction.values())

        # create an array containing the standard heat of formations of all species
        h_f = molarMass
        h_products = 0
        for i in range(len(molarMass[0])):
            h_f[1][i] = self.findHeatOfFormation(molarMass[0][i]) / molarMass[1][i]  # heat of formation [kJ/g]
            h_products += h_f[1][i] * massFraction[1][i][location]
        return h_products

    def findHeatOfFormation(self, species):
        try:
            return self.heatDict[species]
        except:
            print("ERROR:", species, "is not defined in heat of formation dictionary. Look in the init of the CEA class")

    def addCustomSpecies(self):
        # Add custom species to CEA
        card_str = """
                fuel ABS  C 3.85   H 4.85   N 0.43     wt%=100.00
                h,cal=14990    t(k)=298.15   rho=0.975
                """
        add_new_fuel('ABS', card_str)
        card_str = """
                fuel Acrylic  C 5   H 8   O 2     wt%=100.00
                h,cal=91396    t(k)=298.15   rho=1.18
                """
        add_new_fuel('Acrylic', card_str)