Biased multigroup scattering when multiplicity varies with outgoing group

Aperta
#4,205 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 2 giorni

@kongshifer ci sta già lavorando.

Dal 23/10/2026.

  • #4206 di @kongshifer — aperta

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
25/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Ferma
Stack tecnologico
cpp, python
Ambito
backend, databases

Direzione di ricerca

Read the linked sampler code in src/scattdata.cpp at the Legendre, Histogram, and Tabular sampling methods, along with the library conversion in openmc/mgxs/library.py. Start by checking how outgoing-group probabilities and multiplicities produce the reported transfer matrix; use the attached reproduce.py cases as regression tests. Done means the variable-multiplicity cases match the analytical flux and k-effective while the constant-multiplicity controls still agree.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Bugs

Bug Description

I independently reproduced a multigroup transport bias in OpenMC v0.15.3 when the scattering multiplicity varies with the outgoing energy group. The bias affects track-length flux and k-effective, not only scattering tallies.

I would like to contribute a fix and upstream regression tests. I have outlined a possible correction below and would welcome feedback on the intended sampling behavior before preparing a pull request targeting develop.

Expected and implemented transfer

Let:

  • $C_{gh}$ be the scattering event cross section from incoming group $g$ to outgoing group $h$.
  • $B_{gh}=\nu_{gh}C_{gh}$ be the corresponding neutron-production cross section, where $\nu_{gh}$ is the scattering multiplicity.
  • $C_g=\sum_h C_{gh}=\Sigma_{t,g}-\Sigma_{a,g}$ and $B_g=\sum_h B_{gh}$.

The synthetic inputs below explicitly satisfy these consistency relations.

With multiplicity data, the official library conversion supplies the nu-scatter matrix $B$. However, the outgoing-group sampler samples $p_{gh}=B_{gh}/B_g$, and the sample methods then multiply weight by $\nu_{gh}$: Legendre, Histogram, and Tabular.

Since absorption is handled before scattering, the resulting expected production matrix is

$$
B^{\mathrm{actual}}{gh}
= C_g\frac{B
{gh}}{B_g}\nu_{gh},
$$

which generally differs from $B_{gh}$. It agrees when the multiplicity is constant across the nonzero outgoing channels of each incoming group.

Proposed correction

Keep the existing outgoing-group probabilities and conditional angular distributions, but precompute a separate incoming-group weight multiplier:

$$
r_g=\frac{B_g}{C_g}
=\left[\sum_h\frac{p_{gh}}{\nu_{gh}}\right]^{-1}.
$$

Use this multiplier in all three sampling methods, so that

$$
C_g \cdot p_{gh} \cdot r_g = B_{gh}.
$$

For the example below, $r=(1.5,1.0)$.

Implementation considerations:

  • Preserve energy (the normalized production distribution) and mult (group-to-group multiplicities), since cross-section queries and matrix reconstruction also use them.
  • Initialize the separate multiplier consistently after material mixing and Legendre-to-tabular conversion.
  • Skip zero-probability terms, handle empty scattering rows, and check consistency with total minus absorption rather than silently renormalizing inconsistent data.

An alternative is to maintain a separate event-based sampling distribution $C_{gh}/C_g$ and retain the group-to-group weight multiplier $\nu_{gh}$.

This correction is an expectation-level derivation. The independent reproduction attached to this report does not include a rebuilt, corrected OpenMC executable. I am willing to implement the agreed approach, add tests that fail before the fix and pass afterward, and address review feedback.

Steps to Reproduce

  1. Extract the attached archive. It includes reproduce.py, input files, original statepoints, results, logs, and executable version output.
  2. In an environment with the OpenMC Python package and executable available, run:
python reproduce.py --output results --executable openmc
python reproduce.py --output results_survival --executable openmc --survival-biasing

Use new output directories. No external nuclear-data library is required: the script generates synthetic two-group macroscopic data.

The fixed-source model is a homogeneous, fully reflective cube with isotropic scattering, a unit source in the high-energy group, and no fission. Rows are incoming groups and columns are outgoing groups. Cross sections are in $\mathrm{cm}^{-1}$:

Sigma_t = [1.0, 1.0]
Sigma_a = [0.6, 0.8]

C = [[0.2, 0.2],
     [0.0, 0.2]]

B = [[0.2, 0.4],
     [0.0, 0.2]]

multiplicity = [[1.0, 2.0],
                [1.0, 1.0]]

For the volume-integrated flux per unit external source,

$$
\left[\mathrm{diag}(\Sigma_t)-B^{T}\right]\Phi=(1,0)^{T},
$$

so the expected flux is $(1.25,0.625)$ and total absorption is $1.25$.

The implemented transfer instead gives

$$
B^{\mathrm{actual}}=
\begin{pmatrix}
2/15 & 8/15\
0 & 1/5
\end{pmatrix},
$$

predicting the incorrect flux $(15/13,10/13)=(1.153846,0.769231)$ and absorption $17/13=1.307692$.

Independent results

The following runs use analog absorption. Quoted uncertainties are one standard deviation.

Case High-energy group flux Low-energy group flux
Correct analytical solution 1.250000 0.625000
Implemented-transfer prediction 1.153846 0.769231
OpenMC Legendre 1.153274 ± 0.001101 0.768011 ± 0.001767
OpenMC Histogram 1.153138 ± 0.001129 0.767005 ± 0.001736
OpenMC Tabular 1.152969 ± 0.001014 0.766982 ± 0.001933

Legendre-to-tabular conversion is explicitly disabled, so these cases exercise the respective samplers. Legendre fixed-source absorption is $1.306373\pm0.001336$, consistent with the implemented-transfer prediction.

Repeating with survival biasing reproduces the same bias. Controls with all nonzero multiplicities equal to 1.0 or 1.5 agree with their analytical solutions.

The script also runs a separate eigenvalue case with fission cross sections $(0.16,0.32)$, nu-fission $(0.4,0.8)$, and $\chi=(1,0)$. Fission is included in absorption. The correct $k$ is 1.0; the implemented transfer predicts $14/13=1.076923$. The original executable gives $1.076903\pm0.000609$ with analog absorption.

Environment

  • OS: Ubuntu 22.04.4 LTS, x86_64, running under WSL1 on Windows.
  • OpenMC executable: v0.15.3, commit 27e38e894697bb32a1dac7848d2618818b6b8daf.
  • Installation: conda-forge package in Miniforge; package build dagmc_mpi_openmpi_py313ha0fa856_102.
  • OpenMC Python package: 0.15.3; Python: 3.13.13.
  • Compiler reported by the executable: GNU 14.3.0, Release build.
  • Execution: one MPI process, two OpenMP threads.
  • Each run: 30,000 particles per batch, 40 batches, seed 71829; eigenvalue runs discard 10 inactive batches.
  • Nuclear data: synthetic macroscopic multigroup library generated by the reproducer; no continuous-energy data required.

The complete archive contains both analog and survival-biasing runs, including the constant-multiplicity controls.

openmc_scattering_issue.zip

Lingua principale
Python
Stelle
1.1k
Fork
683
Merge medio
3g 10h
PR unite (30g)
17

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di openmc-dev/openmc

Tutte le issue di openmc-dev/openmc

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.