CPP01 Iterate EDM4EIC
To save reconstructed data EDM4EIC file is used. EDM stands for "Event Data Model". This data model is based on PODIO, where IO = Input Output, and [POD is Plain Old Data] - referencing passive data. In HENP it is often called "Flat data format" highlighting that instead of saving complex C++ class hierarchies, the file stores data in a relational way using minimum nesting.
The flat files are good as you can read parts of it generally without knowing full schema. You see a branch like "MCParticle.momentum.z" and with very high probability know what is saved there. Then you can use the branch name to directly read the values. You don't need to load special library for this. This is the advantage of such flat files.
But dealing directly with branches as described above might be more complex when data has many connections to each other. Hits make Tracks, which make particle hypothesis, connected to calorimeter clusters they are combined into Reconstructed Particles and if Monte-Carlo truth is known, these ReconstructedParticles can be connected to the original MC particles. There are decays, vertexes and lots of more connections possible.
One can use EDM4EIC library directly from root macro or using compiled C++ code to conveniently read EDM4EIC files and navigating between different objects. This tutorial is about it.
The downside of this approach is that the exact same version of libraries that were used to save the data should be used in your code. Otherwise EDM4EIC files will not be opened.
Goal
Read EDM4EIC ROOT file with podio::ROOTReader.
Optionally stops after
-n
events.Dumps high-level event meta-data and detailed
MCParticle
info for the first few events.Can be executed either:
- as an interpreted ROOT macro thanks to the
R__LOAD_LIBRARY
guards, or - as a native C++20 executable built by CMake.
- as an interpreted ROOT macro thanks to the
The same source therefore doubles as a hands-on tutorial on mixed scripting / compiled workflows in modern ROOT. (root-forum.cern.ch, root.cern)
Installation
The easies way to start would be to use eic_shell
. Here is a tutorial on the eic_shell
Then you can run as a root macros or build it using the container.
If you want to build the tutorials outside of eic-shell, the dependencies are: CERN ROOT, podio, EDM4hep, EDM4EIC, fmt, CMake
Tip: If you use
eic-shell
you already have every bullet above. The container gives a consistent compiler (GCC 13) and linker setup across Linux/macOS clusters. (eic.github.io)
Running as a ROOT macro
root -x -l -b -q 'cpp_01_read_edm4eic.cxx("events.edm4eic.root",100)'
To make such scripts on your own the important parts are:
#ifdef __CLING__
R__LOAD_LIBRARY(podioDict)
R__LOAD_LIBRARY(podioRootIO)
R__LOAD_LIBRARY(libedm4hepDict)
R__LOAD_LIBRARY(libedm4eicDict)
#endif
- R__LOAD_LIBRARY loads the required libraries to read the files
- The
#ifdef __CLING__
block makes CLING load dictionaries before it JIT-compiles the rest of the file, so every EDM4hep class is known to the interpreter. (root-forum.cern.ch)
build & run in eic-shell
# 1) fire up the standard EPIC / Key4hep environment
./eic-shell # prompt changes to "jug_dev>"
# 2) grab the sources (assume you’re in ~/work)
git clone https://github.com/YOUR_USER/cpp_meson_structure.git
cd cpp_meson_structure
# 3) out-of-source build
cmake -S . -B build
cmake --build build -j
# 4) run on one or many input files
build/cpp01_read_edm4eic reco1.edm4eic.root -n 200
build/csv_mcpart_lambda sample.edm4eic.root > lambdas.csv
eic-shell
auto-sets LD_LIBRARY_PATH
so that the executables can locate libpodioRootIO.so
, libedm4hepDict.so
, etc. No ROOTSYS
needed. (eic.github.io)
Generic CMake workflow (outside eic-shell)
# load your own ROOT / podio / EDM4hep setup first, then:
mkdir -p build && cd build
cmake .. # detects all dependencies via find_package
make -j$(nproc)
# run
./cpp01_read_edm4eic myfile.root -n 50
Code walk-through (what to copy into your own analysis)
Event loop
podio::ROOTReader reader;
reader.openFile(filename); // self-contained I/O backend
const auto nEvents = reader.getEntries(podio::Category::Event);
for (unsigned i=0; i<nEvents; ++i) {
podio::Frame event(reader.readNextEntry()); // zero-copy view
auto& mcp = event.get<edm4hep::MCParticleCollection>("MCParticles");
// your physics logic...
}
podio::Frame
gives schema-aware access; collections keep relations and parameters intact. (indico.cern.ch, indico.cern.ch)