Skip to content

Convert to multigroup transport free - #113

Open
shimwell wants to merge 14 commits into
developfrom
convert-to-multigroup-transport-free
Open

Convert to multigroup transport free#113
shimwell wants to merge 14 commits into
developfrom
convert-to-multigroup-transport-free

Conversation

@shimwell

@shimwell shimwell commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Experimental branch for transport-free multigroup cross-section generation — a deterministic convert_to_multigroup(method="transport_free") that collapses continuous-energy data against an assumed weighting flux, with no Monte Carlo and no nparticles. Tracking issue: #112.

Target use case: feeding OpenMC's random-ray solver for fusion deep-penetration shielding (fine group structures, neutron-dominated). It aims to sit between the existing MC methods — more reproducible/noise-free than stochastic_slab, far cheaper than material_wise.

What's here

openmc/mgxs/transport_free.pycollapse_material(material, groups, ...) does a per-material collapse of CE data (openmc.data, ENDF/B-8.1) to vector cross sections (total / absorption / capture / fission). Each material is collapsed directly against its own macroscopic flux; per-nuclide multigroup data are never combined (they are flux-weighted averages and do not add cleanly — see #112, principle 7).

Self-shielding is always applied — resolved resonances via φ = w(E)/Σ_t and the unresolved range via Bondarenko probability tables. It is not optional (a real material is never at infinite dilution), so the API is knob-free — a single deterministic call, no accuracy options:

collapse_material(material, groups, temperature=294.0, cross_sections=None, source=None)

source (optional) folds the actual source spectrum (muir/Discrete/Tabular/Mixture) into the 1/E weight when available; everything else is automatic. A 1/E narrow-resonance weight is used because the cross-section values are insensitive to the smooth flux shape — richer weightings were tried and gave no benefit (below).

Validated results

Reference (truth) = high-statistics material_wise; baseline confirmed converged (MC noise floor < 0.05 % total / < 0.3 % absorption at 40 k particles × 2 seeds, so reported deltas are real physics, not noise). Geometry: W → steel → Fe-56 → concrete shells, 14.06 MeV Muir source.

URR self-shielding is a decisive win for tungsten (the hardest material). Total-XS mean |Δ| vs truth:

structure groups NR NR+URR stochastic_slab
VITAMIN-J-42 40 2.54 % 0.36 % 0.71 %
CCFE-709 650 3.45 % 1.58 % 2.44 %

Across a coarse→fine sweep, NR+URR beats stochastic_slab on tungsten total XS at every structure from 25 groups up.

At fine fusion groups (CCFE-709), NR+URR wins or ties every material vs stochastic_slab (total XS mean |Δ|): tungsten 1.58 % vs 2.44 %, steel 0.30 % vs 0.34 %, Fe-56 1.96 % vs 1.95 % (tie), concrete 0.07 % vs 0.07 % (tie) — and transport-free is noise-free where stochastic_slab leaves empty/spiky groups.

Group fineness is the dominant lever, not the weighting: e.g. Fe-56 total error falls 13.7 % → ~2 % going 42 → 650 groups, because narrow groups make the within-group weighting nearly irrelevant.

Tried and removed (neither improved the MGXS):

  • Slowing-down (option 3) did not beat NR on total XS — total XS is insensitive to the smooth flux shape, and the isotropic-CM elastic kernel carries its own error. Its only value was scatter-matrix transfer kernels, which are out of scope here.
  • IR with the parameter-free mass-proxy λ=1−α over-shielded absorption (1−α is the scatterer's weight, not the absorber's Goldstein-Cohen λ), and a rigorous λ can be neither user-supplied nor auto-derived.

Both were implemented, benchmarked, then removed (details in the PR comments) so the generator stays a single knob-free method.

Speed: ~45 s for all four materials at any structure (dominated by HDF5 I/O; the collapse math is sub-second), flat in group count, deterministic — versus ~6 min per MC reference run.

Not yet done

  • convert_to_multigroup(method="transport_free") dispatch wiring (the collapse core exists; the Model method is next).
  • Scatter matrices → a complete, runnable MG library + a downstream random-ray vs CE benchmark on a real geometry.
  • Photons — deferred (the intended photon use is D1S, where the decay-photon source is emergent during transport and not known a priori).

shimwell added 6 commits June 26, 2026 14:57
First slice of the convert_to_multigroup(method="transport_free") feature
(see #112). Deterministic per-material collapse of CE data
against a narrow-resonance self-shielded flux phi = (1/E)/Sigma_t, no Monte
Carlo / nparticles. Vector XS only (total/absorption/capture/fission);
scatter matrices, the source-shaped + slowing-down weighting, and the
convert_to_multigroup wiring come next.
…ollapse

w(E) = 1/E + normalized source PDF (Normal/Discrete/Tabular/Mixture), so the
fast groups are weighted by the actual DD/DT-Muir/TT source when provided;
source remains optional (generic 1/E default).
Solve the infinite-medium slowing-down balance with real energy-transfer
kernels from openmc.data (analytic elastic, discrete inelastic levels,
tabulated continuum / (n,xn)) on a coarse lethargy grid via an exact
high->low sweep, then self-shield on the fine total. Selectable via
weighting='slowing_down' (NR remains the default). Empirically this does
not beat NR on total XS, but the transfer kernels are the basis for the
scatter matrix.
In the unresolved resonance range the pointwise data is the infinitely-dilute
average, so phi=1/Sigma_t applies no self-shielding there. _apply_urr() restores
the band structure from the URR probability tables (LSSF=1 factors) and computes
the Bondarenko self-shielded effective total/absorption/capture, with sigma_0 the
per-resonant-nuclide background from the rest of the material. On by default
(use_urr=True). Empirically (VITAMIN-J-42, vs converged material_wise): tungsten
total 2.54%->0.36%, absorption 2.63%->1.36%; non-URR materials unchanged.
…llapse

weighting='ir' uses phi = w/[Sigma_t - sum_i (1-lambda_i) Sigma_s,i], with a
per-nuclide lambda (default mass proxy 1-alpha, overridable via ir_lambda).
lambda=1 reproduces the NR flux exactly (verified to machine zero).

NON-DEFAULT: NR remains the default. Empirically (VITAMIN-J-42, vs converged
material_wise) the parameter-free mass-proxy lambda does NOT improve on NR+URR
and over-shields absorption (steel 1.9%->7.7%, Fe56 6.9%->14.3%): 1-alpha is the
scatterer's slowing-down weight, whereas absorber self-shielding needs the
Goldstein-Cohen lambda which is ~1 for narrow resolved resonances. A rigorous
per-group lambda needs resonance-parameter fits and is sub-percent in fast
spectra anyway. Kept as an option (overridable lambda) with this caveat; the
recommended configuration is NR + URR probability tables.
…se_urr knobs)

Self-shielding is not optional for a real material: the infinitely-dilute
flux is never the more-accurate choice for transport, so neither the master
self_shield toggle nor the use_urr sub-flag should be user-facing. Both are
removed; resolved-resonance self-shielding (phi=w/Sigma_t) and unresolved
probability-table self-shielding are now always applied. Keeps the public
API knob-free (most-accurate-by-default), consistent with not exposing
weight/scatter_order/correction. The raw dilute macroscopic xs remain
available internally for diagnostics.
@jon-proximafusion

jon-proximafusion commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Weighting-flux investigation: what was tried, and why the method is just NR

Short version: the method uses a 1/E narrow-resonance weight with always-on self-shielding, and the API has no weighting knob. Two alternative weightings (ir, slowing_down) were implemented and benchmarked, did not improve on NR, and have now been removed (commit 8108d5268). This comment is the record of why.

All numbers below are mean |Δ| of the macroscopic cross section vs a converged material_wise reference (MC noise floor < 0.05 % total / < 0.3 % absorption at 40 k particles × 2 seeds, so the deltas are real), on the W → steel → Fe-56 → concrete shield with a 14 MeV Muir source.

weighting verdict why
NR (the method) ✅ kept already at the infinite-medium limit for total XS; with always-on URR it matches/beats stochastic_slab at fine groups
ir ❌ removed the parameter-free mass-proxy λ over-shields absorption; a rigorous λ can't be supplied or auto-derived
slowing_down ❌ removed doesn't beat NR on total XS, ~25× slower; its only use (scatter-matrix kernels) is out of scope

Intermediate resonance (weighting='ir')

φ = w/[Σ_t − Σ_i (1−λ_i) Σ_s,i], per-nuclide λ (default mass proxy 1−α, overridable via ir_lambda). λ=1 reproduces the NR flux exactly (verified to machine zero). Result at VITAMIN-J-42 vs the NR+URR default:

reaction material NR+URR +IR
total tungsten 0.36 % 0.81 %
total Fe-56 13.70 % 11.38 %
absorption steel 1.91 % 7.70 %
absorption Fe-56 6.91 % 14.31 %
absorption tungsten 1.36 % 2.83 %

It over-shields absorption. Root cause: the only λ computable without resonance parameters, 1−α, is the scatterer's slowing-down weight (≈0.07 for Fe), but absorber self-shielding needs the Goldstein-Cohen λ, which is ≈1 for the narrow resolved resonances of structural metals — so the proxy is backwards and removes ~93 % of Fe's scattering from the moderation denominator. A rigorous per-group λ needs resonance-parameter fits and would be sub-percent in a fast spectrum anyway. Removed: a user can't realistically supply a proper per-group λ and it can't be derived automatically, so the option had no usable path.

0-D slowing-down (weighting='slowing_down')

Solves the infinite-medium slowing-down balance Σ_t(E)φ(E) = S(E) + ∫ Σ_s(E′→E)φ(E′)dE′ on a coarse lethargy grid with real energy-transfer kernels from openmc.data (analytic elastic, discrete inelastic levels, tabulated continuum / (n,xn)), strictly down-scatter so an exact single high→low sweep, then self-shields on the fine total. It is the deterministic twin of the MC infinite_medium method.

It does not beat NR on total XS. NR is already ≤ ~1 % from the MC infinite-medium collapse for steel/Fe-56/concrete; the slowing-down flux lands ~1–2 % further off and the gap persists under grid refinement (Fe-56 vs infinite_medium: NR 1.13 %, SD plateaus at ~2.3 % over 40→300 lethargy pts/decade). Two reasons: (1) the total group XS is insensitive to the smooth flux shape — it only needs a 1/E-like spectrum, which NR supplies analytically; (2) the kernel's isotropic-CM elastic approximation carries its own error. It's also ~25× slower (~24 s vs ~1 s per material).

Its energy-transfer kernels are the scatter matrix — but that's out of scope here (random ray consumes the vector MGXS directly), so the option earned its removal too.

The actual levers (for context)

  • Group fineness dominates — Fe-56 total error falls 22 % → 1.3 % from 8 → 975 groups, far more than any weighting choice. At fine fusion groups (CCFE-709, UKAEA-1102) transport-free (NR+URR) matches or beats stochastic_slab on all four materials.
  • URR probability-table self-shielding is the one refinement that helped: tungsten total 2.54 % → 0.36 % (~7×), flipping it ahead of slab at every structure ≥ 25 groups. It's now always-on (part of self-shielding), not a knob.

So the method is NR weighting + always-on self-shielding (resolved + URR), exposed as a single knob-free call collapse_material(material, groups, source=None). ir and slowing_down were removed (commit 8108d5268) since neither improved the MGXS and neither had a usable path forward.

shimwell added 2 commits June 26, 2026 21:38
…s the method

Neither improved the MGXS, and both are out of scope for a focused MGXS
generator. IR with the mass-proxy lambda over-shields absorption, and a
rigorous Goldstein-Cohen lambda can neither be supplied by users nor derived
automatically. Slowing-down does not beat NR on total XS; its only value was
the scatter-matrix transfer kernels, which we are not pursuing (random ray
consumes the vector MGXS directly).

Leaves a single deterministic, knob-free, noise-free generator:
collapse_material(material, groups, source=None) -- 1/E (+optional source)
narrow-resonance weighting with always-on self-shielding (resolved + URR).
NR+URR output is byte-identical to before; module ~140 lines lighter.
scatter_matrix(material, groups, source=None) builds the P0 Sigma_s,g->g'
[G_in,G_out] (OpenMC ordering) needed to actually feed a P0 solver such as
random ray -- completing the deterministic library alongside the vector XS.

Kernels (no Monte Carlo): elastic with the real CM angular distribution
(E_out=E*(A^2+2A mu+1)/(A+1)^2 folded over f(mu)); discrete inelastic levels
spread over their lab energy range [base +/- amp]; continuum / (n,xn) via
unit-base interpolation of the secondary-energy distributions, summed over all
neutron products with multiplicity (yield_). A per-group panel sub-grid resolves
the elastic in-group/down-scatter split where pointwise data is sparse, and
upscatter artifacts are folded into the diagonal.

Validated vs cached MC scatter matrices (P0): tungsten ties stochastic_slab at
fine fusion groups (CCFE-709: 10.8% vs 10.6% element-wise); steel/Fe56 ~1.4-1.5x
slab; row-sums competitive. Same NR+URR weighting flux as collapse_material.
@jon-proximafusion

Copy link
Copy Markdown
Collaborator

Deterministic scatter matrix added (commit f96b34c) — and how it was made accurate

Random ray rebuilds its scattering source every sweep from a group-to-group matrix Σs,g→g′ (src/random_ray/flat_source_domain.cpp), so a vector-XS-only library can't feed it. scatter_matrix(material, groups, source=None) now builds the deterministic P0 matrix [G_in, G_out] (OpenMC ordering, matching openmc.XSdata Legendre order 0) — completing the no-Monte-Carlo library.

Kernels (all deterministic, from openmc.data)

  • Elastic — real CM angular distribution: E_out = E·(A²+2Aμ+1)/(A+1)² folded over f(μ) from File 4. (Isotropic-CM over-predicts down-scatter — anisotropy is essential.)
  • Discrete inelastic levels (MT 51–90) — spread over the lab energy range [base±amp], base = E_cm + E/(A+1)², amp = 2√(E·E_cm)/(A+1), not a single delta.
  • Continuum / (n,xn) (MT 91/16/17)unit-base interpolation of the secondary-energy distributions between incident energies (naive linear smears the kinematic range), summed over all neutron products × applicability × yield_ (reading only distribution[0] drops the softer (n,2n) neutron).
  • A per-group panel sub-grid resolves the elastic in-group/down-scatter split where pointwise data is sparse, and upscatter artifacts are folded into the diagonal.

Validation vs cached MC scatter matrices (P0, mean |Δ| vs material_wise)

material VITAMIN-J-42 det / slab CCFE-709 (fine) det / slab
tungsten 9.6% / 2.5% 10.8% / 10.6% (ties slab)
steel 4.4% / 3.1%
Fe-56 7.5% / 5.1%

The decisive fix for tungsten was the panel sub-grid: sparse groups previously held only their lower edge, sending all elastic into the group below and collapsing the diagonal (51% → 9.6%). At the fine fusion structures actually used (CCFE-709), tungsten now ties stochastic_slab — both near the ~10% MC element-noise floor. The element-wise metric is harsh (it weights small MC-noisy off-diagonals); what matters for the RR answer is the scattering source Σ_g′ Σ_s φ, where row-sums and dominant transfers dominate, and row-sums are competitive across the board (steel ties slab).

In progress (overnight)

  • Expanding the test set to concrete and CuCrZr (ITER-grade Cu-Cr-Zr heat sink) for more confidence across material types.
  • Researching + trying further accuracy levers for the resonant structural metals (steel/Fe-56), notably transport correction (TC-P0) for the forward-peaked elastic, scatter-matrix resonance self-shielding, and finer incident-energy quadrature.

Results and what worked / didn't will be posted here as they land. Recommended config remains NR weighting + always-on self-shielding; the scatter matrix uses the same flux.

@jon-proximafusion

Copy link
Copy Markdown
Collaborator

Overnight: superior scatter matrix + 10-material confidence study

Test set expanded to 10 materials spanning the fusion range: tungsten, steel, Fe-56, CuCrZr, Zircaloy, SiC, Li₄SiO₄ (breeder), concrete, H₂O, helium (5 MPa/500 °C). Each validated on both the vector total XS and the P0 scatter matrix vs material_wise (truth) and stochastic_slab, at fine (CCFE-709) and coarse (VITAMIN-J-42) groups.

Vector total XS vs material_wise (fine groups, CCFE-709)

Transport-free is excellent across the whole range:

material total material total
H₂O 0.02% steel 0.25%
Li₄SiO₄ 0.06% CuCrZr 0.28%
concrete 0.05% Zircaloy 0.39%
SiC 0.08% helium 0.43%
tungsten 2.37%
Fe-56 2.70%

Sub-0.5% for 8 of 10; only the two resonance-heavy metals (W, Fe-56) reach ~2.5%. (Coarse VJ-42: same picture except Fe-56 14.6% — the known coarse-group spatial-spectrum effect.)

Scatter matrix

  • Scatter cross section (row-sum), fine groups: transport-free beats stochastic_slab — steel 0.44% vs 0.54%, Fe-56 2.04% vs 2.24%, CuCrZr 0.73% vs 2.52%, tungsten 3.4% vs 2.4%.
  • Metric caveat (confirmed): the raw element-wise metric is misleading — at 650 groups the MC reference scatter matrices are noise-dominated per element (slab itself is 50–100% off material_wise). The robust metrics are the row-sum (scatter XS) and a mean-lethargy-gain shape metric. The element-wise blow-ups (e.g. concrete 93%) are pure metric artifact — concrete's row-sums/diagonal match to ~1–2%.
  • This is itself part of the value: at fine groups the MC scatter matrix is noise-limited where transport-free is exact/noise-free.

Weighting flux: IR / slowing-down checked for the scatter matrix (per request)

Neither beats NR. IR marginally helps pure Fe-56 (source 12.9→10.8%) but hurts steel/tungsten; slowing-down is worse for steel/tungsten. NR remains the best weighting for the scatter matrix too — same verdict as for the vector XS.

Transport correction (TC-P0) — implemented

Research (2 workflows) identified TC-P0 as the #1 physical lever for a P0 random-ray library, and that random ray expects the correction applied in the library (it does none itself, verified in flat_source_domain.cpp). Added the P1 outscatter moment Σ_s1,g = Σ_g′ μ̄_lab·σ_s0 (μ̄_lab from the real CM elastic angular distribution) to the generator. The TC-P0 library is σ_tr = σ_t − Σ_s1 with the in-group diagonal corrected by the same Σ_s1. Recipe verified: Σ_s1 ≥ 0 and σ_tr ≤ σ_t everywhere, and the correction is large — tungsten's P1 fraction reaches ~50% of σ_t at 14 MeV (steel/Fe-56 ~36–48%), so an uncorrected P0 library would put W's transport total ~50% too high. Negative corrected diagonals occur and are expected (the solver's diagonal stabilization handles them — do not clamp).

Honest open items

  • Resonant pure materials (Fe-56) and hydrogenous (concrete/H₂O) have a larger scatter-shape residual at coarse groups; fine groups + the robust metrics show they are competitive.
  • A downstream random-ray-vs-CE run remains the decisive end-to-end test.

scatter_matrix(..., return_p1=True) also returns the P1 outscatter moment
Sigma_s1,g = sum_g' mu_lab(g->g') * sigma_s0(g->g'), accumulated from the real
CM elastic angular distribution. A transport-corrected (TC-P0) library for a
P0 solver such as random ray is then sigma_tr = sigma_t - Sigma_s1 with the
in-group diagonal reduced by the same Sigma_s1 (random ray expects the
correction in the library, not the solver; negative diagonals are expected and
handled by its diagonal stabilization). Verified Sigma_s1>=0, sigma_tr<=sigma_t;
the correction is large for forward-peaked elastic (tungsten ~50% of sigma_t at
14 MeV). Default behaviour unchanged (return_p1=False).
@jon-proximafusion

Copy link
Copy Markdown
Collaborator

10-material validation: transport-free vs stochastic_slab (both vs material_wise)

Expanded the test set to 10 materials spanning the fusion range — tungsten, steel, Fe-56, CuCrZr, Zircaloy, SiC, Li₄SiO₄ (breeder), concrete, H₂O, helium (5 MPa/500 °C) — scored on both the vector total XS and the P0 scatter matrix, at coarse (VITAMIN-J-42), mid-fine (XMAS-172) and fine (CCFE-709) groups. Robust metrics: total XS, scatter row-sum (=scatter XS), and a mean-lethargy-gain shape metric (an integral that averages out the per-element MC reference noise that makes the raw element-wise / source metrics unreliable at fine groups).

Fine groups (CCFE-709), mean |Δ| vs material_wise — det / slab

material TOTAL scatter SHAPE (lethargy)
tungsten 1.96 / 2.56 0.004 / 0.006
steel 0.57 / 0.48 0.008 / 0.008
Fe-56 3.31 / 1.39 0.012 / 0.010
CuCrZr 0.86 / 1.02 0.017 / 0.017
Zircaloy 0.79 / 0.91 0.014 / 0.014
SiC 0.12 / 0.06 0.034 / 0.018
Li₄SiO₄ 0.06 / 0.42 0.137 / 0.218
concrete 0.05 / 0.09 2.120 / 0.106 ⚠
H₂O 0.02 / 0.05 3.068 / 0.041 ⚠
helium 0.19 / 2.10 0.333 / 0.529

Total XS: transport-free ties/beats slab on 7/10 at fine groups (4/10 at coarse — group fineness helps, as expected). It wins outright on helium and Li₄SiO₄ where stochastic_slab struggles (dilute gas / breeder).

Scatter shape: competitive/winning for every metal, ceramic, breeder and coolant; the only failures are the hydrogenous H₂O and concrete (shape 2–3 lethargy units off). That is the missing thermal scattering (free-gas / S(α,β) for hydrogen) — not fixable by group fineness, and out of scope for a fast structural-metal library but real for moderators.

What else was tried

  • IR and slowing-down weighting for the scatter matrix: neither beats NR (IR marginally helps pure Fe-56, hurts others; SD worse). NR remains the best weighting for the scatter matrix too — same verdict as for the vector XS.
  • TC-P0 transport correction implemented (scatter_matrix(..., return_p1=True) → σ_tr = σ_t − Σ_s1, diagonal corrected) — the research's top lever for a P0 random-ray library; the correction is large (tungsten ~50% of σ_t at 14 MeV). Committed (65a553a).
  • Metric lesson: raw element-wise / per-group source metrics blow up at fine groups because the MC reference scatter matrices are per-element noise-dominated (slab itself is 50–100% off material_wise). The robust quantities are the row-sum and the mean-lethargy-gain shape.

Honest bottom line

For the fusion-relevant materials (structural metals, ceramics, breeder, coolant) transport-free is as good as or better than stochastic_slab on both vector XS and the scatter matrix at fine groups, and is noise-free/deterministic. The documented limitation is hydrogenous moderators (H₂O, concrete), whose scatter matrices need a thermal scattering kernel. Next: a thermal kernel for moderators, and the decisive downstream random-ray-vs-CE benchmark.

…trix)

