Hi Iain,
Yes, you can do this using the “set_steady_callback” feature of the 1D solver, assuming you’re using the Python interface. This feature lets you add a callback function that will be evaluated after each steady-state solution is reached (which is when the grid is refined and expanded). To have the simulation stop at this point, you can just raise an exception from within that method. For example, if you have a flame object f
, you can define an exception class and callback method like:
class StopFlame(Exception): pass
def stop_flame(t):
if len(f.grid) > 200:
raise StopFlame()
return 0
Then, before solving the flame, attach the callback method, and catch your exception if it occurs:
f.set_steady_callback(stop_flame)
try:
f.solve(loglevel=loglevel, auto=True)
except StopFlame:
print('stopped due to grid size')
Regards,
Ray
--
You received this message because you are subscribed to a topic in the Google Groups "Cantera Users' Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/cantera-users/5g5ohkLfxoA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to cantera-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/cantera-users/a2935c43-8941-42f7-94f1-c22b0b3dbd5an%40googlegroups.com.
--
Hi Iain,
There are three functions for calling user code within the 1D solver:
set_steady_callback
sets a function that is called after a successful solution of the steady-state flame problemset_time_step_callback
sets a function that is called after each successful time step when taking time steps to get a better initial guess for the steady state solverset_interrupt
sets a function that called after each residual function evaluationIf you break out of the solver using the set_interrupt
method, the state vector will not correspond to a converged solution to the steady state problem that satisfies the error tolerances, and might even just be a perturbed state that is being evaluated in order to compute the system Jacobian. Similarly, the system state after set_time_step_callback
will not correspond to a steady solution. The only place where you can break out of the solver with a correct steady-state solution is via the steady_callback
.
The code I provided above will not limit the grid points to precisely the limit set. The better way to read this limit is that no additional grid refinement operations will be taken once the specified limit is reached. However, a single refinement operation checks the grid refinement criteria at all points in the domain and will typically add multiple points points, so exceeding the limit by a small margin is to be expected. Once the grid is refined, the flame must be re-solved on that new grid — the previous state vector does not satisfy the error tolerances on the new grid. I think this still satisfies the original stated goal of preventing runaway behavior by the solver.
Regards,
Ray
Hi Iain,
That’s an interesting idea for how to use the callback. To get this to work, you need to call t1 = time.time()
in the stop_flame
function, and compare it to the value of t0
that is set just before the call to flame.solve(...)
. Otherwise, t1
won’t be updated until the call to solve
is completed anyway.
I’m somewhat surprised that you’re having to go to such lengths to get the 1D solver to work. My experience is that it is pretty robust in recent versions of Cantera. The one common issue that does come up is reaction mechanisms with non-physical reverse rate constants that make the problem stiffer than it should be. Can you share a complete example (or several) where the solver isn’t converging for you?
Regards,
Ray