Docstrings for undocumented methods of child classes are automatically copied from the corresponding method of the parent class. This works both for docstrings as shown in the Python interpreter as well as the Sphinx-generated documentation. Removed manually duplicated docstrings from setProfile(), solve() and setRefineCriteria() methods.
133 lines
4.6 KiB
Python
133 lines
4.6 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):
|
|
"""
|
|
:param gas:
|
|
object to use to evaluate all gas properties and reaction
|
|
rates. Required
|
|
:param 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.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):
|
|
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):
|
|
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):
|
|
self._initialized = 1
|
|
Stack.setProfile(self, self.flame, component, locs, vals)
|
|
|
|
def set(self, tol = None, energy = '', tol_time = None):
|
|
"""Set parameters.
|
|
:param tol:
|
|
(rtol, atol) for steady-state
|
|
:param tol_time:
|
|
(rtol, atol) for time stepping
|
|
:param 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)
|
|
|
|
fix_docs(FreeFlame)
|