def test_chamber_transport_props(self): """test chamber transport props""" C = CEA_Obj( oxName='LOX', fuelName='LH2', fac_CR=None) CwU = CEA_Obj_w_units( oxName='LOX', fuelName='LH2', pressure_units='MPa', specific_heat_units='kJ/kg-K', # note: cal/g K == BTU/lbm degR viscosity_units='poise', thermal_cond_units='BTU/s-in-degF', fac_CR=None) Cp1, v1, con1, P1 = C.get_Chamber_Transport(Pc=1000.0, MR=6.0, eps=40.0, frozen=0) Cp2, v2, con2, P2 = CwU.get_Chamber_Transport(Pc=1000.0/145.037738, MR=6.0, eps=40.0, frozen=0) Cp3 = C.get_Chamber_Cp(Pc=1000.0, MR=6.0, eps=40.0, frozen=0) # look at heat capacity self.assertAlmostEqual(Cp1, 2.0951, delta=0.001) self.assertAlmostEqual(Cp2, 8.771346, delta=0.001) self.assertAlmostEqual(Cp1, Cp3, delta=0.001) # look at viscosity self.assertAlmostEqual(v1, 1.0588, delta=0.001) self.assertAlmostEqual(v2, 0.0010588, delta=0.000001) # look at conductivity self.assertAlmostEqual(con1, 4.1444, delta=0.0001) self.assertAlmostEqual(con2, 2.3192E-5, delta=1.0E-9)
def calculate_combustion_parameters_at_chamber(self, phi): """ Uses RocketCEA, which wraps NASA CEA, to calculate 4 parameters at the combustion chamber: OF_ratio : Oxidizer/fuel mass ratio. k : exhaust gasses cp/cv = gamma. M : exhaust gasses moleculaer weight. To : adiabatic flame temperature. Parameters ---------- phi : float Equivalence ratio: phi = (fuel-to-oxidizer ratio) / (fuel-to-oxidizer ratio)st. Returns ------- OF_ratio : float Oxidizer/fuel mass ratio based on given phi. gamma : float Exhaust gasses cp/cv. molecular_weight : float Exhaust gasses moleculaer weight. flame_temperature : float Adiabatic flame temperature. """ cea_analysis = CEA_Obj( oxName=self.oxidizer.name, fuelName=self.fuel.name, isp_units="sec", cstar_units="m/sec", pressure_units="bar", temperature_units="K", sonic_velocity_units="m/sec", enthalpy_units="kJ/kg", density_units="kg/m^3", specific_heat_units="kJ/kg-K", viscosity_units="millipoise", thermal_cond_units="W/cm-degC", ) # Get OF ratio based on equivalence ratio OF_ratio = cea_analysis.getMRforER(ERphi=phi) # Calculate outputs area_ratio = cea_analysis.get_eps_at_PcOvPe(Pc=self.p_chamber, MR=OF_ratio, PcOvPe=self.p_chamber / self.Pa) ( Isp, cstar, flame_temperature, molecular_weight, gamma, ) = cea_analysis.get_IvacCstrTc_ChmMwGam(Pc=self.p_chamber, MR=OF_ratio, eps=area_ratio) return OF_ratio, gamma, molecular_weight, flame_temperature
def __init__(self): self.datapathname = './.lookup.npy' self.configpathname = './.lookupconfig.json' self.data = None self.config = None self.__loaded = False # This str provides molecular structure, wt% of fuel, heat of formation, and density information to underlying CEA code fuel_str = """ fuel ABS(S) C 3.85 H 4.85 N 0.43 wt%=100.0 h,kJ=62.63 t(k)=298.15 rho,kg=1224 """ add_new_fuel('ABS', fuel_str) self.cea = CEA_Obj(oxName='N2O', fuelName='ABS', cstar_units='m/s', pressure_units='Pa', temperature_units='K', sonic_velocity_units='m/s', enthalpy_units='J/kg', density_units='kg/m^3', specific_heat_units='J/kg-K', viscosity_units='poise', thermal_cond_units='W/cm-degC', make_debug_prints=True)
def test_use_Mpa_as_input_Pc(self): """test use Mpa as input Pc""" C = CEA_Obj( oxName='LOX', fuelName='LH2', fac_CR=None) CwU = CEA_Obj_w_units( oxName='LOX', fuelName='LH2', pressure_units='MPa', fac_CR=None) a = C.get_Isp(Pc=1000.0, MR=6.0, eps=40.0) b = CwU.get_Isp(Pc=1000.0/145.037738, MR=6.0, eps=40.0) self.assertAlmostEqual(a, b, delta=0.01)
def print_cea_output(self, subar=None, supar=None): """Prints NASA CEA output file.""" cea_analysis = CEA_Obj( oxName=self.oxidizer.name, fuelName=self.fuel.name, isp_units="sec", cstar_units="m/sec", pressure_units="bar", temperature_units="K", sonic_velocity_units="m/sec", enthalpy_units="kJ/kg", density_units="kg/m^3", specific_heat_units="kJ/kg-K", viscosity_units="millipoise", thermal_cond_units="W/cm-degC", ) cea_output = cea_analysis.cea_obj.get_full_cea_output( Pc=self.p_chamber, MR=self.OF_ratio, PcOvPe=self.p_chamber / self.Pa, subar=subar, eps=supar, show_transport=1, pc_units="bar", output="siunits", show_mass_frac=True, frozen=0, frozenAtThroat=1, #fac_CR=2, ) print(cea_output)
def rocket_vars(fu, ox, pcham): C = CEA_Obj( oxName=ox, fuelName=fu, isp_units='sec', cstar_units='m/s') # define CEA object to operate on for rocketCEA OFratio = np.linspace(0.1, 5., 50, endpoint=True) # OF ratio by mass ISP = np.zeros(OFratio.shape) # isp Cstar = np.zeros(OFratio.shape) # cstar efficiency PCPE = np.zeros(OFratio.shape) # p_chamber / p_exit supAR = 1 # supersonic area ratio (1 = converging nozzle only) for i in range(50): ISP[i] = C.get_Isp(pcham, MR=OFratio[i], eps=supAR) # ISP vacuum Cstar[i] = C.get_Cstar(pcham, MR=OFratio[i]) # Cstar efficiency PCPE[i] = C.get_Throat_PcOvPe( pcham, MR=OFratio[i] ) # throat Pc/Pe (we will be using a converging nozzle) return ISP, Cstar, PCPE
def getCeaObj(fuelName, oxName): #print(type(fuelName),type(oxName)) return CEA_Obj(oxName=oxName, fuelName=fuelName, pressure_units='Pa', temperature_units='K', density_units='kg/m^3', sonic_velocity_units='m/s', specific_heat_units='J/kg-K')
def OFtrade(fu, ox, P, N, OFratio, pltname): # O/F ratio trade (OFratio needs to be a vector array) # fu: name of fuel (string, as defined in rocketcea documentation or newly added fuels) # ox: name of ox (string, as defined in rocketcea documentation of newly added fuels) # P: chamber pressure (either a single number, list of numbers, or range()) # N: number of desired O/F ratios to sweep over # OFratio: values of O/F ratios (length of this list must match value of N) # supAR: fixed nozzle expansion ratio C = CEA_Obj( oxName=ox, fuelName=fu, isp_units='sec', cstar_units='m/s') # define CEA object to operate on for rocketCEA if isinstance(P, int) == True: # if P is only one value y = 1 else: y = len(P) # preallocate vars ISP = np.zeros([y, OFratio.shape[0]]) # isp Cstar = np.zeros([y, OFratio.shape[0]]) # cstar eff PCPE = np.zeros([y, OFratio.shape[0]]) # pc/pe cpcv = np.zeros([y, OFratio.shape[0] ]) # ratio of specific heats in thrust chamber fe_pcpe = np.zeros([y, OFratio.shape[0] ]) # nozzle area ratio for fully expanded flow for x in range(y): if y == 1: Pc = P # integers can't be called :( legends = str(Pc) else: Pc = P[x] # chamber pressure legends = P pr = Pc / 14.7 # pc/pe for fully expanded flo for i in range(N): fe_pcpe[x, :] = C.get_eps_at_PcOvPe(Pc=Pc, MR=OFratio[i], PcOvPe=pr) ISP[x, i] = C.get_Isp(Pc=Pc, MR=OFratio[i], eps=fe_pcpe[x, i]) # ISP vacuum Cstar[x, i] = C.get_Cstar(Pc=Pc, MR=OFratio[i]) # Cstar efficiency fe_pcpe[x, i] = C.get_PcOvPe(Pc=Pc, MR=OFratio[i], eps=fe_pcpe[x, i]) # Pc/Pe cpcv[x, i] = C.get_Chamber_Cp(Pc=Pc, MR=OFratio[i], eps=fe_pcpe[x, i]) # cp/cv # generate plots for ISP, Cstar, and Pchamb/Pexit # plots(OFratio,ISP,"O/F ratio","ISP (s)", pltname+"isp.png" , legends ) # isp plot # plots(OFratio,Cstar,"O/F ratio","Cstar", pltname+"cstar.png" , legends ) # Cstar plot # plots(OFratio,PCPE,"O/F ratio","Pc/Pe", pltname+"pcpe.png" , legends ) # Pc/Pe plot return ISP, Cstar, fe_pcpe, cpcv
def ARtrade(fu, ox, P, N, OFratio, supAR, pltname): # expansion ratio trade # fu: name of fuel (string, as defined in rocketcea documentation or newly added fuels) # ox: name of ox (string, as defined in rocketcea documentation of newly added fuels) # P: chamber pressure (either a single number, list of numbers, or range()) # N: number of desired supersonic area ratios (nozzle expansion ratio) to sweep over # OFratio: fixed O/F ratio for this trade # supAR: values of supersonic area ratios (length of this list must match value of N) C = CEA_Obj( oxName=ox, fuelName=fu, isp_units='sec', cstar_units='m/s') # define CEA object to operate on for rocketCEA if isinstance(P, int) == True: # if P is only one value y = 1 else: y = len(P) # preallocate vars ISP = np.zeros([y, supAR.shape[0]]) # isp Cstar = np.zeros([y, supAR.shape[0]]) # cstar eff PCPE = np.zeros([y, supAR.shape[0]]) # pc/pe cpcv = np.zeros([y, supAR.shape[0] ]) # ratio of specific heats in thrust chamber for x in range(y): if y == 1: Pc = P # integers can't be called :( legends = str(Pc) else: Pc = P[x] # chamber pressure legends = P for i in range(N): ISP[x, i] = C.get_Isp(Pc=Pc, MR=OFratio, eps=supAR[i]) # ISP vacuum Cstar[x, i] = C.get_Cstar(Pc=Pc, MR=OFratio) # Cstar efficiency PCPE[x, i] = C.get_PcOvPe(Pc=Pc, MR=OFratio, eps=supAR[i]) # Pc/Pe cpcv[x, i] = C.get_Chamber_Cp(Pc=Pc, MR=OFratio, eps=supAR[i]) # cp/cv # generate plots for ISP, Cstar, and Pchamb/Pexit. Replace the last input with the vectory array of pressures # plots(supAR,ISP,"Ae/At","ISP (s)", pltname+"isp.png" , legends ) # isp plot # plots(supAR,Cstar,"Ae/At","Cstar", pltname+"cstar.png" , legends ) # Cstar plot # plots(supAR,PCPE,"Ae/At","Pc/Pe", pltname+"pcpe.png" , legends ) # Pc/Pe plot return ISP, Cstar, PCPE, cpcv
def getPerformanceParameters(self, combustionPressure, ambientPressure, oxidizerTemperature, expansionRatio, mixtureRatio): import CoolProp.CoolProp as CP from rocketcea.cea_obj import CEA_Obj, add_new_fuel, add_new_oxidizer, add_new_propellant from rocketcea.cea_obj_w_units import CEA_Obj as CEA_Obj_W_Units from rocketcea.blends import makeCardForNewTemperature combustionPressure = max(10, combustionPressure) # Limitation of the library... fuelTemperature = 293 HMOLAR = CP.PropsSI('HMOLAR','T',oxidizerTemperature,'P',combustionPressure,"N2O") / 1e3 oxidizerDensity = CP.PropsSI('D','T',oxidizerTemperature,'P',combustionPressure,"N2O") RHO = oxidizerDensity * 1e3 / (1e2 * 1e2 * 1e2) oxid_card_str = """ oxid=NITROUS wt=1.0 t,K={:.2f} h,kj/mol={:.2f} rho,g/cc={:.2f} N 2 O 1 """.format(oxidizerTemperature, HMOLAR, RHO) fuel_card_str = """ fuel=C(gr) wt={:.4f} t,K={:.2f} fuel=SASOL907 wt={:.4f} t,K={:.2f} h,kj/mol={:.2f} rho,g/cc={:.3f} C 50 H 102 """.format( assumptions.carbonBlackFraction.get(), fuelTemperature, 1 - assumptions.carbonBlackFraction.get(), fuelTemperature, assumptions.fuelEnthalpyOfFormation.get(), assumptions.fuelDensityLiquid.get() / 1e3) problemString = "Pc={:.2f},Pa={:.2f},To={:.2f},Tf={:.2f},ER={:.2f},MR={:.2f},oxid={:},fuel={:}".format( combustionPressure, ambientPressure, oxidizerTemperature, fuelTemperature, expansionRatio, mixtureRatio, oxid_card_str, fuel_card_str ) strHash = hashlib.md5(problemString.encode()).hexdigest() NasaCEA.totalHits = NasaCEA.totalHits + 1 if options.enableCeaLookup and strHash in NasaCEA.inMemoryCache: # print("Hit cache") NasaCEA.cacheHits = NasaCEA.cacheHits + 1 return NasaCEA.inMemoryCache[strHash] # print(HMOLAR, RHO) add_new_oxidizer('NITROUS_COOLPROP', oxid_card_str) add_new_fuel('SASOLWAX907_CARBONBLACK', fuel_card_str) with hiddenPrints: combustionPressure = round(combustionPressure, 2) mixtureRatio = round(mixtureRatio, 2) expansionRatio = round(expansionRatio, 2) ambientPressure = round(ambientPressure, 2) cea = CEA_Obj_W_Units( oxName="NITROUS_COOLPROP", fuelName="SASOLWAX907_CARBONBLACK", pressure_units='Pa', cstar_units='m/s', temperature_units='K', sonic_velocity_units='m/s', enthalpy_units='J/kg', density_units='kg/m^3', specific_heat_units='J/kg-K', viscosity_units='poise', thermal_cond_units="W/cm-degC" ) Isp,mode = cea.estimate_Ambient_Isp(Pc=combustionPressure, MR=mixtureRatio, eps=expansionRatio, Pamb=ambientPressure) IspVac, Cstar, Tc, MW, gamma = cea.get_IvacCstrTc_ThtMwGam(Pc=combustionPressure, MR=mixtureRatio, eps=expansionRatio) Cp = cea.get_Chamber_Cp(Pc=combustionPressure, MR=mixtureRatio, eps=expansionRatio) rho = cea.get_Chamber_Density(Pc=combustionPressure, MR=mixtureRatio, eps=expansionRatio) CfVac, Cf, mode = cea.get_PambCf(Pc=combustionPressure, MR=mixtureRatio, eps=expansionRatio) PcOvPe = cea.get_PcOvPe(Pc=combustionPressure, MR=mixtureRatio, eps=expansionRatio) exitPressure = combustionPressure / PcOvPe result = (Isp, Cp, MW, Cstar, Tc, gamma, rho, Cf, exitPressure, oxidizerDensity) if options.enableCeaLookup: NasaCEA.inMemoryCache[strHash] = result return result
def optimize_combustion_parameters_at_chamber(self): """ Uses RocketCEA, which wraps NASA CEA, to calculate 4 parameters at the combustion chamber: OF_ratio : Oxidizer/fuel mass ratio. k : exhaust gasses cp/cv = gamma. M : exhaust gasses moleculaer weight. To : adiabatic flame temperature. OF_ratio is calculated by optimizing the specific impulse of the motor. Returns ------- optimal_OF_ratio : float Optimized oxidizer/fuel mass ratio generating optimum specific impulse. gamma : float Exhaust gasses cp/cv. molecular_weight : float Exhaust gasses moleculaer weight. flame_temperature : float Adiabatic flame temperature. """ # ---------------Calculated Inputs----------------# # Calculate input parameters from oxidiser and fuel combustion # Initialize CEA analysis cea_analysis = CEA_Obj( oxName=self.oxidizer.name, fuelName=self.fuel.name, # Units isp_units="sec", cstar_units="m/sec", pressure_units="bar", temperature_units="K", sonic_velocity_units="m/sec", enthalpy_units="kJ/kg", density_units="kg/m^3", specific_heat_units="kJ/kg-K", viscosity_units="millipoise", thermal_cond_units="W/cm-degC", ) # Get stoichiometric equivalence ratio stoichiometric_OF_ratio = cea_analysis.getMRforER(ERphi=1.0) # Find optimal specific impulse def minus_specific_impulse_function(OF_ratio): area_ratio = cea_analysis.get_eps_at_PcOvPe(Pc=self.p_chamber, MR=OF_ratio, PcOvPe=self.p_chamber / self.Pa) Isp, cstar, To, M, k = cea_analysis.get_IvacCstrTc_ChmMwGam( Pc=self.p_chamber, MR=OF_ratio, eps=area_ratio) return -Isp res = minimize( fun=minus_specific_impulse_function, x0=stoichiometric_OF_ratio, method="Powell", bounds=[[ stoichiometric_OF_ratio * 0.5, stoichiometric_OF_ratio * 2 ]], ) # Optimization sequence complete, store results optimal_OF_ratio = res.x[0] optimal_area_ratio = cea_analysis.get_eps_at_PcOvPe( Pc=self.p_chamber, MR=optimal_OF_ratio, PcOvPe=self.p_chamber / self.Pa) ( optimal_Isp, cstar, flame_temperature, molecular_weight, gamma, ) = cea_analysis.get_IvacCstrTc_ChmMwGam(Pc=self.p_chamber, MR=optimal_OF_ratio, eps=optimal_area_ratio) return optimal_OF_ratio, gamma, molecular_weight, flame_temperature
def getPerformanceParameters(self, combustionPressure, ambientPressure, oxidizerTemperature, expansionRatio, mixtureRatio): CpAve = CP.PropsSI('CP0MOLAR', 'T', oxidizerTemperature, 'P', combustionPressure, "N2O") MolWt = CP.PropsSI('M', 'T', oxidizerTemperature, 'P', combustionPressure, "N2O") * 1e3 HMOLAR = CP.PropsSI('HMOLAR', 'T', oxidizerTemperature, 'P', combustionPressure, "N2O") / 1e3 RHO = CP.PropsSI('D', 'T', oxidizerTemperature, 'P', combustionPressure, "N2O") * 1e3 / (1e2 * 1e2 * 1e2) # print(HMOLAR, RHO) card_str = """ oxid=NITROUS wt=1.0 t,K={:.4f} h,kj/mol={:.4f} rho,g/cc={:.4f} N 2 O 1 """.format(oxidizerTemperature, HMOLAR, RHO) add_new_oxidizer('NITROUS_COOLPROP', card_str.format(oxidizerTemperature)) fuelTemperature = 293 card_str = """ fuel=C(gr) wt=0.02 t,K={:.4f} fuel=SASOL907 wt=0.98 t,K={:.4f} h,kj/mol=-1438.200 rho,g/cc=0.720 C 50 H 102 """.format(fuelTemperature, fuelTemperature) add_new_fuel('SASOLWAX907_CARBONBLACK', card_str) # cea = CEA_Obj( # oxName="NITROUS_COOLPROP", # fuelName="SASOLWAX907_CARBONBLACK" # ) # s = cea.get_full_cea_output(Pc=combustionPressure/1e5, MR=mixtureRatio, eps=expansionRatio, pc_units="bar", output='siunits') # print(s) # # pass with hiddenPrints: cea = CEA_Obj_W_Units(oxName="NITROUS_COOLPROP", fuelName="SASOLWAX907_CARBONBLACK", pressure_units='Pa', cstar_units='m/s', temperature_units='K', sonic_velocity_units='m/s', enthalpy_units='J/kg', density_units='kg/m^3', specific_heat_units='J/kg-K', viscosity_units='poise', thermal_cond_units="W/cm-degC") Isp, mode = cea.estimate_Ambient_Isp(Pc=combustionPressure, MR=mixtureRatio, eps=expansionRatio, Pamb=ambientPressure) IspVac, Cstar, Tc, MW, gamma = cea.get_IvacCstrTc_ChmMwGam( Pc=combustionPressure, MR=mixtureRatio, eps=expansionRatio) # cea = CEA_Obj( # oxName=oxidizerCard, # fuelName="SASOLWAX907_CARBONBLACK" # ) # s = cea.get_full_cea_output(Pc=combustionPressure/1e5, MR=mixtureRatio, eps=expansionRatio, pc_units="bar", output='siunits') # print(s) return Isp, CpAve, MolWt, Cstar, Tc, gamma
# globals FORMAT = 'png' PSI_TO_PA = 6894.7572931783 M_TO_IN = 39.3701 G0 = 9.81 # define PMMA card_str = ''' fuel PMMA C 5 H 8 O 2 h,kj=-430.5 t(k)=299.82 ''' # Greg Zilliac's recommendation for modeling PMMA add_new_fuel('PMMA', card_str) # rocketCEA function to add PMMA to possible inputs CEA_object = CEA_Obj(oxName='GOX', fuelName='PMMA', isp_units='sec', cstar_units='m/s', sonic_velocity_units='m/s', temperature_units='k') def get_initial_guess(config): Pc_0 = config.getfloat('Params', 'initial_pc') * PSI_TO_PA P0 = config.getfloat('Params', 'p0') OF_0 = config.getfloat('Params', 'initial_of') AR = config.getfloat('Params', 'area_ratio') rho_fuel = config.getfloat('Params', 'rho_fuel') a = config.getfloat('Params', 'a') n = config.getfloat('Params', 'n') L = config.getfloat('Params', 'fuel_length') / M_TO_IN Rt = config.getfloat('Params', 'throat_radius') throat_area = np.pi * Rt**2
from rocketcea.cea_obj_w_units import CEA_Obj from pylab import * Pc = 500.0 P90 = CEA_Obj( propName='Peroxide90', pressure_units='psia', temperature_units='degK', ) epsL = [] TceqL = [] TcfrzL = [] for ieps in range(5, 21): TcEq = P90.get_Temperatures(Pc=Pc, eps=float(ieps))[2] TcFrz = P90.get_Temperatures(Pc=Pc, eps=float(ieps), frozen=1, frozenAtThroat=0)[2] epsL.append(float(ieps)) TceqL.append(TcEq) TcfrzL.append(TcFrz) plot(epsL, TceqL, label='Equilibrium') plot(epsL, TcfrzL, label='Frozen') legend(loc='best')
class HybridCEALookup(): """ Class to generate and manage N2O-ABS Hybrid engine CEA data for Pc and o/f ratios """ __depth = 10 def __init__(self): self.datapathname = './.lookup.npy' self.configpathname = './.lookupconfig.json' self.data = None self.config = None self.__loaded = False # This str provides molecular structure, wt% of fuel, heat of formation, and density information to underlying CEA code fuel_str = """ fuel ABS(S) C 3.85 H 4.85 N 0.43 wt%=100.0 h,kJ=62.63 t(k)=298.15 rho,kg=1224 """ add_new_fuel('ABS', fuel_str) self.cea = CEA_Obj(oxName='N2O', fuelName='ABS', cstar_units='m/s', pressure_units='Pa', temperature_units='K', sonic_velocity_units='m/s', enthalpy_units='J/kg', density_units='kg/m^3', specific_heat_units='J/kg-K', viscosity_units='poise', thermal_cond_units='W/cm-degC', make_debug_prints=True) def generate(self, pcmin=1, pcmax=1000, ofmin=1, ofmax=40, pcint=1, ofint=1): """ Generate NxMx8 array of chamber thermodynamic and transport properties from min to max (inclusive).\n Use CEA to produce the following data at each pc + ofratio combination (8 values)\n pc : chamber pressure (Pa)\n of : mixture ratio\n Tc : chamber temperature (K)\n k : specific heat ratio\n MW : molecular weight (g / mol)\n Pr : Prandtl number\n Cp : specific heat capacity (J/kg-K)\n mu : viscocity (poise)\n cstar : characteristic velocity (m/s)\n isp : isp (s) """ print('Using N2O, ABS, with SI units') if not self.uses(pcmin=pcmin, pcmax=pcmax, pcint=pcint, ofmin=ofmin, ofmax=ofmax, ofint=ofint): try: # Construct NxMx8 numpy array to hold all data xdim, ydim = self.__getDim(pcmin, pcmax, pcint, ofmin, ofmax, ofint) data = np.zeros(shape=(xdim, ydim, HybridCEALookup.__depth), dtype=float) print( f'Generating lookup table, {xdim}x{ydim}x{HybridCEALookup.__depth}' ) # Enumerate over pressure and ofratio ranges and compute CEA results for (pc_i, pc) in enumerate(np.linspace(pcmin, pcmax, xdim)): for (of_i, of) in enumerate(np.linspace(ofmin, ofmax, ydim)): (cp, mu, _, pr) = self.cea.get_Chamber_Transport(pc, of) (mw, k) = self.cea.get_Chamber_MolWt_gamma(pc, of) (isp, cstar, tc) = self.cea.get_IvacCstrTc(pc, of) data[pc_i, of_i, :] = np.array( [pc, of, tc, k, mw, pr, cp, mu, cstar, isp], dtype=float) # assign data to obj and save to cache self.data = data try: config = { "pcmin": pcmin, "pcmax": pcmax, "pcint": pcint, "ofmin": ofmin, "ofmax": ofmax, "ofint": ofint, "pcnum": xdim, "ofnum": ydim, "depth": HybridCEALookup.__depth } self.config = config with open(os.path.abspath(self.datapathname), 'wb') as f: np.save(f, data, allow_pickle=True) with open(os.path.abspath(self.configpathname), 'w') as f: json.dump(config, f) print( f'Lookup table cached, pcrange: {pcmin}-{pcmax}, ofrange: {ofmin}-{ofmax}' ) except IOError as ioerror: print(ioerror) print("uh oh") except Exception as exception: raise exception else: print( f'Using lookup table from cached:\npcrange: {pcmin}-{pcmax}\nofrange: {ofmin}-{ofmax}' ) def open(self): """ Open cached lookup table """ try: with open(os.path.abspath(self.datapathname), 'rb') as f: self.data = np.load(f, allow_pickle=True) with open(os.path.abspath(self.configpathname), 'r') as f: self.config = json.load(f) self.__loaded = True return True except Exception: # Catch all and return false return False def flushCache(self): """ """ try: with open(os.path.abspath(self.datapathname), 'wb') as f: np.save(f, []) with open(os.path.abspath(self.configpathname), 'w') as f: json.dump({}, f) except Exception as exception: print(exception) def get(self, pc, of): """ Retrieve CEA outputs at any chamber pressure """ if pc < self.config["pcmin"] or pc > self.config["pcmax"]: print( f'Pc: {pc}, Pcmin: {self.config["pcmin"]}, Pcmax: {self.config["pcmax"]}' ) raise Exception("Chamber pressure out of bounds") elif of < self.config["ofmin"] or of > self.config["ofmax"]: print( f'OF: {of}, OFmin: {self.config["ofmin"]}, OFmax: {self.config["ofmax"]}' ) raise Exception("OF ratio out of bounds") # Convert to chamber pressure and OF ratio floating point index pc_i = (pc - self.config["pcmin"]) / (self.config["pcmax"] - self.config["pcmin"]) * ( self.config["pcnum"] - 1) of_i = (of - self.config["ofmin"]) / (self.config["ofmax"] - self.config["ofmin"]) * ( self.config["ofnum"] - 1) # Get chamber pressure lower and upper bounds (1d arr) pc_li = floor(pc_i) pc_hi = ceil(pc_i) # OF ratio lower and upper bounds (1d arr) of_li = floor(of_i) of_hi = ceil(of_i) # Get distance of chamber pressure and OF ratio from closest lower index pc_x = (pc_i - pc_li) # / self.config["pcint"] of_x = (of_i - of_li) # / self.config["ofint"] # Interpolate between pressure data pc_lerp_of_l = self.data[pc_li, of_li, :] + pc_x * ( self.data[pc_hi, of_li, :] - self.data[pc_li, of_li, :]) pc_lerp_of_h = self.data[pc_li, of_hi, :] + pc_x * ( self.data[pc_hi, of_hi, :] - self.data[pc_li, of_hi, :]) # Interpolate between OF ratio data and return result return pc_lerp_of_l + of_x * (pc_lerp_of_h - pc_lerp_of_l) def getPc(self, pc): """ Return a row vector of OF Ratio results at a provided chamber pressure """ if pc < self.config["pcmin"] or pc > self.config["pcmax"]: raise Exception("Chamber pressure out of bounds") pc_i = (pc - self.config["pcmin"]) / (self.config["pcmax"] - self.config["pcmin"]) * ( self.config["pcnum"] - 1) # Get chamber pressure lower and upper bounds (1d arr) pc_li = floor(pc_i) pc_hi = ceil(pc_i) pc_x = (pc_i - pc_li) # / self.config["pcint"] return self.data[pc_li, :, :] + pc_x * (self.data[pc_hi, :, :] - self.data[pc_li, :, :]) def uses(self, pcmin=200, pcmax=800, pcint=10, ofmin=1, ofmax=30, ofint=1): """ Check the cached lookup table configuration against specified options\n """ if self.__loaded: xdim, ydim = self.__getDim(pcmin, pcmax, pcint, ofmin, ofmax, ofint) useConfig = { "pcmin": pcmin, "pcmax": pcmax, "pcint": pcint, "ofmin": ofmin, "ofmax": ofmax, "ofint": ofint, "pcnum": xdim, "ofnum": ydim, "depth": HybridCEALookup.__depth } return useConfig == self.config return False def getConfig(self): """ Get current lookup table configuration """ if self.__loaded: return self.config else: return None def __getDim(self, pcmin, pcmax, pcint, ofmin, ofmax, ofint): xdim = ceil((pcmax - pcmin) / pcint) + 1 ydim = ceil((ofmax - ofmin) / ofint) + 1 return xdim, ydim
p1 = round((p / 20) * 19, 1) p2 = round((p / 20), 1) WT0 = j WT1 = k WT2 = p1 WT3 = p2 # same name runs affoul of memoized cache. prop_name = "Propellant" # "prop_{0}_{1}_{2}_{3}".format(WT0, WT1, WT2, WT3) card_str = """ name pbt C 37.33 H 66.73 N 24.89 O 8.48 wt%={0} h,cal= 36728.486 t(k)=298.15 rho=1.3 name a3 C 2.4 H 4.1 O 3.1 N 1.3 wt%={1} h,cal= -46358.545 t(k)=298.15 rho=1.38 name an N 1.0 H 4.0 N 1.0 O 3.0 wt%={2} h,cal= -87332.284 t(k)=298.15 rho=1.725 name kn K 1.0 N 1.0 O 3.0 wt%={3} h,cal= -118167.824 t(k)=298.15 rho=2.109 """.format(WT0, WT1, WT2, WT3) add_new_propellant(prop_name, card_str) C = CEA_Obj(propName=prop_name, pressure_units='bar', cstar_units='m/s', temperature_units='K', isp_units='N-s/kg') tem = C.get_Tcomb(Pc=200) print(prop_name, tem)
from rocketcea.cea_obj_w_units import CEA_Obj from pylab import * Pc = 1000.0 / 145.037738 # convert to MPa eps = 100.0 mrMin = 3.0 mrStep = 0.05 mrMax = 8.0 oxName = 'LOX' fuelName = 'LH2' ispObj = CEA_Obj(propName='', oxName=oxName, fuelName=fuelName, pressure_units='MPa', isp_units='km/s') ispArr = [] MR = mrMin mrArr = [] while MR < mrMax: ispArr.append(ispObj(Pc, MR, eps)) mrArr.append(MR) MR += mrStep plot(mrArr, ispArr, label='%s/%s' % (oxName, fuelName), linewidth=2) legend(loc='best') grid(True) title('%s Performance at Eps=%g, Pc=%g %s' % (ispObj.desc, eps, Pc, ispObj.isp_units))
from rocketcea.cea_obj_w_units import CEA_Obj, CEA_Obj_default from rocketcea.cea_obj import get_rocketcea_data_dir, set_rocketcea_data_dir test_dir = r'D:\temp\cea w spaces' print('ROCKETCEA_DATA_DIR =', get_rocketcea_data_dir()) set_rocketcea_data_dir(test_dir) print('ROCKETCEA_DATA_DIR =', get_rocketcea_data_dir()) # compare 200 psia (13.7895 bar) results C = CEA_Obj(oxName='LOX', fuelName='LH2', pressure_units='bar', cstar_units='m/s', temperature_units='K', isp_units='N-s/kg') IspVac, Cstar, Tcomb = C.get_IvacCstrTc(Pc=13.7895, MR=1.0, eps=40.0, frozen=0, frozenAtThroat=0) print('IspVac=%g, Cstar=%g, Tcomb=%g' % (IspVac, Cstar, Tcomb)) print(' .... converted to English ....') print('IspVac=%g, Cstar=%g, Tcomb=%g' % (IspVac * 0.101972, Cstar * 3.28084, Tcomb * 1.8)) Cd = CEA_Obj_default(oxName='LOX', fuelName='LH2') IspVac, Cstar, Tcomb = Cd.get_IvacCstrTc(Pc=200.0, MR=1.0,