Coverage for rocketcea\cea_obj.py : 0%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
#!/usr/bin/env python # -*- coding: ascii -*-
r""" RocketCEA wraps the NASA FORTRAN CEA code and provides some useful tools.
RocketCEA makes direct calls to the FORTRAN CEA code in "rocket" mode to calculate Isp, Cstar, Tcham etc. and provides tools to help determine useful mixture ratio range, optimum MR and more.
See the NASA CEA code at: `<https://www.grc.nasa.gov/WWW/CEAWeb/>`_
RocketCEA Copyright (C) 2005-2018 Applied Python
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
-----------------------
"""
import os, sys here = os.path.abspath(os.path.dirname(__file__))
# # python >=3.8 needs to be given permission to import DLL files. from rocketcea.find_mingw_lib import add_mingw_lib add_mingw_lib()
# for multi-file projects see LICENSE file for authorship info # for single file projects, insert following information __author__ = 'Charlie Taylor' __copyright__ = 'Copyright (c) 2018 Charlie Taylor' __license__ = 'GPL-3' exec( open(os.path.join( here,'_version.py' )).read() ) # creates local __version__ variable __email__ = "cet@appliedpython.com" __status__ = "4 - Beta" # "3 - Alpha", "4 - Beta", "5 - Production/Stable"
from rocketcea.input_cards import oxCards, fuelCards, propCards from rocketcea.blends import newFuelBlend, newOxBlend, renamePropIfNewHfOrTrefInName from rocketcea.blends import isAPeroxide_Blend, isAnMMH_N2H4_Blend, isMON_Ox_Blend, isFLOX_Ox_Blend, is_HYD_Ammonia_Blend from rocketcea.blends import addPeroxideBlend, addMON_Blend, addFLOX_Blend, addMMH_N2H4_Blend, addHYD_AmmoniaBlend
try: import rocketcea.py_cea as py_cea except: # automodule doc builds fail on ReadTheDocs w/o some error handling. if os.environ.get('READTHEDOCS',False): print('Allowing py_cea import to fail on READTHEDOCS.') py_cea = None else: # go ahead and raise the error. import rocketcea.py_cea as py_cea
from rocketcea.separated_Cf import ambientCf, sepNozzleCf # # gravitational conversion factor GC = 32.174
_last_called = None # remember the last object to read the datafile _NLines_Max_ever = 0 # make sure to overwrite any lines from previous calls
# hold CEA_Cache objects by propellant name _CacheObjDict = {} def getCacheDict(): """Returns internal cache of previously called calculations.""" return _CacheObjDict
def set_py_cea_line(N, line): '''make sure that trailing blanks are on added lines''' ln = line + " " py_cea.setinpline(N, ln) #print( '"'+ln[:77]+'"' )
def add_new_card( name, card_str, propD ): """::
#: Add or Replace a propellant. #: name = string name (e.g. oxName, fuelName or propName) #: card_str = a single multiline string containing CEA input card for new propellant #: propD = dictionary to receive new propellant (e.g. oxCards, fuelCards or propCards) """
sL = card_str.split('\n') cardL = [] for s in sL: s = s.strip() if s: cardL.append( ' ' + s + ' ' ) # make sure there are spaces around each line entry propD[ name ] = cardL
def add_new_fuel( name, card_str ): """Add a new Fuel Card""" add_new_card( name, card_str, fuelCards )
def add_new_oxidizer( name, card_str ): """Add a new Oxidizer Card""" add_new_card( name, card_str, oxCards )
def add_new_propellant( name, card_str ): """Add a new Propellant Card""" add_new_card( name, card_str, propCards )
_PrintCountDict = {}
class CEA_Cache(object): def __init__(self, maxCache=10000, propName=None): """Create the cache object that saves previous calculations in RAM to speed repetitive calls."""
self.maxCache = maxCache self.propName = propName self.ispDict = {} self.cstarDict = {} self.tcDict = {}
# keep track of size, assume faster than a len( xxDict ) call self.Nisp = 0 self.Ncstar = 0 self.Ntc = 0
def setIsp(self, desc='', isp=0.0): # do not check for existence, assume usage logic handles that if self.Nisp < self.maxCache: self.Nisp += 1 #print( 'in setIsp, desc=',desc,' isp=',isp ) self.ispDict[desc] = isp
def setCstar(self, desc='', cstar=0.0): # do not check for existence, assume usage logic handles that if self.Ncstar < self.maxCache: self.Ncstar += 1 self.cstarDict[desc] = cstar
def setTcK(self, desc='', tc=0.0): # do not check for existence, assume usage logic handles that if self.Ntc < self.maxCache: self.Ntc += 1 self.tcDict[desc] = tc
def getIsp(self, desc=''): try: return self.ispDict[desc] except: return None
def getCstar(self, desc=''): try: return self.cstarDict[desc] except: return None
def getTcK(self, desc=''): try: return self.tcDict[desc] except: return None
class CEA_Obj(object): """ RocketCEA wraps the NASA FORTRAN CEA code to calculate Isp, cstar, and Tcomb """
def __init__(self, propName='', oxName='', fuelName='', fac_CR=None, useFastLookup=0, # depricated makeOutput=0, make_debug_prints=False): """ #: Create the base CEA wrapper object. #: Fast Lookup is depricated. #: fac_CR = Contraction Ratio of finite area combustor (None=infinite) #: if make_debug_prints is True, print debugging info to terminal. """
self.makeOutput = makeOutput # makes "f.out" self.make_debug_prints = make_debug_prints
if fac_CR is not None: self.fac_CR = float( fac_CR ) #print('Creating CEA_Obj with finite area combustor CR = ', self.fac_CR) else: self.fac_CR = None
oxName = renamePropIfNewHfOrTrefInName( oxCards, oxName ) fuelName = renamePropIfNewHfOrTrefInName( fuelCards, fuelName ) propName = renamePropIfNewHfOrTrefInName( propCards, propName )
oxName = oxName.replace('(g)', '(G)') fuelName = fuelName.replace('(g)', '(G)') propName = propName.replace('(g)', '(G)')
# do NOT allow "-" or "+" as part of the name oxName = oxName.replace('-', '_') fuelName = fuelName.replace('-', '_') propName = propName.replace('-', '_')
oxName = oxName.replace('+', '_') fuelName = fuelName.replace('+', '_') propName = propName.replace('+', '_')
if oxName[-3:]=='(G)': oxName = 'G' + oxName[:-3] if self.make_debug_prints: print('Ox name changed to',oxName) if fuelName[-3:]=='(G)': fuelName = 'G' + fuelName[:-3] if self.make_debug_prints: print('Fuel name changed to',fuelName) if propName[-3:]=='(G)': propName = 'G' + propName[:-3] if self.make_debug_prints: print('Propellant name changed to',propName)
# may want to interpolate tables of CEA runs for speed self.useFastLookup = useFastLookup
self.readDatafileOnce = 0
#check for propellant (mono or solid) vs. fuel and ox self.cea_deck = ["reac"] self.desc = '' self.useMR = 1 self.propName = propName if len(propName)>0: # can be in propCards, fuelCards, or oxCards if propName in propCards: self.cea_deck.append( propCards[ propName ] ) self.desc += ' ' + propName
elif is_HYD_Ammonia_Blend( propName ): #HYD40 will be caught above addHYD_AmmoniaBlend( propName, self.cea_deck ) # e.g. HYD30, HYD25.5 self.desc += propName
elif propName in fuelCards: tempList = fuelCards[ propName ] if type(tempList) == type(''): tempList = [tempList]
propList = [] for p in tempList: propList.append( p.replace(' fuel ',' name ' ) )
self.cea_deck.append( propList ) self.desc += ' ' + propName if self.make_debug_prints: print("fuel Cards converted into prop Cards") for card in self.cea_deck: if type(card) == type(''): print(card) else: for c in card: print(c) elif propName in oxCards: tempList = oxCards[ propName ] if type(tempList) == type(''): tempList = [tempList]
propList = [] for p in tempList: propList.append( p.replace(' oxid ',' name ' ) )
self.cea_deck.append( propList ) self.desc += ' ' + propName if self.make_debug_prints: print("ox Cards converted into prop Cards") for card in self.cea_deck: if type(card) == type(''): print(card) else: for c in card: print(c) else: print('ERROR... bad propellant name (%s) in cea_obj.py'%propName)
self.useMR = 0
#check for fuel self.fuelName = fuelName if len(fuelName)>0: if fuelName in fuelCards: self.cea_deck.append( fuelCards[ fuelName ] ) self.desc += fuelName
elif isAnMMH_N2H4_Blend( fuelName ): #M20 will be caught above addMMH_N2H4_Blend( fuelName, self.cea_deck ) # e.g. M10, M15, M23.789 self.desc += fuelName
else: print('ERROR... bad fuel name (%s) in cea_obj.py'%fuelName) raise Exception('ERROR... bad fuel name (%s) in cea_obj.py'%fuelName)
#check for oxidizer self.oxName = oxName if len(oxName)>0: if oxName in oxCards: self.cea_deck.append( oxCards[ oxName ] ) self.desc = oxName + ' / ' + self.desc
elif isAPeroxide_Blend( oxName ): addPeroxideBlend( oxName, self.cea_deck ) self.desc = oxName + ' / ' + self.desc
elif isMON_Ox_Blend( oxName ): addMON_Blend(oxName, self.cea_deck) self.desc = oxName + ' / ' + self.desc
elif isFLOX_Ox_Blend( oxName ): addFLOX_Blend( oxName, self.cea_deck ) self.desc = oxName + ' / ' + self.desc
else: print('ERROR... bad oxidizer name (%s) in cea_obj.py'%oxName) raise Exception('ERROR... bad oxidizer name (%s) in cea_obj.py'%oxName)
if self.fac_CR is not None: self.desc += ' CR=%g'%self.fac_CR
#thisPath = py_cea.__file__ #print('py_cea.__file__ =' + py_cea.__file__) #print('here =' + here) #dataPath = os.path.dirname( thisPath ) #sp = dataPath.split('\\') #dataPath = '/'.join( sp ) + '/ ' # be sure to leave extra space self.pathPrefix = here + os.sep + ' ' # be sure to leave extra space # dataPath #self.pathPrefix = self.pathPrefix.replace('\\','/') #print( "self.pathPrefix",self.pathPrefix )
# make a cache object for this propellant combo if it does not already exist try: cacheObj = _CacheObjDict[ self.desc ] except: _CacheObjDict[ self.desc ] = CEA_Cache(maxCache=10000, propName=self.desc )
#print( self.cea_deck ) if self.useFastLookup: if self.useMR : self.fastModuleName = "cea_fit_" + self.oxName.replace('-','_') + '_' + self.fuelName.replace('-','_') else: self.fastModuleName = "cea_fit_" + self.propName.replace('-','_') fp = None try: pathList = [os.path.dirname( os.path.abspath(sys.argv[0])[:] ), self.pathPrefix[:-1]] #print( 'pathList',pathList ) fp, pathname, description = imp.find_module(self.fastModuleName, pathList) self.fastModule = imp.load_module(self.fastModuleName, fp, pathname, description) except: # Since we may exit via an exception, close fp explicitly. self.useFastLookup = 0 print("WARNING... Fast Module",self.fastModuleName,"failed to load") print(" Will call CEA code instead (slower but more accurate)") print(traceback.print_exc()) if fp: fp.close()
def setupCards(self, Pc=100.0, MR=1.0, eps=40.0, subar=None, PcOvPe=None, frozen=0, ERphi=None, ERr=None, frozenAtThroat=0, short_output=0, show_transport=0, pc_units='psia', output='calories', show_mass_frac=False): ''' Set up card deck and call CEA FORTRAN code.::
#: Pc = combustion end pressure (psia) #: eps = Nozzle Expansion Area Ratio #: if PcOvPe has a value, use it instead of eps to run case #: ERphi = Equivalence ratios in terms of fuel-to-oxidant weight ratios. #: ERr = Chemical equivalence ratios in terms of valences. #: pc_units = 'psia', 'bar', 'atm', 'mmh'(mm of mercury) #: frozen flag (0=equilibrium, 1=frozen) #: frozenAtThroat flag, 0=frozen in chamber, 1=frozen at throat '''
global _last_called, _NLines_Max_ever
N = 1 for line in self.cea_deck: if type(line) == type("str"): set_py_cea_line(N, line) N += 1 else: # might be a list of strings for ln in line: set_py_cea_line(N, ln) N += 1
set_py_cea_line(N," ") N += 1
#if self.desc==self.oxName + ' / ' + self.fuelName: # temp_prop_case = self.oxName + '_/_' + self.fuelName #else: # temp_prop_case = self.desc temp_prop_case='RocketCEA'
set_py_cea_line(N,"prob case="+temp_prop_case+", ") #set_py_cea_line(N,"prob case="+self.desc+" ")
N += 1 #print( "prob case="+self.desc+" " )
if frozen: if frozenAtThroat: if self.fac_CR is not None: eqfrStr = 'frozen nfz=3 ' # nfz=3 for fac run else: eqfrStr = 'frozen nfz=2 ' # nfz=2 is throat, nfz=1 is chamber else: eqfrStr = 'frozen nfz=1 ' # nfz=1 is chamber else: eqfrStr = 'equilibrium'
# ======================== make input strings for single or multiple values ================== # i.e. get_full_cea_output may input lists for eps, PcOvPe, Pc, MR, or subar
def make_inp_str( param=' supar=', val=1.0 ): """allow number, list or None. Return empty string for error or None.""" if val is None: return '' try: rtn_str = param + '%f, '%val #e.g. " supar=%f, "%eps return rtn_str except: pass try: # e.g. " supar=%s, "% ','.join( ['%g'%v for v in eps] ) rtn_str = param + '%s, '%','.join( ['%g'%v for v in val] ) except: rtn_str = ''
return rtn_str
# ------------ Eps String ------------ eps_str = make_inp_str( " supar=", eps )
# ------------ Pc String ------------- pc_str = make_inp_str( " p,%s="%pc_units, Pc )
# ------------ Subsonic Area Ration String ---------- subar_str = make_inp_str( " subar=", subar )
# ------------ Pc/Pe String ------------- pcope_str = make_inp_str( " pi/p=", PcOvPe )
# ------------------------------------------------ # set up rocket line with Pc, PC/Pe and Epsilon set_py_cea_line(N," rocket %s %s"%(eqfrStr,pc_str) + subar_str + pcope_str + eps_str )
# ------------ Finite Area Combustor String ------
#print('In setupCards, fac_CR =', self.fac_CR) if self.fac_CR is not None: N += 1 fac_str = ' fac ' + make_inp_str(" ac/at=", self.fac_CR )
set_py_cea_line(N, fac_str )
self.i_injface = 0 self.i_chm = 1 self.i_thrt = 2 self.i_exit = 3 else: self.i_injface = 0 self.i_chm = 0 self.i_thrt = 1 self.i_exit = 2
N += 1
if self.useMR : if ERphi != None: # use ER,phi as an input instead of MR # phi = Equivalence ratios in terms of fuel-to-oxidant weight ratios set_py_cea_line(N,"phi,eq.ratio=%f"%ERphi+" ") N += 1 elif ERr != None: # use ER,r as an input instead of MR # r = Chemical equivalence ratios in terms of valences set_py_cea_line(N,"r,eq.ratio=%f"%ERr+" ") N += 1 else: # use MR as input
# ------------ Mixture Ratio String ------------- mr_str = make_inp_str(" o/f=", MR)
set_py_cea_line(N, mr_str) N += 1 else: set_py_cea_line(N," ") N += 1
for i_line,line in enumerate([" "," "," ","end "]): if i_line == 2: line = 'output %s '%output if short_output: line += " short " if show_transport: line += " transport " if show_mass_frac: line += " massf "
set_py_cea_line(N,line) N += 1
# make sure to overwrite any lines from previous calls if N>_NLines_Max_ever: _NLines_Max_ever=N if _NLines_Max_ever>N: while N<_NLines_Max_ever: set_py_cea_line(N," ") N += 1
# now call CEA myfile = "f.inp " # be sure to leave extra space at end
readData = 1 if (self is _last_called): readData = 0
try: if self.readDatafileOnce and (self.desc==_last_called.desc): readData = 0 except: print("ERROR reading data file for",self.desc)
if readData: _last_called = self self.readDatafileOnce = 1 if self.desc in _PrintCountDict: _PrintCountDict[self.desc] = _PrintCountDict[self.desc] + 1 if _PrintCountDict[self.desc] % 100 == 0: print("reading cea isp data files for",self.desc,_PrintCountDict[self.desc],'times') else: #print("reading cea isp data files for",self.desc) _PrintCountDict[self.desc] = 1
if self.make_debug_prints: if self.makeOutput: print("NOTICE... making an output file")
# Before calling CEA, init values to zero so bad run can be detected py_cea.rockt.vaci[ self.i_thrt ] = 0.0 # Vacuum Isp at throat py_cea.rockt.vaci[ self.i_exit ] = 0.0 # Vacuum Isp at exit py_cea.rockt.cstr = 0.0 # cstar py_cea.prtout.ttt[ self.i_chm ] = 0.0 # chamber temperature py_cea.rockt.app[ self.i_thrt ] = 0.0 # Pc/Pt py_cea.rockt.app[ self.i_exit ] = 0.0 # Pc/Pe py_cea.rockt.aeat[ self.i_exit ] = 0.0 # exit area/throat area py_cea.rockt.vmoc[ self.i_exit ] = 0.0 py_cea.miscr.eqrat = 0.0 # equivalence ratio
for i in range(3): py_cea.rockt.sonvel[i] = 0.0 py_cea.prtout.hsum[i] = 0.0 py_cea.prtout.wm[i] = 0.0 py_cea.prtout.gammas[i] = 0.0 py_cea.prtout.vlm[i] = 0.0 py_cea.prtout.cpr[i] = 0.0
py_cea.trpts.vis[i] = 0.0 # viscosity py_cea.trpts.cpeql[i] = 0.0 # equilibrium specific heat py_cea.trpts.coneql[i] = 0.0 # equilibrium thermal conductivity py_cea.trpts.preql[i] = 0.0 # equilibrium prandtl number py_cea.trpts.cpfro[i] = 0.0 # frozen specific heat py_cea.trpts.confro[i] = 0.0 # frozen thermal conductivity py_cea.trpts.prfro[i] = 0.0 # frozen prandtl number
# set species concentrations to 0.0 prior to calcs #for k,p in enumerate(py_cea.cdata.prod): # for i in range(3): # py_cea.comp.en[k-1,i] = 0.0 # py_cea.therm.mw[k-1] = 0.0 # if k>=50: # break
#print( 'calling py_cea with pathPrefix and myfile=' ) #print( '"'+self.pathPrefix+'"',' and ', '"'+myfile+'"' ) py_cea.py_cea(self.pathPrefix, myfile, self.makeOutput, readData)
def get_full_cea_output(self, Pc=100.0, MR=1.0, eps=40.0, subar=None, PcOvPe=None, frozen=0, frozenAtThroat=0, short_output=0, show_transport=1, pc_units='psia', output='calories', show_mass_frac=False, fac_CR=None): """ Get the full output file created by CEA. Return as a string.::
#: Pc = combustion end pressure #: eps = Nozzle Expansion Area Ratio #: pc_units = 'psia', 'bar', 'atm', 'mmh'(mm of mercury) #: frozen = flag (0=equilibrium, 1=frozen) #: frozenAtThroat = flag 0=frozen in chamber, 1=frozen at throat #: fac_CR = Contraction Ratio of finite area combustor, (None=infinite) """
# regardless of how run was set up, change makeOutput flag True save_flag = self.makeOutput self.makeOutput = True
# Allow user to override fac_CR from CEA_Obj __init__ save_fac_CR = self.fac_CR if fac_CR is not None: self.fac_CR = fac_CR
self.setupCards( Pc=Pc, MR=MR, eps=eps, subar=subar, PcOvPe=PcOvPe, frozen=frozen, frozenAtThroat=frozenAtThroat, short_output=short_output, show_transport=show_transport, pc_units=pc_units, output=output, show_mass_frac=show_mass_frac)
self.makeOutput = save_flag # restore makeOutput self.fac_CR = save_fac_CR # restore fac_CR
return open( os.path.join(here,'f.out'),'r').read()
def get_Pinj_over_Pcomb(self, Pc=100.0, MR=1.0, fac_CR=None): """ Get the full output file created by CEA. Return as a string.::
#: Pc = combustion end pressure (psia) #: fac_CR = Contraction Ratio of finite area combustor, (None=infinite) """
# Allow user to override fac_CR from CEA_Obj __init__ save_fac_CR = self.fac_CR if fac_CR is not None: self.fac_CR = fac_CR
if self.fac_CR is None: print('ERROR in get_Pinj_over_Pcomb... Need value for fac_CR') raise Exception('ERROR in get_Pinj_over_Pcomb... Need value for fac_CR')
self.setupCards( Pc=Pc, MR=MR )
self.fac_CR = save_fac_CR # restore fac_CR
Pinj_over_Pcomb = py_cea.prtout.ppp[0] / py_cea.prtout.ppp[1]
return Pinj_over_Pcomb
def __call__(self, Pc=100.0, MR=1.0, eps=40.0): """Returns IspVac(sec) if CEA_Obj is simply called like a function.""" if self.useFastLookup: isp = self.fastModule.get_isp(Pc, eps, MR) return isp else: return self.get_Isp(Pc=Pc, MR=MR, eps=eps)
def get_IvacCstrTc(self, Pc=100.0, MR=1.0, eps=40.0): """::
#: Return the tuple (IspVac, Cstar, Tcomb)in(sec, ft/sec, degR) #: Pc = combustion end pressure (psia) #: eps = Nozzle Expansion Area Ratio #: MR is only used for ox/fuel combos. """ if self.useFastLookup: isp,cstr,tc = self.fastModule.get_ivaccstrtc(Pc, eps, MR) return isp,cstr,tc else:
#cacheDesc1 = '%g|%g|%g'%(Pc,MR,eps) # %g only shows 6 sig digits cacheDesc1 = (Pc,MR,eps) try: IspVac = _CacheObjDict[ self.desc ].getIsp( cacheDesc1 ) except: IspVac = None
# don't bother looking at Cstar and Tc if there's no Isp #cacheDesc2 = '%g|%g'%(Pc,MR) # %g only shows 6 sig digits cacheDesc2 = (Pc,MR) if IspVac: try: Cstar = _CacheObjDict[ self.desc ].getCstar( cacheDesc2 ) TcK = _CacheObjDict[ self.desc ].getTcK( cacheDesc2 ) except: Cstar = None TcK = None if Cstar and TcK: Tcomb = TcK * 1.8 # convert from Kelvin to Rankine return IspVac, Cstar, Tcomb
self.setupCards( Pc=Pc, MR=MR, eps=eps)
#print( "py_cea.rockt.vaci",py_cea.rockt.vaci ) IspVac = py_cea.rockt.vaci[ self.i_exit ] #print('py_cea.rockt.cstr',py_cea.rockt.cstr) #print( 'py_cea.rockt.app', py_cea.rockt.app ) Cstar = float(py_cea.rockt.cstr)
#print( "py_cea.prtout.ttt",py_cea.prtout.ttt ) TcK = py_cea.prtout.ttt[ self.i_chm ] Tcomb = TcK * 1.8 # convert from Kelvin to Rankine _CacheObjDict[ self.desc ].setIsp( cacheDesc1, IspVac ) _CacheObjDict[ self.desc ].setCstar( cacheDesc2, Cstar ) _CacheObjDict[ self.desc ].setTcK( cacheDesc2, TcK ) return IspVac, Cstar, Tcomb
def getFrozen_IvacCstrTc(self, Pc=100.0, MR=1.0, eps=40.0, frozenAtThroat=0): """::
#: Return the tuple (IspFrozen, Cstar, Tcomb)in(sec, ft/sec, degR) #: Pc = combustion end pressure (psia) #: eps = Nozzle Expansion Area Ratio #: MR is only used for ox/fuel combos. #: frozenAtThroat flag, 0=frozen in chamber, 1=frozen at throat """
self.setupCards( Pc=Pc, MR=MR, eps=eps, frozen=1, frozenAtThroat=frozenAtThroat) IspFrozen = py_cea.rockt.vaci[ self.i_exit ] Cstar = float(py_cea.rockt.cstr) TcK = py_cea.prtout.ttt[ self.i_chm ] Tcomb = TcK * 1.8 # convert from Kelvin to Rankine return IspFrozen, Cstar, Tcomb
def get_IvacCstrTc_exitMwGam(self, Pc=100.0, MR=1.0, eps=40.0): """::
#: return the tuple (IspVac, Cstar, Tcomb, mw, gam)in(sec, ft/sec, degR, lbm/lbmole, -) #: Pc = combustion end pressure (psia) #: eps = Nozzle Expansion Area Ratio #: mw and gam apply to nozzle exit. #: MR is only used for ox/fuel combos. """
self.setupCards( Pc=Pc, MR=MR, eps=eps)
#print( "py_cea.rockt.vaci",py_cea.rockt.vaci ) IspVac = py_cea.rockt.vaci[ self.i_exit ] Cstar = float(py_cea.rockt.cstr) Tcomb = py_cea.prtout.ttt[ self.i_chm ] * 1.8 # convert from Kelvin to Rankine mw,gam = py_cea.prtout.wm[ self.i_exit ], py_cea.prtout.gammas[ self.i_exit ]
return IspVac, Cstar, Tcomb, mw, gam
def get_IvacCstrTc_ChmMwGam(self, Pc=100.0, MR=1.0, eps=40.0): """::
#: return the tuple (IspVac, Cstar, Tcomb, mw, gam)in(sec, ft/sec, degR, lbm/lbmole, -) #: Pc = combustion end pressure (psia) #: eps = Nozzle Expansion Area Ratio #: mw and gam apply to chamber. #: MR is only used for ox/fuel combos. """
self.setupCards( Pc=Pc, MR=MR, eps=eps)
#print( "py_cea.rockt.vaci",py_cea.rockt.vaci ) IspVac = py_cea.rockt.vaci[ self.i_exit ] Cstar = float(py_cea.rockt.cstr) Tcomb = py_cea.prtout.ttt[ self.i_chm ] * 1.8 # convert from Kelvin to Rankine mw,gam = py_cea.prtout.wm[ self.i_chm ], py_cea.prtout.gammas[ self.i_chm ]
return IspVac, Cstar, Tcomb, mw, gam
def get_IvacCstrTc_ThtMwGam(self, Pc=100.0, MR=1.0, eps=40.0): """::
#: return the tuple (IspVac, Cstar, Tcomb, mw, gam)in(sec, ft/sec, degR, lbm/lbmole, -) #: Pc = combustion end pressure (psia) #: eps = Nozzle Expansion Area Ratio #: mw and gam apply to throat. #: MR is only used for ox/fuel combos. """
self.setupCards( Pc=Pc, MR=MR, eps=eps)
#print( "py_cea.rockt.vaci",py_cea.rockt.vaci ) IspVac = py_cea.rockt.vaci[ self.i_exit ] Cstar = float(py_cea.rockt.cstr) Tcomb = py_cea.prtout.ttt[ self.i_chm ] * 1.8 # convert from Kelvin to Rankine mw,gam = py_cea.prtout.wm[ self.i_thrt ], py_cea.prtout.gammas[ self.i_thrt ]
return IspVac, Cstar, Tcomb, mw, gam
def get_Isp(self, Pc=100.0, MR=1.0, eps=40.0): """::
#: return IspVac (sec) #: Pc = combustion end pressure (psia) #: eps = Nozzle Expansion Area Ratio #: MR is only used for ox/fuel combos. """ if self.useFastLookup: isp = self.fastModule.get_isp(Pc, eps, MR) return isp else: #cacheDesc1 = '%g|%g|%g'%(Pc,MR,eps) # %g only shows 6 sig digits cacheDesc1 = (Pc,MR,eps) try: IspVac = _CacheObjDict[ self.desc ].getIsp( cacheDesc1 ) except: IspVac = None if IspVac: return IspVac
self.setupCards( Pc=Pc, MR=MR, eps=eps)
IspVac = py_cea.rockt.vaci[ self.i_exit ] _CacheObjDict[ self.desc ].setIsp( cacheDesc1, IspVac ) #print( 'py_cea.rockt.vaci',py_cea.rockt.vaci ) #print( 'py_cea.rockt.cstr',py_cea.rockt.cstr ) return IspVac
def get_Cstar(self, Pc=100.0, MR=1.0): """::
#: return Cstar (ft/sec) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. """ if self.useFastLookup: Cstar = self.fastModule.get_cstar(Pc, MR) return Cstar else: #cacheDesc2 = '%g|%g'%(Pc,MR) # %g only shows 6 sig digits cacheDesc2 = (Pc,MR) try: Cstar = _CacheObjDict[ self.desc ].getCstar( cacheDesc2 ) except: Cstar = None if Cstar: return Cstar
self.setupCards( Pc=Pc, MR=MR, eps=2.0) Cstar = float(py_cea.rockt.cstr) _CacheObjDict[ self.desc ].setCstar( cacheDesc2, Cstar ) return Cstar
def get_Tcomb(self, Pc=100.0, MR=1.0): """::
#: return Tcomb (degR) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. """ if self.useFastLookup: tc = self.fastModule.get_tcomb(Pc, MR) return tc else: #cacheDesc2 = '%g|%g'%(Pc,MR) # %g only shows 6 sig digits cacheDesc2 = (Pc,MR) try: TcK = _CacheObjDict[ self.desc ].getTcK( cacheDesc2 ) Tcomb = TcK * 1.8 # convert from Kelvin to Rankine except: TcK = None Tcomb = None if Tcomb: return Tcomb
self.setupCards( Pc=Pc, MR=MR, eps=2.0) TcK = py_cea.prtout.ttt[ self.i_chm ] Tcomb = TcK * 1.8 # convert from Kelvin to Rankine _CacheObjDict[ self.desc ].setTcK( cacheDesc2, TcK ) return Tcomb
def get_PcOvPe(self, Pc=100.0, MR=1.0, eps=40.0): """::
#: return Pc / Pexit. #: Pc = combustion end pressure (psia) #: eps = Nozzle Expansion Area Ratio #: MR is only used for ox/fuel combos. """ if self.useFastLookup: PcOvPe = self.fastModule.get_pcovpe(Pc, eps, MR) return PcOvPe else: self.setupCards( Pc=Pc, MR=MR, eps=eps) PcOvPe = py_cea.rockt.app[ self.i_exit ] if self.fac_CR is not None: PcOvPe = PcOvPe * py_cea.rockt.app[ self.i_chm ]
#print( 'py_cea.rockt.app',py_cea.rockt.app ) #Pexit = py_cea.prtout.ppp[ self.i_exit ]*14.7/1.01325 #return Pc/Pexit return PcOvPe
def get_eps_at_PcOvPe(self, Pc=100.0, MR=1.0, PcOvPe=1000.0): """::
#: Given a Pc/Pexit, return the Area Ratio that applies. #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. """ self.setupCards( Pc=Pc, MR=MR, PcOvPe=PcOvPe) eps = py_cea.rockt.aeat[ self.i_exit ] #print( 'py_cea.rockt.aeat',py_cea.rockt.aeat ) return eps
def get_Throat_PcOvPe(self, Pc=100.0, MR=1.0): """::
#: return Pc/Pexit at throat. #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. """ self.setupCards( Pc=Pc, MR=MR, eps=2.0) PcOvPe = py_cea.rockt.app[ self.i_thrt ] if self.fac_CR is not None: PcOvPe = PcOvPe * py_cea.rockt.app[ self.i_chm ] return PcOvPe
def get_MachNumber(self, Pc=100.0, MR=1.0, eps=40.0): """::
#: return nozzle exit mach number. #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio """ self.setupCards( Pc=Pc, MR=MR, eps=eps) M = py_cea.rockt.vmoc[ self.i_exit ] return M
def get_Chamber_MachNumber(self, Pc=100.0, MR=1.0, fac_CR=None): """::
#: Return mach numbers at the chamber #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: fac_CR = Contraction Ratio of finite area combustor, (None=infinite) """ # Allow user to override fac_CR from CEA_Obj __init__ save_fac_CR = self.fac_CR if fac_CR is not None: self.fac_CR = fac_CR
if self.fac_CR is None: print('ERROR in get_Chamber_MachNumber... Need value for fac_CR') raise Exception('ERROR in get_Chamber_MachNumber... Need value for fac_CR')
self.setupCards( Pc=Pc, MR=MR )
self.fac_CR = save_fac_CR # restore fac_CR
M = py_cea.rockt.vmoc[ 1 ] return M
def get_Temperatures(self, Pc=100.0, MR=1.0,eps=40.0, frozen=0, frozenAtThroat=0): """::
#: Return a list of temperatures at the chamber, throat and exit (degR) #: (Note frozen flag determins whether Texit is equilibrium or Frozen temperature) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio #: frozen flag (0=equilibrium, 1=frozen) #: frozenAtThroat flag, 0=frozen in chamber, 1=frozen at throat """ #self.setupCards( Pc=Pc, MR=MR, eps=eps) self.setupCards( Pc=Pc, MR=MR, eps=eps, frozen=frozen, frozenAtThroat=frozenAtThroat)
# convert from Kelvin to Rankine #tempList = 1.8 * py_cea.prtout.ttt[:3] if self.fac_CR is not None: tempList = list( py_cea.prtout.ttt[1:4] ) else: tempList = list( py_cea.prtout.ttt[:3] )
tempList = [1.8*T for T in tempList] return tempList # Tc, Tthroat, Texit
def get_SonicVelocities(self, Pc=100.0, MR=1.0,eps=40.0): """::
#: Return a list of sonic velocities at the chamber, throat and exit (ft/sec) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio """ self.setupCards( Pc=Pc, MR=MR, eps=eps) # convert from m/sec into ft/sec if self.fac_CR is not None: sonicList = list(py_cea.rockt.sonvel[1:4]) else: sonicList = list(py_cea.rockt.sonvel[:3])
sonicList = [v * 3.28083 for v in sonicList] return sonicList
def get_Chamber_SonicVel(self, Pc=100.0, MR=1.0, eps=40.0): """::
#: Return the sonic velocity in the chamber (ft/sec) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio """ sonicList = self.get_SonicVelocities( Pc=Pc, MR=MR, eps=eps) return sonicList[ 0 ] # 0 == self.i_chm here
def get_Entropies(self, Pc=100.0, MR=1.0,eps=40.0): """::
#: Return a list of entropies at the chamber, throat and exit CAL/(G)(K) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio """ self.setupCards( Pc=Pc, MR=MR, eps=eps)
if self.fac_CR is not None: sList = list(py_cea.prtout.ssum[1:4]) else: sList = list(py_cea.prtout.ssum[:3])
for i,s in enumerate( sList ): sList[i] = s * 8314.51 / 4184.0 # convert into CAL/(G)(K) return sList
def get_Enthalpies(self, Pc=100.0, MR=1.0,eps=40.0): """::
#: Return a list of enthalpies at the chamber, throat and exit (BTU/lbm) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio """ self.setupCards( Pc=Pc, MR=MR, eps=eps)
if self.fac_CR is not None: hList = list(py_cea.prtout.hsum[1:4]) else: hList = list(py_cea.prtout.hsum[:3])
for i,h in enumerate( hList ): hList[i] = h * 1.8 * 8314.51 / 4184.0 # convert into BTU/lbm return hList
def get_SpeciesMassFractions(self, Pc=100.0, MR=1.0,eps=40.0, frozen=0, frozenAtThroat=0, min_fraction=0.000005): """::
#: Returns species mass fractions at the injector face, chamber, throat and exit. #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio #: frozen flag (0=equilibrium, 1=frozen) #: frozenAtThroat flag, 0=frozen in chamber, 1=frozen at throat #: Returns 2 dictionaries #: molWtD dictionary: index=species: value=molecular weight #: massFracD dictionary: index=species: value=[massfrac_injface, massfrac_chm, massfrac_tht, massfrac_exit] """
self.setupCards( Pc=Pc, MR=MR, eps=eps, frozen=frozen, frozenAtThroat=frozenAtThroat)
massFracD = {} # index=species: value=[massfrac_chm, massfrac_tht, massfrac_exit] molWtD = {} # index=species: value=molecular weight
for k in range( py_cea.indx.ngc ): p = py_cea.cdata.prod[k] p = p.decode("utf-8").strip() if p: sL = [] mfL = [] gt_zero = False #for i in range(3): for i in [self.i_injface, self.i_chm, self.i_thrt, self.i_exit]: en = py_cea.comp.en[k-1,i] mw = py_cea.therm.mw[k-1]
mfL.append( en*mw ) if mfL[-1] >= min_fraction: # default = 0.000005 gt_zero = True
if gt_zero: if frozen: if frozenAtThroat: mfL = [ mfL[0], mfL[1], mfL[2], mfL[2] ] else: mfL = [ mfL[0] for _ in mfL ]
massFracD[p] = mfL molWtD[p] = mw
return molWtD, massFracD
def get_SpeciesMoleFractions(self, Pc=100.0, MR=1.0,eps=40.0, frozen=0, frozenAtThroat=0, min_fraction=0.000005): """::
#: Returns species mole fractions at the injector face, chamber, throat and exit. #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio #: frozen flag (0=equilibrium, 1=frozen) #: frozenAtThroat flag, 0=frozen in chamber, 1=frozen at throat #: Returns 2 dictionaries #: molWtD dictionary: index=species: value=molecular weight #: moleFracD dictionary: index=species: value=[molefrac_injface, molefrac_chm, molefrac_tht, molefrac_exit] """
self.setupCards( Pc=Pc, MR=MR, eps=eps, frozen=frozen, frozenAtThroat=frozenAtThroat)
moleFracD = {} # index=species: value=[molefrac_chm, molefrac_tht, molefrac_exit] molWtD = {} # index=species: value=molecular weight
for k in range( py_cea.indx.ngc ): p = py_cea.cdata.prod[k] p = p.decode("utf-8").strip() if p: sL = [] mfL = [] gt_zero = False #for i in range(3): for i in [self.i_injface, self.i_chm, self.i_thrt, self.i_exit]: en = py_cea.comp.en[k-1,i] totn = py_cea.prtout.totn[i] mw = py_cea.therm.mw[k-1]
mfL.append( en/totn ) if mfL[-1] >= min_fraction: # default = 0.000005 gt_zero = True
if gt_zero: if frozen: if frozenAtThroat: mfL = [ mfL[0], mfL[1], mfL[2], mfL[2] ] else: mfL = [ mfL[0] for _ in mfL ]
moleFracD[p] = mfL molWtD[p] = mw return molWtD, moleFracD
def get_Chamber_H(self, Pc=100.0, MR=1.0, eps=40.0): """::
#: Return the enthalpy in the chamber (BTU/lbm) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio """ hList = self.get_Enthalpies( Pc=Pc, MR=MR, eps=eps) return hList[ 0 ] # BTU/lbm # 0 == self.i_chm here
def get_Densities(self, Pc=100.0, MR=1.0,eps=40.0): """::
#: Return a list of densities at the chamber, throat and exit(lbm/cuft) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio """ self.setupCards( Pc=Pc, MR=MR, eps=eps)
if self.fac_CR is not None: dList = list(py_cea.prtout.vlm[1:4]) else: dList = list(py_cea.prtout.vlm[:3])
for i,v in enumerate( dList ): dList[i] = 62.42796 * 100.0 / v # convert into lbm/cuft return dList
def get_Chamber_Density(self, Pc=100.0, MR=1.0, eps=40.0): """::
#: Return the density in the chamber(lbm/cuft) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio """ dList = self.get_Densities( Pc=Pc, MR=MR, eps=eps) return dList[ 0 ] # lbm/cuft # 0 == self.i_chm here
def get_HeatCapacities(self, Pc=100.0, MR=1.0,eps=40.0, frozen=0): """::
#: Return a list of heat capacities at the chamber, throat and exit(BTU/lbm degR) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio #: frozen flag (0=equilibrium, 1=frozen) """ self.setupCards( Pc=Pc, MR=MR, eps=eps, frozen=frozen) # convert from m/sec into ft/sec if self.fac_CR is not None: cpList = list(py_cea.prtout.cpr[1:4]) else: cpList = list(py_cea.prtout.cpr[:3])
for i,cp in enumerate( cpList ): cpList[i] = cp * 8314.51 / 4184.0 # convert into BTU/lbm degR (aka cal/gm K) return cpList
def get_Chamber_Cp(self, Pc=100.0, MR=1.0, eps=40.0, frozen=0): """::
#: Return the heat capacity in the chamber(BTU/lbm degR) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio #: frozen flag (0=equilibrium, 1=frozen) """ cpList = self.get_HeatCapacities( Pc=Pc, MR=MR, eps=eps, frozen=frozen) return cpList[ 0 ] # BTU/lbm degR # 0 == self.i_chm here
def get_Throat_Isp(self, Pc=100.0, MR=1.0): """::
#: Return the IspVac for the throat(sec). #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. """ eps=1.0 cacheDesc1 = (Pc,MR,eps) try: IspVac = _CacheObjDict[ self.desc ].getIsp( cacheDesc1 ) except: IspVac = None if IspVac: return IspVac
self.setupCards( Pc=Pc, MR=MR, eps=2.0)
IspVac = py_cea.rockt.vaci[ self.i_thrt ] _CacheObjDict[ self.desc ].setIsp( cacheDesc1, IspVac ) #print( 'py_cea.rockt.vaci',py_cea.rockt.vaci ) #print( 'py_cea.rockt.cstr',py_cea.rockt.cstr ) return IspVac
def get_Chamber_MolWt_gamma(self, Pc=100.0, MR=1.0, eps=40.0): """::
#: return the tuple (mw, gam) for the chamber (lbm/lbmole, -) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio """ #common /prtout/ cpr,dlvpt,dlvtp,gammas,hsum,ppp,ssum,totn,ttt,vlm,wm,pltout self.setupCards( Pc=Pc, MR=MR, eps=eps)
mw,gam = py_cea.prtout.wm[ self.i_chm ], py_cea.prtout.gammas[ self.i_chm ] return mw,gam
def get_Throat_MolWt_gamma(self, Pc=100.0, MR=1.0, eps=40.0): """::
#: return the tuple (mw, gam) for the throat (lbm/lbmole, -) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio """ #common /prtout/ cpr,dlvpt,dlvtp,gammas,hsum,ppp,ssum,totn,ttt,vlm,wm,pltout self.setupCards( Pc=Pc, MR=MR, eps=eps)
mw,gam = py_cea.prtout.wm[ self.i_thrt ], py_cea.prtout.gammas[ self.i_thrt ] return mw,gam
def get_exit_MolWt_gamma(self, Pc=100.0, MR=1.0, eps=40.0): """::
#: return the tuple (mw, gam) for the nozzle exit (lbm/lbmole, -) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio """ #common /prtout/ cpr,dlvpt,dlvtp,gammas,hsum,ppp,ssum,totn,ttt,vlm,wm,pltout self.setupCards( Pc=Pc, MR=MR, eps=eps)
mw,gam = py_cea.prtout.wm[ self.i_exit ], py_cea.prtout.gammas[ self.i_exit ] return mw,gam
def get_eqratio(self, Pc=100.0, MR=1.0, eps=40.0): '''Returns BOTH ERr and ERphi (valence basis and mass basis respectively)''' #common /miscr/ a,atwt,avgdr,boltz,b0,eqrat,... self.setupCards( Pc=Pc, MR=MR, eps=eps)
ERr = py_cea.miscr.eqrat try: # the logic below is lifted directly from the CEA FORTRAN source code tem = (py_cea.inpt.vpls[ self.i_chm ]+py_cea.inpt.vmin[ self.i_chm ])*py_cea.miscr.oxfl ERphi = -(py_cea.inpt.vmin[ self.i_thrt ]+py_cea.inpt.vpls[ self.i_thrt ])/tem except: ERphi = 0.0
return float(ERr), float(ERphi)
def getMRforER(self, ERphi=None, ERr=None): """::
#: return the value of mixture ratio that applies to the input equivalence ratio. #: Can be ERr or ERphi (valence basis and mass basis respectively) """ #common /miscr/ a,atwt,avgdr,boltz,b0,eqrat,...
if ERphi != None: self.setupCards( Pc=100.0, ERphi=ERphi, eps=40.0 ) MR = py_cea.miscr.oxfl elif ERr != None: self.setupCards( Pc=100.0, ERr=ERr, eps=40.0 ) MR = py_cea.miscr.oxfl else: print('WARNING... ERROR in call to getMRforER. No ER value input') MR = 0.0 #ERROR
#self.setupCards( Pc=100.0, MR=1.0, eps=40.0 ) # fix any mismatches in system from ER call return float(MR)
def get_description(self): """Return a string description of the propellant(s). e.g. 'LOX / MMH'""" return str(self.desc)
def estimate_Ambient_Isp(self, Pc=100.0, MR=1.0, eps=40.0, Pamb=14.7, frozen=0, frozenAtThroat=0): """::
#: return the tuple (IspAmb, mode) #: Use throat gam to run ideal separation calculations. #: mode is a string containing, UnderExpanded, OverExpanded, or Separated #: Pc = combustion end pressure (psia) #: Pamb ambient pressure (e.g. sea level=14.7 psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio #: frozen flag, 0=equilibrium, 1=frozen #: frozenAtThroat flag, 0=frozen in chamber, 1=frozen at throat """
self.setupCards( Pc=Pc, MR=MR, eps=eps, frozen=frozen, frozenAtThroat=frozenAtThroat)
IspVac = py_cea.rockt.vaci[ self.i_exit ] mw,gam = py_cea.prtout.wm[ self.i_thrt ], py_cea.prtout.gammas[ self.i_thrt ] # throat gamma #PcOvPe = py_cea.rockt.app[ self.i_exit ] Pexit = py_cea.prtout.ppp[ self.i_exit ]*14.7/1.01325 #print( "=============== Pexit ", Pexit, py_cea.prtout.ppp[ self.i_exit ]/1.01325, py_cea.prtout.ppp[ self.i_exit ] ) Cstar = float(py_cea.rockt.cstr) # ==================================
CfOvCfvacAtEsep, CfOvCfvac, Cfsep, CfiVac, CfiAmbSimple, CfVac, epsSep, Psep = \ sepNozzleCf(gam, eps, Pc, Pamb)
if Pexit > Psep: # if not separated, use theoretical equation for back-pressure correction IspAmb = IspVac - Cstar*Pamb*eps/Pc/32.174 CfAmb = IspAmb * 32.174 / Cstar else: # if separated, use Kalt and Badal estimate of ambient thrust coefficient # NOTE: there are better, more modern methods available IspODEepsSep,CstarODE,Tc = \ self.get_IvacCstrTc(Pc=Pc, MR=MR, eps=epsSep)
CfvacAtEsep = CfVac * IspODEepsSep / IspVac
CfAmb = CfvacAtEsep * CfOvCfvacAtEsep IspAmb = CfAmb * Cstar / 32.174
# figure out mode of nozzle operation if Pexit > Psep: if Pexit > Pamb + 0.05: mode = 'UnderExpanded (Pe=%g)'%Pexit elif Pexit < Pamb - 0.05: mode = 'OverExpanded (Pe=%g)'%Pexit else: mode = 'Pexit = %g'%Pexit else: mode = 'Separated (Psep=%g, epsSep=%g)'%(Psep,epsSep)
return IspAmb, mode
def get_PambCf(self, Pamb=14.7, Pc=100.0, MR=1.0, eps=40.0): """::
#: Return the Thrust Coefficient (CF) for equilibrium chemistry and ambient pressure #: Pc = combustion end pressure (psia) #: Pamb ambient pressure (e.g. sea level=14.7 psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio """
IspAmb, mode = self.estimate_Ambient_Isp( Pc=Pc, MR=MR, eps=eps, Pamb=Pamb) Cstar = float(py_cea.rockt.cstr)
CFamb = GC * IspAmb / Cstar CFcea = GC * float(py_cea.rockt.spim[ self.i_exit ]) / Cstar
return CFcea, CFamb, mode
def getFrozen_PambCf(self, Pamb=0.0, Pc=100.0, MR=1.0, eps=40.0, frozenAtThroat=0): """::
#: Return the Thrust Coefficient (CF) for frozen chemistry and ambient pressure #: Pc = combustion end pressure (psia) #: Pamb ambient pressure (e.g. sea level=14.7 psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio #: frozenAtThroat flag, 0=frozen in chamber, 1=frozen at throat """
IspAmb, mode = self.estimate_Ambient_Isp( Pc=Pc, MR=MR, eps=eps, Pamb=Pamb, frozen=1, frozenAtThroat=frozenAtThroat) Cstar = float(py_cea.rockt.cstr)
CFfrozen = GC * IspAmb / Cstar CFcea = GC * float(py_cea.rockt.spim[ self.i_exit ]) / Cstar
return CFcea,CFfrozen, mode
def get_Chamber_Transport(self, Pc=100.0, MR=1.0, eps=40.0, frozen=0): """::
#: Return a list of heat capacity, viscosity, thermal conductivity and Prandtl number #: in the chamber. (units are default printout units) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio... has no effect on chamber properties #: frozen flag (0=equilibrium, 1=frozen) """ self.setupCards( Pc=Pc, MR=MR, eps=eps, show_transport=1)
if frozen: Cp = py_cea.trpts.cpfro[ self.i_chm ] visc = py_cea.trpts.vis[ self.i_chm ] cond = py_cea.trpts.confro[ self.i_chm ] Prandtl = py_cea.trpts.prfro[ self.i_chm ] else: Cp = py_cea.trpts.cpeql[ self.i_chm ] visc = py_cea.trpts.vis[ self.i_chm ] cond = py_cea.trpts.coneql[ self.i_chm ] Prandtl = py_cea.trpts.preql[ self.i_chm ]
return Cp, visc, cond, Prandtl
def get_Throat_Transport(self, Pc=100.0, MR=1.0, eps=40.0, frozen=0): """::
#: Return a list of heat capacity, viscosity, thermal conductivity and Prandtl number #: in the throat. (units are default printout units) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio... has no effect on throat properties #: frozen flag (0=equilibrium, 1=frozen) """ self.setupCards( Pc=Pc, MR=MR, eps=eps, show_transport=1)
if frozen: Cp = py_cea.trpts.cpfro[ self.i_thrt ] visc = py_cea.trpts.vis[ self.i_thrt ] cond = py_cea.trpts.confro[ self.i_thrt ] Prandtl = py_cea.trpts.prfro[ self.i_thrt ] else: Cp = py_cea.trpts.cpeql[ self.i_thrt ] visc = py_cea.trpts.vis[ self.i_thrt ] cond = py_cea.trpts.coneql[ self.i_thrt ] Prandtl = py_cea.trpts.preql[ self.i_thrt ]
return Cp, visc, cond, Prandtl
def get_Exit_Transport(self, Pc=100.0, MR=1.0, eps=40.0, frozen=0): """::
#: Return a list of heat capacity, viscosity, thermal conductivity and Prandtl number #: at the exit. (units are default printout units) #: Pc = combustion end pressure (psia) #: MR is only used for ox/fuel combos. #: eps = Nozzle Expansion Area Ratio #: frozen flag (0=equilibrium, 1=frozen) """ self.setupCards( Pc=Pc, MR=MR, eps=eps, show_transport=1)
if frozen: Cp = py_cea.trpts.cpfro[ self.i_exit ] visc = py_cea.trpts.vis[ self.i_exit ] cond = py_cea.trpts.confro[ self.i_exit ] Prandtl = py_cea.trpts.prfro[ self.i_exit ] else: Cp = py_cea.trpts.cpeql[ self.i_exit ] visc = py_cea.trpts.vis[ self.i_exit ] cond = py_cea.trpts.coneql[ self.i_exit ] Prandtl = py_cea.trpts.preql[ self.i_exit ]
return Cp, visc, cond, Prandtl
# ----------------------- DEBUG OUTPUT ----------------------------- def print_py_cea_vars(): """ Print all the interface variables to the FORTRAN pyd file. Normally used for debugging or verifying FORTRAN internal values. """ commonL = dir(py_cea) for common in commonL: if common[:1] != '_': print(common) vL = dir( getattr(py_cea,common) ) print(vL) for v in vL: var = getattr( getattr(py_cea,common), v) print(v,var) print()
if __name__ == '__main__':
from pylab import *
if 0: #ispNew = CEA_Obj(oxName="O2(g)", fuelName="Ethanol", useFastLookup=1) ispNew = CEA_Obj(oxName="GOX", fuelName="GCH4", useFastLookup=0) Pc = 1000.0 mr = 1.05 i,c,t = ispNew.get_IvacCstrTc(Pc,mr,25.0) print('=========================================') print('for ',ispNew.desc) print('MR = ',mr) print('Isp = ',i) print('Cstar = ',c) print('Tcomb = ',t) print('=========================================')
for e in [ 50., 30.0, 20.0, 10.0]: ispArr = [] MR = 0.5 mrArr = [] while MR < 6.0: ispArr.append( ispNew(Pc, MR, e )) mrArr.append(MR) MR += 0.1 plot(mrArr, ispArr, label='eps %.1f'%e, linewidth=4)
legend(loc='best') grid(True) title( ispNew.desc ) xlabel( 'Mixture Ratio' ) ylabel( 'Isp (sec)' ) if not sys.argv[-1]=='suppress_show': show()
def showOutput( ispObj ): print() print(ispObj.desc,' at Pc=%.1f, MR=%.3f, eps=%.2f...'%(Pc,MR,eps)) i,c,t = ispObj.get_IvacCstrTc(Pc,MR,eps) print('Isp = ',i) print('Cstar = ',c) print('Tcomb = ',t) print(' at eps =',eps) PcOvPe = ispObj.get_PcOvPe(Pc=Pc, MR=MR, eps=eps) print('PcOvPe = ',PcOvPe) epsAtPcOvPe = ispObj.get_eps_at_PcOvPe(Pc=Pc, MR=MR, PcOvPe=PcOvPe) print('epsAtPcOvPe=',epsAtPcOvPe) print('Mach Number=',ispObj.get_MachNumber(Pc=Pc, MR=MR, eps=eps)) print() print('Chamber Sonic Vel =',ispObj.get_Chamber_SonicVel( Pc=Pc, MR=MR,eps=eps)) print('Enthalpies =',ispObj.get_Enthalpies( Pc=Pc, MR=MR,eps=eps)) print('Densities =',ispObj.get_Densities( Pc=Pc, MR=MR,eps=eps)) print('Cp =',ispObj.get_HeatCapacities( Pc=Pc, MR=MR,eps=eps)) print('=======================================')
Pc,MR,eps = 1000.0, 1.0, 30.0 ispNew = CEA_Obj(fuelName="MMH", oxName="N2O4") showOutput( ispNew )
ispNew = CEA_Obj(propName="ARC311") showOutput( ispNew )
ispNew = CEA_Obj(propName="N2O") showOutput( ispNew )
ispNew = CEA_Obj(oxName="LOX", fuelName="H2", useFastLookup=0) showOutput( ispNew )
ispNew = CEA_Obj(oxName="LOX", fuelName="GH2_160", useFastLookup=0) showOutput( ispNew )
print() print('amb_'*14) C = CEA_Obj(oxName="LOX", fuelName="H2", useFastLookup=0) MR = 6.0 for Pc in [100., 500., 1500., 5000.]: for eps in [2.0, 5., 10., 20., 50., 100.]:
IspVac = C.get_Isp( Pc=Pc, MR=MR, eps=eps) IspAmb, mode = C.estimate_Ambient_Isp(Pc=Pc, MR=MR, eps=eps, Pamb=14.7)
print('Pc=%4i eps=%3i IspAmb=%10.2f IspVac=%10.2f Mode=%s'%(int(Pc),int(eps), IspAmb, IspVac, mode)) print(' ---') |