-
Notifications
You must be signed in to change notification settings - Fork 91
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
Improving efficiency of reaction rate calcs #1887
Conversation
The error is avoided by upstream preparation of the inputs.
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 the PR probably does what you want it to do, but just added some suggestions to maybe make things more clear.
try: | ||
mgFlux = np.array(obj.getMgFlux()) | ||
except TypeError: | ||
continue |
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.
Should we allow for this function to silently continue if an object without flux is passed in? The explicit purpose of this function is to calculate reaction rates, so passing an object without flux is just a fundamentally wrong premise.
A hard error feels appropriate to me here, unless there is a common case that I am not aware of.
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.
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 guess I understand what is happening, but it feels outside of the purview of this method to not fail in this scenario. If I pass a block into a method called calcReactionRates()
and it can't calculate the reaction rates, I would expect that method to fail, or at least tell me that it can't do it.
Just skipping feels like an error trap, to me. This is getting a bit outside the scope of your PR, because like you said you just copy/pasted. But maybe an opportunity for improvement in the future?
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 don't know whether we're ever actually hitting this exception. It might be good to remove it if possible, but that could probably be a separate PR where it is also removed from the original function I copied it out of.
for nucName, numberDensity in numberDensities.items(): | ||
if numberDensity == 0.0: | ||
continue |
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.
Instead of looping over numberDensities
and then checking that the number density is non-zero, would it make more sense to loop over the nuclides in xsNucDict
? You've already done work to screen out isotopes with zero number density from there, so the number of isotopes in there is less and you don't have to do any further checking for zero values.
I might be misinterpreting this, I'm finding the logic somewhat complex.
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.
xsNucDict
will have an entry for any nuclide that exists at a non-zero number density in any blockin the
blockList`.
This line is checking whether the nuclide has a nonzero density in a particular block or other object.
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.
True, maybe the check cannot be removed. But I still think that looping over the other list might make more sense, no? xsNucDict
is shorter without loss of needed information.
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.
xsNucDict
is not necessarily shorter than obj.getNumberDensities()
. You could have a list of 500 blocks where 495 of them have 3 nuclides and 5 of them have 400 nuclides, and xsNucDict
would have 400 nuclides. This is obviously an extreme situation that I've devised here that isn't realistic, but it's just hard to say that one of these lists is always going to be shorter than the other one.
If you refactored, it would be something like:
for nucName in xsNucDict:
numberDensity = numberDensities.get(nucName, 0.0)
if numberDensity == 0.0:
continue
I think since you always have to get the dict value from numberDensities
, it makes sense to iterate over numberDensities.items()
instead of iterating over the keys and then doing numberDensities.get(key, 0.0)
. In general, in a group of blocks, if any of the blocks have a non-zero number density for a given nucName
, then you'd have to iterate through that nuclide for every block and run numberDensities.get(nucName, 0.0)
to check if that nuclide is there.
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 those last couple comments, make any changes if you so desire. But I am good to approve this as-is. Thank you for this work, it will be a big improvement!
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.
Approved, barring one change.
What is the change?
Improve the efficiency of reaction rate calculations.
Why is the change being made?
A common post-processing step for a
GlobalFluxInterface
is to compute reaction rates from the flux solution and the microscopic cross sections that exist on the reactor model. The implementation of this calculation is done in a straightforward way, but it is naive with-respect-to the typical data structure in an ARMI simulation. The efficiency for typical problems can be greatly improved by refactoring the loops so that the outermost loop is over cross section type.Often, there are thousands of blocks in a reactor model but only a handful of unique microscopic cross section types; each set of microscopic cross sections might be shared across several hundred blocks. An outer iteration over cross section types with an inner iteration over blocks can significantly reduce the number of times a microscopic cross section set needs to be retrieved.
Checklist
doc
folder.pyproject.toml
.