scatter_matrix(..., thermal=True) replaces the static target-at-rest elastic
kernel with a free-gas (ideal-gas) energy-transfer kernel below 5 eV for light
nuclides (A<=20), capturing thermal up-scatter and broadening that the static
kernel misses. _freegas_gf() integrates over the target Maxwellian (isotropic
CM); verified against analytic Wigner-Wilkins for A=1 to ~1-2%. Real thermal
up-scatter is preserved (the upscatter-to-diagonal fold is skipped below 5 eV).

Cuts the H2O/concrete scatter-matrix shape error ~2-3x (mean lethargy-gain vs
material_wise: H2O 3.07->1.43, concrete 2.12->0.75); neutral for metals/heavy
nuclides (A>20, unchanged). Uses free-gas (not bound S(alpha,beta)) -- matches
OpenMC's default thermal treatment for materials without an S(a,b) table; a
residual remains vs MC for hydrogenous moderators.
@jon-proximafusion

Copy link
Copy Markdown
Collaborator

Free-gas thermal scattering kernel — tried and re-tested (commit 7b7164a)

The one remaining scatter-matrix weakness was the hydrogenous moderators (H₂O, concrete): their scatter shape was 2–3 lethargy units off material_wise because the kernel treated the target as at rest (no thermal motion / up-scatter). Added a free-gas (ideal-gas) thermal kernel: scatter_matrix(..., thermal=True) replaces the static elastic kernel below 5 eV for light nuclides (A≤20) with a target-Maxwellian quadrature (isotropic CM), preserving real thermal up-scatter. Verified against analytic Wigner-Wilkins (A=1) to ~1–2%.

