Skip to content

Fast & accurate three-flavor neutrino oscillation probabilities in Rust/Zig. Port of NuFast by Denton & Parke. ~60ns vacuum, ~95ns matter.

License

Notifications You must be signed in to change notification settings

planckeon/nufast

Repository files navigation

nufast

Crates.io docs.rs Zig License: MIT

Three-flavor neutrino oscillation probabilities in vacuum and constant-density matter.

Implementations in Rust, Zig, and WebAssembly, based on NuFast by P.B. Denton (arXiv:2405.02400).

Overview

This repository provides implementations of the NuFast algorithm for computing neutrino oscillation probabilities. The algorithm achieves sub-microsecond performance while maintaining numerical accuracy suitable for experimental analyses.

The original NuFast is used in production by T2K (via MaCH3) and JUNO.

Implementations

Platform Location Features
Rust src/lib.rs crates.io, no_std, VacuumBatch
Zig benchmarks/zig/ SIMD, f32 mode, MatterBatch
WASM benchmarks/zig/wasm/ Browser, Node.js, TypeScript, batch API

All implementations support:

  • Vacuum oscillations (exact analytic)
  • Matter effects via the DMP approximation with optional Newton refinement
  • Anti-neutrino mode (sign-flipped δCP and matter potential)
  • Batch APIs for pre-computed mixing matrices

Features

  • Vacuum oscillations — Exact analytic formula
  • Matter effects — DMP approximation with optional Newton refinement
  • PREM Earth model (Zig) — Variable density for long-baseline and atmospheric neutrinos
  • NSI support (Zig) — Non-Standard Interactions with complex ε matrix
  • Sterile neutrinos (Zig) — 3+1 model with exact 4-flavor vacuum oscillations
  • Anti-neutrino mode — Sign-flipped δCP and matter potential
  • Batch APIs — Pre-computed mixing for 45% speedup
  • SIMD vectorization (Zig) — 4×f64 or 8×f32 lanes
  • Experiment presets (Zig) — DUNE, T2K, NOvA, Hyper-K, JUNO
  • Cross-validated — Tested against original Python implementation

Usage

Rust

cargo add nufast
use nufast::{VacuumParameters, probability_vacuum_lbl};
use std::f64::consts::PI;

let params = VacuumParameters {
    s12sq: 0.307,
    s13sq: 0.0218,
    s23sq: 0.545,
    delta: 1.36 * PI,
    Dmsq21: 7.42e-5,
    Dmsq31: 2.517e-3,
    L: 295.0,
    E: 0.6,
    antineutrino: false,
};

let probs = probability_vacuum_lbl(&params);
// probs[1][0] = P(νμ → νe)

Zig

const nufast = @import("nufast");

const params = nufast.VacuumParams.default;
const probs = nufast.vacuumProbability(params, 1300.0, 2.5);
// probs[1][0] = P(νμ → νe)

// SIMD: compute 4 energies simultaneously
const batch = nufast.VacuumBatch.init(params);
var energies: nufast.F64Vec = .{ 1.0, 2.0, 3.0, 4.0 };
const p_vec = nufast.vacuumProbabilitySimd(batch, 1300.0, energies);

// Experiment presets
const dune = nufast.experiments.dune;
const matter_params = dune.toMatterParams();
const probs = nufast.matterProbability(matter_params, dune.L, dune.E);

WebAssembly (TypeScript)

import { loadNuFast } from '@nufast/wasm';

const nufast = await loadNuFast();
const Pme = nufast.vacuumPmeDefault(1300, 2.5);
console.log(`P(νμ → νe) = ${(Pme * 100).toFixed(2)}%`);

// Batch mode (2× faster)
const energies = new Float64Array([0.5, 1.0, 1.5, 2.0, 2.5]);
nufast.initVacuumBatch();
const results = nufast.vacuumBatchPme(1300, energies);

Benchmarks

AMD Ryzen, WSL2, 10M iterations per measurement.

Scalar Performance

Implementation Vacuum Matter (N=0)
Zig 42 ns 108 ns
Rust 61 ns 95 ns
C++ (original) 49 ns 130 ns
Fortran (original) 51 ns 107 ns
Python (original) 14.7 µs 21.9 µs

Zig SIMD

Mode f64 (4 lanes) f32 (8 lanes)
Vacuum 44 ns/calc 21 ns/calc
Matter 56 ns/calc 37 ns/calc

Throughput with f32 SIMD: ~48M vacuum/sec, ~27M matter/sec.

WebAssembly

Mode Single-point Batch (1000)
Vacuum ~100 ns ~50 ns/point
Matter ~150 ns ~110 ns/point

Batch mode gives 2× speedup by amortizing JS↔WASM overhead.

Physics

The probability matrix probs[α][β] gives P(ν_α → ν_β):

        e       μ       τ
    ┌───────────────────────┐
e   │ P_ee    P_eμ    P_eτ  │
μ   │ P_μe    P_μμ    P_μτ  │
τ   │ P_τe    P_τμ    P_ττ  │
    └───────────────────────┘

Default parameters use NuFit 5.2 (2022) best-fit values for normal ordering.

For anti-neutrinos, set antineutrino = true. This flips the sign of δCP and the matter potential.

The N_Newton parameter controls matter eigenvalue accuracy:

  • 0: DMP approximation (~0.1% accuracy)
  • 1: One Newton iteration (~0.01%)
  • ≥2: Machine precision

Repository Structure

src/              Rust implementation
benchmarks/
  zig/            Zig implementation + WASM
    src/          Core physics + WASM exports
    wasm/         WASM binaries, TypeScript, npm package
  cpp/            C++ (original NuFast)
  fortran/        Fortran (original NuFast)
  python/         Python (original NuFast)
paper/            Benchmark methodology and results

Building WASM

cd benchmarks/zig

# Build WASM (baseline + SIMD)
zig build wasm wasm-simd

# Copy to wasm/ directory
cp .zig-cache/o/*/nufast*.wasm wasm/

# Test
cd wasm && bun test-ts.ts

References

  1. P.B. Denton, arXiv:2405.02400 (2024)
  2. NuFast — original implementations
  3. NuFit 5.2 (2022)

Citation

If you use nufast in your research, please cite:

@software{nufast,
  author = {Kataru, Baalateja},
  title = {nufast: Fast Three-Flavor Neutrino Oscillation Probabilities},
  year = {2026},
  publisher = {GitHub},
  url = {https://github.com/planckeon/nufast},
  note = {Rust/Zig/WebAssembly implementation of the NuFast algorithm}
}

The algorithm is based on:

@article{Denton:2024xzk,
  author = {Denton, Peter B. and Parke, Stephen J.},
  title = "{NuFast: Fast and Accurate Neutrino Oscillation Probabilities}",
  eprint = "2405.02400",
  archivePrefix = "arXiv",
  primaryClass = "hep-ph",
  year = "2024"
}

Benchmark Paper (PDF)

License

MIT