Skip to content

Commit

Permalink
Add support for reading several rntuple files
Browse files Browse the repository at this point in the history
  • Loading branch information
jmcarcell committed Nov 19, 2024
1 parent b57b8de commit 06d207b
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 19 deletions.
10 changes: 7 additions & 3 deletions include/podio/RNTupleReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,10 @@ class RNTupleReader {
/**
* Read and reconstruct the generic parameters of the Frame
*/
GenericParameters readEventMetaData(const std::string& name, unsigned entNum);
GenericParameters readEventMetaData(const std::string& name, unsigned localEntry, unsigned readerIndex);

template <typename T>
void readParams(const std::string& name, unsigned entNum, GenericParameters& params);
void readParams(const std::string& name, unsigned entNum, unsigned readerIndex, GenericParameters& params);

std::unique_ptr<ROOT::Experimental::RNTupleReader> m_metadata{};

Expand All @@ -147,7 +147,11 @@ class RNTupleReader {
std::unordered_map<std::string, std::unique_ptr<ROOT::Experimental::RNTupleReader>> m_metadata_readers{};
std::vector<std::string> m_filenames{};

std::unordered_map<std::string, int> m_entries{};
std::unordered_map<std::string, unsigned> m_entries{};
// Map category to a vector that contains at how many entries each reader starts
// For example, if we have 3 readers and the first one has 10 entries, the second one 20 and the third one 30
// then the vector will be {0, 10, 30, 60}
std::unordered_map<std::string, std::vector<unsigned>> m_readerEntries;
std::unordered_map<std::string, unsigned> m_totalEntries{};

struct CollectionInfo {
Expand Down
46 changes: 30 additions & 16 deletions src/RNTupleReader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,27 @@

#include <ROOT/RError.hxx>

#include <algorithm>
#include <memory>

namespace podio {

template <typename T>
void RNTupleReader::readParams(const std::string& name, unsigned entNum, GenericParameters& params) {
auto keyView = m_readers[name][0]->GetView<std::vector<std::string>>(root_utils::getGPKeyName<T>());
auto valueView = m_readers[name][0]->GetView<std::vector<std::vector<T>>>(root_utils::getGPValueName<T>());
void RNTupleReader::readParams(const std::string& name, unsigned localEntry, unsigned readerIndex,
GenericParameters& params) {
auto keyView = m_readers[name][readerIndex]->GetView<std::vector<std::string>>(root_utils::getGPKeyName<T>());
auto valueView = m_readers[name][readerIndex]->GetView<std::vector<std::vector<T>>>(root_utils::getGPValueName<T>());

params.loadFrom(keyView(entNum), valueView(entNum));
params.loadFrom(keyView(localEntry), valueView(localEntry));
}

GenericParameters RNTupleReader::readEventMetaData(const std::string& name, unsigned entNum) {
GenericParameters RNTupleReader::readEventMetaData(const std::string& name, unsigned localEntry, unsigned readerIndex) {
GenericParameters params;

readParams<int>(name, entNum, params);
readParams<float>(name, entNum, params);
readParams<double>(name, entNum, params);
readParams<std::string>(name, entNum, params);
readParams<int>(name, localEntry, readerIndex, params);
readParams<float>(name, localEntry, readerIndex, params);
readParams<double>(name, localEntry, readerIndex, params);
readParams<std::string>(name, localEntry, readerIndex, params);

return params;
}
Expand Down Expand Up @@ -101,15 +103,20 @@ void RNTupleReader::openFiles(const std::vector<std::string>& filenames) {

unsigned RNTupleReader::getEntries(const std::string& name) {
if (m_readers.find(name) == m_readers.end()) {
m_readerEntries[name].reserve(m_filenames.size() + 1);
m_readerEntries[name].push_back(0);
for (auto& filename : m_filenames) {
try {
m_readers[name].emplace_back(ROOT::Experimental::RNTupleReader::Open(name, filename));
} catch (const ROOT::Experimental::RException& e) {
m_readerEntries[name].push_back(m_readerEntries[name].back() + m_readers[name].back()->GetNEntries());

} catch (const ROOT::Experimental::RException&) {
std::cout << "Category " << name << " not found in file " << filename << std::endl;
}
}
m_totalEntries[name] = std::accumulate(m_readers[name].begin(), m_readers[name].end(), 0,
[](int total, auto& reader) { return total + reader->GetNEntries(); });
m_totalEntries[name] = m_readerEntries[name].back();
// The last entry is not needed since it's the total number of entries
m_readerEntries[name].pop_back();
}
return m_totalEntries[name];
}
Expand Down Expand Up @@ -143,15 +150,22 @@ std::unique_ptr<ROOTFrameData> RNTupleReader::readEntry(const std::string& categ

m_entries[category] = entNum + 1;

// m_readerEntries contains the accumulated entries for all the readers
// therefore, the first number that is lower or equal to the entry number
// is the index of the reader that contains the entry
auto upper = std::ranges::upper_bound(m_readerEntries[category], entNum);
auto localEntry = entNum - *(upper - 1);
auto readerIndex = upper - m_readerEntries[category].begin() - 1;

ROOTFrameData::BufferMap buffers;
#if ROOT_VERSION_CODE >= ROOT_VERSION(6, 31, 0)
// We need to create a non-bare entry here, because the entries for the
// parameters are not explicitly (re)set and we need them default initialized.
// In principle we would only need a bare entry for the collection data, since
// we set all the fields there in any case.
auto dentry = m_readers[category][0]->GetModel().CreateEntry();
auto dentry = m_readers[category][readerIndex]->GetModel().CreateEntry();
#else
auto dentry = m_readers[category][0]->GetModel()->GetDefaultEntry();
auto dentry = m_readers[category][readerIndex]->GetModel()->GetDefaultEntry();
#endif

for (size_t i = 0; i < m_collectionInfo[category].id.size(); ++i) {
Expand Down Expand Up @@ -211,9 +225,9 @@ std::unique_ptr<ROOTFrameData> RNTupleReader::readEntry(const std::string& categ
buffers.emplace(m_collectionInfo[category].name[i], std::move(collBuffers));
}

m_readers[category][0]->LoadEntry(entNum, *dentry);
m_readers[category][readerIndex]->LoadEntry(localEntry, *dentry);

auto parameters = readEventMetaData(category, entNum);
auto parameters = readEventMetaData(category, localEntry, readerIndex);

return std::make_unique<ROOTFrameData>(std::move(buffers), m_idTables[category], std::move(parameters));
}
Expand Down

0 comments on commit 06d207b

Please sign in to comment.