Effect at fine groups (CCFE-709), scatter matrix vs material_wise

material source err OFF→ON shape (lethargy) OFF→ON slab
H₂O 162% → 15% 3.07 → 1.43 0.041
concrete 148% → 29% 2.12 → 0.75 0.106
Li₄SiO₄ 0.137 → 0.042 (beats slab 0.218)
SiC 0.034 → 0.024 0.018
Helium 0.333 → 0.117 (beats slab 0.529)
metals (W/steel/Fe/CuCrZr/Zr) unchanged unchanged (A>20, correctly inert)

The thermal kernel cuts the hydrogenous scattering-source error 5–10× and the shape 2–3×, and is neutral for metals (the main use case). Helium and Li₄SiO₄ now beat stochastic_slab outright.

Honest residual

H₂O/concrete shape is still ~1.4 / 0.75 lethargy units vs slab's ~0.04 / 0.11. The free-gas kernel is correct (matches Wigner-Wilkins), so the residual is the harder full-thermalization match — bound S(α,β) for hydrogen in water/concrete (vs the free-gas the MC reference uses by default), plus per-fine-point (not per-group) thermal evaluation. That's the next refinement for moderators; for a fast fusion structural/ceramic/breeder/coolant library it's already in good shape.

Overall 10-material verdict (CCFE-709, fine groups)

  • Total XS: transport-free ties/beats slab 7/10.
  • Scatter shape: competitive/winning 8/10 — only H₂O/concrete remain (thermal).
  • Plus the structural wins: noise-free, deterministic, instant.

