This document explains how data flows through XIA2tree, from raw XIA list-mode files on disk to ROOT histograms and TTrees, and how the main components fit together.
At a high level, XIA2tree:
- Reads raw XIA list-mode data files (32-bit words from XIA digitizers).
- Converts raw data into calibrated detector hits using a YAML configuration/calibration file.
- Groups hits into time-ordered clusters and then into events, based on coincidence windows and split times.
- Performs physics analysis (particle identification, excitation energy, gamma–particle coincidences, etc.).
- Fills ROOT histograms and, optionally, a ROOT TTree with selected events.
- Optionally calls user-defined sorting plugins for additional analysis.
The work is split into several tasks connected by lock-free queues and executed concurrently in a thread pool.
-
Executable
XIA2tree(main.cpp): parses command line options, loads configuration, constructs the pipeline, runs all tasks in parallel, and writes/merges ROOT output.
-
Configuration and calibration
OCL::ConfigManager: owns the detector mapping (crate/slot/channel → detector type + ID) and calibration coefficients.OCL::UserConfiguration: owns analysis parameters, trigger type and sort mode, gates and excitation-curve parameters.ParticleRange: provides a mapping between energy and range, used to compute particle thickness.
-
Data model
XIA_base_t: low-level representation of a raw XIA event word.Entry_t: calibrated detector hit (detector type, ID, calibrated energy, corrected time, etc.).Triggered_event: a collection ofEntry_tbelonging to one event, plus information about which hit acted as the trigger (if any).
-
Pipeline tasks
Task::XIAReader: reads raw XIA data from disk and produces a stream ofXIA_base_tpointers.Task::Calibrator: converts each raw word into a calibratedEntry_tusingOCL::ConfigManager.Task::Buffer: accumulates and time-sorts hits, then flushes them as large, roughly time-ordered blocks.Task::Splitter: splits blocks into smaller time-contiguous clusters based on a split-time gap.Task::Triggers: constructs events around trigger hits, using coincidence windows and sort type.Task::MTSort/Sorters: performs analysis on triggered events, fills histograms and optional TTrees, and delegates to user plugins.
-
ROOT integration
ThreadSafeHistograms/OCL::Histogram(external library): thread-safe histogram container backed by ROOT.TTreeManager: helper for writing triggered events to a ROOT TTree.RootWriter/TFileMerger: write histograms and merge multiple ROOT files into a single output file.
The following sections describe the flow in order, referencing the main tasks and files.
- The
XIA2treeexecutable parses the command line using theCommandLineInterfacemodule. - It validates required parameters:
-i/--input: one or more raw list-mode files.-o/--output: output ROOT filename (base name).-C/--CalibrationFile: YAML configuration/calibration file.
- It then:
- Loads
OCL::ConfigManagerfrom the YAML file. - Constructs a
ParticleRangefrom-R/--RangeFileif provided. - Loads
OCL::UserConfigurationwith analysis parameters (trigger type, sort type, gates, etc.). - Derives the histogram and (optional) tree output file names based on
-oand the-tflag.
- Loads
The processing pipeline is built from tasks connected by lock-free queues:
XIAReader -> Calibrator -> Buffer -> Splitter -> Triggers -> MTSort (xN)
- Each arrow represents a concurrent queue.
- All tasks run in parallel in a
ThreadPool, so reading, calibration, event building and histogram filling can overlap.
- Input: list of files passed via
-i. - Output: queue of
const XIA_base_t*.
For each file:
- The data file is memory-mapped into virtual memory.
XIAReaderscans the mapped region and, for each XIA event word/header, enqueues a pointer to it in its output queue.- The task can run with or without progress UI, but its logical output is the same: a stream of raw XIA words.
- Input: queue of
const XIA_base_t*fromXIAReader. - Output: queue of
Entry_t.
For each raw XIA word:
ConfigManager::keep(raw)is called to decide whether this word corresponds to a detector type that should be kept.- If kept,
ConfigManager::operator()(raw):- Looks up the crate/slot/channel in its detector table.
- Determines detector type and index.
- Applies energy calibration (
quad,gain,shift) and time offsets (time_shift/ CFD shift). - Produces a calibrated
Entry_tcontaining:- Detector type and ID.
- Calibrated energy and timestamp.
- CFD information and any additional metadata (e.g. QDC).
- The resulting
Entry_tis enqueued for the next stage.
- Input: queue of
Entry_t. - Output: queue of
std::vector<Entry_t>.
The buffer stage:
- Maintains an in-memory buffer of hits.
- Once the buffer exceeds a configurable size:
- Sorts all buffered hits by time (using calibrated/CFD-corrected timestamps).
- Searches for a large time gap (e.g. > 50 000 units).
- Flushes the earliest part of the buffer as a
std::vector<Entry_t>to the next stage.
This ensures that hits are more strictly ordered in time and that subsequent steps work with reasonably sized, time-ordered blocks.
- Input: queue of
std::vector<Entry_t>fromBuffer. - Output: queue of
std::vector<Entry_t>.
Within each incoming vector:
- The splitter scans neighboring hits and computes time differences.
- Whenever the gap between hits exceeds the configured split time (
-S):- A new cluster is started.
- Each cluster is emitted as its own
std::vector<Entry_t>into the next queue.
These clusters are small, time-contiguous groups of hits that are convenient for event building.
- Input: queue of
std::vector<Entry_t>fromSplitter. - Output: queue of
std::pair<std::vector<Entry_t>, int>(the event and trigger index).
The trigger stage is controlled by:
-T/--Trigger: detector type that defines triggers (e.g.deDet,eDet,labr).-c/--coincidenceTime: width of the coincidence window around each trigger.-s/--sortType: event definition mode (coincidence,time,gap).
For each incoming cluster, the trigger logic does one of:
-
sortType = coincidence:- Find all hits of the trigger detector type.
- For each trigger candidate, construct an event consisting of all hits whose times are within the coincidence window around that trigger.
- Emit one
Triggered_eventper trigger candidate.
-
sortType = time:- As for
coincidence, but only hits from detector ID0of the trigger type are accepted as triggers. - Useful for time-alignment runs where a single detector serves as the reference.
- As for
-
sortType = gap:- Events are defined by time gaps only.
- If a trigger type is specified, clusters without any hit of that type may be discarded.
- The event is essentially the whole cluster, with no distinguished trigger index.
Each event is represented as:
- A vector of
Entry_thits. - An integer index pointing to the trigger hit inside that vector (or
-1when there is no single trigger).
- Input: queue of
Triggered_eventobjects from the trigger stage. - Output: filled histograms and, optionally, a TTree.
Sorters and MTSort provide the analysis layer:
Sortersowns:- A shared
ThreadSafeHistogramsinstance used across analysis threads. - One or more
MTSortworkers, each running in its own thread. - Optional per-thread ROOT files for trees when
-tis enabled.
- A shared
- Each
MTSort:- Pulls events from the shared event queue.
- Uses
HistManagerto:- Fill:
- Per-detector histograms (time, energy, multiplicity).
- ΔE–E plots and particle identification histograms.
- Excitation-energy vs gamma-energy matrices.
- Gated prompt/background spectra.
- Other analysis histograms.
- Compute quantities such as:
- Particle thickness via
ParticleRange. - Excitation energy via the analysis parameters.
- Particle thickness via
- Fill:
- Optionally writes each selected event into a TTree via
TTreeManagerif-tis set. - Delegates to the
UserSortManagerto allow user-defined plugins to inspect and analyze each event.
At the end:
HistManager::Flush()is called to flush any buffered histograms.UserSortManager::Flush()is called to allow plugins to finish and write their results.
Once all tasks are finished:
- The shared
ThreadSafeHistogramsare written to the histogram file usingRootWriter. - If
-twas requested, eachMTSortmay have produced its own tree file. - All produced ROOT files (histograms and trees) are merged using
TFileMergerinto the final output file specified by-o. - Temporary per-thread files are deleted after the merge.
The final output is a single ROOT file containing:
- All histograms filled during the run.
- A TTree with selected events (if enabled).
The pipeline is designed for high throughput on multi-core machines:
- Each task (reader, calibrator, buffer, splitter, triggers, and each sorter) runs in its own thread.
- Lock-free queues are used between stages to minimize contention.
- ROOT thread safety is enabled so that multiple threads can interact with histograms safely.
- When writing trees, each sorter writes to a separate ROOT file that is merged later, avoiding contention on a single TTree.
User sorting plugins are integrated at the MTSort/HistManager level:
- When a
Triggered_eventis processed,HistManagerfirst fills the built-in histograms. - Then, it calls
UserSortManager::FillEvent(event):- This forwards the event to the user-defined
UserSortobject (if one is loaded). - The plugin receives:
- The complete event (all hits).
- Implicit access to the shared histogram manager and user configuration.
- This forwards the event to the user-defined
- At the end of the run,
UserSortManager::Flush()is called so plugins can finalize and write any remaining results.
See docs/plugins.md for details on writing and loading plugins.
Some key command line options directly configure internal components:
-
-C/--CalibrationFile:- Loaded by
ConfigManagerandUserConfiguration. - Controls:
- Detector mapping (which detector is on which channel).
- Energy and time calibration coefficients.
- Analysis gates and excitation-curve parameters.
- Loaded by
-
-R/--RangeFile:- Loaded by
ParticleRange. - Used by
MTSortto convert particle energy to thickness and to apply thickness gates.
- Loaded by
-
-T/--Trigger:- Passed to the trigger stage.
- Determines which detector type is used as trigger when building events.
-
-c/--coincidenceTimeand-S/--SplitTime:- Configure the width of the coincidence window in the trigger stage.
- Configure the time gap that defines separate clusters in the splitter.
-
-s/--sortType:- Selects how events are built:
- By coincidence around triggers.
- By coincidence around a single reference detector.
- By time gaps alone.
- Selects how events are built:
-
-u/--userSort:- Points to a shared library implementing the
UserSortinterface. - Loaded into the
UserSortManagerused byHistManager.
- Points to a shared library implementing the
Understanding how these options map onto the pipeline will help when tuning performance and interpreting results.