Skip to content

Commit

Permalink
[1D] Try harder to find non-extinct diffusion flames when using 'auto'
Browse files Browse the repository at this point in the history
Increasing the density of grid points is more likely to lead to a non-extinct
solution, but takes longer to solve. To give good average-case performance,
first try solving on a grid with few points, then increase the number of points
until a reacting solution is found, if possible.
  • Loading branch information
speth committed Mar 27, 2016
1 parent b56094b commit 77c7442
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 28 deletions.
2 changes: 2 additions & 0 deletions interfaces/cython/cantera/_cantera.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,8 @@ cdef class Sim1D:
cdef CxxSim1D* sim
cdef readonly object domains
cdef object _initialized
cdef object _initial_guess_args
cdef object _initial_guess_kwargs
cdef Func1 interrupt

cdef class ReactionPathDiagram:
Expand Down
9 changes: 5 additions & 4 deletions interfaces/cython/cantera/onedim.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,9 @@ def set_initial_guess(self, fuel=None, oxidizer=None, stoich=None):
for k,spec in enumerate(self.gas.species_names):
self.set_profile(spec, zrel, Y[:,k])

def extinct(self):
return max(self.T) - max(self.fuel_inlet.T, self.oxidizer_inlet.T) < 10

def solve(self, loglevel=1, refine_grid=True, auto=False):
"""
Solve the problem.
Expand All @@ -644,10 +647,8 @@ def solve(self, loglevel=1, refine_grid=True, auto=False):
super(CounterflowDiffusionFlame, self).solve(loglevel, refine_grid, auto)
# Do some checks if loglevel is set
if loglevel > 0:
# Check if flame is extinct
if max(self.T) - max(self.fuel_inlet.T, self.oxidizer_inlet.T) < 1.0:
if self.extinct():
print('WARNING: Flame is extinct.')
return

# Check if the flame is very thick
# crude width estimate based on temperature
Expand Down Expand Up @@ -835,7 +836,7 @@ def set_initial_guess(self, products='inlet'):
used to form the initial guess. Otherwise the inlet composition will
be used.
"""
super(ImpingingJet, self).set_initial_guess()
super(ImpingingJet, self).set_initial_guess(products=products)

Y0 = self.inlet.Y
T0 = self.inlet.T
Expand Down
96 changes: 72 additions & 24 deletions interfaces/cython/cantera/onedim.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,8 @@ cdef class Sim1D:
self.domains = tuple(domains)
self.set_interrupt(interrupts.no_op)
self._initialized = False
self._initial_guess_args = ()
self._initial_guess_kwargs = {}