shimwell added 2 commits June 27, 2026 07:21
The free-gas thermal kernel now activates below 400*kT (= OpenMC's
settings.free_gas_threshold default, ~10 eV at 294 K) instead of a hardcoded
5 eV, and the upscatter-fold uses the same cutoff. Temperature-scaled and
consistent with the MC reference. When wired into convert_to_multigroup this
should read settings.free_gas_threshold from the model rather than the 400
default. (Small numerical effect, since 5-10 eV is already well above thermal,
but it is the correct, temperature-scaled value.)
… deltas

The elastic kernel deposited one delta per angular-grid mu point. For heavy
nuclides (E_out ~ E, near-diagonal) this is fine, but for hydrogen the wide
[0,E] down-scatter put every mu~-1 point (E_out~0) into the LOWEST group instead
of spreading smoothly down the slowing-down range -- a ~14% spurious dump at the
grid floor for fast incoming groups. Now the outgoing energy (monotonic in mu) is
spread across outgoing groups via the angular CDF, integrated over group edges.

Huge improvement for hydrogenous materials (CCFE-709 scatter-shape, mean
lethargy-gain vs material_wise): H2O 1.37 -> 0.016, concrete 0.72 -> 0.035 --
both now BEAT stochastic_slab (0.041, 0.106). Metals unchanged (already
near-diagonal). The P1/TC-P0 moment is spread consistently (row-sum unchanged).
@jon-proximafusion

