#root #binary-data #binary-file #physics #particle #tree-root #branch

oxyroot

Another attempt to make library reading and writing of .root binary files which are commonly used in particle physics

23 releases

0.1.25 Oct 10, 2024
0.1.24 Apr 24, 2024
0.1.12 Mar 30, 2024
0.1.6 Jul 29, 2022

#59 in Compression

23 downloads per month
Used in 6 crates (3 directly)

MIT/Apache

765KB
21K SLoC

oxyroot

Crates.io Documentation

Another attempt to make library reading and writing .root binary files which are commonly used in particle physics

Cli tools

  • oxyroot-ls : List the content of trees of a root file
  • oxyroot-dump : Dump the content of trees of a root file

Inspiration

To make this library :

  • heavy inspiration taken from groot for reading root file, even the code organisation
  • inspiration taken from uproot to provide branch interface (for reading basket buffer)

Limitations

For now:

  • can only write uncompressed file

See also

Another rust implementation of a root reader is root-io.

Getting started

Example: Iter over a branch tree containing i32 values

use oxyroot::RootFile;
let s = "examples/from_uproot/data/HZZ.root";
let tree = RootFile::open(s).unwrap().get_tree("events").unwrap();
let NJet = tree.branch("NJet").unwrap().as_iter::<i32>();
NJet.for_each( | v| trace!("v = {v}"));

Example: Write i32 values in a branch

use oxyroot::{RootFile, WriterTree};
let s = "/tmp/simple.root";
let mut file = RootFile::create(s).expect("Can not create file");
let mut tree = WriterTree::new("mytree");
let it = (0..15);
tree.new_branch("it", it);
tree.write( & mut file).expect("Can not write tree");
file.close().expect("Can not close file");

Example: Iter over a branch tree containing Vec<i32> (aka std::vector<int32_t>) values

use oxyroot::RootFile;
let s = "tests/stl_containers/stl_containers.root";
let tree = RootFile::open(s).unwrap().get_tree("tree").unwrap();
let vector_int32 = tree.branch("vector_int32")
.unwrap().as_iter::<Vec<i32> > ()
.collect::<Vec<_ > > ();
assert_eq!(
    vector_int32,
    [
        vec![1],
        vec![1, 2],
        vec![1, 2, 3],
        vec![1, 2, 3, 4],
        vec![1, 2, 3, 4, 5]
    ]
);

Example : Iter over several branches by using ReadFromTree.

If you a root file containing several branches, you can use ReadFromTree to read them all at once. To read Point from branches x, y:

use oxyroot::ReadFromTree;

#[derive(ReadFromTree)]
struct Point {
    // will read from branch "x"  
    x: f64,
    // will read from branch "y"
    y: f64,
}

let s = "tests/point/point.root";
let tree = RootFile::open(s).unwrap().get_tree("tree").unwrap();
let points = Point::from_tree(tree).unwrap();

for point in points {
println!("x = {}, y = {}", point.x, point.y);
}

Example : Write to several branches by using WriteToTree.

use oxyroot::ReadFromTree;

#[derive(WriteToTree)]
struct Point {
    // will write to branch "x"  
    x: f64,
    // will write to branch "y"
    y: f64,
}

let s = "tests/point/point.root";
let mut f = RootFile::create(s).unwrap();
let mut tree = WriterTree::new("tree");

let points = vec![Point { x: 1.0, y: 2.0 }, Point { x: 3.0, y: 4.0 }];

Test::to_tree(points.into_iter(), & mut tree).unwrap();

tree.write( & mut f).unwrap();
f.close().unwrap();

Feature

oxyroot use flate2 to decompress zlib compressed data. The default backend is miniz_oxide, pure Rust crate.
If you want maximum performance, you can use the zlib-ng C library:

[dependencies]
oxyroot = { version = "0.1", features = ["zlib-ng"] }

Dependencies

~10MB
~181K SLoC