Repository navigation
Conversation
score_fission_eout() scores analog nu-fission, prompt-nu-fission and delayed-nu-fission tallies that have an EnergyoutFilter once for each neutron banked at the collision. For a delayed neutron on a tally that also has a DelayedGroupFilter, it multiplied the score by the product of the filter weights and passed the result to score_fission_delayed_dg(), which multiplies by the same product again. The helper has applied the weights itself since openmc-dev#1462, but this call site kept its own multiplication, so any filter with non-unit weights, such as EnergyFunctionFilter or the Legendre, spherical harmonics, spatial Legendre and Zernike expansion filters, was applied twice on this path: a bin that should score w scored w^2, e.g. four times the unweighted tally instead of twice for an EnergyFunctionFilter with a constant value of 2. The score is now passed without the weights, as at every other call site of the helper. Add the mg_delayed_eout_weights regression test. It tallies analog delayed-nu-fission in a two-group slab with an EnergyoutFilter, a DelayedGroupFilter and a SpatialLegendreFilter, and checks that summing the tally over the outgoing energy bins reproduces the same tally without the EnergyoutFilter, and that summing it over the delayed groups reproduces the same tally without the DelayedGroupFilter. Both reference tallies are scored along other code paths. Before this change the P1 bins differed by about 30%; now all bins agree to round-off. The test generates its multigroup cross sections, so it needs no nuclear data.
Author
|
The last CI run of this PR did not reach the code. In Tests and Coverage (run 37666792023, attempt 2), five jobs hung while installing packages, in
The C++ Format Check run was cancelled in the same way. The jobs that did run all passed, including Python 3.12 (omp=y, mpi=y). Could a maintainer re-run the failed jobs? Thank you. |
Author
|
Thanks for the re-run. Only Python 3.12 (omp=n, mpi=n, umesh_libs=y) was re-run, and it passed. These four jobs are still cancelled from the original apt hang, so Check CI status still fails:
Could they be re-run too? |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
score_fission_eout()applied the filter weights twice when it scored a delayed fission neutron on a tally that has both anEnergyoutFilterand aDelayedGroupFilter. It multiplied the score by the product of the filter weights, then passed the result toscore_fission_delayed_dg(), which multiplies by the same product again. As a result, every filter with non-unit weights on such a tally was applied twice: a score that should be multiplied by the weightwwas multiplied byw^2.This PR removes the multiplication at the call site. The weights are now applied once, inside the helper, as for every other caller. The PR also adds a regression test that needs no nuclear data. The bug was found while developing a time-moment tally filter (see "Related PRs").
Fixes #4181
Motivation
Affected tallies. The bug affects analog
delayed-nu-fissiontallies that combine all three of:EnergyoutFilter,DelayedGroupFilter,EnergyFunctionFilter(continuous energy only) or the expansion filters (LegendreFilter,SphericalHarmonicsFilter,SpatialLegendreFilter,ZernikeFilter,ZernikeRadialFilter).With an
EnergyoutFilter, these scores always use the analog estimator. Continuous-energy and multigroup runs both take this path.Unaffected tallies:
openmc.mgxs(for exampleChiDelayedandDelayedNuFissionMatrixXS).nu-fissionandprompt-nu-fissionwith anEnergyoutFilter.delayed-nu-fissionwith anEnergyoutFilterbut noDelayedGroupFilter.delayed-nu-fissionwithout anEnergyoutFilter.History. The call site's own multiplication was correct until d5a2340 ("Consistent use of filter_weight", merged in #1462 and first released in v0.12.0). That commit moved the weight product into
score_fission_delayed_dg()but did not remove it from this caller. Every release since v0.12.0, anddevelopup to a5bc348, applies the weights twice on this path.Example (continuous energy). A UO2/water pin cell with an
EnergyFunctionFilterof constant value 2, measured ondevelopat 3cded0f, before and after this change, with ENDF/B-VII.1 data (a check outside the test suite):[EO, DG, EF]/[EO, DG][EO, DG, EF]/[DG, EF](analog, noEnergyoutFilter)The "after" ratios are exact.
Design
The change deletes the loop that computed the weight product at the call site and passes
scoreunchanged.score_fission_delayed_dg()already computes both the filter index (after swapping in the delayed group bin) and the product of all filter weights, so the loop was redundant. A comment at the call site now says the helper applies the weights.The opposite fix, keeping the multiplication at the call site and removing it from the helper, would break the helper's 15 other callers. All of them pass unweighted scores and rely on the helper to apply the weights. After this change, every call site in
tally_scoring.cppapplies the weights exactly once.The fix also removes a loop over the tally filters for each banked delayed neutron, so this path does slightly less work.
Tests
New regression test:
tests/regression_tests/mg_delayed_eout_weightsModel. The test uses
openmc.examples.slab_mg(): a 929.45 cm multigroup slab, reflective at x = 0 and vacuum at x = 929.45 cm, run with 1000 particles for 10 batches (5 inactive). The test writes a two-group library,2g.h5:mg_tallies.Tallies. The test defines three analog
delayed-nu-fissiontallies that score the same delayed neutrons.SLisSpatialLegendreFilter(1, 'x', -929.45, 929.45), so the P1 weight is x/929.45, which lies between 0 and 1 inside the slab. The analog estimator is set explicitly on all three tallies: without it, theSpatialLegendreFilterwould give thedelayedgrouptally a collision estimator, and the checks below rely on all three tallies scoring the same analog events. A comment in the test says so.energyout-delayedgroup[EO, DG, SL]score_fission_eout()delayed-group branch (the one that was wrong)delayedgroup[DG, SL]score_general_mg()analog delayed-group path (noEnergyoutFilter)energyout[EO, SL]score_fission_eout()branch without a delayed group filterChecks. Each check compares two tallies that score the same events through different code paths, so they must agree to round-off:
[DG, SL], withinrtol=1e-10.[EO, SL], withinrtol=1e-10.inputs_true.datandresults_true.datcomparison then runs.All P1 weights are non-negative, so the P1 sums do not cancel and a relative tolerance is meaningful. The observed deviation after the fix is at most 1.6e-15. The P0 bins have unit weight and agree even without the fix, so the P1 bins are what detect the bug.
Harness choice. The test subclasses
PyAPITestHarness, as the other Python-API MG tests do:inputs_true.datrecords the generatedmodel.xml.results_true.datrecords k-effective and the tally sums: 37 short lines, so a plain diff is easier to read than a hashed result._cleanupdeletes the generated2g.h5, as inmg_tallies._compare_resultsadds assertions, asfilter_energyfundoes. These checks run before the reference comparison and use no stored values, so they test the scoring itself: aresults_true.datregenerated by the unfixed code would not make the test pass. Ondevelopthe test fails at the first of these checks.Checking simulation output needs a transport run that banks delayed neutrons, and OpenMC keeps such tests in
tests/regression_testsrather than in the unit tests.Why the test needs no nuclear data. It runs in multigroup mode with a library it writes itself, so it needs neither
OPENMC_CROSS_SECTIONSnor the NNDC library. The consistency checks compare tallies of the same events with each other, so they use no statistical tolerance and no analytic values derived from data. The reference files come from a build with-DOPENMC_ENABLE_STRICT_FP=on, as in CI, and the references of the existing MG tests reproduce on the same build. The test runs in about 0.2 s.Before and after
"Before" is
developat a5bc348 and "after" is this PR's commit on top of it. All builds are RelWithDebInfo with strict FP and OpenMP on; the MPI build uses parallel HDF5. All runs useOMP_NUM_THREADS=2.--event)--mpi, 2 ranks)[DG, SL]check finds 2/4 bins mismatched, max relative difference 0.312Ratios of the tally means (history mode; event mode gives the same values to 1e-15):
[EO,DG,SL]/[DG,SL][EO,DG,SL]/[EO,SL]--mpi)For example, the DG 1 P1 mean is 0.0394368 before and 0.0563121 after; the
[DG, SL]reference is 0.0563121 in both runs. Before the fix the P1 bins scored the sum of (x/L)² instead of x/L. Between the results the test writes ondevelopand on this PR, only 8 numbers differ: the sum and sum of squares of the four P1 bins of the first tally. k-effective and the other two tallies are identical. The committedresults_true.datmatches without regeneration.Test suite
The test set of CI (
tests/test_matplotlib_import.py tests/unit_tests tests/regression_tests) was run on a5bc348 and on this PR in the same environment: the NNDC HDF5 library (itscross_sections.xmlmatches the md5 intests/conftest.py) andOMP_NUM_THREADS=2, in three pytest processes per run (the unit tests, and the regression tests split in two).--event--mpi --mpi-np=2(2 ranks x 2 threads)No test failed in any run. The one extra pass is the new test. The skipped tests and the tests with errors are the same on both sides, and every error is raised at setup by the environment:
OPENMC_ENDF_DATA, which was not set (test_data_*.py,test_deplete_chain.py,test_endf.py).cpp_driver,source_dlopen,source_parameterized_dlopen) build against an installed OpenMC, and these builds were not installed.mpi4py, which was not installed.MPI run. The MPI run used Open MPI 4.1.6 with process binding off, through a small wrapper around
mpiexecthat unsets theOMPI_*,PMIX_*,OPAL_*andORTE_*environment variables before it callsmpiexec. Without the wrapper, the in-processopenmc.lib.init()of the CMFD regression tests (a singletonMPI_Initunder Open MPI) leaves these variables in the pytest process, and every latermpiexec -n 2 openmcin that process aborts, ondevelopand on this PR alike.Reference files. Regenerating every regression reference with
pytest --update tests/regression_tests(history mode) on a5bc348 and on this PR gives byte-identical files, apart from run-to-run differences:collision_track, the fourdeplete_*directories,microxs,surface_source,surface_source_write). All 58 also differ between two runs ofdevelop.depletion timedataset of the depletion results, and the modification times in HDF5 object headers. The same two kinds of fields differ between two 1-thread runs ofdevelop.No existing reference value changes.
Other checks.
cteston the serial and the MPI build: 14 tests, 13 passed,test_mcpl_stat_sumskipped because MCPL is not enabled. The same holds on a5bc348.--dry-run --Werror) reports no changes forsrc/tallies/tally_scoring.cpp. pyflakes 3.2.0 on the new test files and pycodestyle 2.11.1 on the Python diff report nothing.Not run (CI configurations not reproduced):
mpi4py.OPENMC_ENDF_DATAor an installed OpenMC (errors on both sides, listed above).Compatibility
openmc.lib.winstead ofw^2. Users who post-processed such tallies to undo the extra weight would need to drop that step.Related PRs
developat a5bc348.delayed-nu-fissionwith anEnergyoutFilter, aDelayedGroupFilterand the moment weights tau^n, which this bug would turn into tau^(2n). It should be merged after this PR.AI Assistance
Code, tests, analysis, reviews and text:
Review of the pull request formalities:
Review of the change:
Checklist