def set_interrupt(self, f):
"""
Expand Down Expand Up @@ -722,12 +724,14 @@ cdef class Sim1D:
def __set__(self, nmax):
self.sim.setMaxTimeStepCount(nmax)

def set_initial_guess(self):
def set_initial_guess(self, *args, **kwargs):
"""
Set the initial guess for the solution. Derived classes extend this
function to set approximations for the temperature and composition
profiles.
"""
self._initial_guess_args = args
self._initial_guess_kwargs = kwargs
self._get_initial_solution()
self._initialized = True

Expand All @@ -739,6 +743,13 @@ cdef class Sim1D:
self.sim.resize()
self.sim.getInitialSoln()

def extinct(self):
"""
Method overloaded for some flame types to indicate if the flame has been
extinguished. Base class method always returns 'False'
"""
return False

def solve(self, loglevel=1, refine_grid=True, auto=False):
"""
Solve the problem.
Expand All @@ -757,10 +768,10 @@ cdef class Sim1D:
transport is enabled, an additional solution using these options
will be calculated.
"""
if not self._initialized:
self.set_initial_guess()

if not auto:
if not self._initialized:
self.set_initial_guess()
self.sim.solve(loglevel, <cbool>refine_grid)
return

Expand All @@ -784,28 +795,65 @@ cdef class Sim1D:
if isinstance(dom, _FlowBase):
dom.set_transport(self.gas)

def log(msg):
def log(msg, *args):
if loglevel:
print('\n{:*^78s}'.format(' ' + msg + ' '))

try:
# Try solving with energy enabled, which usually works
log('Solving on initial grid with energy equation enabled')
self.energy_enabled = True
self.sim.solve(loglevel, <cbool>False)
except Exception:
# If initial solve using energy equation fails, fall back on the
# traditional fixed temperature solve followed by solving the energy
# equation
log('Initial solve failed; Retrying with energy equation disabled')
self.energy_enabled = False
self.sim.solve(loglevel, <cbool>False)
log('Solving on initial grid with energy equation re-enabled')
self.energy_enabled = True
self.sim.solve(loglevel, <cbool>False)

log('Solving with grid refinement enabled')
self.sim.solve(loglevel, <cbool>True)
print('\n{:*^78s}'.format(' ' + msg.format(*args) + ' '))

flow_domains = [D for D in self.domains if isinstance(D, _FlowBase)]
zmin = [D.grid[0] for D in flow_domains]
zmax = [D.grid[-1] for D in flow_domains]
nPoints = [len(flow_domains[0].grid), 12, 24, 48]

for N in nPoints:
for i,D in enumerate(flow_domains):
if N != len(D.grid):
D.grid = np.linspace(zmin[i], zmax[i], N)

self.set_initial_guess(*self._initial_guess_args,
**self._initial_guess_kwargs)

try:
# Try solving with energy enabled, which usually works
log('Solving on {} point grid with energy equation enabled', N)
self.energy_enabled = True
self.sim.solve(loglevel, <cbool>False)
solved = True
except Exception:
solved = False

if not solved:
# If initial solve using energy equation fails, fall back on the
# traditional fixed temperature solve followed by solving the energy
# equation
log('Initial solve failed; Retrying with energy equation disabled')
try:
self.energy_enabled = False
self.sim.solve(loglevel, <cbool>False)
log('Solving on {} point grid with energy equation re-enabled', N)
self.energy_enabled = True
self.sim.solve(loglevel, <cbool>False)
solved = True
except Exception:
pass

if solved and not self.extinct():
# Found a non-extinct solution on the fixed grid
log('Solving with grid refinement enabled')
try:
self.sim.solve(loglevel, <cbool>True)
solved = True
except Exception:
solved = False

if solved and not self.extinct():
# Found a non-extinct solution on the refined grid
break

if self.extinct():
log('Flame is extinct on {} point grid', N)

if not solved:
raise Exception('Could not find a solution for the 1D problem')

if solve_multi:
log('Solving with multicomponent transport')
Expand Down
22 changes: 22 additions & 0 deletions interfaces/cython/cantera/test/test_onedim.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,28 @@ def test_mixture_averaged(self, saveReference=False):
rtol=1e-2, atol=1e-8, xtol=1e-2)
self.assertFalse(bad, bad)

def test_auto(self, saveReference=False):
referenceFile = '../data/DiffusionFlameTest-h2-auto.csv'
self.create_sim(p=ct.one_atm, mdot_fuel=2, mdot_ox=3)

self.sim.set_refine_criteria(ratio=3.0, slope=0.1, curve=0.12, prune=0.0)
self.sim.solve(loglevel=0, auto=True)

data = np.empty((self.sim.flame.n_points, self.gas.n_species + 4))
data[:,0] = self.sim.grid
data[:,1] = self.sim.u
data[:,2] = self.sim.V
data[:,3] = self.sim.T
data[:,4:] = self.sim.Y.T

if saveReference:
np.savetxt(referenceFile, data, '%11.6e', ', ')
else:
bad = utilities.compareProfiles(referenceFile, data,
rtol=1e-2, atol=1e-8, xtol=1e-2)
self.assertFalse(bad, bad)


def test_mixture_averaged_rad(self, saveReference=False):
referenceFile = '../data/DiffusionFlameTest-h2-mix-rad.csv'
self.create_sim(p=ct.one_atm)
Expand Down
Loading

0 comments on commit 77c7442

Please sign in to comment.