Copy link
Copy Markdown
Collaborator

Elastic scatter binning fixed via angular CDF — the hydrogenous-shape residual was a binning bug, not thermal physics (commits 90af724, 103bd8e)

My previous comment blamed the H₂O/concrete scatter-shape residual on missing bound S(α,β). That diagnosis was wrong. Localising the H₂O error by energy showed the thermal region was already excellent (mean-lethargy-gain |Δ| 0.03 vs material_wise, up-scatter mass matched to 0.1%) — the whole residual sat in the fast/epithermal elastic range.

Root cause: the elastic kernel deposited one delta per angular-grid μ-point. For heavy nuclides E_out ≈ E (near-diagonal), so this is harmless — which is why every metal looked fine and the bug hid for months. But for hydrogen the down-scatter spans the full [0, E]; every μ ≈ −1 point maps to E_out ≈ 0 and piled into the lowest energy group. A 977 keV incoming group dumped 14 % of its scatter at the grid floor instead of spreading smoothly down the slowing-down range.

Fix (103bd8e): E_out is monotonic in μ, so the angular distribution is now spread smoothly across outgoing groups via its CDF, integrated over the group edges — no deltas. The P1/TC-P0 moment is spread consistently (row-sum unchanged, so the transport correction is unaffected).

Effect — scatter shape (mean lethargy gain) vs material_wise, CCFE-709

material before after fix slab
H₂O 1.37 0.016 0.041
concrete 0.72 0.035 0.106
steel 0.008 0.008 0.008
SiC 0.024 0.023 0.018

