PODIO v00-16-03
An Event-Data-Model Toolkit for High Energy Physics Experiments
Loading...
Searching...
No Matches
ROOTReader.cc
Go to the documentation of this file.
1#include "rootUtils.h"
2
3// podio specific includes
7#include "podio/ROOTReader.h"
8
9// ROOT specific includes
10#include "TChain.h"
11#include "TClass.h"
12#include "TFile.h"
13#include "TTree.h"
14#include "TTreeCache.h"
15#include <memory>
16#include <stdexcept>
17
18namespace podio {
19// todo: see https://github.com/AIDASoft/podio/issues/290
20ROOTReader::~ROOTReader() { // NOLINT(modernize-use-equals-default)
21}
22
23std::pair<TTree*, unsigned> ROOTReader::getLocalTreeAndEntry(const std::string& treename) {
24 auto localEntry = m_chain->LoadTree(m_eventNumber);
25 auto* tree = static_cast<TTree*>(m_chain->GetFile()->Get(treename.c_str()));
26 return {tree, localEntry};
27}
28
29GenericParameters* ROOTReader::readEventMetaData() {
30 auto* emd = new GenericParameters();
31 auto [evt_metadatatree, entry] = getLocalTreeAndEntry("evt_metadata");
32 auto* branch = root_utils::getBranch(evt_metadatatree, "evtMD");
33 branch->SetAddress(&emd);
34 evt_metadatatree->GetEntry(entry);
35 return emd;
36}
37std::map<int, GenericParameters>* ROOTReader::readCollectionMetaData() {
38 auto* emd = new std::map<int, GenericParameters>;
39 auto* col_metadatatree = getLocalTreeAndEntry("col_metadata").first;
40 auto* branch = root_utils::getBranch(col_metadatatree, "colMD");
41 branch->SetAddress(&emd);
42 col_metadatatree->GetEntry(0);
43 return emd;
44}
45std::map<int, GenericParameters>* ROOTReader::readRunMetaData() {
46 auto* emd = new std::map<int, GenericParameters>;
47 auto* run_metadatatree = getLocalTreeAndEntry("run_metadata").first;
48 auto* branch = root_utils::getBranch(run_metadatatree, "runMD");
49 branch->SetAddress(&emd);
50 run_metadatatree->GetEntry(0);
51 return emd;
52}
53
54CollectionBase* ROOTReader::readCollection(const std::string& name) {
55 // has the collection already been constructed?
56 auto p =
57 std::find_if(begin(m_inputs), end(m_inputs), [&name](const ROOTReader::Input& t) { return t.second == name; });
58 if (p != end(m_inputs)) {
59 return p->first;
60 }
61
62 // Do we know about this collection? If so, read it
63 if (const auto& info = m_storedClasses.find(name); info != m_storedClasses.end()) {
64 return getCollection(*info);
65 }
66
67 // At this point this collection is definitely not in this file, because we
68 // have no information on how to construct it in the first place
69 return nullptr;
70}
71
72CollectionBase* ROOTReader::getCollection(const std::pair<std::string, CollectionInfo>& collInfo) {
73 const auto& name = collInfo.first;
74 const auto& [theClass, collectionClass, index] = collInfo.second;
75 auto& branches = m_collectionBranches[index];
76
77 auto* collection = static_cast<CollectionBase*>(collectionClass->New());
78 auto collBuffers = collection->getBuffers();
79 // If we have a valid data buffer class we know that have to read data,
80 // otherwise we are handling a subset collection
81 if (theClass) {
82 collBuffers.data = theClass->New();
83 } else {
84 collection->setSubsetCollection();
85 }
86
87 const auto localEntry = m_chain->LoadTree(m_eventNumber);
88 // After switching trees in the chain, branch pointers get invalidated so
89 // they need to be reassigned.
90 // NOTE: root 6.22/06 requires that we get completely new branches here,
91 // with 6.20/04 we could just re-set them
92 if (localEntry == 0) {
93 branches.data = root_utils::getBranch(m_chain, name.c_str());
94
95 // reference collections
96 if (auto* refCollections = collBuffers.references) {
97 for (size_t i = 0; i < refCollections->size(); ++i) {
98 const auto brName = root_utils::refBranch(name, i);
99 branches.refs[i] = root_utils::getBranch(m_chain, brName.c_str());
100 }
101 }
102
103 // vector members
104 if (auto* vecMembers = collBuffers.vectorMembers) {
105 for (size_t i = 0; i < vecMembers->size(); ++i) {
106 const auto brName = root_utils::vecBranch(name, i);
107 branches.vecs[i] = root_utils::getBranch(m_chain, brName.c_str());
108 }
109 }
110 }
111
112 // set the addresses
113 root_utils::setCollectionAddresses(collection->getBuffers(), branches);
114
115 return readCollectionData(branches, collection, localEntry, name);
116}
117
118CollectionBase* ROOTReader::readCollectionData(const root_utils::CollectionBranches& branches,
119 CollectionBase* collection, Long64_t entry, const std::string& name) {
120 // Read all data
121 if (branches.data) {
122 branches.data->GetEntry(entry);
123 }
124 for (auto* br : branches.refs) {
125 br->GetEntry(entry);
126 }
127 for (auto* br : branches.vecs) {
128 br->GetEntry(entry);
129 }
130
131 // do the unpacking
132 const auto id = m_table->collectionID(name);
133 collection->setID(id);
134 collection->prepareAfterRead();
135
136 m_inputs.emplace_back(std::make_pair(collection, name));
137 return collection;
138}
139
140void ROOTReader::openFile(const std::string& filename) {
141 openFiles({filename});
142}
143
144void ROOTReader::openFiles(const std::vector<std::string>& filenames) {
145 m_chain = new TChain("events");
146 for (const auto& filename : filenames) {
147 //-1 forces the headers to be read so that
148 // the validity of the files can be checked
149 if (!m_chain->Add(filename.c_str(), -1)) {
150 delete m_chain;
151 throw std::runtime_error("File " + filename + " couldn't be found");
152 }
153 }
154
155 // read the meta data and build the collectionBranches cache
156 // NOTE: This is a small pessimization, if we do not read all collections
157 // afterwards, but it makes the handling much easier in general
158 auto metadatatree = static_cast<TTree*>(m_chain->GetFile()->Get("metadata"));
159 m_table = std::make_shared<podio::CollectionIDTable>();
160 auto* table = m_table.get();
161 metadatatree->SetBranchAddress("CollectionIDs", &table);
162
163 podio::version::Version* versionPtr{nullptr};
164 if (auto* versionBranch = root_utils::getBranch(metadatatree, "PodioVersion")) {
165 versionBranch->SetAddress(&versionPtr);
166 }
167
168 // Check if the CollectionTypeInfo branch is there and assume that the file
169 // has been written with with podio pre #197 (<0.13.1) if that is not the case
170 if (auto* collInfoBranch = root_utils::getBranch(metadatatree, "CollectionTypeInfo")) {
171 auto collectionInfo = new std::vector<root_utils::CollectionInfoT>;
172 collInfoBranch->SetAddress(&collectionInfo);
173 metadatatree->GetEntry(0);
174 createCollectionBranches(*collectionInfo);
175 delete collectionInfo;
176 } else {
177 std::cout << "PODIO: Reconstructing CollectionTypeInfo branch from other sources in file: \'"
178 << m_chain->GetFile()->GetName() << "\'" << std::endl;
179 metadatatree->GetEntry(0);
180 const auto collectionInfo = root_utils::reconstructCollectionInfo(m_chain, *m_table);
181 createCollectionBranches(collectionInfo);
182 }
183
184 m_fileVersion = versionPtr ? *versionPtr : podio::version::Version{0, 0, 0};
185 delete versionPtr;
186}
187
189 closeFiles();
190}
191
193 delete m_chain;
194}
195
197 m_chain->GetEntry(m_eventNumber);
198 // first prepare all collections in memory...
199 for (auto inputs : m_inputs) {
200 inputs.first->prepareAfterRead();
201 }
202 // ...then clean-up the references between them
203 // for(auto inputs : m_inputs){
204 // inputs.first->setReferences(m_registry);
205
206 // }
207}
209 return m_chain->GetFile()->IsOpen() && !m_chain->GetFile()->IsZombie();
210}
211
213 ++m_eventNumber;
214 m_inputs.clear();
215}
216
217unsigned ROOTReader::getEntries() const {
218 return m_chain->GetEntries();
219}
220
221void ROOTReader::goToEvent(unsigned eventNumber) {
222 m_eventNumber = eventNumber;
223 m_inputs.clear();
224}
225
226void ROOTReader::createCollectionBranches(const std::vector<root_utils::CollectionInfoT>& collInfo) {
227 size_t collectionIndex{0};
228
229 for (const auto& [collID, collType, isSubsetColl] : collInfo) {
230 // We only write collections that are in the collectionIDTable, so no need
231 // to check here
232 const auto name = m_table->name(collID);
233
234 root_utils::CollectionBranches branches{};
235 const auto collectionClass = TClass::GetClass(collType.c_str());
236
237 // Make sure that ROOT actually knows about this datatype before running
238 // into a potentially cryptic segmentation fault by accessing the nullptr
239 if (!collectionClass) {
240 std::cerr << "PODIO: Cannot create the collection type \'" << collType << "\' stored in branch \'" << name
241 << "\'. Contents of this branch cannot be read." << std::endl;
242 continue;
243 }
244 // Need the collection here to setup all the branches. Have to manage the
245 // temporary collection ourselves
246 auto collection =
247 std::unique_ptr<podio::CollectionBase>(static_cast<podio::CollectionBase*>(collectionClass->New()));
248 collection->setSubsetCollection(isSubsetColl);
249
250 if (!isSubsetColl) {
251 // This branch is guaranteed to exist since only collections that are
252 // also written to file are in the info metadata that we work with here
253 branches.data = root_utils::getBranch(m_chain, name.c_str());
254 }
255
256 const auto buffers = collection->getBuffers();
257 for (size_t i = 0; i < buffers.references->size(); ++i) {
258 const auto brName = root_utils::refBranch(name, i);
259 branches.refs.push_back(root_utils::getBranch(m_chain, brName.c_str()));
260 }
261
262 for (size_t i = 0; i < buffers.vectorMembers->size(); ++i) {
263 const auto brName = root_utils::vecBranch(name, i);
264 branches.vecs.push_back(root_utils::getBranch(m_chain, brName.c_str()));
265 }
266
267 const std::string bufferClassName = "std::vector<" + collection->getDataTypeName() + ">";
268 const auto bufferClass = isSubsetColl ? nullptr : TClass::GetClass(bufferClassName.c_str());
269
270 m_storedClasses.emplace(name, std::make_tuple(bufferClass, collectionClass, collectionIndex++));
271 m_collectionBranches.push_back(branches);
272 }
273}
274
275} // namespace podio
void openFile(const std::string &filename) override
Definition: ROOTReader.cc:140
void goToEvent(unsigned evnum) override
Preparing to read a given event.
Definition: ROOTReader.cc:221
unsigned getEntries() const override
Returns number of entries in the TTree.
Definition: ROOTReader.cc:217
void readEvent() override
Read all collections requested.
Definition: ROOTReader.cc:196
void openFiles(const std::vector< std::string > &filenames)
Definition: ROOTReader.cc:144
bool isValid() const override
Check if TFile is valid.
Definition: ROOTReader.cc:208
void closeFile() override
Definition: ROOTReader.cc:188
void endOfEvent() override
Preparing to read next event.
Definition: ROOTReader.cc:212
auto reconstructCollectionInfo(TTree *eventTree, podio::CollectionIDTable const &idTable)
Definition: rootUtils.h:130
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