Limiting flame speed computing in a mixture

117 views
Skip to first unread message

a1e5...@gmail.com

unread,
Sep 15, 2021, 4:46:49 PM9/15/21
to Cantera Users' Group

Is there a way to limit the number of "refinements" with flame.solve in the flame object? For certain combinations of fuel-air, T & P, the solver gets into runaway mode.  I would like to put in an exit if the gridpoints is > 200 or width > 2 cm etc ...

Thanks
Iain

Ray Speth

unread,
Sep 16, 2021, 8:56:38 PM9/16/21
to Cantera Users' Group

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

Sam Edgar

unread,
Sep 19, 2021, 7:00:00 PM9/19/21
to canter...@googlegroups.com
Hi Ray:

Thanks for your message.  I put in your code snippets into my python script but it did not stop the code when the grid condition was met.
Instead of f.grid/f.set_steady_callback,  I used flame.grid/flame.set_refine_callback since I use flame.solve and I changed the number of gridpoints to 20.
everything else was the same

I set the log level to 3 and I see that the output reports
************ Solving on 8 point grid with energy equation enabled ************
*********** Solving on 12 point grid with energy equation enabled ************
*********** Solving on 24 point grid with energy equation enabled ************
Problem solved on [24] point grid(s).
*********** Solving on 24 point grid with energy equation enabled ************
So it has jumped past the 20 gridpoint limit.
I am not sure if there is something else that I have to have in the code.

Thanks

Iain


--
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.

Sam Edgar

unread,
Sep 19, 2021, 9:03:54 PM9/19/21
to canter...@googlegroups.com
Hi Ray:

I was not able to stop the code at the specified grid points with
flame.set_steady_callback(stop_flame)
but it works with
flame.set_interrupt(stop_flame)

Thanks

Iain

On Thu, Sep 16, 2021 at 7:56 PM Ray Speth <yar...@gmail.com> wrote:
--

Ray Speth

unread,
Sep 20, 2021, 9:43:21 AM9/20/21
to Cantera Users' Group

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 problem
  • set_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 solver
  • set_interrupt sets a function that called after each residual function evaluation

If 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

a1e5...@gmail.com

unread,
Sep 20, 2021, 5:09:44 PM9/20/21
to Cantera Users' Group
Thanks for the clarification, Ray.  When I turned log-level to 3, I saw that even for the initial grid with 8 points there were a lot of failures for a particular case with low equivalence ratio.  I was wondering if there is a way to stop the run if the total run-time exceeds a fixed time - say 120 seconds.  I tried to use the time.time function but could not get it to work.  I tried something like the snippet shown below.

Thanks

Iain

######

class StopFlame(Exception): pass

def stop_flame(t):
    if (t1-t0) > 120:
        raise StopFlame()
    return 0

######

# Define logging level
loglevel = 0
#flame.set_steady_callback(stop_flame)
t1 = 0
t0 = 0

flame.set_interrupt(stop_flame)

try:
    t0 = time.time()
    flame.solve(loglevel=loglevel, auto=True)
    t1 = time.time()
    print('T1 = ',t1)
except StopFlame:
    print('stopped due to long time')


Ray Speth

unread,
Sep 20, 2021, 9:50:59 PM9/20/21
to Cantera Users' Group

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

a1e5...@gmail.com

unread,
Sep 21, 2021, 9:32:21 AM9/21/21
to Cantera Users' Group
Hi Ray:

Thanks for the tip on trying to fix the time for solution.    I will try it out.
Indeed, the flame-speed case/solver is robust and works well.  I was trying out some "edge-cases" where the equivalence ratio is very low (<0.2) . This is where the solver  has some numerical issues, otherwise all is well.

Thanks again for all your suggestions and help.

Iain

Ingmar Schoegl

unread,
Sep 21, 2021, 1:54:21 PM9/21/21
to Cantera Users' Group
Thanks Iain for the interesting discussion - fwiw, I have seen quite a few 'hung' cases for marginal mixtures before. I likewise don't put the solver at fault, but what you suggested above to terminate hung simulations definitely looks interesting. In addition to using a callback, It's likely something that could be added as a new functionality in the C++ core - feel free to file an enhancement request on https://github.com/Cantera/enhancements

-ingmar-

a1e5...@gmail.com

unread,
Sep 25, 2021, 9:08:43 AM9/25/21
to Cantera Users' Group
Thanks, Ingmar. It might be helpful to put an overall time limit for solution or a maximum number for "solver attempts"  - which could be a user-defined parameter.  I will put in the enhancement request as you suggested.
Reply all
Reply to author
Forward
0 new messages