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
