Updates
nucleide
validation
rust
python
pyne
openmc

Nucleide 0.1.0 is released: a modern, validated take on nuclear-engineering workflow glue

Nucleide 0.1.0 ships today as a Rust/Python toolkit for the connective tissue of nuclear simulations. It validates directly against PyNE 0.7.5 and OpenMC 0.16.0 on shared inputs. Here is what the numbers look like.

9 min read

Today we are releasing Nucleide 0.1.0, the first tagged version of a Rust toolkit for the connective tissue of nuclear-engineering workflows: nuclide identification, materials, legacy transport-code I/O, CRAM depletion, enrichment cascades, and variance reduction — all exposed through a typed Python APInucleide-repo.

This post walks through what is in the release, why it exists, and the cross-code validation harness that compares Nucleide against PyNE 0.7.5 and OpenMC 0.16.0 on shared inputs.

Why Nucleide, and not just PyNE?

PyNE (“Python for Nuclear Engineering”) pioneered this spacepyne. It is a genuinely multi-language toolkit — C++ core, Cython bindings, pure-Python modules, and Fortran 90 subsystems — covering an enormous surface area: nuclide naming and cross-code dialects, nuclear data access, materials and radioanalytics, enrichment cascades, MCNP/Serpent/FLUKA/ALARA/PARTISN/ORIGEN interfaces, CRAM depletion, mesh-based variance reduction, and much more. If you work in computational nuclear engineering, you have almost certainly benefited from PyNE, either directly or through the tools that depend on it.

PyNE is also aging. Its build chain (CMake + Fortran + Cython) and generated decay/CRAM data tables can make installation and extension difficult on modern systems, and the project has not had the maintenance bandwidth to keep pace with the current Python packaging and Rust ecosystems. That does not make PyNE obsolete — its breadth is still unmatched — but it does create room for a fresh implementation of the high-value glue layer.

Nucleide is that implementation. It is intentionally narrower: no transport solvers, no MOAB/DAGMC meshing, no ENSDF evaluators, no Qt GUIs. Instead, it focuses on the data-handling and file-format work that sits between transport codes, rebuilt in memory-safe Rust with pip install-able abi3 wheels and a typed Python facade. The goal is not to replace PyNE. It is to give the community a maintainable, embeddable foundation for the pieces PyNE proved were worth having.

What 0.1.0 brings

The 0.1.0 release is the first version we are tagging with a full cross-code validation report. It includes:

  • Nine workspace cratesnuclei, material, mcnp-io, serpent-io, fluka-io, enrichment, depletion, vr-tools, and linalg — plus PyO3 and WASM bindings.
  • A typed Python API organized into domain submodules (nucleide.nuclei, nucleide.material, nucleide.mcnp, nucleide.serpent, nucleide.fluka, nucleide.enrichment, nucleide.depletion, nucleide.vr).
  • A containerized validation harness in validation/ that runs Nucleide against PyNE 0.7.5 and OpenMC 0.16.0 on shared inputs and commits the measured results.
  • Full-chain depletion validation on the CASL/VERA simplified chain (228 nuclides, fission yields, decay branching).
  • Parser cross-validation against independent oracles: Serpent _res.m/_dep.m/_det.m readers vs serpentTools, and MCNP xsdir/surface-source/PTRAC readers vs PyNE.
  • Python wheels for Linux, macOS, and Windows on Python ≥ 3.10 (abi3), plus workspace crates published to crates.io.
  • A documentation website with theory pages and interactive WASM tutorials at nucleide.nukehub.orgnucleide-docs.

Install the Python package today:

pip install nucleide

Validation strategy

The harness is deliberately simple: run the same calculation in Nucleide and a reference code on the same input, then report the difference. The canonical run uses ./validation/run_container.sh, which builds a container from validation/Containerfile (Python 3.12, PyNE 0.7.5 from conda-forge, OpenMC 0.16.0 built from its release tag, serpentTools 0.11.0, and a Nucleide abi3 release wheel built by the PyO3 maturin container) and regenerates validation/results.md from machine-readable JSON reports.

