Skip to content

FW/CADIS-Ω angle-informed weight windows for fusion VR: extend random ray (not Sₙ), staged & gated #111

Description

@jon-proximafusion

Summary

Investigate adding angle-informed weight windows (FW/CADIS-Ω) to OpenMC's random-ray FW-CADIS pipeline for fusion fixed-source VR (deep penetration + streaming through ports/ducts/gaps), and do it as a staged, gated plan that measures benefit before building anything large. The conclusion of the design analysis below is: extend random ray — do not build a from-scratch Denovo-like Sₙ solver — and prove the benefit over a converged ℓ=0 FW-CADIS map before writing any angular-moment machinery.

Related: #106 (RR FW-CADIS distance auto-tune) and the convert_to_multigroup convergence auto-tune. Tier 0 of this plan is that work.

Background: the angular-importance gap

CADIS/FW-CADIS build weight windows (WW) from the scalar adjoint flux φ†. In streaming geometry the importance is strongly direction-dependent (a neutron headed into a duct mouth is worth orders of magnitude more than one headed at the wall beside it), and the scalar adjoint averages that away.

FW/CADIS-Ω (Munk & Slaybaugh, ANS M&C 2017, arXiv:1612.00793) replaces φ† with a forward-weighted adjoint scalar flux

φ†_Ω(r,E) = [ ∫_4π ψ(r,E,Ω) ψ†(r,E,Ω) dΩ ] / [ ∫_4π ψ(r,E,Ω) dΩ ]

and feeds it into the same FW-CADIS WW formula. The output is still ordinary space/energy WW (angle-informed, not angle-dependent), so the WW file and the CE transport step are unchanged. By spherical-harmonic orthogonality the numerator is a contraction of the angular flux moments of the forward and adjoint solves; the dominant correction is the ℓ=1 (current) term J·J†, which is large and positive where the forward and adjoint currents align along a streaming channel.

Key finding: today this is a no-op in OpenMC

OpenMC's random-ray solver is strictly P0 / isotropic-scatter and stores only the scalar (ℓ=0) flux:

  • scatter source is a pure G×G sigma_s × scalar-flux contraction, no Legendre index — src/random_ray/flat_source_domain.cpp:121-139
  • anisotropic MGXS is hard-rejected — src/random_ray/random_ray_simulation.cpp:79 (fatal_error("Anisotropic MGXS detected..."))
  • the only stored "moments" are spatial linear-source gradients (MomentArray = Position), not angular — include/openmc/random_ray/moment_matrix.h:10-14

With only ℓ=0 available, φ†_Ω collapses exactly to φ† → CADIS-Ω is bit-identical to FW-CADIS. The missing input is angular flux moments (ℓ≥1) for both the forward and adjoint solves.

Decision: extend random ray, not build Sₙ

A 4-lens design review (performance / engineering-cost / physics-accuracy / OpenMC-strategy) was unanimous for extending RR. Rationale:

  1. Ray effects cut for RR. Sₙ ray effects are worst in optically-thin ducts/voids/streaming with localized sources — the exact fusion regime — and the standard mitigations (first-collision source, quadrature rotation, finer order) are problem-specific knobs. RR/MOC samples direction continuously and is ray-effect-free by construction. (The CADIS-Ω paper itself flagged ray effects on its labyrinth case.)
  2. Low-knob. Sₙ irreducibly adds quadrature order/type, spatial differencing, DSA/upscatter acceleration, negative-flux fixup, and a CAD→Cartesian voxel mesh. RR adds ~one internal knob (moment order, default P1) and reuses the existing CSG/DAGMC geometry and CE→MGXS pipeline.
  3. Engineering / strategy. The FW-CADIS pipeline already exists and is tested on RR (forward+adjoint solves, set_fw_adjoint_sources at flat_source_domain.cpp:1234, WW export, 26 random_ray_* regression dirs incl. weightwindows_fw_cadis*); CADIS-Ω reuses it unchanged. A Denovo-like Sₙ is person-decades of zero-overlap code that doubles OpenMC's transport surface area and breaks the self-contained-MC ethos RR was built to honor.

