NextStatNextStat

Ntuple-to-Workspace Pipeline

NextStat provides a complete pipeline from ROOT ntuples to HistFactory workspaces, replacing TRExFitter with a native Rust implementation that is ~8.5× faster than uproot+numpy on the full pipeline. No ROOT C++ dependency required.

Rust Builder API

use ns_translate::NtupleWorkspaceBuilder;

let ws = NtupleWorkspaceBuilder::new()
    .ntuple_path("ntuples/")
    .tree_name("events")
    .measurement("meas", "mu")
    .add_channel("SR", |ch| {
        ch.variable("mbb")
          .binning(&[0., 50., 100., 150., 200., 300.])
          .selection("njet >= 4 && pt > 25.0")
          .data_file("data.root")
          .add_sample("signal", |s| {
              s.file("ttH.root")
               .weight("weight_mc * weight_sf")
               .normfactor("mu")
          })
          .add_sample("background", |s| {
              s.file("ttbar.root")
               .weight("weight_mc * weight_sf")
               .normsys("bkg_norm", 0.9, 1.1)
               .weight_sys("jes", "weight_jes_up", "weight_jes_down")
               .tree_sys("jer", "jer_up.root", "jer_down.root")
               .staterror()
          })
    })
    .build()?;  // → Workspace (same type as pyhf JSON path)

Expression Engine

The ns-root crate includes a compiled expression engine for string-based selections and weights:

use ns_root::CompiledExpr;

let expr = CompiledExpr::compile("pt > 25.0 && abs(eta) < 2.5")?;

Low-level TTree Access

use ns_root::RootFile;

let file = RootFile::open("data.root")?;
let tree = file.get_tree("events")?;

// Columnar access
let pt: Vec<f64> = file.branch_data(&tree, "pt")?;
let eta: Vec<f64> = file.branch_data(&tree, "eta")?;

Supported Systematics

  • normsys — Normalization systematics (up/down factors)
  • weight_sys — Weight-based shape systematics
  • tree_sys — Alternative-tree shape systematics
  • staterror — Barlow-Beeston lite statistical uncertainties