Variance reduction
MAGIC weight windows and alias-table source sampling in Nucleide.
Nucleide provides two variance-reduction utilities built on MCNP mesh tallies: MAGIC weight-window generation, weight-window emission for OpenMC and Serpent, and mesh-based source sampling with alias tables.
MAGIC weight windows
MAGIC converts a forward mesh tally into weight-window lower bounds. The algorithm is simple and deterministic:
For each energy group , find the maximum flux over all volume elements:
Then the weight-window lower bound for volume element and group is
where is the relative error of the tally and is the error tolerance. The factor of normalizes the peak-flux voxel to a lower bound of ; MAGIC is intended to be iterated so the weight windows refine over successive forward runs (Cooper & Larsen 2001)cooper-2001.
MAGIC is implemented in crates/vr-tools/src/magic.rs. The public functions
are magic() for energy-integrated totals and magic_with() for explicit
array selection and parameters.
Total vs. per-group mode
| Aspect | Total | Per-group |
|---|---|---|
| Source arrays | `total_result`, `total_rel_error` | `result`, `rel_error` |
| Lower bounds per voxel | 1 | 1 per energy group |
| Output tag | `ww_n` / `ww_p` | `ww_n` / `ww_p` |
| Energy bounds tag | `n_e_upper_bounds` / `p_e_upper_bounds` (single upper bound) | `n_e_upper_bounds` / `p_e_upper_bounds` (`e_bounds[1:]`) |
Parameters
| Parameter | Default | Meaning |
|---|---|---|
| tolerance τ | 0.5 | Relative error above which a bound is nulled. |
| null_value | 0.0 | Value assigned to nulled elements. |
Worked example
Consider a tally with four volume elements and total fluxes and relative errors all below the default tolerance of .
Find the group maximum: .
Compute the scale factor: .
The lower bounds are .
If the tolerance were tightened to , the element with error would
be nulled to null_value instead.
Emitting weight windows for OpenMC and Serpent
MAGIC produces lower bounds. Two functions reformat the same MagicOutput for
other transport codes — pure formatting over the meshtal mesh bounds, with no
new math:
emit_openmc_weight_windows(tally, output, ...)returns asettings.xmlfragment: a<mesh>element (id,dimension,lower_left,upper_right) plus a<weight_windows>element that references it (mesh,particle_type,energy_bounds,lower_ww_bounds,upper_ww_bounds,survival_ratio,max_split,weight_cutoff). The element spelling matches what OpenMC’s own writer emits and its transport code parses (settings specification §3.29 and §3.66). Energies are converted from MeV to eV, and the window values are written with the x index varying fastest inside each energy group — the same ordering OpenMC uses internally. Paste the fragment inside the existing<settings>root.emit_serpent_wwin(tally, output, name, file)returns the text of a weight-window file plus the input card that references it. Serpent reads third-party window meshes in the MCNP WWINP text format throughwwin <name> wf "<file>" 2(Serpent user guide §2.2.8.3), so that is the spelling the emitter writes; the file re-parses cleanly with the workspace WWINP reader. Serpent’s own first file format is not publicly documented, so it is not produced — requesting it raises a clear error.
MAGIC computes lower bounds only. OpenMC requires upper bounds as well, so the emitter derives them as five times the lower bound (the same ratio OpenMC applies when importing MCNP files) and says so in its notes; Serpent derives its upper bounds itself at load time. Inputs that cannot be represented — negative or non-finite bounds, energy or mesh bounds that are not increasing, or tuning values outside the ranges the code accepts — raise a clear error instead of writing a partial file. Cells nulled by MAGIC (zero lower bounds) are written as zeros and called out in the notes.
The emitters live in crates/vr-tools/src/windows.rs, exposed as
nucleide.vr.emit_openmc_weight_windows and nucleide.vr.emit_serpent_wwin.
Alias-table source sampling
The MeshSourceSampler uses a Walker/Vose alias table to draw particle
birth voxels in time per sample after an construction step.
Alias-table construction
Given a discrete probability mass function over bins:
- Normalize so that .
- Scale each probability by , giving .
- Partition bins into “small” () and “large” ().
- Pair a small bin with a large bin :
- Set .
- Set .
- Reduce the large bin’s surplus: .
- Drain any remaining bins with .
Sampling
To draw one index:
Generate .
Pick column .
Return if ; otherwise return .
Mesh source sampling modes
| Mode | Sampling PDF | Birth weight |
|---|---|---|
| Analog | ∝ flux × volume | 1.0 |
| Uniform | ∝ volume | analog_pdf / uniform_pdf |
| User | ∝ user_density × volume | analog_pdf / user_pdf |
MeshSourceSampler selects a voxel uniformly within the chosen cell. Sub-voxel
or fractional-cell sampling modes are not implemented.
Assumptions and limitations
- MAGIC requires positive flux somewhere: if every value in an energy group
is , the normalization divides by zero and
Error::ZeroMaxFluxis returned. - MAGIC rejects non-finite flux or error values:
NaNor infinite entries in the input arrays produceError::NonFiniteTallyrather than poisoned lower bounds. - Mesh source sampling rejects negative values: negative
total_resultoruser_pdfentries produceError::NegativeTally; zero values remain valid zero-probability bins. - Error comparison is strict: a relative error exactly equal to the tolerance keeps its scaled value; only errors greater than are nulled.
- Alias tables are exact for the given PDF: the construction reproduces the input probabilities to machine precision.
- Voxel resolution: birth coordinates are returned as integer voxel indices; users must sample a uniform point inside the voxel themselves if sub-voxel positions are needed.
- Emission carries lower bounds only: upper bounds are derived (OpenMC) or code defaults (Serpent), and any structure the target format cannot spell is a clear error rather than a silent approximation.
Related work beyond Nucleide
Adjacent capabilities found in PyNE, OpenMC, and the literature that Nucleide does not implement:
- MAGIC iteration: the published method iterates — each forward run refines the windows for the next — and derives upper bounds from a fixed ratio to the lower bounds; Nucleide performs a single lower-bound pass.
- FW-CADIS and adjoint-based global variance reduction: hybrid deterministic/Monte Carlo methods that build weight windows from an adjoint importance solve; see Wagner et al. (2014)wagner-2014.
- Built-in generators in OpenMC:
WeightWindowsandWeightWindowGenerator(MAGIC-like and FW-CADIS modes, updated on the fly during transport), including an internal random-ray adjoint solver. - Source biasing: OpenMC supports energy/space/angle biasing of
independent sources; PyNE’s mesh sampler additionally supports sub-voxel
sampling modes. Nucleide’s
MeshSourceSampleris voxel-level and energy-integrated.