Non-empty Reactor and Connector Objects#1788
Conversation
b3dd2d1 to
d295959
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1788 +/- ##
==========================================
+ Coverage 73.23% 73.33% +0.09%
==========================================
Files 381 389 +8
Lines 54376 54459 +83
Branches 9253 9270 +17
==========================================
+ Hits 39824 39935 +111
+ Misses 11579 11551 -28
Partials 2973 2973 ☔ View full report in Codecov by Sentry. |
6fcbd68 to
7ae226a
Compare
|
@speth ... while there are likely more paper cuts, I don't necessarily want to go beyond 2k lines. Among the things that could be tackled are lowercase/hyphenated type names to be consistent with what we do with |
|
I just realized that there are some connections to Cantera/enhancements#201 and Cantera/enhancements#202. While this PR doesn't address either directly, it does ensure that a resolution will become easier. Without trying to pre-empt any eventual resolution, my personal take would be:
|
a05281f to
706861f
Compare
speth
left a comment
There was a problem hiding this comment.
I think the changes to have Reactor objects always contain a valid Solution object make sense, and I agree that this will help with Cantera/enhancements#201. I also like the idea of always providing the Reactor objects to the constructor for the connector objects and bringing that feature of the Python API to all the interfaces.
However, it's not quite clear to me what the benefit is of making all Reactor and connector objects into mandatory shared_ptrs. Currently, the ownership model is simple: none of the Reactor/ReactorNet/FlowDevice/etc. objects take ownership of anything they are connected to; the lifetimes of all these objects are managed by the caller. Within this set of objects, we need connections in all directions. Avoiding reference cycles will require the use of weak_ptr for many of the connections, with the associated overhead of "upgrading" those to shared_ptr where they are used. And you will still be left with the situation where it's possible to hold on to some element of the network but not be able to use it because the rest of the network has been deleted, though at least that would be checked and generate an exception rather than undefined behavior. My apologies for not thinking this through earlier and discussing it on Cantera/enhancements#213 before you put the time into implementing it.
Regarding the extension of the graph idiom, I think there's a simplification that may be worth considering. Instead of seeing just Reactor and ReactorSurface objects as nodes in the graph, you could also see valves and flow devices as nodes, with the edges of the graph just being the abstract connections among all of the entities that make up the reactor network. This way, there's only the need for one new base class, and no need for anything to sit between a Reactor and a ReactorSurface. This also gets closer to the original intent of Cantera/enhancements#212, and may work better as the amount of information you might want to display about a connector increases, given some of the limitations of how Graphviz handles (or doesn't) text associated with edges. That said, I do like the Connector class as a generalization combining walls and flow devices, and there's probably some further room to adjust this idea.
| //! Set the Solution specifying the ReactorBase content. | ||
| //! @param sol Solution object to be set. | ||
| //! @since New in %Cantera 3.1. | ||
| //! @deprecated To be removed after %Cantera 3.1. Superseded by instantiation of | ||
| //! ReactorBase with Solution object. | ||
| void setSolution(shared_ptr<Solution> sol); |
There was a problem hiding this comment.
Now that I think about this more, my preferred resolution to Cantera/enhancements#201 will require allowing ReactorNet to replace Solution objects in Reactors.
There was a problem hiding this comment.
Could you expand? My thinking was a strict hierarchy where the ReactorNet is responsible for Reactor, which themselves are responsible for Solution. I am not sure that I see why we should give ReactorNet the ability to muddle with reactor contents?
There was a problem hiding this comment.
There was a problem hiding this comment.
I responded in Cantera/enhancements#201 (comment). Irrespective of the logic we go with eventually, the detection of previously used Solution objects should be handled by ReactorNode and not ReactorNet.
| { | ||
| try { | ||
| return ReactorCabinet::at(i)->mass(); | ||
| return ReactorCabinet::as<ReactorBase>(i)->mass(); |
There was a problem hiding this comment.
The fact that almost all usage of ReactorNode objects requires downcasting to ReactorBase, ReactorSurface, or Reactor suggests to me that we shouldn't be defining our interface in terms of ReactorNode objects (which is not to say that the base class isn't useful for implementing some features like the automatic name generation).
There was a problem hiding this comment.
Once the API is fixed, ReactorBase methods should be either shifted to ReactorNode or Reactor, with ReactorBase eventually being removed. From that perspective, this is transitional behavior.
Adding the following to ReactorBase.h:
* @todo After completion of the %Cantera 3.1 deprecation cycle, all methods should be
* either moved to ReactorNode or Reactor, with ReactorBase entering its own
* deprecation cycle in %Cantera 3.2.
The newReactor function with contents was only introduced in 3.1 and thus can be modified without deprecations.
1749566 to
e51053c
Compare
e51053c to
c17b309
Compare
|
@speth ... thank you again for your feedback. After further consideration, I decided to move ahead with revisions on this PR after all, as some of the API changes are necessary to tackle updates envisioned by various enhancement requests. I adopted most of your suggestions, specifically:
Beyond, I tried to clarify future plans that motivated API changes, see various comments in the contexts of Cantera/enhancements#201, Cantera/enhancements#202 and Cantera/enhancements#213. |
(moving out of a specific line-by-line comment to prevent GitHub from hiding this higher-level discussion) I think this gets to my main concern with the API changes that this PR creates. Right now, there's a bit too much importance being placed on the idea of the reactor network as a graph -- most users don't care about this, but it now becomes the most important thing about a reactor and represents almost the only set of directly accessible functionality when using I'd like to explore whether we can directly skip over creating the I'd rather do this than leave users with an unnecessarily difficult-to-use interface for a full Cantera version. |
|
Thanks for your response, @speth.
Interesting thought - my attempt to simplify was definitely influenced by viewing 'reactor networks as a graph', although my objective was to simplify/generalize rather than making things more complicated.
I agree that we have one superfluous layer, which needs to be addressed. I was thinking along the lines of differentiating between bulk and surface reactors. I still think that nodes and edges make sense overall, so my introduction of a new base class was a move to phase out
I think at this point it makes sense to defer to 3.2. I will change the project planner accordingly. |
|
@speth ... I pulled out the less controversial commits to #1848; I also added some comments to Cantera/enhancements#213. |
Changes proposed in this pull request
This PR ensures that the Reactor/zeroD API uses shared pointers consistently. After removing raw pointers/references from various methods, it becomes possible to update the underlying code base, which at this point is a mix of shared pointers, raw pointers, and references. Details are:
ReactorNodeandConnector, which are bases for all 0D objects (which from the perspective of a graph are either nodes or edges); all objects are captured in updated factories.ReactorBaseandReactorSurfaceare now derived fromReactorNode.WallandFlowDeviceare both derived fromConnector.AllReactorNodeandConnectorobjects require contents to be available to the constructor (other than deprecated versions)with new convenience methods creating objects accessed by shared pointers (examples:... Edit: constructors are accessed vianewReservoirandnewValve). The old constructors (without arguments) are deprecated. The implementation loosely followsnewSolution.Reservoir::create,Valve::createetc..SharedFactoryfactory variant stores shared pointers rather than raw pointers.shared_from_thiswhen connecting aReactorNet.Add wall names toEdit: Moved to Graphviz tweaks #1792ReactorNetgraphviz illustrations.If applicable, fill in the issue number this pull request is fixing
Closes Cantera/enhancements#213
If applicable, provide an example illustrating new features this pull request is introducing
Checklist
scons build&scons test) and unit tests address code coverage