Skip to content

Fix Mgxs::get_xs CHI_DELAYED indexing the wrong tensor when gout is null - #4067

Open
dallonby wants to merge 1 commit into
openmc-dev:developfrom
dallonby:fix-mgxs-chi-delayed
Open

Fix Mgxs::get_xs CHI_DELAYED indexing the wrong tensor when gout is null#4067
dallonby wants to merge 1 commit into
openmc-dev:developfrom
dallonby:fix-mgxs-chi-delayed

Conversation

@dallonby

Copy link
Copy Markdown

Description

Found while porting the OpenMC transport engine to Apple Silicon GPUs (Metal) — dallonby/openmc-metal — where flattening the MG data model for the device meant auditing these tensor layouts against the code that reads them.

The gout == nullptr branches of the CHI_DELAYED case in Mgxs::get_xs (src/mgxs.cpp) sum delayed_nu_fission where they should sum chi_delayed:

  • delayed_nu_fission is rank 3 with shape [angle][delayed group][incoming group] (src/xsdata.cpp), but was indexed with four indices, (a, *dg, gin, g). tensor::Tensor::operator() performs no rank check, so the four-index read walks past the stride vector and reads out of bounds.
  • In the dg == nullptr branch, the inner loop bound was delayed_nu_fission.shape(3), which returns 0 for a rank-3 tensor — so that branch silently returned 0 rather than a spectrum sum.

Both branches are meant to return chi_delayed summed over outgoing groups (mirroring the structure of the CHI_PROMPT case); they now read chi_delayed with its actual shape [angle][delayed group][incoming group][outgoing group] and loop over chi_delayed.shape(1) / shape(3).

Also fixed: the dimension comment for chi_delayed in include/openmc/xsdata.h documented the layout as [angle][in group][out group][delayed group], which does not match the allocation in src/xsdata.cpp ({n_ang, n_dg, n_g, n_g}). The comment now matches the code.

Reachability / impact: no current caller reaches the fixed branches — the only external CHI_DELAYED/CHI_PROMPT caller (src/random_ray/flat_source_domain.cpp) always passes a non-null gout, and the direct-index gout != nullptr path (which is correct) is untouched. So this changes no existing results; it removes silent out-of-bounds reads / silent zeros waiting for the first caller that asks for a group-summed delayed spectrum.

A possible follow-up hardening (not included here to keep this minimal): a debug-mode rank assertion in tensor::Tensor::operator(), which would have turned this into a loud failure. Happy to add a unit test exercising get_xs(CHI_DELAYED, gin, nullptr, ...) if that's preferred.

Checklist

  • I have performed a self-review of my own code
  • I have run clang-format on any C++ source files (if applicable)
  • I have followed the style guidelines for Python source files (not applicable)
  • I have made corresponding changes to the documentation (the xsdata.h layout comment)
  • I have added tests that prove my fix is effective (not included — the fixed branches are currently unreachable from any caller; can add a C++ unit test on request)

🤖 Generated with Claude Code

The gout == nullptr branches of the CHI_DELAYED case summed
delayed_nu_fission instead of chi_delayed:

- delayed_nu_fission is rank 3, [angle][delayed group][incoming group]
  (xsdata.cpp), but was indexed with four indices. tensor::Tensor's
  operator() performs no rank check, so the four-index read walks past
  the stride vector and reads out of bounds.
- With dg == nullptr, the inner loop bound used
  delayed_nu_fission.shape(3), which is 0 for a rank-3 tensor, so the
  branch silently returned 0.

Both branches are meant to return chi_delayed summed over outgoing
groups; they now read chi_delayed with its actual shape
[angle][delayed group][incoming group][outgoing group]. The chi_delayed
dimension comment in xsdata.h documented the layout as
[angle][in][out][delayed group] and is corrected to match the
allocation in xsdata.cpp.

No current caller reaches the fixed branches: the only external
CHI_DELAYED caller (random_ray/flat_source_domain.cpp) always passes a
non-null gout, so this produces no behavior change today — but any new
caller would have hit silent out-of-bounds reads or a silent zero.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dallonby
dallonby requested a review from nelsonag as a code owner August 21, 2026 02:14
dallonby added a commit to dallonby/openmc that referenced this pull request Aug 21, 2026
CHI_DELAYED -> PR openmc-dev#4067; discrete-line lin-lin sampling (with the
ENDF/B-VIII.0 photon-table census) -> issue openmc-dev#4068 + PR openmc-dev#4069;
MG density_mult tally asymmetry -> issue openmc-dev#4070.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant