openmc icon indicating copy to clipboard operation
openmc copied to clipboard

Add reactivity control to coupled transport-depletion analyses

Open church89 opened this issue 2 years ago • 8 comments

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_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 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.Cell and openmc.Material, respectively.

A batch-wise scheme can be added to an integrator instance and a coupled transport-depletion simulation can be run like this:

...
...
op = openmc.deplete.CoupledOperator(model)
integrator = openmc.deplete.CECMIntegrator(op, timesteps , power)
integrator.add_batchwise(cell, 'translation', axis = 2, bracket = [-4, 4], bracket_limit = [-100,20])
integrator.integrate()

where cell is an openmc.Cell conveniently defined that can be translated along the z-axis during the run.

Checklist

  • [x] I have performed a self-review of my own code
  • [x] I have run clang-format on any C++ source files (if applicable)
  • [x] I have followed the style guidelines for Python source files (if applicable)
  • [ ] I have made corresponding changes to the documentation (if applicable)
  • [x] I have added tests that prove my fix is effective or that my feature works (if applicable)

church89 avatar Sep 14 '23 11:09 church89

Hi @drewejohnson, thanks for starting this review. I've begun to address your comments/suggestions.

I can see how batchwise might create some confusion. The routine acts in between a transport and a depletion step, so an alternatives could be stepwise to maintain the general purpose. Otherwise, we might think of linking the concepts of depletion and criticality, as ultimately is what it does, like depletion_critical , criticality_depletion or something similar.

church89 avatar Feb 05 '24 15:02 church89

@drewejohnson thanks, I've addressed most of your comments and changed the name to reactivity_control, which I like it and think also is appropriate. Regarding the adaptive search routine, as I tried to explain in one of the review comment, is probably less complicated than it looks, and right now relies on the fact that the method for search_for_keff is a bracketed one, so that convergence within tolerance is always ensured and we can simply rely on the algorithm to move the bracket to where the two limits have opposite sign with respect to the target.

church89 avatar Mar 15 '24 12:03 church89

@drewejohnson Thank you for your comments. Regarding your concerns:

  • Infinite loop: As long as the search_for_keff bracketed algorithm returns two arguments (meaning that the search have failed to bound the root) the adaptive algorithm will try to move the bracket range to bound the target. When that happens the search_for_keff returns three arguments and the first exit point to the while loop. If the adaptive algorithm moves the bracket range outside of the user defined limits (e.g. the entire span of a control rod), the closest limit is set as the root and the while loop exits as well. 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 might take awhile depending on user settings and simulation model but eventually should make it. Inside the loop there is also another check condition that is: when search_for_keff returns two arguments, (guesses and keffs) and keffs difference is below 1 pcm, the algorithm is already very close to target and the root will be set as the closest guess to target, exiting the loop. This 1 pcm can be user defined, but one should not go lower than 1, otherwise there is a risk of overshooting the adaptive bracket out of user limits and invalid the method

  • Reactivity control setter: Generally I like your idea and I think it makes sense, in practice I think it is not so straightforward and by letting users define their own controllers there is still a high risk of not being able to prevent misleading code. We would need to think of some very general helper methods that would need to include any user ideas and that might not be an easy task. What cases were you thinking that are not already covered by existing controllers?

  • Search method: These changes here are related to this PR. As explained above in the infinite loop, the search_for_keff must be able to fail (returning two arguments instead of three) to enable the adaptive algorithm and find the right bracket range the bounds the root. The run_in_memory argument instead is simply to enable search_for_keff to work with a model instantiated in memory. This is also related, as the operator class runs the model in memory.

church89 avatar Apr 11 '24 09:04 church89

@drewejohnson I thought a bit more about the reactivity control definition and added a setter method that hopefully goes in the right direction. Now users can instantiate directly their own ReactivityController class similar to what happens for the TransportOperator ones. So now a user can either set directly aReactivityController based on the current implementation of the reactivity_control.pymodule or defined its own. In the setter method there are a few checks for inheritance and attributes, but there is no check for the different methods needed to build a reactivity controller (and here is where to tricky part might come). Just would like to have your feedback before moving on and if that is pretty much what you were thinking. Thanks!

church89 avatar Apr 16 '24 12:04 church89

Hi @drewejohnson and thanks again.

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?

I've reduced the reactivity controller classes to only two: CellReactivityController and MaterialReactivityController, which both inherit from the abstract ReactivityController, and update the setter. It should be possible in principle now to have the users defined their own controllers.

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.)

That's exactly the reason we have to set a bracket_limit: if one of the bounds (upper or lower) gets hit the while loop exits and the search is stopped. In case of a removable control rod, you would set this bracket_limit to be the active length of your rod inside the core, so that when the it gets pulled out completely the routine knows that there is not margin anymore and needs to stop.

church89 avatar Jun 06 '24 11:06 church89