-
-
Notifications
You must be signed in to change notification settings - Fork 348
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Eliminate unnecessary specialized Reaction types #1183
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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).
@@ -23,16 +23,16 @@ | |||
import matplotlib.pyplot as plt | |||
|
|||
#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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I went ahead with implementing that option, so we'll see if that ends up improving things.
@@ -804,7 +815,7 @@ def test_no_rate(self): | |||
# check behavior for instantiation from keywords / no rate | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per your comment above, requiring rate as a parameter would resolve this edge case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the introduction of the
ReactionRate
class, 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++
Reaction
class.ElementaryReaction
,PlogReaction
, andBlowersMaselReaction
, and should be easily expandable to coverCustomFunc1Reaction
andTwoTempPlasmaReaction
.ThreeBodyReaction
,FalloffReaction
andChebyshevReaction
do 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 thinkInterfaceReaction
will probably need to stay)ThermoPhase
class in Python -- with a few exceptions, there aren't wrappers for differentThermoPhase
types. Right now, I'm a bit stuck based on one of the routes that's been introduced for constructingReaction
objects.If applicable, provide an example illustrating new features this pull request is introducing
Before this PR, a
PlogReaction
could 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 justReaction
but presents a problem for the reaction types where we still need C++ specializations of theReaction
class, 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
ReactionRate
object 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