These changes make it unnecessary to copy header files around during the build process, which tends to confuse IDEs and debuggers. The headers which comprise Cantera's external C++ interface are now in the 'include' directory. All of the samples and demos are now in the 'samples' subdirectory.
135 lines
4.9 KiB
Python
135 lines
4.9 KiB
Python
from onedim import *
|
|
from Cantera import _cantera
|
|
|
|
from Cantera.num import array, zeros
|
|
|
|
class FreeFlame(Stack):
|
|
"""A freely-propagating flat flame."""
|
|
|
|
def __init__(self, gas = None, grid = None, tfix = 500.0):
|
|
"""
|
|
gas -- object to use to evaluate all gas properties and reaction
|
|
rates. Required
|
|
grid -- array of initial grid points
|
|
|
|
A domain of type FreeFlame named 'flame' will be created to
|
|
represent the flame. The three domains comprising the stack
|
|
are stored as self.inlet, self.flame, and self.outlet.
|
|
"""
|
|
|
|
self.inlet = Inlet('burner')
|
|
self.gas = gas
|
|
self.inlet.set(temperature = gas.temperature())
|
|
self.outlet = Outlet('outlet')
|
|
self.pressure = gas.pressure()
|
|
|
|
# type 2 is Cantera C++ class FreeFlame
|
|
self.flame = AxisymmetricFlow('flame',gas = gas,type=2)
|
|
|
|
self.flame.setupGrid(grid)
|
|
Stack.__init__(self, [self.inlet, self.flame, self.outlet])
|
|
self.setRefineCriteria()
|
|
self._initialized = 0
|
|
self.tfix = tfix
|
|
|
|
|
|
def init(self):
|
|
"""Set the initial guess for the solution. The adiabatic flame
|
|
temperature and equilibrium composition are computed for the
|
|
inlet gas composition. The temperature profile rises linearly
|
|
in the first 20% of the flame to Tad, then is flat. The mass
|
|
fraction profiles are set similarly.
|
|
"""
|
|
self.getInitialSoln()
|
|
gas = self.gas
|
|
nsp = gas.nSpecies()
|
|
yin = zeros(nsp, 'd')
|
|
for k in range(nsp):
|
|
yin[k] = self.inlet.massFraction(k)
|
|
gas.setState_TPY(self.inlet.temperature(), self.pressure, yin)
|
|
u0 = self.inlet.mdot()/gas.density()
|
|
t0 = self.inlet.temperature()
|
|
|
|
# get adiabatic flame temperature and composition
|
|
gas.equilibrate('HP',solver=1)
|
|
teq = gas.temperature()
|
|
yeq = gas.massFractions()
|
|
u1 = self.inlet.mdot()/gas.density()
|
|
|
|
z1 = 0.5
|
|
locs = array([0.0, 0.3, z1, 1.0],'d')
|
|
self.setProfile('u', locs, [u0, u0, u1, u1])
|
|
self.setProfile('T', locs, [t0, t0, teq, teq])
|
|
self.setFixedTemperature(self.tfix)
|
|
for n in range(nsp):
|
|
self.setProfile(gas.speciesName(n), locs, [yin[n], yin[n],
|
|
yeq[n], yeq[n]])
|
|
self._initialized = 1
|
|
|
|
|
|
def solve(self, loglevel = 1, refine_grid = 1):
|
|
"""Solve the flame. See Stack.solve"""
|
|
if not self._initialized: self.init()
|
|
Stack.solve(self, loglevel = loglevel, refine_grid = refine_grid)
|
|
|
|
|
|
def setRefineCriteria(self, ratio = 10.0, slope = 0.8,
|
|
curve = 0.8, prune = 0.0):
|
|
"""See Stack.setRefineCriteria"""
|
|
Stack.setRefineCriteria(self, domain = self.flame,
|
|
ratio = ratio, slope = slope, curve = curve,
|
|
prune = prune)
|
|
|
|
def setFixedTemperature(self, temp):
|
|
_cantera.sim1D_setFixedTemperature(self._hndl, temp)
|
|
|
|
def setProfile(self, component, locs, vals):
|
|
"""Set a profile in the flame"""
|
|
self._initialized = 1
|
|
Stack.setProfile(self, self.flame, component, locs, vals)
|
|
|
|
def set(self, tol = None, energy = '', tol_time = None):
|
|
"""Set parameters.
|
|
tol -- (rtol, atol) for steady-state
|
|
tol_time -- (rtol, atol) for time stepping
|
|
energy -- 'on' or 'off' to enable or disable the energy equation
|
|
"""
|
|
if tol:
|
|
self.flame.setTolerances(default = tol)
|
|
if tol_time:
|
|
self.flame.setTolerances(default = tol_time, time = 1)
|
|
if energy:
|
|
self.flame.set(energy = energy)
|
|
|
|
def T(self, point = -1):
|
|
"""Temperature profile or value at one point."""
|
|
return self.solution('T', point)
|
|
|
|
def u(self, point = -1):
|
|
"""Axial velocity profile or value at one point."""
|
|
return self.solution('u', point)
|
|
|
|
def V(self, point = -1):
|
|
"""Radial velocity profile or value at one point."""
|
|
return self.solution('V', point)
|
|
|
|
def solution(self, component = '', point = -1):
|
|
"""Solution component at one point, or full profile if no
|
|
point specified."""
|
|
if point >= 0: return self.value(self.flame, component, point)
|
|
else: return self.profile(self.flame, component)
|
|
|
|
def setGasState(self, j):
|
|
"""Set the state of the object representing the gas to the
|
|
current solution at grid point j."""
|
|
nsp = self.gas.nSpecies()
|
|
y = zeros(nsp, 'd')
|
|
for n in range(nsp):
|
|
nm = self.gas.speciesName(n)
|
|
y[n] = self.solution(nm, j)
|
|
self.gas.setState_TPY(self.T(j), self.pressure, y)
|
|
|
|
|
|
|
|
|
|
|