-
Notifications
You must be signed in to change notification settings - Fork 580
Add reactivity control to coupled transport-depletion analyses #2693
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
base: develop
Are you sure you want to change the base?
Conversation
update pr with latest commits from development branch
Update with latest develop before open pr
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.
@church89 thank you for this lengthy and useful PR! I think this is going to unlock a lot of doors for people and provide a lot of value. I haven't done a full review but I wanted to get some of my larger thoughts out first, make sure we understand the vision and goal, and then refine my review as we go.
Some simple things
- Please re-evaluate the docstrings you've added to align with the
numpydocspec Otherwise our built documentation isn't going to process this properly - Please run a python formatter like
blackto make sure your code adheres to pep8 formatting style like the dev guide requests - Please consolidate property setters / getters / validators. I think it's going to be easier for us in the long run to maintain / add validators if we do validation on things like
self.tolif all validation is done in property setters
Maybe a larger lift: I think the high-level class and method name, using batch wise, might not communicate what we want to communicate. My rationale is I believe this engages after a full transport simulation, while openmc uses the "batch" terminology to mean generations of particles in a given transport simulation - docs
so users who already are configuring an openmc run to have so many inactive / active generations per batch may expect this search to be performed more often than it is actually performed.
But, based on your PR message
It effectively runs an iterative search_for_keff sub-step algorithm to maintain keff equal to 1 (or some other user defined targets) as a function of some user defined model parameter to update, before calculating the BOS from the transport run
and my non-exhaustive review, I could be wrong. If we are making changes to the model during batches of active generations, then this name makes sense. But if we are not, I would encourage us to consider new names.
I hope to have time in the next week or so for a more detailed review, but I wanted to get something out the door to let you know I've seen this, I believe it's valuable, and I have some (hopefully) low-hanging requests
| res_test = openmc.deplete.Results(path_test) | ||
| res_ref = openmc.deplete.Results(path_reference) | ||
|
|
||
| # Use high tolerance here |
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.
Oof a 2% relative tolerance is high. But we've got a stochastic code, and probably wanting to get the simulation to converge reasonably quickly.
I'd like to see a tighter tolerance but I understand that might not be tenable.
Co-authored-by: Andrew Johnson <[email protected]>
|
Hi @drewejohnson, thanks for starting this review. I've begun to address your comments/suggestions. I can see how |
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.
Thank you for incorporating some of the changes. I want to make one last call for the following items to be either incorporated or rejected with explanation.
Infinite loop
I've personally been bitten by an unterminated while loop and it can be deeply frustrating. And, since users of this feature are likely going to be running expensive simulations, there is a likelihood that someone expends some unnecessary computational resources because there is no hard upper limit on iterations.
If there is some other way that I'm not seeing where the main loop will terminate if it cannot find a satisfactory solution, please let me know.
reactivity controller setter
The add_reactivity_control method is nice, I'm not trying to deny that. But it does not make it easy for people to develop their own reactivity controller outside of openmc and then use that in a simulation. They would need to modify the source code (either locally or through a PR here) to add their specific flavor of controller. Or they push an issue here and wait for someone else to make those changes.
If the reactivity_controller is a publicly settable attribute, then people have the freedom to use their own controller without needing to make changes to the core of openmc. It can (and should) be used by the add_reactivity_control helper method.
search.py
These changes don't feel intrinsically related to the PR at hand. They feel valuable, but the relationship is not clear to me. There is some issue you are trying to workaround that isn't transparent to me.
I also have some concerns about variable return signature (two or three arguments) and would welcome other opinions on the matter.
|
@drewejohnson
|
made ReactivityControllers settable through the integrator
|
@drewejohnson |
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.
Apologies again for my delay. Life has been a bit hectic and I finally found time to review this.
Thank you for adding the reactivity control setter. I think it enforces too many checks and doesn't allow users to expand beyond what OpenMC can do already without source code changes. Please consider requiring the setter to only check that the object is an instance of the base ReactivityController. If there are concerns about allowing the users to construct those subclasses properly, what checks and validation steps can be added to the subclasses? e.g., to ensure that CellReactivityController.cell is always a Cell subclass?
Regarding the infinite loop,
The only case the loop won't exit easily is if the adaptive algorithm won't bound the target but still remain inside the user defined limits
This is not an uncommon situation. Consider control rod movement through depletion. It is conceivable that, towards the end of life, there is no way to remove the control rods enough from the reactor to achieve a critical state with sufficiently spent fuel. Same for other reactivity control mechanisms where a poison is modified (control rods, control drums, soluble boron, etc.)
I am going to signal for an additional reviewer to help close the gap on the infinite loop and API changes to openmc/search.py.
openmc/deplete/abc.py
Outdated
| check_value('attribute', reactivity_control.attrib_name, | ||
| ('translation', 'rotation', 'temperature', 'refuel')) |
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.
Why only these four control mechanisms? What about the interplay between the Operator and the ReactivityController requires only these four mechanisms?
For light water reactors, adding and changing soluble boron concentration might be akin to "refueling" but we're not adding fuel there so someone could set attrib_name = "dillution" (for example).
|
Hi @drewejohnson and thanks again.
I've reduced the reactivity controller classes to only two:
That's exactly the reason we have to set a |
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.
Finally getting around to giving this a proper review. Thanks for the work on this PR and for your patience @church89. And also many thanks to @drewejohnson for providing very thoughtful comments that have helped shaped the PR thus far.
Overall I have a few thoughts:
- I personally like the idea of giving users more control over the criticality search and keeping it general rather than having a bunch of subclasses of a ReactivityController class. Right now, if a user wants to do some other search, they are forced to write a class that implements the ReactivityController interface. I feel like this could be much simpler overall. There could be a generic reactivity controller that accepts a function that takes one argument (the search value) and makes a corresonding change in the model via openmc.lib. So for example, if the user wanted to translate cell 50 along the y axis, the function could be as simple as:
This may arguably be less fool-proof than providing specific controllers but we can try to make things more obvious for users by providing examples (in the docstrings and/or example notebooks).
def translate_cell(value): cell = openmc.lib.cells[50] cell.translation = (0, value, 0)
- I agree with @drewejohnson's earlier comment about the changes in
search_for_keff. Let's separate those out into a new PR to get them merged sooner. - I've been wanting to make some other changes in
search_for_keff, namely to use thescipy.optimize.root_scalarfunction that can dispatch tobrentq,bisect, etc. This would make it future-proof (if a new method is added, we don't need to update OpenMC). It probably makes sense to get that in before we merge this PR since it might affect the interface, so I'll try to get that PR submitted soon.
|
On the use of root_scalar: have you all experimented with using that in a function with noise? I just wanted to share this paper since it presents a method for adjusting some parameter (drum angle in this case) to find the root of a function you can only get samples of with noise. It's not equivalent to applying secant method or bisection to the samples. So, that being the case, I would argue that using the And lastly, I agree that with so much robust C API functionality already in place, parametrizing the reactivity search around a scalar passed to C API calls implemented in a python callback would be the cleanest and most general way to implement this! |
|
Thanks @paulromano for getting back to this PR. Looks reasonable to me to separate the |
Description
This pr adds the capability to perform batch-wise reactivity control during a coupled transport-depletion analysis.
It effectively runs an iterative
search_for_keffsub-step algorithm to maintain keff equal to 1 (or some other user defined targets) as a function of some user defined model parameter to update, before calculating the BOS from the transport run and proceed with the depletion step.The model variable to parametrize during the sub-step can be of geometrical (e.g. control rod position) or material (e.g. refuel) nature, acting on a
openmc.Cellandopenmc.Material, respectively.A batch-wise scheme can be added to an
integratorinstance and a coupled transport-depletion simulation can be run like this:where
cellis anopenmc.Cellconveniently defined that can be translated along thez-axisduring the run.Checklist