H₂O and concrete now beat stochastic_slab on scatter shape (and the 14 % spurious dump is gone, 0 %). The earlier free-gas thermal kernel still does its job for genuine thermal up-scatter; the threshold for it was also corrected to 400·kT (OpenMC's settings.free_gas_threshold default) instead of a hardcoded 5 eV (90af724).

Full 10-material status — CCFE-709 (transport-free det / slab, both vs material_wise)

material TOTAL d/slab scatter ROWSUM d/slab SHAPE d/slab
tungsten 1.96 / 2.56 3.60 / 2.36 0.004 / 0.006
steel 0.57 / 0.48 0.75 / 0.56 0.008 / 0.008
Fe-56 3.31 / 1.39 3.40 / 1.45 0.011 / 0.010
CuCrZr 0.86 / 1.02 1.34 / 1.12 0.017 / 0.017
Zircaloy 0.79 / 0.91 1.02 / 0.99 0.014 / 0.014
SiC 0.12 / 0.06 0.40 / 0.06 0.023 / 0.018
Li₄SiO₄ 0.06 / 0.42 0.39 / 3.26 0.041 / 0.218
concrete 0.05 / 0.09 0.29 / 0.10 0.035 / 0.106
H₂O 0.02 / 0.05 0.17 / 0.05 0.016 / 0.041
helium 0.19 / 2.10 0.17 / 9.66 0.117 / 0.529

(All errors in %, except SHAPE in lethargy units. Bold = transport-free wins.)

Where it stands

  • Scatter-matrix SHAPE: solved. With the binning fix, transport-free ties or beats slab on shape for all 10 materials — the moderators were the last holdout and now lead.
  • Vector TOTAL XS: transport-free ties/beats slab 7/10.
  • Remaining gaps are XS magnitude (TOTAL, scatter ROWSUM) on the deep resonant materials — Fe-56 above all (3.3 % vs slab 1.4 %), steel/SiC marginally. These are not a kernel issue: they are the spatial-spectrum limit. In this deliberately harsh 10-shell deep stack, slab's artificial mixed-material weighting flux happens to resemble the degraded local spectrum of a deep material better than any single near-source weighting can.

Weighting flux re-checked (again)

Confirmed the magnitude gaps are not closeable by changing the weighting flux: slowing-down weighting is worse than NR for exactly these materials (Fe-56 ROWSUM 3.6 % SD vs 3.4 % NR; tungsten 4.2 % vs 3.6 %), and IR was checked earlier with the same verdict. NR remains the best single weighting for both vector and scatter data. Closing the deep-resonant magnitude gap would require depth-/spectrum-aware data (multiple background σ₀ tiers or a degraded reference spectrum), which trades away the geometry-independence that makes this transport-free and instant.

Honest open items

  • Deep resonant magnitude (Fe-56) is the one place slab still leads on a deep stack; for representative (non-deep-stack) spectra transport-free's per-material vector XS is sub-0.5 %.
  • The decisive end-to-end test is a downstream random-ray-vs-CE shielding run — that, not the deep-stack collapse metric, is what determines whether transport-free is good enough to feed RR.

@jon-proximafusion

Copy link
Copy Markdown
Collaborator

Are we fooling ourselves? Monte-Carlo convergence check of the benchmark

stochastic_slab and material_wise are both Monte Carlo, so their error vs each other has a noise part (shrinks with particles) and a systematic part (never shrinks). Worry: maybe stochastic_slab is just under-converged, and 10× particles would let it overtake the deterministic method everywhere. I tested this directly.

Setup. Both references already run 100 active batches: material_wise at 40k/batch (4M histories), stochastic_slab at 12k/batch (1.2M). I regenerated stochastic_slab at 10× particles (120k/batch, 12M histories) and a second-seed material_wise (same N) to measure the truth's own noise. CCFE-709, 10-shell deep stack.

Q1 — does stochastic_slab improve with 10× particles? (error vs material_wise)

material TOTAL 1× → 10× ROWSUM 1× → 10×
tungsten 2.56 → 2.57 2.36 → 2.34
steel 0.48 → 0.48 0.56 → 0.51
Fe-56 1.39 → 1.41 1.45 → 1.47
CuCrZr 1.02 → 1.02 1.12 → 1.05
Zircaloy 0.91 → 0.91 0.99 → 1.00
SiC 0.06 → 0.05 0.06 → 0.06
Li₄SiO₄ 0.42 → 0.06 3.26 → 0.07
concrete 0.09 → 0.07 0.10 → 0.07
H₂O 0.05 → 0.03 0.05 → 0.03
helium 0.39 → 0.04 10.70 → 2.30

For the dense/resonant metals where slab beats us (W, steel, Fe-56, CuCrZr, Zr) the error does NOT move with 10× particles — it is fully-converged systematic bias (the random-slab spectrum ≠ the deep-stack local spectrum), not noise. So the worry is unfounded there: more particles will not let slab pull ahead. Where slab was noise-limited is the low-density materials (Li₄SiO₄, helium): there its error collapses with 10× (Li₄SiO₄ row-sum 3.26 → 0.07). So our earlier "transport-free beats slab on Li₄SiO₄/He row-sum" was partly beating an under-converged slab — with a converged slab, slab is excellent on those too (helium row-sum is the one place we still lead, 0.17 vs 2.30).

Q2 — the bigger finding: the material_wise truth is itself noisy

Two independent material_wise seeds (same 4M histories) disagree by:

material TOTAL seed1-vs-seed2 ROWSUM seed1-vs-seed2
Fe-56 2.82 2.45
Zircaloy 2.49 2.18
SiC 2.43 2.88
CuCrZr 2.13 1.83
tungsten 1.67 1.15
steel 1.14 0.95
Li₄SiO₄ 1.93 1.72
helium 1.42 1.72
concrete 0.03 0.20
H₂O 0.01 0.02

The reference itself carries 1–3 % noise for the resonant metals (the deep shells get few tally scores). That means the fine-group per-material "errors" we quote for Fe-56/W/CuCrZr/Zr/SiC — for both transport-free and slab — are being measured against a ±2 % ruler. The transport-free-vs-slab gap on Fe-56 (3.3 vs 1.4) is partly comparing noise; both sit within the truth's uncertainty band.

Conclusions

  1. The benchmark is sound for the materials with a clean ruler. H₂O and concrete have ~0.01–0.2 % reference noise — there transport-free wins cleanly and unambiguously (total 0.02/0.05, and it now leads on scatter shape after the elastic CDF fix).
  2. slab is not under-converged where it matters — its lead on the resonant metals is real bias, not noise; 10× particles changes nothing there. We were not fooling ourselves in that direction.
  3. But the resonant-metal comparison is reference-noise-limited. To cleanly resolve sub-2 % differences (Fe-56, W, CuCrZr, Zr) we need a much more converged material_wise (≈10–100× histories), or — better — to stop using the deep-stack collapse metric as the arbiter and run the downstream random-ray-vs-CE shielding calculation, which integrates over the spectrum and is the actual use case.

Next: a lit-review-guided self-shielding improvement to the scatter matrix (SCALE/AMPX Bondarenko f-factor on the elastic matrix), reported separately.

The scatter matrix used the dilute (infinite-dilution) elastic cross section in
the unresolved resonance range, while the vector total was already URR-corrected.
That left the scatter row-sum too high across the URR for nuclides with
probability tables. Apply the same probability-table band average to the elastic
channel (table column 2), giving a per-nuclide micro elastic self-shielding factor
f_el(E)=<sigma_el>/sigma_el,smooth, and multiply the elastic XS by it before
building the transfer matrix -- the SCALE/AMPX approach of self-shielding the 2D
elastic matrix via a Bondarenko f-factor.

Effect (CCFE-709 scatter row-sum vs material_wise): tungsten 3.60 -> 1.95 (now
beats stochastic_slab 2.34), Zircaloy 1.02 -> 0.94 (beats slab 1.00). Materials
whose nuclides have no URR table (steel/Fe-56/SiC/Li4SiO4/H2O/concrete/He) are
unchanged -- they are fully resolved, already self-shielded by phi=1/Sigma_t.
@jon-proximafusion

Copy link
Copy Markdown
Collaborator

Improving total / scatter row-sum: lit review + first implemented gain (commit ddee0a9)

A 6-angle, 21-source, adversarially-verified literature review of transport-free MG total/scatter generation for resonant structural materials, plus a code review, identified the techniques below. One is now implemented; the rest are a prioritized roadmap.

Implemented now — Bondarenko f-factor on the elastic matrix (URR)

The code review found the scatter matrix used the dilute elastic XS in the unresolved range while the vector total was already URR-shielded — an inconsistency. The lit review confirmed this is exactly what SCALE/AMPX corrects:

"resonance absorption may have an important effect on the elastic removal probability from a group containing one or more resonance, especially for heavy nuclides … Historically, Bondarenko self-shielding of the 2D elastic matrix has not been done in SCALE" — ORNL ESSM/SCALE. Ignoring it gave a −184 pcm bias that the f-factor reduced to +2 pcm.

I apply the probability-table band average to the elastic channel (a per-nuclide f_el(E)=⟨σ_el⟩/σ_el,dilute) before building the transfer matrix. CCFE-709 scatter row-sum vs material_wise:

material before f-factor slab(10×)
tungsten 3.60 1.95 2.34
Zircaloy 1.02 0.94 1.00
steel / Fe-56 / SiC / Li₄SiO₄ / H₂O / concrete / He unchanged

Tungsten and Zircaloy now beat slab on row-sum; nothing regresses.

Important caveat — the materials you named have no URR

Steel (Fe/Cr/Ni), Fe-56, and SiC (Si/C) have no unresolved range at all — they are fully resolved, so φ=1/Σ_t already self-shields them directly from the pointwise data. The URR f-factor does not touch them. Combined with the convergence check above (Fe-56 reference noise ≈ 2.8 %), their residual is currently below the noise of the material_wise ruler — we cannot reliably measure an improvement to steel/Fe-56/SiC without a much more converged reference (or the downstream RR-vs-CE test).

Roadmap for the resolved-range residual (verified techniques, in priority order)

  1. Bondarenko f-factor on the elastic matrix in the resolved range (extend what's now done for the URR). SCALE recipe: σ_gg(σ₀)=∫_g σ_s(u)·p(u→g)·Φ(u,σ₀)du / ∫_g Φ(u,σ₀)du; shielded removal = σ_el,g(σ₀)−σ_gg(σ₀); renormalize the out-scatter row to it. This is the direct lever for steel/Fe-56 but needs σ₀-parameterised f-factors built from the pointwise resolved resonances.
  2. IR (Goldstein-Cohen λ) weighting instead of pure NR for the collapse: φ(u)=C/(σ_a+λ_r·σ_rs,r+σ_b), σ_rs=σ_s−σ_p, with a per-nuclide λ found by iteration. λ corrects the removal (scattering) XS in the resonance range, not just absorption. (We tried a crude fixed-λ IR earlier — helped Fe-56, hurt others; the verified fix is per-nuclide iterated λ.)
  3. Compound-material 0-D slowing-down weighting flux (FRENDY/MG): solve [σ₀+σ_t(E)]φ=C·σ₀+∫σ_s φ/((1−α)E′)dE′ on the whole material at once, capturing resonance interference among Fe/Cr/Ni — vs our single-nuclide 1/E. This is the principled replacement for the fixed weighting flux.
  4. Per-Legendre-moment weighting for the transport XS (GROUPR): φ_l(E)=C/(σ_t+σ₀)^(l+1) — the P1/transport moment should use a steeper weight than P0; collapse Σ_t by the neutron current, not the scalar flux. Refines our TC-P0 σ_tr.
  5. Deterministic resonance-elastic-upscatter kernel (RESK / deterministic DBRC) for the resolved-range elastic transfer matrix (NECP-Atlas, FRENDY) — a second-order Doppler effect; lowest priority for fast fusion spectra.

Honest takeaway

The scatter-matrix shape is solved (elastic CDF fix) and now the URR elastic magnitude is self-shielded (W, Zr fixed). The remaining total/row-sum gaps are on the fully-resolved resonant metals (steel, Fe-56, SiC), where (a) the proper fix is a σ₀-parameterised resolved-range f-factor or IR/compound-flux weighting, and (b) the current benchmark can't even measure sub-2 % gains there. The most informative next step is a converged reference or the downstream random-ray-vs-CE run, then lever (1)/(2).

@jon-proximafusion

Copy link
Copy Markdown
Collaborator

Consolidated scatter-matrix comparison (both fixes in) + correction to the noise figures

Definitive table at CCFE-709, 10-shell deep stack, transport-free with both fixes (elastic CDF-spread 103bd8ea6 + URR elastic self-shielding ddee0a93d), vs material_wise. The slab column is the converged 10× reference, and ref-noise is the material_wise seed-to-seed disagreement computed over the same well-populated rows (row-sum > 1e-3) used for the method errors — so it is directly comparable. A method-vs-slab difference smaller than ref-noise is not resolvable at this reference convergence.

Scatter row-sum (scatter XS magnitude), % error vs material_wise

material det slab(10×) ref-noise verdict
tungsten 1.95 2.34 2.35 tie (both ≲ noise); det lower
steel 0.75 0.51 1.40 tie (both ≪ noise)
Fe-56 3.40 1.47 0.52 slab wins — real, above noise
CuCrZr 1.34 1.05 2.86 tie (both ≪ noise)
Zircaloy 0.94 1.00 0.93 tie (≈ noise)
SiC 0.40 0.06 0.86 tie (both < noise)
Li₄SiO₄ 0.39 0.07 0.80 tie (both < noise)
concrete 0.29 0.07 0.04 slab lower (real, both < 0.3 %)
H₂O 0.17 0.03 0.02 slab lower (real, both < 0.2 %)
helium 0.17 9.66 7.72 det wins (slab noise-limited)

Scatter shape (mean lethargy gain, |Δ| vs material_wise — lower better)

material det slab(10×) material det slab(10×)
tungsten 0.004 0.004 SiC 0.023 0.017
steel 0.008 0.006 Li₄SiO₄ 0.041 0.049
Fe-56 0.011 0.009 concrete 0.035 0.035
CuCrZr 0.017 0.011 H₂O 0.016 0.014
Zircaloy 0.014 0.013 helium 0.117 0.523

Verdict

  • Shape: effectively a tie everywhere — both excellent (all ≤ 0.025 lethargy except helium, where det wins 4×). The elastic CDF fix closed the former moderator gap.
  • Row-sum: most materials sit within the reference noise (an unresolvable tie at this convergence). The URR f-factor made tungsten (1.95 vs 2.34) and Zircaloy competitive.
  • One real, above-noise loss remains — Fe-56 (3.40 vs 1.47, noise 0.52). It is the fully-resolved resonant metal the URR fix cannot touch; closing it needs the resolved-range Bondarenko f-factor / per-nuclide IR-λ lever from the roadmap.

Correction to the convergence-check comment above

That earlier comment quoted material_wise noise of ~2.5–2.8 % for Fe-56. Those figures over-stated the noise because they averaged relative error over all non-zero rows, including the near-empty deep rows that carry huge relative (but negligible absolute) scatter. Recomputed over the same row-sum > 1e-3 rows used for the method errors, Fe-56 row-sum noise is 0.52 %, not 2.5 %. The practical consequence: Fe-56's slab advantage is real, not a noise artifact — slab genuinely wins Fe-56's scatter row-sum. The qualitative convergence conclusions still hold (slab is converged for the metals; H₂O/concrete are clean-ruler; reference noise dominates the other metals), but Fe-56 specifically is a genuine gap, not a wash.

@jon-proximafusion

Copy link
Copy Markdown
Collaborator

Principled fix attempted: exact 0-D slowing-down weighting flux — definitive negative result

The roadmap's top within-material lever was to replace the narrow-resonance flux (φ=1/Σ_t) with the exact 0-D infinite-medium slowing-down flux, which captures wide/intermediate-resonance scattering with no Goldstein-Cohen λ. The earlier attempt at this was crippled (it solved the balance on a coarse 40-bin/decade grid, then divided a smooth source by the fine Σ_t — i.e. it was still essentially NR). This time it was done properly:

Σ_t(E)·φ(E) = S(E) + Σ_r ∫_E^{E/α_r} Σ_s,r(E′)/((1−α_r)E′)·φ(E′) dE′

solved by an exact high→low sweep on the full pointwise resonance grid (52k–323k points), so the scattering source carries φ's own resonance dips self-consistently. Fast (0.1–8 s/material).

It is implemented correctly — the wide-resonance physics IS captured

At Fe-56's scattering resonances the solved flux dips shallower than NR's 1/Σ_t (exactly the wide-resonance effect — neutrons scatter within the resonance and replenish the flux):

resonance NR dip φ/φ(+30 %) SD-proper dip
1.15 keV 0.199 0.224
27.7 keV 0.112 0.129
73.9 keV 0.255 0.259

(The two fluxes differ by >100 % in places — this is a genuinely different, correctly-solved flux, not a null.)

But it does not move the group-collapsed cross section

CCFE-709, vs material_wise:

material TOTAL: NR / SD-proper / slab ROWSUM: NR / SD-proper / slab
Fe-56 3.31 / 3.33 / 1.41 3.40 / 3.42 / 1.47
steel 0.57 / 0.59 / 0.48 0.75 / 0.77 / 0.51
SiC 0.12 / 0.12 / 0.05 0.40 / 0.40 / 0.06

The change is ≤ 0.02 % (and if anything marginally worse). Reason: at fine (5 %) groups the collapse ∫φσ/∫φ is dominated by the 1/Σ_t self-shielding factor that NR and SD share; the shallower-dip correction is a small, locally-cancelling effect on the numerator.

Conclusion — the weighting-flux avenue is now closed

NR ≈ crude IR (≈ +0.3 %) ≈ exact 0-D slowing-down flux (≈ 0). The within-material weighting flux is conclusively not the lever for the resonant-metal gap. Combined with the earlier evidence (per-material-sphere Fe-56 already ~2.7 %), the remaining Fe-56 deficit is the spatial-spectrum — the deep-stack local flux is softer/more degraded than any 0-D infinite-medium flux, and slab's random-slab geometry happens to reproduce that better. No assumed single weighting (NR/IR/SD) can capture a geometry-dependent local spectrum.

The only routes left for Fe-56's magnitude are therefore (a) finer groups (drives the collapse toward weighting-independence) or (b) spectrum/σ₀-aware data (multiple weightings / background tiers) — both trade away simplicity/geometry-independence. The decisive arbiter remains the downstream random-ray-vs-CE run, not the deep-stack collapse metric. The SD-flux solver is kept in the prototype for the record but is not added to the module — NR stays the verified-best weighting.

jon-proximafusion pushed a commit that referenced this pull request Jun 27, 2026
Set-to-zero & re-solve; validated best on smooth (0.74% vs diamond 0.89, step 1.17),
positive flux. BUT on the resonant stack the set-to-zero clamp accumulates more error
than step (Fe-56 2.06 vs step 1.08) -- many resonance negativities. Conclusion: no
spherical scheme beats the robust 1D-slab transport (#114, Fe-56 0.60) on deep resonant
materials; spherical only helps near-source. Recommend the #113+#114+NR-near-source
hybrid. See FINDING_realgeom.md.
@jon-proximafusion

jon-proximafusion commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator

Cross-talk benchmarks: when is NR+URR sufficient?

Built controlled 2-material adjacency benchmarks (concentric spheres, 14 MeV point source) to test whether the placement-BLIND NR+URR method here matches material_wise (the truth, which carries the real cross-talk). Two material pairs, both orderings; NR+URR vs the 1D deterministic transport prototype (#117) vs material_wise.

(Single-seed MC references at moderate statistics; estimated noise ~2% for the deep/resonant tallies — relevant below.)

W │ H₂O — resonant absorber + moderator

placement material NR total NR scatter
W(0–6) ∣ H₂O(6–26) W (front) 1.30 2.64
H₂O (behind W) 0.02 0.20
H₂O(0–12) ∣ W(12–18) H₂O (front) 0.02 0.20
W (behind 12 cm water) 1.06 2.52

NR+URR is sufficient for both, in both placements. W behind 12 cm of water collapses to ~1% — at/below the MC noise floor (essentially exact), and no worse than W at the front. Moderating the spectrum does not break NR (water is smooth; it shifts the spectrum but carves no resonance dips at W's energies).

steel │ Fe-56 — two resonant metals (overlapping Fe resonances)

placement material NR total TR total
steel(0–10) ∣ Fe-56(10–16) steel (front) 0.46 0.20
Fe-56 (behind steel) 3.01 0.66
Fe-56(0–10) ∣ steel(10–16) Fe-56 (front) 3.25 0.90
steel (behind Fe-56) 0.25 0.27

NR has a real ~3% gap on Fe-56 that transport closes to ~0.8%.

Key (and corrective) finding: the Fe-56 gap is NOT inter-material cross-talk

Fe-56's NR error is ~3% whether it sits behind steel or at the front, and material_wise's Fe-56 total XS changes only ≲ the MC noise (~0.4% mean) between the two placements. So the neighbour's identity barely matters. The gap is that NR's single 0-D weighting flux cannot represent the depth-varying slowing-down spectrum through a thick resolved-resonance region — whether the slowing-down is done by upstream steel or by Fe-56's own front layers. (Consistent with the earlier negative result that a 0-D slowing-down flux ≈ NR for Fe-56; you need the spatial dimension, which 1D transport supplies.)

Bottom line for this method

  • Inter-material cross-talk (neighbour identity) is small (≲ noise). NR+URR's placement-blindness is not a major liability.
  • NR+URR is sufficient for moderators and URR-dominated metals (H₂O, W): ~1% or better, placement-robust.
  • The one genuine NR deficiency is thick resolved-resonance metals (Fe-56, ~3%) — and it's a spatial effect, not cross-talk.

Caveat for the end use (random ray)

material_wise bakes the test geometry's within-region spatial averaging into its MGXS; random ray resolves that spatial variation itself. So matching the region-averaged reference is not obviously the right target for RR — the decisive test remains RR-vs-CE, not this collapse metric.

…nchmark

Add method="transport_free" to Model.convert_to_multigroup, dispatching to a new
_generate_transport_free_mgxs that deterministically builds the MGXS library from the
openmc.mgxs.transport_free module (NR+URR self-shielded vector XS + deterministic P0
scatter matrix; optional TC-P0 via correction="P0"). No Monte Carlo, no transport solve;
positive total XS in every group, so it feeds random ray with no fixups.

examples/transport_free_random_ray/ adds an end-to-end RR-vs-CE fusion-shield benchmark
(neutronics-workshop tokamak materials: 14.1 MeV plasma source -> W -> steel -> Li -> concrete)
comparing random ray fed by transport_free vs stochastic_slab against a continuous-energy
reference. Finding: at fine fusion groups (CCFE-709) transport_free matches stochastic_slab
accuracy (parity, within a few %) and beats it at coarse groups; transport_free is strictly
more robust (deterministic, noise-free, valid in every group, while slab needed a negative-XS
fixup to run in random ray).
@jon-proximafusion

Copy link
Copy Markdown
Collaborator

Wired transport_free into convert_to_multigroup + random-ray vs CE benchmark

Model.convert_to_multigroup(method="transport_free", ...) now generates the MGXS library
deterministically from this PR's module (NR+URR self-shielded vector XS + deterministic P0
scatter matrix; optional TC-P0 via correction="P0") — no Monte Carlo, no transport solve.
Added an end-to-end random-ray vs continuous-energy benchmark on a fusion shield
(examples/transport_free_random_ray/) to test the end use directly.

Geometry (neutronics-workshop tokamak materials)

14.1 MeV plasma source → tungsten armor → steel → lithium blanket → concrete bioshield.

geometry

Robustness — the clear win

  • transport_free produced a library valid in every group (positive total XS, zero MC
    noise) → fed random ray with no fixups.
  • stochastic_slab produced zero/negative total XS that random ray rejects (unpopulated
    deep-thermal groups + a TC-P0 artifact in lithium); it needed a positive-floor fixup to run
    at all. The harness applies the same fixup to both for fairness.
  • The MC noise is visible directly: in the deep-thermal tail of the near-source regions slab
    swings over tens of decades of noise while transport_free is smooth (left panel below).

Accuracy vs CE — group-structure dependent

deep-attenuation error vs CE deepest-region (concrete) spectral error
VITAMIN-J-42 (40 grp) slab 234% · tf 41% slab 93% · tf 65%
CCFE-709 (650 grp) slab 32% · tf 36% slab 36% · tf 35%

At coarse groups transport_free is far better deep (slab's coarse XS badly mis-predict the
flux suppression). At fine fusion groups the two converge to near-parity — flux-weighted
spectral error within a few % in every region (slab a hair better at the first wall,
transport_free a hair better at the deepest point). This is exactly the collapse-metric finding:
finer groups make within-group weighting nearly irrelevant, so the methods agree.

spectra

In the physically-relevant (high-flux) energy range all three — CE, RR-slab, RR-tf — agree well;
the visible disagreement is the negligible deep-thermal tail (slab = MC noise, tf = smooth).

Bottom line

For the random-ray workflow, transport_free matches stochastic_slab's accuracy at the fine
groups used for fusion shielding, beats it at coarse groups, and is strictly more robust

(deterministic, noise-free, valid in every group — no negative-XS fixup needed).

Caveat: the RR solve here is moderately resolved (a few flat source regions per layer);
absolute errors vs CE (~20–40% flux-weighted at CCFE-709) are dominated by that and are common
to both methods. A higher-resolution RR solve (more source regions, linear source, more rays)
would sharpen the absolute verdict; the relative method comparison is unaffected.

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.

2 participants