Reading and writing podio files
Podio supports file I/O through multiple backends in both C++ and Python. Below are the recommended approaches for reading and writing these files, as well as additional notes to guide usage.
C++
Podio provides generic and format-specific I/O interfaces.
Reading
The preferred way to read any ROOT file is with the generic reader factory:
#include <podio/Reader.h>
auto reader = podio::makeReader(filename);
auto event = reader.getNextEvent();
Here, filename can also be a vector of strings or POSIX glob pattern (on platforms supporting glob.h), allowing you to read multiple
files at once. This will automatically inspect the first file to select the
appropriate backend, creating either a TTree or RNTuple reader as needed. Mixing
TTree or RNTuples with the same reader is not supported.
Alternatively, you can instantiate format-specific readers directly:
#include <podio/ROOTReader.h> // For TTrees
#include <podio/RNTupleReader.h> // For RNTuples
auto ttreeReader = podio::ROOTReader(); // For TTree files (.root)
ttreeReader.openFile(filename); // Open a TTree file
auto rntupleReader = podio::RNTupleReader(); // For RNTuple files (.root)
for (size_t i = 0; i < ttreeReader.getEntries(podio::Category::Event); ++i) {
auto frame = podio::Frame(ttreeReader.readNextEntry(podio::Category::Event));
...
}
Writing
For writing, use the generic writer factory:
#include <podio/Writer.h>
auto writer = podio::makeWriter(filename);
writer.writeFrame(frame, podio::Category::Event, collsToWrite);
By default, TTrees are written. To explicitly select an output backend, provide the type:
auto ttreeWriter = podio::makeWriter(filename, "root"); // Use TTree
auto rntupleWriter = podio::makeWriter(filename, "rntuple"); // Use RNTuple
auto parquetWriter = podio::makeWriter(filename, "parquet"); // Use Arrow/Parquet
auto sioWriter = podio::makeWriter(filename, "sio"); // Use SIO
An explicitly provided type takes precedence over the file extension. Unknown types result in an exception.
The format can also be set by the environment variable PODIO_DEFAULT_WRITE_RNTUPLE. If
the environment variable is set to a non-empty string, RNTuples will be the default.
File extensions:
.root: Uses the default backend (TTree or RNTuple ifPODIO_DEFAULT_WRITE_RNTUPLEis set to a non-empty string), unless specified..sio: Uses the SIO writer..podio_parquet: Uses the Arrow/Parquet writer.Other extensions are not allowed.
Configuring writers with WriterFor
To configure backend specific options, use WriterFor. It allows for a more
flexible selection of the backend as well, which will take precedence over types
derived from filenames and / or environment variables. If specifying options and
a type (using either withBackend or withType) they have to match, otherwise
an exception will be thrown.
#include <podio/Writer.h>
// Explicitly select the RNTuple backend
auto rntupleWriter = podio::WriterFor{filename}.withBackend(podio::WriterFor::Backend::RNTuple).create();
// Equivalent, selecting via name, as with podio::makeWriter(filename, "rntuple")
auto sameWriter = podio::WriterFor{filename}.withType("rntuple").create();
// Configure compression, TTree or RNTuple depending on PODIO_DEFAULT_WRITE_RNTUPLE
auto configuredWriter = podio::WriterFor{filename}.withOptions({.compressionSettings = 505}).create();
// Configure compression and always use RNTuple
auto configuredRNTupleWriter = podio::WriterFor{filename}
.withBackend(podio::WriterFor::Backend::RNTuple)
.withOptions(podio::ROOTWriteOptions{.compressionSettings = 505})
.create();
Specific writers for each backend are also available:
#include <podio/ROOTWriter.h> // For TTree output
#include <podio/RNTupleWriter.h> // For RNTuple output
#include <podio/ArrowWriter.h> // For Arrow/Parquet output
podio::ROOTWriter writer(filename); // For TTree output
podio::RNTupleWriter rntupleWriter(filename); // For RNTuple output
podio::ArrowWriter parquetWriter(directoryName); // For Arrow/Parquet output
These also offer a constructor that takes writer specific options.
Arrow/Parquet I/O
The Arrow/Parquet backend writes a directory with the .podio_parquet
extension. The directory contains one Parquet file per category and a
metadata.json file with the podio metadata needed for reading.
#include <podio/Reader.h>
#include <podio/Writer.h>
auto writer = podio::makeWriter("events.podio_parquet", "parquet");
writer.writeFrame(frame, podio::Category::Event);
writer.finish();
auto reader = podio::makeReader("events.podio_parquet");
auto event = reader.readEvent(0);
The backend-specific classes can also be used directly:
#include <podio/ArrowReader.h>
#include <podio/ArrowWriter.h>
podio::ArrowWriter writer("events.podio_parquet");
writer.writeFrame(frame, podio::Category::Event);
writer.finish();
podio::ArrowReader reader;
reader.openFile("events.podio_parquet");
auto event = podio::Frame(reader.readEntry(podio::Category::Event, 0));
The default compression for Arrow/Parquet output is controlled at configure
time with the PODIO_ARROW_DEFAULT_COMPRESSION CMake option. Supported values
are UNCOMPRESSED, SNAPPY, and ZSTD.
Note
Note that the generic readers and writers have methods that are not available in
the backend-specific classes. For example, the generic reader has a
readNextEvent() method that reads the next podio::Frame in the category of
events, while using the backend-specific readers, one would use readNextEntry
and pass the category and build a Frame with the result. Similarly, the generic
writer has a writeEvent() method that writes a podio::Frame in the category
used for events.
Python
Python does not currently provide a single generic Reader or Writer class, but includes helpers to select the correct one at runtime.
Reading
Use the helper function to obtain the appropriate reader:
from podio.reading import get_reader
reader = get_reader(filename)
events = reader.get(category)
Here, filename can be a string or a list of strings, allowing you to read
multiple files at once. The function will automatically select the correct reader
depending on the format of the first file.
Alternatively, instantiate backend-specific readers explicitly:
from podio.root_io import Reader # For TTrees
from podio.root_io import RNTupleReader # For RNTuples
from podio.arrow_io import Reader as ArrowReader
reader = Reader(filename) # For TTree files (.root)
rntuple_reader = RNTupleReader(filename) # For RNTuple files (.root)
arrow_reader = ArrowReader(directory) # For Arrow/Parquet directories (.podio_parquet)
Writing
Similarly, use the appropriate writer class for the file format:
from podio.root_io import Writer # For TTrees
from podio.root_io import RNTupleWriter # For RNTuples
from podio.arrow_io import Writer as ArrowWriter
writer = Writer(filename) # For TTree output (.root)
rntuple_writer = RNTupleWriter(filename) # For RNTuple output (.root)
arrow_writer = ArrowWriter(directory) # For Arrow/Parquet output (.podio_parquet)
writer.write_frame(frame, category)
arrow_writer.write_frame(frame, category)