Sₙ would only win if angular fidelity (high moments) dominated over ray-effect-freedom and the importance solve became the memory/wall-clock wall and the low-knob constraint were relaxed — a conjunction that does not hold here.

Important caveats / risks

  • RR moment noise is not benign. φ†_Ω's numerator is a product of two noisy estimators, and RR has documented structured biases (large overestimates, negative fluxes) in exactly the low-flux void/duct regions of interest (docs/source/methods/random_ray.rst:533-561). RR's real edge over Sₙ is ray-effect-freedom + geometry/pipeline reuse — not that its error averages away. Needs denominator flooring, moment smoothing, and an auto-fallback to ℓ=0.
  • Self-consistency. A physically consistent ℓ=1 current moment requires anisotropic scatter in the solve (lift the fatal_error, generate anisotropic MGXS — which grows the MGXS burden adding trigger to mgxs convert openmc-dev/openmc#3925/auto-tune is shrinking, and adds per-region angular source state). Prior art exists: anisotropic scattering (and linear sources) in the random ray method (Neame & Cosgrove, NSE 2024) — but validated on a thick reactor benchmark (C5G7), not sparse-hit fusion streaming.
  • No MPI domain decomposition in RR (random_ray_simulation.cpp:269, rank-0 only). Adding forward+adjoint × P1/P3 moments multiplies the single-node footprint and could hit the memory ceiling on the first real fusion CAD model. This is the one factor that would flip the answer toward Sₙ at extreme scale — gate on a memory/runtime check.
  • WW are applied angle-blind (space/energy bins only). CADIS-Ω is a scalar reweighting of the same map: in a straight duct it largely rescales importance ℓ=0 already places along the channel; the genuine redistribution is at bends/corners/junctions. So the benefit over a converged ℓ=0 map may be modest, and the published ~28× (Denovo vs coarse CADIS, one labyrinth) does not transfer.

Proposed staged plan

Tier 0 — ship auto-tuned ℓ=0 FW-CADIS (this largely exists).
Close #106 (runtime miss-rate-driven distance_inactive/distance_active) and fold in the convert_to_multigroup convergence auto-tune. This is today's genuine lowest-knob / highest-performance baseline — and possibly the whole answer.

GO / NO-GO gate (before any moment plumbing).
On a representative fusion single-bend duct problem, measure the FOM delta of an angle-informed importance map over the converged Tier-0 map. If the delta is small → stop; Tier 0 is the workflow.

Tier 1 — cheap post-hoc P1 current tally (only if Tier 0 underperforms).
Accumulate a per-region/per-group current moment J = ∫ ψ Ω dΩ on the existing P0 solve (accept P0-transport / P1-diagnostic inconsistency), for forward and adjoint, and form φ†_Ω from the ℓ=0 + ℓ=1 (J·J†) terms. Avoids lifting the fatal_error and avoids anisotropic MGXS. Reuses the existing directional-accumulation + locking + reduction pattern already proven for the linear-source spatial moments (src/random_ray/random_ray.cpp ~446-461, ~583-639). Substitute φ†_Ω at the single WW scoring point flat_source_domain.cpp:640-641 (scoped to the FW-CADIS flux path — that line also feeds total/fission scores). Add an auto-fallback to ℓ=0 when the J·J† moment is too noisy.

Tier 2 — full self-consistent CADIS-Ω (only if Tier 1 insufficient and measured FOM gap justifies).
Lift random_ray_simulation.cpp:79, add anisotropic-scatter transport + anisotropic MGXS (fold into the auto-tune, not a user knob), leverage the NSE-2024 anisotropic-RR machinery, extend to P3.

Parallel watch-item. Add MPI domain decomposition (or a hierarchical/coarsened importance mesh) to RR if the importance solve becomes the bottleneck.

The φ†_Ω contraction (P1 form to implement)

Expanding to first order, ψ(Ω) ≈ (1/4π)(φ + 3 J·Ω) with scalar flux φ = ∫ψ dΩ and current J = ∫ψΩ dΩ, and using ∫Ω dΩ = 0 and ∫(J·Ω)(J†·Ω) dΩ = (4π/3) J·J†, the CADIS-Ω quantity reduces (up to an overall constant absorbed by the WW 1/(2·max) normalization) to:

φ†_Ω(r,E)  ∝  φ†_adj(r,E)  +  3 · [ J_fwd(r,E) · J†_adj(r,E) ] / φ_fwd(r,E)
  • First term = the ordinary scalar adjoint flux → recovers plain FW-CADIS exactly (the N=0 baseline / regression check).
  • Second term = the angular correction: forward current · adjoint current, normalized by forward scalar flux; large and positive where both currents align along a streaming channel.
  • Inputs per (region, group): φ_fwd, φ†_adj (both already computed) plus the NEW current vectors J_fwd, J†_adj.
  • Watch: φ_fwd → 0 in deep voids (needs a floor); J·J† can be negative when currents anti-align (clamp φ†_Ω ≥ the ℓ=0 term, or floor at 0).
  • P3 would add Σ_{ℓ=2,3} φ_ℓm φ†_ℓm; defer unless P1 proves insufficient.

Implementer's map (code pointers, branch making-wheel-3)

Task Location Note
Accumulate new current moment J (fwd + adj) src/random_ray/random_ray.cpp:440-462 (flat-source scalar accum) + void/linear variants Mirror the linear-source spatial-moment accumulation at random_ray.cpp:600-646 (MomentArray, locking, MPI reduce). Ray direction u() and angular_flux_[g] are already in scope.
New per-region/group storage for J include/openmc/random_ray/source_region.h:367-385 (beside scalar_flux_*) A 3-vector per (region, group), × {fwd, adj}.
Snapshot forward J before the adjoint overwrites it flux_swap (src/random_ray/source_region.cpp:175-181) Mirror how set_fw_adjoint_sources (flat_source_domain.cpp:1234-1273) snapshots the forward scalar flux.
Adjoint construction (exists, no change) transpose_scattering_matrix (flat_source_domain.cpp:1395-1414)
Form φ†_Ω & substitute flat_source_domain.cpp:640-649 (random_ray_tally, SCORE_FLUX) Scope to the FW-CADIS flux path — that line also feeds total/fission scores.
CADIS inversion / WW formula (unchanged) src/weight_windows.cpp:624-658 WW = 1/φ†, normalized by 1/(2·max).
New method string fw_cadis_omega Python openmc/weight_windows.py:614; C++ src/weight_windows.cpp:790-814 (branch after :798) Or a moment-order option defaulting to 0 (= FW-CADIS).
Tier 2 only: allow anisotropic scatter lift fatal_error at random_ray_simulation.cpp:79 Needs anisotropic MGXS + per-region angular source state.
Scaling watch-item no MPI domain decomposition: random_ray_simulation.cpp:268-271 fwd + adj × moments live on rank 0 only.
WW export/import (unchanged) to_hdf5 weight_windows.cpp:739-747; import simulation.cpp:162

GO/NO-GO benchmark & metric

  • No duct/streaming geometry exists in-tree. The RR FW-CADIS regression tests tests/regression_tests/weightwindows_fw_cadis{,_local,_mesh}/ all use a simple three-region void-layered cube (random_ray_three_region_cube() in openmc/examples.py ~:875), not a true duct. The gate needs a new single-bend duct benchmark — extend the random_ray_* model factories in openmc/examples.py:875+, modeled on the labyrinth / single-bend duct from the references.
  • The metric is built in: tally.figure_of_merit = 1/(rel_err² · simulation_time) (openmc/tallies.py:955-962), with tally.std_dev (:589-609) and tally.mean. Gate = FOM(angle-informed WW) vs FOM(converged ℓ=0 FW-CADIS WW) at the deepest tally, both consuming their WW in the same CE transport.

Acceptance criteria

Open questions / decisions to make

  • Moment order: start at P1 (current only). Is P3 ever worth it, given RR is ray-effect-free?
  • Consistency (the Tier-1→Tier-2 gate): does the cheap post-hoc P1 tally on a P0 solve yield a usable φ†_Ω, or is self-consistent anisotropic transport required? (Empirical.)
  • Denominator flooring: what floor for φ_fwd → 0 in deep voids? (reuse the ZERO_FLUX_CUTOFF pattern, or a relative floor.)
  • Negative correction: clamp φ†_Ω ≥ the ℓ=0 term, or floor at 0, when J·J† < 0?
  • Moment denoising: is coarse-mesh averaging of the currents needed, and at what length scale?
  • Auto-fallback trigger: what rel-err threshold on the J·J† moment falls back to ℓ=0 FW-CADIS?
  • Memory: does fwd+adj × (scalar + 3-vector current) per region·group fit a single node (no MPI DD) on a real fusion CAD model?

Side discussions & dead ends (for the record)

Approaches considered and rejected:

  • Build an in-tree Denovo-like Sₙ solver — rejected (see Decision): ray effects are worst in the fusion ducts/voids we target, it explodes user-facing knobs, it's person-decades of zero-overlap code, and it breaks the self-contained-MC ethos RR exists to honor.
  • Couple to an external Sₙ code (Denovo/ADVANTG) — rejected: reintroduces exactly the external deterministic dependency RR was built to eliminate; Denovo is SCALE-gated and drives MCNP, not OpenMC.
  • "Just swap φ†_Ω in" as a quick patch — dead end: there are no ℓ>0 angular moments in RR to swap, and the single WW scoring line (flat_source_domain.cpp:640-641) also feeds total/fission scores, so a blind variable replacement would corrupt other RR tallies. The substitution must be scoped to the FW-CADIS flux path.

Useful side insights that shaped the plan:

  • Backend-invariance collapses the RR-vs-Sₙ question. CADIS-Ω emits ordinary space/energy WW, so the FOM-dominating CE transport step is identical regardless of backend. The decision reduces to "which backend gives the best importance map per unit of one-time preprocessing effort" — which is why solver raw speed matters far less than map quality in the ducts.
  • The angular correction is dominated by ℓ=1. By spherical-harmonic orthogonality ∫ ψ ψ† dΩ = Σ_ℓm φ_ℓm φ†_ℓm; in a streaming duct the dominant correction is the current term J·J† (both currents align with the duct axis). So low order (P1) likely captures most of the benefit — this is what makes the cheap Tier-1 path viable and means high-order Sₙ fidelity is not where the win is.
  • "Add P1 to RR" has two distinct meanings (often conflated): a cheap post-hoc current tally on the existing P0 solve (Tier 1, inconsistent but possibly sufficient) vs self-consistent anisotropic P1 transport (Tier 2, needs anisotropic MGXS + lifting the fatal_error). Keeping these separate is what keeps Tier 1 cheap.
  • Course-correction during analysis: RR moment noise was initially framed as "benign zero-mean that averages out" — that's wrong. RR has structured biases (huge overestimates, negative fluxes) in low-flux void/duct regions, so the correct justification for RR is ray-effect-freedom + pipeline reuse, and the plan must include moment smoothing + ℓ=0 auto-fallback.
  • WW are applied angle-blind, so CADIS-Ω only reshapes the scalar map — it rescales importance ℓ=0 already places in a straight duct and redistributes meaningfully only at bends/corners. Hence the benefit-vs-converged-ℓ=0 question, and the GO/NO-GO gate, rather than assuming the paper's ~28× (which was Denovo vs coarse CADIS on one labyrinth and does not transfer).

Related in-flight work

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions