RAD is a header-only framework designed around a Structure of Arrays (SoA) philosophy to maximize cache locality and allow efficient vectorization within the RDataFrame event loop.
The Orchestrator.
Manages Data Streams (Rec/Truth), Lambda Recipes, and Lifecycle Execution.
Wraps ROOT::RDataFrame.
Handles Combinatorics and Podio / HIPO Data Extraction.
The Engine.
Operates on raw SoA columns (Px, Py, Pz) using SIMD instructions.
Data Normalization
Topology & Grouping
Calibrations & Smearing
To avoid deep copies of heavy particle objects (like TLorentzVector), RAD separates Topology (Indices) from Data (Momentum Arrays).
rec_px, rec_py...) containing all tracks in the event.ReactionMap. A matrix of indices pointing to the flat arrays. The physics engine performs integer lookups directly.
Writing TTrees from multiple threads typically causes segmentation faults. RAD handles this safely via SnapshotCombi, which is invoked by AnalysisManager::Snapshot().
gDirectory to prevent file operation crashes during the event loop.
Standard Filter() drops events entirely, ruining sideband analyses. RAD employs a Masking strategy:
How to write and inject custom physics kernels into the recipe manager.
To add new physics variables (like Helicity Angles or specific Mandelstam variables), developers write a C++ function and register it inside the Topology Recipe. Because RAD uses lazy evaluation, you don't call this function directly to get a return value; instead, you register it as a named column in the RDataFrame graph.
Define your calculation in a separate header or macro cell before your main analysis script.
Include your custom kernel and inject it via the Lambda recipes.