# Diagnose k-effective eigenvalue convergence in OpenMC

Diagnose OpenMC eigenvalue convergence: classify unconverged fission source vs insufficient statistics vs batch-size bias vs converged-keff-masking-unconverged-source using the per-batch Shannon entropy trace and k-effective, then set inactive batches, entropy mesh, and batch size accordingly.

Exact reference: {"kind":"skill_version","skill_id":"skl_6whHcQ11uU5Ipm6w2d5WxQ","version_id":"skv_j7fjFZpOvhMPW-kzc7cDtQ"}

Applicability: [{"constraint":">=0.13 (entropy mesh auto-sizing and StatePoint.entropy/k_combined documented in 0.13-0.14 API)","technology":"OpenMC","version_scheme":"semver"}]

# Diagnose k-effective eigenvalue convergence in OpenMC

Use this when an OpenMC eigenvalue (`k-effective`) run gives a suspicious,
drifting, or hard-to-reproduce answer, or when you need to choose
`batches`, `inactive`, and `particles` defensibly. A k-effective run can fail
in two distinct ways — unconverged fission source vs insufficient statistics —
and the fix is different for each. Classify from the observables before
changing settings.

## 1. Gather the observables first

You need per-batch evidence, not just the final number. From a statepoint:

```python
import openmc
with openmc.StatePoint('statepoint.10.h5') as sp:
    k = sp.k_combined          # combined k-effective estimator with std dev
    entropy = sp.entropy       # Shannon entropy of the fission source, per batch
    batches = sp.current_batch
```

Or read the run stdout: OpenMC prints k-effective estimates and the Shannon
entropy of the fission source distribution at every batch. What you are
looking for:

- **Shannon entropy per batch** — the diagnostic for whether the *spatial*
  fission source distribution has converged. A still-trending entropy (rising
  or falling systematically batch to batch) means the source is not
  converged; a flat, noisy-around-a-mean entropy means it is.
- **Per-batch and cumulative k-effective** — the diagnostic for whether the
  *eigenvalue* is statistically stable.

## 2. Classify the failure mode

Plot or eyeball entropy vs batch and k-effective vs batch, then pick exactly
one:

- **A. Source not converged.** Entropy shows a clear trend (drift up or down)
  through the end of your inactive batches, and/or the mean k-effective of
  the first active batches differs systematically from the later ones. The
  run needs more inactive batches, not more statistics. Converged entropy —
  "no clear trend in either direction, just stochastic noise" — is the
  criterion for switching to active batches.
- **B. Source converged, statistics insufficient.** Entropy is flat, but the
  k-effective uncertainty is larger than you need. The fix is more *active*
  batches or more particles: to halve the uncertainty you need 4x the active
  histories (active batches x particles per batch), since uncertainty falls
  as 1/sqrt(N).
- **C. Biased from too few particles per batch.** Under ~10,000
  particles/batch, k-effective and tallies carry a systematic bias that more
  batches cannot average away (source renormalization bias). If
  `settings.particles` is in the hundreds or low thousands, raise the batch
  size first — batch count cannot fix this.
- **D. Converged-looking k-effective hiding an unconverged source.** The
  literature (and OpenMC practice) is explicit: k-effective converges *before*
  the source distribution does, so a stable-looking k can mask a bad source.
  Never declare convergence from k-effective alone — always check the entropy
  trace too. This matters most for loosely coupled systems (full cores, spent
  fuel pools, large arrays), where source convergence is slow and the
  dominance ratio is high.

## 3. Set inactive batches from entropy, not from habit

Guidance from OpenMC maintainers (verified on the forum):

- For many problems, 100 or fewer inactive batches is sufficient; full-core
  reactors and spent fuel storage pools may need significantly more.
- Source convergence is driven by the number of *batches* (generations), not
  by particles per batch. Raising particles per batch improves spatial
  fidelity but can make convergence *slower*, because stochastic noise stops
  dominating sooner.
- If you use `generations_per_batch > 1`, only the total generation count
  matters for source convergence: 100 expected generations with 10
  generations per batch means 10 inactive batches.

Procedure: run with a generous inactive count, inspect `sp.entropy`, and
keep only the batches after the entropy flattened as active. If entropy is
still trending at your last batch, the run's active tallies are suspect —
rerun with more inactive.

## 4. Configure the entropy mesh deliberately

By default OpenMC computes Shannon entropy over an automatically chosen mesh
(sized so each mesh cell sees about 20 source sites on average). For an
explicit, reproducible diagnostic, set it yourself:

```python
entropy_mesh = openmc.RegularMesh()
entropy_mesh.lower_left = (-50, -50, -25)
entropy_mesh.upper_right = (50, 50, 25)
entropy_mesh.dimension = (8, 8, 8)
settings.entropy_mesh = entropy_mesh
```

If you do not know good bounds, derive them from the geometry:

```python
m = openmc.RegularMesh()
m.lower_left, m.upper_right = geometry.bounding_box
m.dimension = (8, 8, 8)
settings.entropy_mesh = m
```

Entropy from an entropy mesh that misses part of the fissile region
understates convergence problems, so prefer the geometry bounding box over
guessed coordinates.

## 5. Checklist for choosing run settings

1. Reproduce the observables: per-batch k-effective and `sp.entropy`.
2. Classify: (A) entropy trending → more inactive; (B) entropy flat, error
   too big → 4x active histories to halve uncertainty; (C) particles <
   ~10k/batch → raise batch size (batch count cannot fix bias); (D) never
   trust k-effective alone — check entropy.
3. Set inactive from the entropy trace (≤100 typical; more for full-core /
   storage-pool / loosely coupled systems), counting total generations if
   `generations_per_batch > 1`.
4. Set an explicit `entropy_mesh` over the geometry bounding box.
5. In fixed-source runs none of this applies: there is no fission source to
   converge, so all batches are active — see the run-mode skill if you hit
   "No fission sites banked" instead.


## Supporting basis and limitations

Built from OpenMC maintainer guidance on the Discourse forum (inactive batch and particle count rules of thumb), the source-convergence forum thread on reading the Shannon entropy trace, the OpenMC user's guide section on Shannon entropy (entropy_mesh, RegularMesh setup, bounding-box derivation), and the openmc.StatePoint API docs (entropy and k_combined attributes). The draft was written from these sources' diagnostics, parameter names, and documented behavior.

## Change and rationale

New skill: diagnose k-effective eigenvalue convergence in OpenMC.

New OpenMC users routinely mis-set inactive batches and particles-per-batch, and the classic trap is a stable-looking k-effective masking an unconverged fission source. This skill adds a decision procedure that classifies the failure from the entropy and k-effective traces before prescribing more inactive batches vs more active histories vs larger batch size.
