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
def test_full_cea_output(self): C = CEA_Obj(oxName="LOX", fuelName="LH2", fac_CR=None) s = C.get_full_cea_output(Pc=1000.0, MR=6.0, eps=40.0) #print( s ) ipos = s.find('Isp, LB-SEC/LB 154.4 431.2') self.assertGreater(ipos, 4000) del C
from rocketcea.cea_obj import CEA_Obj ispObj = CEA_Obj(oxName='LOX', fuelName='LH2', fac_CR=2.5) s = ispObj.get_full_cea_output(Pc=1000.0, MR=6.0, eps=40.0) print(s)
from rocketcea.cea_obj import CEA_Obj ispObj = CEA_Obj(oxName='LOX', fuelName='LH2') s = ispObj.get_full_cea_output(Pc=1000.0, MR=6.0, eps=40.0, frozen=1, frozenAtThroat=0, short_output=1) print(s)
from rocketcea.cea_obj import CEA_Obj Pc = 40.0 eps = 5.0 ispObj = CEA_Obj(oxName='GOX', fuelName='GH2') s = ispObj.get_full_cea_output(Pc=Pc, MR=5.0, eps=eps, frozen=0, frozenAtThroat=0, short_output=1, show_transport=1) print(s) print("""==================================""") print(ispObj.get_HeatCapacities(Pc=Pc, MR=.25, eps=eps)) print(ispObj.get_HeatCapacities(Pc=Pc, MR=5.0, eps=eps))
""" figure out Pcinj_face to get desired Pcomb_end (100 atm in example) """ from rocketcea.cea_obj import CEA_Obj cr = 2.5 # contraction ratio ispObj = CEA_Obj(oxName='LOX', fuelName='LH2', fac_CR=cr) # Use 100 atm to make output easy to read Pc = 100.0 * 14.6959 # use correlation to make 1st estimate of Pcinj_face / Pcomb_end PinjOverPcomb = 1.0 + 0.54 / cr**2.2 # use RocketCEA to refine initial estimate PinjOverPcomb = ispObj.get_Pinj_over_Pcomb(Pc=Pc * PinjOverPcomb, MR=6.0) # print results (noting that "COMB END" == 100.00 atm) s = ispObj.get_full_cea_output(Pc=Pc * PinjOverPcomb, MR=6.0, eps=40.0) print(s)
from rocketcea.cea_obj import CEA_Obj, add_new_fuel, add_new_oxidizer, add_new_propellant # ========== card_str = """ name H2O2(L) H 2 O 2 wt%=100.00 h,cal=-44880.0 t(k)=298.15 rho.g/cc=1.407 """ add_new_propellant('MyProp', card_str) C = CEA_Obj(propName="MyProp") s = C.get_full_cea_output(Pc=250.0, eps=40.0, short_output=1) print(s)
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)
print( 'cal_per_mole:%g'%cal_per_mole ) card_str = """ oxid Peroxide_90h2o2 H %g O %g wt%%=100.0 h,cal=%g t(k)=298.15 rho,g/cc = 1.395 """%(frac_h, frac_ox, cal_per_mole) print( card_str ) # ============== Add the new card to RocketCEA ============== add_new_oxidizer( 'Peroxide_90h2o2', card_str ) # ============= Make a sample run at nominal conditions ========== # (gives exact same results as library Peroxide90) C = CEA_Obj(propName="Peroxide_90h2o2") s = C.get_full_cea_output( Pc = 1000.0,eps=2.0,short_output = 1) print( s ) # =============== make plot ================ TvalL = [] IspL = [] for TdegR in range(500, 660, 10): new_card = makeCardForNewTemperature(ceaName='Peroxide_90h2o2', newTdegR=TdegR, CpAve=0.66, MolWt=MolWtMixture) ispObj = CEA_Obj( propName=new_card ) TvalL.append( TdegR ) IspL.append( ispObj(Pc=1000.0, eps=2.0 ) ) plot(TvalL, IspL, label='90% Peroxide', linewidth=2)
from rocketcea.cea_obj import CEA_Obj ispObj = CEA_Obj(oxName='LOX', fuelName='LH2') s = ispObj.get_full_cea_output(Pc=1000.0, MR=6.0, eps=40.0, short_output=1, show_transport=1) print(s)
from rocketcea.cea_obj import CEA_Obj, add_new_fuel, add_new_oxidizer, add_new_propellant card_str = """ fuel NASA_RP-1 C 1.0 H 1.95 wt%=100.00 h,cal=-5907.672 t(k)=298.15 rho=.773 """ add_new_fuel( 'NASA_RP_1', card_str ) C = CEA_Obj(oxName="GOX", fuelName="NASA_RP_1") s = C.get_full_cea_output( Pc=1000.0, MR=3.0, eps=40.0, short_output=1) print( s )
from rocketcea.cea_obj import CEA_Obj, add_new_fuel, add_new_oxidizer, add_new_propellant card_str = """ oxid N2O4(L) N 2 O 4 wt%=96.5 h,cal=-4676.0 t(k)=298.15 oxid SiO2 Si 1.0 O 2.0 wt%=3.5 h,cal=-216000.0 t(k)=298.15 rho=1.48 """ add_new_oxidizer('GelN2O4', card_str) # ========== card_str = """ fuel CH6N2(L) C 1.0 H 6.0 N 2.0 wt%=60.00 h,cal=12900.0 t(k)=298.15 rho=.874 fuel AL AL 1.0 wt%=40.00 h,cal=0.0 t(k)=298.15 rho=0.1 """ add_new_fuel('MMH_AL', card_str) C = CEA_Obj(oxName="GelN2O4", fuelName="MMH_AL") s = C.get_full_cea_output(Pc=1850.0, MR=0.7, eps=40.0, short_output=1) print(s)
def createPropellant(wt1,wt2,wt3): card_str = """ name H2O H 2 O 1 wt%={:.1f} h,kj/mol=-285.8 t(k)=293.15 name Methanol C 1 H 4 O 1 wt%={:.1f} h,kj/mol=-239.2 t(k)=293.15 name ADN H 4 N 4 O 4 wt%={:.1f} h,kj/mol=-134.6 t(k)=293.15 """.format(wt1,wt2,wt3) add_new_propellant("WaterMethanolADN_Mix",card_str) def bar2psi(bar): return bar*14.504 """ prepare fuel """ meth = 39 adn = 59 h2o = 2 createPropellant(h2o,meth,adn) """ get full output """ chamber_pressure = 16 expansion_ratio = 60 temp = CEA_Obj(propName="WaterMethanolADN_Mix") (isp,cstr,tc) = temp.getFrozen_IvacCstrTc(Pc=bar2psi(chamber_pressure),eps=expansion_ratio,frozenAtThroat=1) print(isp,cstr,tc) s = temp.get_full_cea_output( Pc=bar2psi(chamber_pressure), eps=expansion_ratio, frozen=1, frozenAtThroat=1) with open("b4.out","w") as f: f.write(s) print(s)
from rocketcea.cea_obj import CEA_Obj ispObj = CEA_Obj(oxName='LOX', fuelName='LH2') s = ispObj.get_full_cea_output( Pc=[1000, 2000], # number or list of chamber pressures MR=[6.0, 7.0], # number or list of mixture ratios PcOvPe=[100, 200], # number or list of Pc/Pexit eps=[40.0, 60], # number or list of supersonic area ratios subar=[3, 2], # number or list of subsonic area ratios short_output=0, # 0 or 1 to control output length pc_units='psia', # pc_units = 'psia', 'bar', 'atm', 'mmh' output='siunits') # output = 'calories' or 'siunits' print(s)
from rocketcea.cea_obj import CEA_Obj C = CEA_Obj(oxName='LOX', fuelName='RP1') full_cea = C.get_full_cea_output(Pc=100, MR=1.0, eps=None, subar=None, PcOvPe=100, show_transport=1, pc_units='bar', output='KJ', short_output=1) print( 'this is the cea string:------------------------------------------------------------------------------------------------------------------' ) print(full_cea)
from rocketcea.cea_obj import CEA_Obj ispObj = CEA_Obj(propName='Peroxide98') s = ispObj.get_full_cea_output(Pc=1000.0, eps=10.0) print(s)
from rocketcea.cea_obj import CEA_Obj ispObj = CEA_Obj(oxName='LOX', fuelName='LH2') s = ispObj.get_full_cea_output(Pc=1000.0, MR=6.0, eps=40.0, frozen=1, frozenAtThroat=0, short_output=0, pc_units='psia', show_mass_frac=True) print(s)