Every number below is taken directly from that run. Skipped comparisons — files an oracle cannot read, features that require PyMOAB, or formats with no working reference reader — are listed explicitly in the report rather than silently omittednucleide-validation-results.

Depletion: CRAM-48 against OpenMC

The depletion solver uses Chebyshev Rational Approximation Method (CRAM) of orders 16 and 48. On the small chain_ni.xml fixture, Nucleide’s CRAM-48 result matches OpenMC’s own CRAM-48 solver to machine precision:

MetricValue
Max relative difference8.30 × 10⁻¹⁵
Mean relative difference1.12 × 10⁻¹⁵
CRAM-48 depletion on chain_ni.xml, Nucleide vs OpenMC 0.16.0.

A 3-nuclide analytic Bateman check (I-135, Xe-135, Cs-135) gives the same story: both Nucleide and OpenMC sit within ~10⁻¹⁵ of the analytic solution.

The more demanding test is the full CASL/VERA simplified chain — 228 nuclides with thermal-spectrum branching and fission-product yields. On identical uniform one-group fission and capture rates, the per-nuclide density vector after a 30-day CRAM-48 step agrees to better than 10⁻¹⁴:

MetricValue
Max relative difference8.86 × 10⁻¹⁵
Mean relative difference5.65 × 10⁻¹⁶
Full CASL/VERA chain depletion, Nucleide vs OpenMC 0.16.0.
Per-nuclide density agreement between Nucleide and OpenMC on the CASL/VERA simplified chain after one 30-day step.

Notable actinides and fission products (U-235, U-238, Pu-239, Xe-135, I-135, Cs-137, Sm-149) agree to 10⁻¹⁵ or better. These comparisons exercise two parser behaviors that differ across codes — fission-yield borrowing via <neutron_fission_yields parent="..."/> and decay branching ratios that do not sum to 1 — and Nucleide now matches OpenMC’s verbatim reading behavior, as validated here.

Enrichment cascades: Nucleide vs PyNE

PyNE’s enrichment module is one of its standout capabilities: symbolic closed-form multicomponent cascade solutions generated by sympy codegen, plus numeric fixed-point iteration. Nucleide implements a multicomponent cascade solver in Rust and exposes it through Python.

Agreement depends on whether both codes are allowed to optimize the M* cut. When Nucleide is run with a fixed M* while PyNE optimizes, the M* and stage-count differences are expected. Run both in optimizing mode and the numbers converge:

QuantityNumeric solverSymbolic solver
N (stages)8.28 × 10⁻⁴2.79 × 10⁻⁴
M (stages)1.03 × 10⁻³3.50 × 10⁻⁴
M*8.83 × 10⁻⁶3.01 × 10⁻⁶
SWU / F7.97 × 10⁻⁸2.54 × 10⁻⁸
Max product comp. rel. diff6.17 × 10⁻⁵2.68 × 10⁻⁵
Default uranium cascade: optimizing Nucleide vs optimizing PyNE, like-for-like.

With M* optimization enabled on both sides, scalar quantities agree to better than 10⁻³ and most to better than 10⁻⁴. A tungsten / von-Halle multicomponent feed shows the same pattern: fixed-M* vs optimizing PyNE shows expected stage-count differences, while optimizing-vs-optimizing brings product compositions to within a few × 10⁻³.

MAGIC, nuclear data, and parsers

  • MAGIC weight windows: on a synthetic MCNP meshtal, Nucleide’s total-mode and per-group MAGIC output matched the PyNE-equivalent reference formula exactly (0 absolute difference across all cells and groups). PyNE in the validation container is built without PyMOAB, so the comparison uses a pure-Python reimplementation of PyNE’s documented MAGIC formula.
  • Nuclear data: atomic masses, natural abundances, and half-lives match OpenMC exactly. Differences against PyNE are at the 10⁻⁶ u / 10⁻³ abundance / 10⁻³ half-life level, consistent with independent data sources. Name-dialect conversions (ZZAAAMM, ZAID, Serpent, FLUKA, NIST, CINDER, ALARA, SZA) match pyne.nucname exactly.
  • Parsers: Serpent _dep.m/_det.m fields match serpentTools 0.11.0 to zero relative difference on every field that could be compared. MCNP xsdir, surface-source, and PTRAC readers match PyNE where PyNE can run. Skipped comparisons — Serpent-1-format files that serpentTools cannot read, PyMOAB-dependent PyNE readers for Wwinp/Meshtal, and binary FLUKA USRBIN oracles — are listed explicitly in the report.

