Your First CLAS12 Analysis¶
A complete, compilable starter: open a CLAS12 HIPO file, iterate events, keep charged particles, and histogram the vertex-z distribution. Once this runs on your machine, the rest of CLAS12 analysis is just swapping in better cuts and adding banks.
What you need¶
- A CLAS12 HIPO file: any reconstructed output works, e.g.
rec_clas_*.evio.*.hipo. - A working
hipo4install (see Installation).
The program¶
The program uses the sequential chain — the recommended way to read HIPO files. It
works for one file or many, and event.getBank("...") looks each bank up by name, so
there is no separate dictionary or schema setup.
#include "chain.h"
#include "twig.h"
#include <cstdio>
int main(int argc, char** argv) {
if (argc < 2) { std::fprintf(stderr, "usage: %s <file.hipo>\n", argv[0]); return 1; }
// Build the chain — one file here; ch.add_pattern("dir/*.hipo") for many.
hipo::chain ch;
ch.add(argv[1]);
twig::h1d hvz(120, -15.0, 5.0); // vertex-z histogram, −15 cm … +5 cm
long events = 0, charged = 0;
for (auto& [event, file_idx, event_idx] : ch) {
++events;
auto parts = event.getBank("REC::Particle");
for (int row = 0; row < parts.getRows(); row++) {
if (parts.getInt("charge", row) == 0) continue; // keep charged tracks
hvz.fill(parts.getFloat("vz", row));
++charged;
}
}
std::printf("processed %ld events, %ld charged tracks\n", events, charged);
hvz.print(); // ASCII histogram to the terminal
return 0;
}
Build it against hipo4 via pkg-config (see
Installation — pkg-config):
g++ -std=c++17 first_analysis.cc \
$(pkg-config --cflags --libs hipo4) -o first_analysis
./first_analysis path/to/rec_clas.hipo
What the code is doing¶
- Build the chain.
ch.add()registers a file; the chain opens it and reads its schema dictionary lazily when iteration starts. Add more files with repeatedch.add()calls or a glob viach.add_pattern(). - Iterate every event. The range-based
forloop walks every event across every file in the chain.file_idxis the current file;event_idxis the running event count. - Get the bank.
event.getBank("REC::Particle")returns the bank for the current event, looked up by name — no pre-built schema needed. - Filter charged tracks.
parts.getInt("charge", row) == 0skips neutrals (photons, neutrons). Flip the comparison for a neutrals-only selection. - Fill the histogram.
twig::h1dis a tiny built-in histogram class with an ASCIIprint(). For anything beyond eyeballing, see Integration — ROOT RDataFrame.
Caching column indices
getInt("charge", row) looks the column up by name. In a hot loop you can resolve
the column's integer index once and reuse it, which avoids a name lookup on every
access — see Performance — Optimization Tips.
Common next steps¶
Replace the charge check with a CLAS12-style selection. Three representative cuts:
The CLAS12 status field encodes the detector combination that assigned the particle:
|status| in [2000, 4000) is the Forward Detector and [1000, 2000) is the Forward
Tagger. The sign distinguishes negative/positive detector assignment in some
reconstruction versions — check the CLAS12 analysis note for your pass if the exact
sign matters.
Where to go next¶
- More bank columns → The REC:: bank family
- Joining
REC::Particleto detector banks → Cross-bank linking viapindex - Filter one electron, several pions, a proton … → Recipes — Row filtering
- Scale the same chain across many cores → Recipes — Parallel processing