Eliminate unnecessary specialized Reaction types#1183
Eliminate unnecessary specialized Reaction types#1183ischoegl merged 14 commits intoCantera:mainfrom
Conversation
|
@speth … I ended up deleting my earlier comment as I’m curious what you’re coming up with. I believe that |
|
When I started this, my hope was that it would lead to enabling removal of all the |
Agreed. But for setup purposes it may be necessary to let them have a peek (without saving anything)
... sure! For interface reactions, I had to do a fair amount of parsing when it comes to cantera/include/cantera/kinetics/ReactionRate.h Lines 114 to 116 in d211185 I am planning to use the same to eliminate ElectrochemicalReaction (and the double-parsing required for their detection).
FWIW, here's the (preliminary) implementation used for cantera/src/kinetics/Coverage.cpp Lines 176 to 245 in d211185 This function is called when the reaction is attached to a PS:
The situation is not too dissimilar to coverage dependence for |
a4a2373 to
97c20b6
Compare
Codecov Report
@@ Coverage Diff @@
## main #1183 +/- ##
==========================================
+ Coverage 65.37% 65.39% +0.02%
==========================================
Files 318 318
Lines 46145 46109 -36
Branches 19615 19601 -14
==========================================
- Hits 30166 30153 -13
+ Misses 13475 13452 -23
Partials 2504 2504
Continue to review full report at Codecov.
|
e1a4d74 to
0ec03e3
Compare
There was a problem hiding this comment.
@speth ... this looks very good as it does cut a substantial amount of clutter that accumulated as Cantera/enhancements#87 progressed: you were even able to untangle the Python API, which is something I though would have to be deferred!
I have a couple of relatively small comments. The main question I have is whether the instantiation of a ReactionRate object shouldn't be called from within Reaction.h rather than ReactionFactory, as I have some hopes that we can eliminate the latter eventually.
Regarding merges, I believe this can be safely merged around the same time as #1166, and I will build on this to rework #1181 (which would otherwise introduce a slew of new objects that would be immediately removed).
Beyond, I think it may make sense to have another look at ThirdBodyCalc as this is the only obstacle I see to removing some of the remaining reaction specializations. Of course, some changes will also be necessary for the science section on Cantera/cantera-website 😢
PS: ugh, it looks like all of my multi-line comments were converted to regular comments (I reviewed from VSCode this time).
|
|
||
| #Create an elementary reaction O+H2<=>H+OH | ||
| r1 = ct.ElementaryReaction({'O':1, 'H2':1}, {'H':1, 'OH':1}) | ||
| r1 = ct.Reaction({"O":1, "H2":1}, {"H":1, "OH":1}) |
There was a problem hiding this comment.
I think that
r1 = ct.Reaction({"O":1, "H2":1}, {"H":1, "OH":1})
r1.rate = ct.ArrheniusRate(3.87e1, 2.7, 6260*1000*4.184)could be combined to
r1 = ct.Reaction({"O":1, "H2":1}, {"H":1, "OH":1},
ct.ArrheniusRate(3.87e1, 2.7, 6260*1000*4.184))for clarity.
Same goes for instances below and similar occurrences in test_kinetics.py.
There was a problem hiding this comment.
Are you suggesting that we make rate a required argument to the Reaction constructor? I certainly think that would simplify matters.
There was a problem hiding this comment.
I wasn't necessarily suggesting this, but it would probably avoid undesirable edge cases that need to be caught otherwise.
There was a problem hiding this comment.
Well, I went ahead with implementing that option, so we'll see if that ends up improving things.
| if self._rate_obj is None: | ||
| return | ||
| rxn = self.from_rate(None) | ||
| rxn = self.from_rate(self._rate_cls() if self._rate_cls else None) |
There was a problem hiding this comment.
I assume this is necessary as an empty type is needed to check that uninitialized rate objects work correctly?
I actually think that this PR will make uninitialized ReactionRate objects unnecessary. I.e. if no rate is attached, evaluation should fail. Likewise, generation of partial YAML input (e.g. equation without rate information) can be removed as most of the YAML content is now attached to the rate object anyways.
There was a problem hiding this comment.
Without this, the tests of the __call__ method fail for the rate types where the __call__ method takes two parameters, but the default ReactionRate object is an ArrheniusRate that only takes one.
There was a problem hiding this comment.
Ah, ok. I think we can leave the handling of empty rate parameterizations for another time (but a comment should be added) … edit: actually, requiring rate as a parameter should resolve this?
There was a problem hiding this comment.
Well, it would resolve it in the sense that None would not be a viable argument to from_rate.
I put in a comment in from_rate that I hope explains this well enough. I'm looking forward to getting rid of the "legacy" rates so we can reduce the complexity of both the actual implementations and this testing infrastructure.
| return | ||
|
|
||
| if reactants and products and not equation: | ||
| equation = self.equation |
There was a problem hiding this comment.
This leaves the object in an interesting state. Should there be any tests? I.e. what does calling the rate property getter do?
There was a problem hiding this comment.
Per your comment above, requiring rate as a parameter would resolve this edge case
There was a problem hiding this comment.
Right now, this gives you a nan-initialized ArrheniusRate object. I think that ultimately stems from the fact that not specifying a reaction type implies an elementary/Arrhenius rate.
|
@speth ... I thought about this some more over the weekend, and ended up opening Cantera/enhancements#133. Beyond, to unwind the remaining tasks pertaining to Cantera/enhancements#87, I believe this PR should go first, then #1184, then #1181, and finally whatever we decide for Cantera/enhancements#133. The outcome would be complete removal of |
An elementary reaction is just a Reaction with an ArrheniusRate as its rate coefficient.
This is useful for cases where the deprecation refers to something that appears in the input file, rather than being a deprecated method.
While these reactions are pressure dependent, that dependence is fully incorporated into the rate coefficient and the concentration of third bodies is never directly used in calculating the reaction rate.
This maintains the standing behavior of treating different reaction types as non-duplicates after making reactions with different rate types use the base Reaction class.
42b6d17 to
2e000fd
Compare
2e000fd to
8a8a7bb
Compare
|
@ischoegl - I think I've addressed all of your review comments on this. |
With the introduction of the
ReactionRateclass, most of the behavior that is specialized for particular kinds of reactions is contained in those classes, but we still have a (more or less) 1:1 correspondence with classes derived fromReaction, even though many of them don't have any unique behavior.Changes proposed in this pull request
Eliminate unnecessary specializations of C++
Reactionclass.ElementaryReaction,PlogReaction, andBlowersMaselReaction, and should be easily expandable to coverCustomFunc1ReactionandTwoTempPlasmaReaction.ThreeBodyReaction,FalloffReactionandChebyshevReactiondo implement some specialized behaviors, mostly around parsing and representing the reaction equation, so I think they need to stay for now.In the Python module, my goal is to eliminate all the specializations of
Reaction, at least for homogeneous phase reactions (I thinkInterfaceReactionwill probably need to stay)ThermoPhaseclass in Python -- with a few exceptions, there aren't wrappers for differentThermoPhasetypes. Right now, I'm a bit stuck based on one of the routes that's been introduced for constructingReactionobjects.If applicable, provide an example illustrating new features this pull request is introducing
Before this PR, a
PlogReactioncould be created in one step as:Or in a two steps:
With this PR, the first example becomes:
which is pretty similar.
The second case becomes:
This is fine in the case of
PlogRate, where the base C++ reaction type is justReactionbut presents a problem for the reaction types where we still need C++ specializations of theReactionclass, as there's no information about the rate type available in the initial constructor.What I'm wondering is whether we need this second constructor, where no rate information is provided. Would it make sense require specifying at least an empty
ReactionRateobject of the correct type here, e.g.I'm also wondering if there's a good way to clean up the split between specifying the reactants and products separately versus specifying the reaction equation in these constructors.
Checklist
scons build&scons test) and unit tests address code coverage