PODIO v00-16-03
An Event-Data-Model Toolkit for High Energy Physics Experiments
Loading...
Searching...
No Matches
ROOTFrameReader.cc
Go to the documentation of this file.
6#include "rootUtils.h"
7
8// ROOT specific includes
9#include "TChain.h"
10#include "TClass.h"
11#include "TFile.h"
12#include "TTree.h"
13#include "TTreeCache.h"
14
15#include <stdexcept>
16#include <unordered_map>
17
18namespace podio {
19
20std::tuple<std::vector<root_utils::CollectionBranches>, std::vector<std::pair<std::string, detail::CollectionInfo>>>
21createCollectionBranches(TChain* chain, const podio::CollectionIDTable& idTable,
22 const std::vector<root_utils::CollectionInfoT>& collInfo);
23
24GenericParameters ROOTFrameReader::readEventMetaData(ROOTFrameReader::CategoryInfo& catInfo) {
25 // Parameter branch is always the last one
26 auto& paramBranches = catInfo.branches.back();
27 auto* branch = paramBranches.data;
28
29 GenericParameters params;
30 auto* emd = &params;
31 branch->SetAddress(&emd);
32 branch->GetEntry(catInfo.entry);
33 return params;
34}
35
36std::unique_ptr<ROOTFrameData> ROOTFrameReader::readNextEntry(const std::string& name) {
37 auto& catInfo = getCategoryInfo(name);
38 return readEntry(catInfo);
39}
40
41std::unique_ptr<ROOTFrameData> ROOTFrameReader::readEntry(const std::string& name, const unsigned entNum) {
42 auto& catInfo = getCategoryInfo(name);
43 catInfo.entry = entNum;
44 return readEntry(catInfo);
45}
46
47std::unique_ptr<ROOTFrameData> ROOTFrameReader::readEntry(ROOTFrameReader::CategoryInfo& catInfo) {
48 if (!catInfo.chain) {
49 return nullptr;
50 }
51 if (catInfo.entry >= catInfo.chain->GetEntries()) {
52 return nullptr;
53 }
54
56 for (size_t i = 0; i < catInfo.storedClasses.size(); ++i) {
57 buffers.emplace(catInfo.storedClasses[i].first, getCollectionBuffers(catInfo, i));
58 }
59
60 auto parameters = readEventMetaData(catInfo);
61
62 catInfo.entry++;
63 return std::make_unique<ROOTFrameData>(std::move(buffers), catInfo.table, std::move(parameters));
64}
65
66podio::CollectionReadBuffers ROOTFrameReader::getCollectionBuffers(ROOTFrameReader::CategoryInfo& catInfo,
67 size_t iColl) {
68 const auto& name = catInfo.storedClasses[iColl].first;
69 const auto& [theClass, collectionClass, index] = catInfo.storedClasses[iColl].second;
70 auto& branches = catInfo.branches[index];
71
72 // Create empty collection buffers, and connect them to the right branches
73 auto collBuffers = podio::CollectionReadBuffers();
74 // If we have a valid data buffer class we know that have to read data,
75 // otherwise we are handling a subset collection
76 const bool isSubsetColl = theClass == nullptr;
77 if (!isSubsetColl) {
78 collBuffers.data = theClass->New();
79 }
80
81 {
82 auto collection =
83 std::unique_ptr<podio::CollectionBase>(static_cast<podio::CollectionBase*>(collectionClass->New()));
84 collection->setSubsetCollection(isSubsetColl);
85
86 auto tmpBuffers = collection->createBuffers();
87 collBuffers.createCollection = std::move(tmpBuffers.createCollection);
88 collBuffers.recast = std::move(tmpBuffers.recast);
89
90 if (auto* refs = tmpBuffers.references) {
91 collBuffers.references = new podio::CollRefCollection(refs->size());
92 }
93 if (auto* vminfo = tmpBuffers.vectorMembers) {
94 collBuffers.vectorMembers = new podio::VectorMembersInfo();
95 collBuffers.vectorMembers->reserve(vminfo->size());
96
97 for (const auto& [type, _] : (*vminfo)) {
98 const auto* vecClass = TClass::GetClass(("vector<" + type + ">").c_str());
99 collBuffers.vectorMembers->emplace_back(type, vecClass->New());
100 }
101 }
102 }
103
104 const auto localEntry = catInfo.chain->LoadTree(catInfo.entry);
105 // After switching trees in the chain, branch pointers get invalidated so
106 // they need to be reassigned.
107 // NOTE: root 6.22/06 requires that we get completely new branches here,
108 // with 6.20/04 we could just re-set them
109 if (localEntry == 0) {
110 branches.data = root_utils::getBranch(catInfo.chain.get(), name.c_str());
111
112 // reference collections
113 if (auto* refCollections = collBuffers.references) {
114 for (size_t i = 0; i < refCollections->size(); ++i) {
115 const auto brName = root_utils::refBranch(name, i);
116 branches.refs[i] = root_utils::getBranch(catInfo.chain.get(), brName.c_str());
117 }
118 }
119
120 // vector members
121 if (auto* vecMembers = collBuffers.vectorMembers) {
122 for (size_t i = 0; i < vecMembers->size(); ++i) {
123 const auto brName = root_utils::vecBranch(name, i);
124 branches.vecs[i] = root_utils::getBranch(catInfo.chain.get(), brName.c_str());
125 }
126 }
127 }
128
129 // set the addresses and read the data
130 root_utils::setCollectionAddresses(collBuffers, branches);
131 root_utils::readBranchesData(branches, localEntry);
132
133 collBuffers.recast(collBuffers);
134
135 return collBuffers;
136}
137
138ROOTFrameReader::CategoryInfo& ROOTFrameReader::getCategoryInfo(const std::string& category) {
139 if (auto it = m_categories.find(category); it != m_categories.end()) {
140 // Use the id table as proxy to check whether this category has been
141 // initialized alrready
142 if (it->second.table == nullptr) {
143 initCategory(it->second, category);
144 }
145 return it->second;
146 }
147
148 // Use a nullptr TChain to signify an invalid category request
149 // TODO: Warn / log
150 static auto invalidCategory = CategoryInfo{nullptr};
151
152 return invalidCategory;
153}
154
155void ROOTFrameReader::initCategory(CategoryInfo& catInfo, const std::string& category) {
156 catInfo.table = std::make_shared<podio::CollectionIDTable>();
157 auto* table = catInfo.table.get();
158 auto* tableBranch = root_utils::getBranch(m_metaChain.get(), root_utils::idTableName(category));
159 tableBranch->SetAddress(&table);
160 tableBranch->GetEntry(0);
161
162 auto* collInfoBranch = root_utils::getBranch(m_metaChain.get(), root_utils::collInfoName(category));
163 auto collInfo = new std::vector<root_utils::CollectionInfoT>();
164 collInfoBranch->SetAddress(&collInfo);
165 collInfoBranch->GetEntry(0);
166
167 std::tie(catInfo.branches, catInfo.storedClasses) =
168 createCollectionBranches(catInfo.chain.get(), *catInfo.table, *collInfo);
169
170 delete collInfo;
171
172 // Finaly set up the branches for the paramters
173 root_utils::CollectionBranches paramBranches{};
174 paramBranches.data = root_utils::getBranch(catInfo.chain.get(), root_utils::paramBranchName);
175 catInfo.branches.push_back(paramBranches);
176}
177
178std::vector<std::string> getAvailableCategories(TChain* metaChain) {
179 auto* branches = metaChain->GetListOfBranches();
180 std::vector<std::string> brNames;
181 brNames.reserve(branches->GetEntries());
182
183 for (int i = 0; i < branches->GetEntries(); ++i) {
184 const std::string name = branches->At(i)->GetName();
185 const auto fUnder = name.find("___");
186 if (fUnder != std::string::npos) {
187 brNames.emplace_back(name.substr(0, fUnder));
188 }
189 }
190
191 std::sort(brNames.begin(), brNames.end());
192 brNames.erase(std::unique(brNames.begin(), brNames.end()), brNames.end());
193 return brNames;
194}
195
196void ROOTFrameReader::openFile(const std::string& filename) {
197 openFiles({filename});
198}
199
200void ROOTFrameReader::openFiles(const std::vector<std::string>& filenames) {
201 m_metaChain = std::make_unique<TChain>(root_utils::metaTreeName);
202 // NOTE: We simply assume that the meta data doesn't change throughout the
203 // chain! This essentially boils down to the assumption that all files that
204 // are read this way were written with the same settings.
205 // Reading all files is done to check that all file exists
206 for (const auto& filename : filenames) {
207 if (!m_metaChain->Add(filename.c_str(), -1)) {
208 throw std::runtime_error("File " + filename + " couldn't be found");
209 }
210 }
211
212 podio::version::Version* versionPtr{nullptr};
213 if (auto* versionBranch = root_utils::getBranch(m_metaChain.get(), root_utils::versionBranchName)) {
214 versionBranch->SetAddress(&versionPtr);
215 versionBranch->GetEntry(0);
216 }
217 m_fileVersion = versionPtr ? *versionPtr : podio::version::Version{0, 0, 0};
218 delete versionPtr;
219
220 if (auto* edmDefBranch = root_utils::getBranch(m_metaChain.get(), root_utils::edmDefBranchName)) {
221 auto* datamodelDefs = new DatamodelDefinitionHolder::MapType{};
222 edmDefBranch->SetAddress(&datamodelDefs);
223 edmDefBranch->GetEntry(0);
224 m_datamodelHolder = DatamodelDefinitionHolder(std::move(*datamodelDefs));
225 delete datamodelDefs;
226 }
227
228 // Do some work up front for setting up categories and setup all the chains
229 // and record the available categories. The rest of the setup follows on
230 // demand when the category is first read
231 m_availCategories = ::podio::getAvailableCategories(m_metaChain.get());
232 for (const auto& cat : m_availCategories) {
233 auto [it, _] = m_categories.try_emplace(cat, std::make_unique<TChain>(cat.c_str()));
234 for (const auto& fn : filenames) {
235 it->second.chain->Add(fn.c_str());
236 }
237 }
238}
239
240unsigned ROOTFrameReader::getEntries(const std::string& name) const {
241 if (auto it = m_categories.find(name); it != m_categories.end()) {
242 return it->second.chain->GetEntries();
243 }
244
245 return 0;
246}
247
248std::vector<std::string_view> ROOTFrameReader::getAvailableCategories() const {
249 std::vector<std::string_view> cats;
250 cats.reserve(m_categories.size());
251 for (const auto& [cat, _] : m_categories) {
252 cats.emplace_back(cat);
253 }
254 return cats;
255}
256
257std::tuple<std::vector<root_utils::CollectionBranches>, std::vector<std::pair<std::string, detail::CollectionInfo>>>
259 const std::vector<root_utils::CollectionInfoT>& collInfo) {
260
261 size_t collectionIndex{0};
262 std::vector<root_utils::CollectionBranches> collBranches;
263 collBranches.reserve(collInfo.size() + 1);
264 std::vector<std::pair<std::string, detail::CollectionInfo>> storedClasses;
265 storedClasses.reserve(collInfo.size());
266
267 for (const auto& [collID, collType, isSubsetColl] : collInfo) {
268 // We only write collections that are in the collectionIDTable, so no need
269 // to check here
270 const auto name = idTable.name(collID);
271
273 const auto collectionClass = TClass::GetClass(collType.c_str());
274
275 // Need the collection here to setup all the branches. Have to manage the
276 // temporary collection ourselves
277 auto collection =
278 std::unique_ptr<podio::CollectionBase>(static_cast<podio::CollectionBase*>(collectionClass->New()));
279 collection->setSubsetCollection(isSubsetColl);
280
281 if (!isSubsetColl) {
282 // This branch is guaranteed to exist since only collections that are
283 // also written to file are in the info metadata that we work with here
284 branches.data = root_utils::getBranch(chain, name.c_str());
285 }
286
287 const auto buffers = collection->getBuffers();
288 for (size_t i = 0; i < buffers.references->size(); ++i) {
289 const auto brName = root_utils::refBranch(name, i);
290 branches.refs.push_back(root_utils::getBranch(chain, brName.c_str()));
291 }
292
293 for (size_t i = 0; i < buffers.vectorMembers->size(); ++i) {
294 const auto brName = root_utils::vecBranch(name, i);
295 branches.vecs.push_back(root_utils::getBranch(chain, brName.c_str()));
296 }
297
298 const std::string bufferClassName = "std::vector<" + collection->getDataTypeName() + ">";
299 const auto bufferClass = isSubsetColl ? nullptr : TClass::GetClass(bufferClassName.c_str());
300
301 storedClasses.emplace_back(name, std::make_tuple(bufferClass, collectionClass, collectionIndex++));
302 collBranches.push_back(branches);
303 }
304
305 return {collBranches, storedClasses};
306}
307
308} // namespace podio
const std::string name(int collectionID) const
return name for given collection ID
std::vector< std::tuple< std::string, std::string > > MapType
The "map" type that is used internally.
std::unordered_map< std::string, podio::CollectionReadBuffers > BufferMap
Definition: ROOTFrameData.h:19
void openFile(const std::string &filename)
std::unique_ptr< podio::ROOTFrameData > readNextEntry(const std::string &name)
void openFiles(const std::vector< std::string > &filenames)
std::vector< std::string_view > getAvailableCategories() const
Get the names of all the availalable Frame categories in the current file(s)
unsigned getEntries(const std::string &name) const
Returns number of entries for the given name.
std::unique_ptr< podio::ROOTFrameData > readEntry(const std::string &name, const unsigned entry)
std::string refBranch(const std::string &name, size_t index)
Definition: rootUtils.h:75
std::string vecBranch(const std::string &name, size_t index)
Definition: rootUtils.h:79
TBranch * getBranch(Tree *chain, const char *name)
Definition: rootUtils.h:66
void setCollectionAddresses(const BufferT &collBuffers, const CollectionBranches &branches)
Definition: rootUtils.h:84
std::string idTableName(const std::string &category)
Definition: rootUtils.h:49
void readBranchesData(const CollectionBranches &branches, Long64_t entry)
Definition: rootUtils.h:108
std::string collInfoName(const std::string &category)
Definition: rootUtils.h:58
std::tuple< std::vector< root_utils::CollectionBranches >, std::vector< std::pair< std::string, detail::CollectionInfo > > > createCollectionBranches(TChain *chain, const podio::CollectionIDTable &idTable, const std::vector< root_utils::CollectionInfoT > &collInfo)
std::vector< std::pair< std::string, void * > > VectorMembersInfo
std::vector< std::string > getAvailableCategories(TChain *metaChain)
std::vector< UVecPtr< podio::ObjectID > > CollRefCollection