Performance

The harness records coarse wall times so users can reason about overhead, not to claim Nucleide is a faster physics solver. The transport and depletion physics are the same; the difference is in the implementation language and memory layout.

Nucleide’s CRAM-48 solve on chain_ni.xml runs in about 1.4 × 10⁻⁴ s, roughly 21× faster than OpenMC’s own CRAM-48 solve at 2.9 × 10⁻³ s in this harness. The native Rust Criterion benchmark for the same solve is even lower at 7.7 × 10⁻⁵ s, which suggests most of the remaining Python-side time is PyO3 boundary overhead.

Mean wall time over 20 repeats for key Nucleide operations vs reference codes.
OperationNucleideReference
CRAM-48 solve (chain_ni.xml)1.37 × 10⁻⁴ sOpenMC: 2.94 × 10⁻³ s
Default uranium enrichment1.06 × 10⁻⁴ sPyNE: 5.62 × 10⁻³ s
MAGIC total-mode solve5.71 × 10⁻⁷ sPyNE-equivalent: 3.78 × 10⁻⁶ s
Coarse wall-time comparison, mean over 20 repeats.

Scope and limitations

Nucleide 0.1.0 is deliberately a subset of what PyNE covers. At this release, the implemented surface area includes:

  • Nuclide IDs, naming dialects, atomic masses, natural abundances, and half-lives.
  • Materials: compositions, mixing, unit conversions, DOE/PNNL Materials Compendium loading, and XML export.
  • MCNP I/O: xsdir, meshtal, SSW/SURFSRC, PTRAC, WWINP, MCTAL, and input-deck material extraction.
  • Serpent I/O: _res.m, _dep.m, _det.m readers.
  • FLUKA I/O: USRBIN tally reader and material/compound card generation.
  • Depletion: CRAM-16/48 and OpenMC-style chain XML parsing.
  • Enrichment: multicomponent cascade solving and SWU helpers.
  • Variance reduction: MAGIC weight-window generation and mesh source sampling with alias tables.

What is explicitly out of scope: transport solvers, deterministic SN kernels, ENSDF evaluators, MOAB/DAGMC meshing, ACE/ENDF processing, HDF5-based material libraries, and GUIs. Nucleide complements transport codes; it does not replace them.

How to reproduce

The validation is not a black box. If you have podman, one command rebuilds the wheel, runs every comparison, and regenerates the report:

./validation/run_container.sh

Or point the harness at any Python that already has PyNE, OpenMC, and the Nucleide wheel installed:

./validation/run_all.sh /path/to/python

What is next

Nucleide is still pre-alpha; APIs may change without notice. The immediate roadmap focuses on stabilizing the Rust public API, expanding parser coverage and golden-byte fixtures, and adding ndarray/NumPy zero-copy bridges where they improve Python ergonomics. Longer term, the project is building the public history and research use needed for a JOSS submission, with per-version validation archives preserved so the paper can quote correctness across releases.

You can follow development, file issues, and read the full measured tables here:

If Nucleide saves you from compiling a toolchain, please consider supporting the project or contributing back. The cleaner we can make the glue layer, the more time the community can spend on the physics that matters.

About the author

Ahnaf Tahmid Chowdhury
NukeHub·Bangladesh·tahmid@nukehub.org·Website

Founder of NukeHub. Open-source nuclear engineer, educator, and community builder working to make nuclear engineering tools accessible to everyone.

References

  1. [nucleide-repo]Nucleide source codeNukeHub Developers on GitHub
  2. [openmc]OpenMCOpenMC Development Team