Cantera / enhancements

Repository for proposed and ongoing enhancements to Cantera
11 stars 5 forks source link

Julia support for Cantera #81

Open RSuryaNarayan opened 3 years ago

RSuryaNarayan commented 3 years ago

Motivation With Julia being increasingly turned towards by the scientific computing community, Cantera's support to Julia shall be a valuable feature addition. Two such paths exist to extend Cantera's support to Julia: Possible solutions

References-Cantera user's group discussions

  1. https://groups.google.com/g/cantera-users/c/AkjunMzAkJs
  2. https://groups.google.com/g/cantera-users/c/WGi-PTq9Wgg/m/M5LTO-1HAwAJ
jiweiqi commented 3 years ago

I would suggest we explore both of those two approaches.

On one hand, there seem to be some needs for machine learning research that are not easy to realize by extends Canetra. But this needs more careful discussions.

On the other hand, there are very successful examples of building a wrapper for C++ packages in Julia. See Sundials.jl for Sundials. This might be categorized as different solutions to PyCall or cccall, as discussed in #39

speth commented 3 years ago

The Sundials.jl package uses ccall, as you can see in cvode.jl.

For Cantera, we could wrap the Cantera C interface using ccall, or interact directly with the C++ interface using something like Cxx.jl or CxxWrap.jl. Wrapping the C++ interface directly would be more like what we do for the Python module, and would probably make it easier to translate data structures like the AnyMap class across language boundaries.

jiweiqi commented 3 years ago

I just invited Chris to see if he could share some suggestions on the choice of ccall .vs. C++ wrapper.

ischoegl commented 3 years ago

I believe a hybrid option would be to use Cantera's existing framework to handle loading of mechanisms etc. and expose essential reaction parameters to Julia (not too dissimilar of what ReacTorch does in a targeted way). Conversely, it should be possible to write reaction equations in Julia and call them from the C++ framework (which may incur some overhead, but would be quite useful for testing). Another route would be to leverage existing projects, e.g. ReactionMechanismSimulator.jl or others.

ChrisRackauckas commented 3 years ago

The latest results from ReactionMechanismSimulator.jl show some really nice speedups, so for the most part I plan on spending my time there. But for how to wrap, Sundials.jl uses Clang.jl to automatically generate a full wrapper of the sundials C API, which then gets a Julia wrapper into the DifferentialEquations.jl interface, but can also be used directly if one wished. Cxx.jl and CxxWrap.jl get you to a similar place, but IMO are a bit harder to maintain. But with Clang.jl you cannot make good use of templates, while with Cxx.jl you can JIT compile templated calls (hence the C++ REPL it provides). I like working with Clang.jl because then there's a direct Julia-side equivalent to all structs making the memory matching easy (to me), but YMMV.

jiweiqi commented 3 years ago

For a hybrid option, using Cantera's interpreter is a very mature way and it is something that we can decide inside Cantera communities. Both ReacTorch and Arrhenius.jl are trying to work in this style.

One thing that I am not sure about is whether there is already API in Cantera's C/Python API that one can access every kinetic parameter. For instance, for now, ReacTorch has to interpret from the YAML files directly for parts of parameters. But I believe there are already APIs existing but I didn't know back at that time.

For the equations, more specifically, computing reaction source term, I believe we certainly should build a wrapper to do that. As Chris mentioned, we could have some nice speedups with DifferentialEquations.jl. But I guess that speed up is based on better Jacobian computation with auto-differentiation. Nevertheless, this is something we should do within Canetra's community as we did for Matlab to facilitate Julia users.

Regarding the efforts of re-implementing the equations for computing reaction source terms in native Julia code, I am not sure whether it should be a part of Cantera or a standalone package since it does equivalent functionality as of Cantera.

ischoegl commented 3 years ago

One thing that I am not sure about is whether there is already API in Cantera's C/Python API that one can access every kinetic parameter. For instance, for now, ReacTorch has to interpret from the YAML files directly for parts of parameters. But I believe there are already APIs existing but I didn't know back at that time.

Most parameters should be available for Python via the cython interface, and adding ones that may not be exposed at the moment is relatively straightforward. The C API (clib) is less developed, but it may not be needed if Julia accesses C++ directly. On cython/clib I can provide pointers if you know what is missing.

jiweiqi commented 3 years ago

Thanks @ischoegl , I did try to use the wrapper to access that information. I had some difficulties in using ccall since I haven't written c/c++ code for many years. For me, I would like to join the efforts after someone sets up the environment. I mean figure out what package to use, how to set up the environment for development etc.

For the current time being, the development of ReacTorch and Arrhenius.jl are focusing on doing minimal value products to show combustion communities that those PINN and neural ODE stuff are exciting (which is indeed not easy to convince ... based on my experience). By saying exciting, I mean doing things fundamentally new that we can not do with a conventional method. The current mechanism interpreter is sufficient for those algorithms development. But in the long run, I expect that it can rely more on Canetra's interpreter.

jiweiqi commented 3 years ago

Share some of my recent experience on this topic.

Regarding calling Cantera via PyCall: I think this is a pretty convenient approach if the integration doesn't add much overhead, and we don't need auto-differentiation across the solver. For example, in the package of Arrhenius.jl, it is fairly easy to make a zero-D reactor, although might not robust as Cantera was given the limited time period. But for one-dimensional flame, one has to implement the switching between newton iterations and time-stepping, adaptive grid, etc. Then, it is a good idea to call Cantera to do the calculation of one-d flame. Also, solving one-d flame is usually time-consuming, such that the communication is neglectable. Furthermore, for a steady solution of one-D flame, the sensitivity computation can be easily done offline in Julia by reading the results from Cantera.

looking forward, it will be certainly great to have something like Cantera's Matlab toolbox.

jiweiqi commented 3 years ago

For reference, below are some example codes calling Cantera in Julia. https://github.com/DENG-MIT/Arrhenius_Flame_1D/blob/4e88cd98dc6de9b573ee4754a197d3b29d52345d/src/ct_flame_1d.jl#L5-L37

It is pretty convenient if the goal is not to using Julia's AD eco-system

Naikless commented 2 years ago

Just out of interest: In a package I am writing, I am currently using the approach suggested above where I access cantera‘s python interface via PyCall to obtain thermodynamic and kinetic data or calculate equilibriums. Any ODEs are solved using OrdinaryDiffEq.jl.

This works quite conveniently, even though it adds a little extra organizational effort in managing the package’s dependencies (ensure python is installed, choose a compatible cantera version…)

But what I am more interested in are the implications regarding performance. I call some cantera routines via pycall inside my ODE function calls and wonder how much of a bottleneck this actually is. Does anyone have a feeling if trying to switch to a pure Julia implementation using e.g. Arrhenius.jl or trying to access cantera‘s c++ interface directly would significantly improve performance here?