Survival Normalization
Please close https://github.com/openmc-dev/openmc/pull/2650 as I will be attempting to shepherd this through. Apologies for the long read ahead.
Description
This PR creates the functionality of Survival Normalization, perhaps better described as Survival Biasing Source Normalization. It is meant to complement and enhance OpenMC Survival Biasing in certain situations. This functionality is used to make the weight parameters (weight and weight_avg (known in the C++ code as weight_cutoff and weight_survive) relative to the weight of the source.
Situations where this should be of benefit is when numerous important particles are present on the source at weights below that of the weight_cutoff, normalization prevents them from being rapidly rouletted. This should notably be the case for biased general sources (which OpenMC currently lacks natively). It is currently only applicable to phase-space sources (.mcpl and .h5). Should/could later be expanded and enabled for general (biased) sources.
Background
In comparisons between MCNP and OpenMC with survival biasing and with phase-spaces I kept seeing significant differences in uncertainties. This was partly complicated by the tracklength heating being disabled in np. Eventually I tracked it down to how the two are respectively handling survival biasing. Unfortunately my analysis erred and this feature will not improve my work, I do believe however that it is still a useful feature and will aid some. (In my case FOMs decrease by ~2%).
For phase-space sources, the weight parameters are made relative to the starting weight of each initialized history. That is, unique weight parameters per particle history. This follows the practice in the grand-daddy of Monte Carlos https://apps.dtic.mil/sti/tr/pdf/ADA231425.pdf doc page 64/65, pdf page 70/71 code block 375
Here is the best reference and investigation into weight cutoffs (survival biasing parameters) that I have come across. https://www.osti.gov/servlets/purl/5823239 doc page 87, pdf page 96 paragraphs + Table 2.2
Example
An example application of Survival Biasing with Survival Normalization can be found here: https://github.com/yrrepy/OMC-SurvNorm_Example The .xlsx in that repository describes the problem and contains the results.
Case 1 is an SSW/SSR where the user changed the weight parameters between the two calculations. Survival normalization improves the FOM by a minimum of +12% in the outer shell, the most difficult region to score in this case. FOMs elsewhere decrease.
Case 2&3 is a constructed MCPL phase-space source masquerading as a biased isotropic point source. Survival normalization almost across the board significantly improves FOMs Case 2&3 Xb use the Survival Normalization feature. Case 2&3 Xc uses a manual multiplication of the weight parameters by the minimum weight of the biased source. The in-code per history Survival Normalization produces better FOMs than with the singular adjustment. It could well be that the current phase-space condition in the code could be removed and allow Survival Normalization to work for all sources (under the hypothesis that someone produced a biased library source). But whether the per history FOM improvement continued in general I am not sure and could well be not the case.
In term one these examples could be the basis for additional test(s).
Code Changes
We added a few bits of functionality into the settings.cpp, particle_data.h, simulation.cpp and connecting physics files. The code takes the xml Boolean and enables the functionality of survival normalization. The values inside the survival normalization are then stored inside new object variables inside particle class. These values are then used inside all the physics files for calculations.
Settings.cpp
Added survival_normalization and source_file Booleans Added source_file boolean inside the source xml toggle Added new xml toggle boolean to enable and disable survival_normalization
Particle_data.h
Added private variables inside the particle class Added new object variables wgt_cutoff and wgt_survive Added setters and getters for both new object variables
Simulation.cpp
Toggle to adjust weight cutoff and weight survive by multiplying the current weight Added the survival normalization functionality inside the given if statements scenario from settings.cpp
Physics.cpp/physics_common.cpp/physics_mg.cpp
Add the object variable into the appropriate weight_cutoff and weight_survive given the if statement scenario
Fixes
This PR seeks to address in part: https://openmc.discourse.group/t/tally-uncertainty-openmc-vs-mcnp/1872/11
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)
- [x] I have made corresponding changes to the documentation (if applicable)
- [ ] I have added tests that prove my fix is effective or that my feature works (if applicable)
To-Do
- Implement Python API functionality
Hi Ethan, thank you for the review. This is my first time formally PR'ing, so apologies if I don't get all the workflow correct.
Indeed, I find your suggestion to simplify the mechanics of the normalization much cleaner. Having the variable wgt0 in the particle class is arguably much more useful than normalized cutoffs in the class.
I left the if statement in physicsX.cpp for the case where a source is biased (or of varying weights) but the user does not want to normalize. But perhaps there is a way to have the code check instantly there when it multiplies by wgt0?, I'm not terribly familiar with the fancier functions in C++. The if survival_normalization=false could go in simulation.cpp and tell it to not set wgt0. But seems better to just always set wgt0.
Re: General Sources
I did some testing and in my two simple cases found that the per particle survival normalization was better than normalization by the minimum weight of all the particles.
The current condition that the normalization mechanics only work for phase spaces,
if ((settings::source_file || settings::surf_source_read),
could be removed so that this mechanism works for general sources. But I would recommend testing it on some purpose-built biased sources first.
What should I focus on the keep this moving forward?
Some tests? Python bindings?
@eepeterson @pshriwise and I talked about this PR the other day. I'll let @eepeterson summarize our thoughts as we were all on the same page.
Hi, well glad you guys think this kind of normalization will work in general. From what I looked at, it did seem effective.
I'm happy to remove the Boolean conditions that were limiting it to only phase-spaces, but I do think it would be best to keep the survival_normalization Boolean allowing it to be switched on and off (a-la MCNP where wc1,wc2 can be <0 or >0 determining whether to norm, but here with the Boolean) I did find some situations where it was better to not normalize the weight cutoffs.
Bump on the above, and comments on the approach to take for a Boolean switch (before coding it and the other suggested changes)
Closed in favor of https://github.com/openmc-dev/openmc/pull/3070 which is synced with latest OpenMC version