Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TTreeReader.cxx
Go to the documentation of this file.
1// @(#)root/treeplayer:$Id$
2// Author: Axel Naumann, 2011-09-21
3
4/*************************************************************************
5 * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers and al. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include "TTreeReader.h"
13
14#include "TChain.h"
15#include "TDirectory.h"
16#include "TEntryList.h"
17#include "TTreeCache.h"
18#include "TTreeReaderValue.h"
19#include "TFriendElement.h"
20#include "TFriendProxy.h"
22
23// clang-format off
24/**
25 \class TTreeReader
26 \ingroup treeplayer
27 \brief A simple, robust and fast interface to read values from ROOT columnar datasets such as TTree, TChain or TNtuple
28
29 TTreeReader is associated to TTreeReaderValue and TTreeReaderArray which are handles to concretely
30 access the information in the dataset.
31
32 Example code can be found in
33 - tutorials/tree/hsimpleReader.C
34 - tutorials/tree/h1analysisTreeReader.C
35 - <a href="https://github.com/root-project/roottest/tree/master/root/tree/reader">This example</a>
36
37 You can generate a skeleton of `TTreeReaderValue<T>` and `TTreeReaderArray<T>` declarations
38 for all of a tree's branches using `TTree::MakeSelector()`.
39
40 Roottest contains an
41 <a href="https://github.com/root-project/roottest/tree/master/root/tree/reader">example</a>
42 showing the full power.
43
44A simpler analysis example can be found below: it histograms a function of the px and py branches.
45
46~~~{.cpp}
47// A simple TTreeReader use: read data from hsimple.root (written by hsimple.C)
48
49#include "TFile.h"
50#include "TH1F.h"
51#include "TTreeReader.h"
52#include "TTreeReaderValue.h"
53
54void hsimpleReader() {
55 // Create a histogram for the values we read.
56 TH1F("h1", "ntuple", 100, -4, 4);
57
58 // Open the file containing the tree.
59 TFile *myFile = TFile::Open("$ROOTSYS/tutorials/hsimple.root");
60
61 // Create a TTreeReader for the tree, for instance by passing the
62 // TTree's name and the TDirectory / TFile it is in.
63 TTreeReader myReader("ntuple", myFile);
64
65 // The branch "px" contains floats; access them as myPx.
66 TTreeReaderValue<Float_t> myPx(myReader, "px");
67 // The branch "py" contains floats, too; access those as myPy.
68 TTreeReaderValue<Float_t> myPy(myReader, "py");
69
70 // Loop over all entries of the TTree or TChain.
71 while (myReader.Next()) {
72 // Just access the data as if myPx and myPy were iterators (note the '*'
73 // in front of them):
74 myHist->Fill(*myPx + *myPy);
75 }
76
77 myHist->Draw();
78}
79~~~
80
81A more complete example including error handling and a few combinations of
82TTreeReaderValue and TTreeReaderArray would look like this:
83
84~~~{.cpp}
85#include <TFile.h>
86#include <TH1.h>
87#include <TTreeReader.h>
88#include <TTreeReaderValue.h>
89#include <TTreeReaderArray.h>
90
91#include "TriggerInfo.h"
92#include "Muon.h"
93#include "Tau.h"
94
95#include <vector>
96#include <iostream>
97
98bool CheckValue(ROOT::Internal::TTreeReaderValueBase& value) {
99 if (value.GetSetupStatus() < 0) {
100 std::cerr << "Error " << value.GetSetupStatus()
101 << "setting up reader for " << value.GetBranchName() << '\n';
102 return false;
103 }
104 return true;
105}
106
107
108// Analyze the tree "MyTree" in the file passed into the function.
109// Returns false in case of errors.
110bool analyze(TFile* file) {
111 // Create a TTreeReader named "MyTree" from the given TDirectory.
112 // The TTreeReader gives access to the TTree to the TTreeReaderValue and
113 // TTreeReaderArray objects. It knows the current entry number and knows
114 // how to iterate through the TTree.
115 TTreeReader reader("MyTree", file);
116
117 // Read a single float value in each tree entries:
118 TTreeReaderValue<float> weight(reader, "event.weight");
119
120 // Read a TriggerInfo object from the tree entries:
121 TTreeReaderValue<TriggerInfo> triggerInfo(reader, "triggerInfo");
122
123 //Read a vector of Muon objects from the tree entries:
124 TTreeReaderValue<std::vector<Muon>> muons(reader, "muons");
125
126 //Read the pT for all jets in the tree entry:
127 TTreeReaderArray<double> jetPt(reader, "jets.pT");
128
129 // Read the taus in the tree entry:
130 TTreeReaderArray<Tau> taus(reader, "taus");
131
132
133 // Now iterate through the TTree entries and fill a histogram.
134
135 TH1F("hist", "TTreeReader example histogram", 10, 0., 100.);
136
137 bool firstEntry = true;
138 while (reader.Next()) {
139 if (firstEntry) {
140 // Check that branches exist and their types match our expectation.
141 if (!CheckValue(weight)) return false;
142 if (!CheckValue(triggerInfo)) return false;
143 if (!CheckValue(muons)) return false;
144 if (!CheckValue(jetPt)) return false;
145 if (!CheckValue(taus)) return false;
146 firstentry = false;
147 }
148
149 // Access the TriggerInfo object as if it's a pointer.
150 if (!triggerInfo->hasMuonL1())
151 continue;
152
153 // Ditto for the vector<Muon>.
154 if (!muons->size())
155 continue;
156
157 // Access the jetPt as an array, whether the TTree stores this as
158 // a std::vector, std::list, TClonesArray or Jet* C-style array, with
159 // fixed or variable array size.
160 if (jetPt.GetSize() < 2 || jetPt[0] < 100)
161 continue;
162
163 // Access the array of taus.
164 if (!taus.IsEmpty()) {
165 // Access a float value - need to dereference as TTreeReaderValue
166 // behaves like an iterator
167 float currentWeight = *weight;
168 for (const Tau& tau: taus) {
169 hist->Fill(tau.eta(), currentWeight);
170 }
171 }
172 } // TTree entry / event loop
173
174 // Return true if we have iterated through all entries.
175 return reader.GetEntryStatus() == TTreeReader::kEntryBeyondEnd;
176}
177~~~
178*/
179// clang-format on
180
182
183using namespace ROOT::Internal;
184
185// Provide some storage for the poor little symbol.
187
188////////////////////////////////////////////////////////////////////////////////
189/// Default constructor. Call SetTree to connect to a TTree.
190
191TTreeReader::TTreeReader() : fNotify(this), fFriendProxies() {}
192
193////////////////////////////////////////////////////////////////////////////////
194/// Access data from tree.
195///
196/// \param tree The TTree or TChain to read from
197/// \param entryList It can be a single TEntryList with global entry numbers (supported, as
198/// an extension, also in the case of a TChain) or, if the first parameter
199/// is a TChain, a TEntryList with sub-TEntryLists with local entry numbers.
200/// In the latter case, the TEntryList must be associated to the TChain, as
201/// per chain.SetEntryList(&entryList).
202
203TTreeReader::TTreeReader(TTree *tree, TEntryList *entryList /*= nullptr*/, bool warnAboutLongerFriends,
204 const std::vector<std::string> &suppressErrorsForMissingBranches)
205 : fTree(tree),
206 fEntryList(entryList),
207 fNotify(this),
208 fFriendProxies(),
209 fWarnAboutLongerFriends(warnAboutLongerFriends),
210 fSuppressErrorsForMissingBranches(suppressErrorsForMissingBranches)
211{
212 if (!fTree) {
213 ::Error("TTreeReader::TTreeReader", "TTree is NULL!");
214 } else {
215 // We do not own the tree
217 Initialize();
218 }
219}
220
221////////////////////////////////////////////////////////////////////////////////
222/// Access data from the tree called keyname in the directory (e.g. TFile)
223/// dir, or the current directory if dir is NULL. If keyname cannot be
224/// found, or if it is not a TTree, IsInvalid() will return true.
225///
226/// \param keyname The name of the TTree to read from file
227/// \param dir The TDirectory to read keyname from
228/// \param entryList It can be a single TEntryList with global entry numbers (supported, as
229/// an extension, also in the case of a TChain) or, if the first parameter
230/// is a TChain, a TEntryList with sub-TEntryLists with local entry numbers.
231/// In the latter case, the TEntryList must be associated to the TChain, as
232/// per chain.SetEntryList(&entryList).
233
234TTreeReader::TTreeReader(const char *keyname, TDirectory *dir, TEntryList *entryList /*= nullptr*/)
235 : fEntryList(entryList), fNotify(this), fFriendProxies()
236{
237 if (!dir) dir = gDirectory;
238 dir->GetObject(keyname, fTree);
239 if (!fTree) {
240 std::string msg = "No TTree called ";
241 msg += keyname;
242 msg += " was found in the selected TDirectory.";
243 Error("TTreeReader", "%s", msg.c_str());
244 }
245 Initialize();
246}
247
248////////////////////////////////////////////////////////////////////////////////
249/// Tell all value readers that the tree reader does not exist anymore.
250
252{
253 for (std::deque<ROOT::Internal::TTreeReaderValueBase*>::const_iterator
254 i = fValues.begin(), e = fValues.end(); i != e; ++i) {
255 (*i)->MarkTreeReaderUnavailable();
256 }
257 if (fTree && fNotify.IsLinked())
259
261 // a plain TTree is automatically added to the current directory,
262 // do not delete it here
263 if (IsChain()) {
264 delete fTree;
265 }
266 }
267}
268
269////////////////////////////////////////////////////////////////////////////////
270/// Initialization of the director.
271
273{
274 fEntry = -1;
275 if (!fTree) {
278 return;
279 }
280
284 } else if (fEntryList && fEntryList->GetLists()) {
285 Error("Initialize", "We are not processing a TChain but the TEntryList contains sublists. Please "
286 "provide a simple TEntryList with no sublists instead.");
289 return;
290 }
291
292 fDirector = std::make_unique<ROOT::Internal::TBranchProxyDirector>(fTree, -1);
293
294 if (!fNotify.IsLinked()) {
296
297 if (fTree->GetTree()) {
298 // The current TTree is already available.
300 Notify();
302 }
303 }
304}
305
307{
308 if (friendIdx >= fFriendProxies.size()) {
309 fFriendProxies.resize(friendIdx + 1);
310 }
311
312 if (!fFriendProxies[friendIdx]) {
313 fFriendProxies[friendIdx] = std::make_unique<ROOT::Internal::TFriendProxy>(fDirector.get(), fTree, friendIdx);
314 }
315
316 return *fFriendProxies[friendIdx];
317}
318
319////////////////////////////////////////////////////////////////////////////////
320/// Notify director and values of a change in tree. Called from TChain and TTree's LoadTree.
321/// TTreeReader registers its fNotify data member with the TChain/TTree which
322/// in turn leads to this method being called upon the execution of LoadTree.
324{
325
326 // We are missing at least one proxy, retry creating them when switching
327 // to the next tree
328 if (!fMissingProxies.empty())
329 SetProxies();
330
333 // This can happen if someone switched trees behind us.
334 // Likely cause: a TChain::LoadTree() e.g. from TTree::Process().
335 // This means that "local" should be set!
336 // There are two entities switching trees which is bad.
337 Warning("SetEntryBase()",
338 "The current tree in the TChain %s has changed (e.g. by TTree::Process) "
339 "even though TTreeReader::SetEntry() was called, which switched the tree "
340 "again. Did you mean to call TTreeReader::SetLocalEntry()?",
341 fTree->GetName());
342 }
344 } else {
346 }
347
349 Warning("SetEntryBase()",
350 "The TTree / TChain has an associated TEntryList. "
351 "TTreeReader ignores TEntryLists unless you construct the TTreeReader passing a TEntryList.");
353 }
354
355 if (!fDirector->Notify()) {
357 Error("SetEntryBase()", "There was an error while notifying the proxies.");
359 return false;
360 }
361
362 if (fProxiesSet) {
363 for (auto value: fValues) {
364 value->NotifyNewTree(fTree->GetTree());
365 }
366 }
367
368 return true;
369}
370
371////////////////////////////////////////////////////////////////////////////////
372/// Tell readers we now have a tree.
373/// fValues gets insertions during this loop (when parametrized arrays are read),
374/// invalidating iterators. Use old-school counting instead.
375
377{
378
379 for (size_t i = 0; i < fValues.size(); ++i) {
381 // Check whether the user wants to suppress errors for this specific branch
382 // if it is missing. This information is used here to act in the situation
383 // where the first tree of the chain does not contain that branch. In such
384 // case, we need to postpone the creation of the corresponding proxy until
385 // we find the branch in a following tree of the chain.
386 const bool suppressErrorsForThisBranch =
389 // Because of the situation described above, we may have some proxies
390 // already created and some not, if their branch was not available so far.
391 // Make sure we do not recreate the proxy unnecessarily, unless the
392 // data member was set outside of this function (e.g. in Restart).
393 if (!reader->GetProxy() || !fProxiesSet)
394 reader->CreateProxy();
395
396 // The creation of the proxy failed again. If it was due to a missing
397 // branch, we propagate this information upstream, otherwise we return
398 // false to signify there was some other problem.
399 if (!reader->GetProxy()) {
400 if (suppressErrorsForThisBranch ||
402 fMissingProxies.push_back(reader->fBranchName.Data());
403 else
404 return false;
405 } else {
406 // Erase the branch name from the missing proxies if it was present
407 fMissingProxies.erase(std::remove(fMissingProxies.begin(), fMissingProxies.end(), reader->fBranchName.Data()),
408 fMissingProxies.end());
409 }
410 }
411 // If at least one proxy was there and no error occurred, we assume the proxies to be set.
412 fProxiesSet = !fValues.empty();
413
414 // Now we need to properly set the TTreeCache. We do this in steps:
415 // 1. We set the entry range according to the entry range of the TTreeReader
416 // 2. We add to the cache the branches identifying them by the name the user provided
417 // upon creation of the TTreeReader{Value, Array}s
418 // 3. We stop the learning phase.
419 // Operations 1, 2 and 3 need to happen in this order. See:
420 // https://sft.its.cern.ch/jira/browse/ROOT-9773?focusedCommentId=87837
421 if (fProxiesSet) {
422 const auto curFile = fTree->GetCurrentFile();
423 if (curFile && fTree->GetTree()->GetReadCache(curFile, true)) {
424 if (!(-1LL == fEndEntry && 0ULL == fBeginEntry)) {
425 // We need to avoid to pass -1 as end entry to the SetCacheEntryRange method
426 const auto lastEntry = (-1LL == fEndEntry) ? fTree->GetEntriesFast() : fEndEntry;
428 }
429 for (auto value : fValues) {
430 if (value->GetProxy())
431 fTree->AddBranchToCache(value->GetProxy()->GetBranchName(), true);
432 }
434 }
435 }
436
437 return true;
438}
439
441{
443 return;
444 if (!fTree)
445 return;
446 // Make sure all proxies are set, as in certain situations we might get to this
447 // point without having set the proxies first. For example, when processing a
448 // TChain and calling `SetEntry(N)` with N beyond the real number of entries.
449 // If the proxies can't be set return from the function and give up the warning.
450 if (!fProxiesSet && !SetProxies())
451 return;
452
453 // If we are stopping the reading because we reached the last entry specified
454 // explicitly via SetEntriesRange, do not bother the user with a warning
455 if (fEntry == fEndEntry)
456 return;
457
458 const std::string mainTreeName =
460
461 const auto *friendsList = fTree->GetListOfFriends();
462 if (!friendsList || friendsList->GetEntries() == 0)
463 return;
464
465 for (decltype(fFriendProxies.size()) idx = 0; idx < fFriendProxies.size(); idx++) {
466 auto &&fp = fFriendProxies[idx];
467 if (!fp)
468 continue;
469 // In case the friend is indexed it may very well be that it has a different number of events
470 // e.g. the friend contains information about luminosity block and
471 // all the entries in the main tree are from the same luminosity block
472 if (fp->HasIndex())
473 continue;
474 const auto *frTree = fp->GetDirector()->GetTree();
475 if (!frTree)
476 continue;
477
478 // Need to retrieve the real friend tree from the main tree
479 // because the current friend proxy points to the tree it is currently processing
480 // i.e. the current tree in a chain in case the real friend is a TChain
481 auto *frEl = static_cast<TFriendElement *>(friendsList->At(idx));
482 if (!frEl)
483 continue;
484 auto *frTreeFromMain = frEl->GetTree();
485 if (!frTreeFromMain)
486 continue;
487 // We are looking for the situation where there are actually still more
488 // entries to read in the friend. The following checks if the current entry to read
489 // is greater than the available entries in the dataset. If not, then we know there
490 // are more entries left in the friend.
491 //
492 // GetEntriesFast gives us a single handle to assess all the following:
493 // * If the friend is a TTree, it returns the total number of entries
494 // * If it is a TChain, then two more scenarios may occur:
495 // - If we have processed until the last file, then it returns the total
496 // number of entries.
497 // - If we have not processed all files yet, then it returns TTree::kMaxEntries.
498 // Thus, fEntry will always be smaller and the warning will be issued.
499 if (fEntry >= frTreeFromMain->GetEntriesFast())
500 continue;
501 // The friend tree still has entries beyond the last one of the main
502 // tree, warn the user about it.
503 const std::string frTreeName = dynamic_cast<const TChain *>(frTree)
504 ? frTree->GetName()
506 std::string msg = "Last entry available from main tree '" + mainTreeName + "' was " + std::to_string(fEntry - 1) +
507 " but friend tree '" + frTreeName + "' has more entries beyond the end of the main tree.";
508 Warning("SetEntryBase()", "%s", msg.c_str());
509 }
510}
511////////////////////////////////////////////////////////////////////////////////
512/// Set the range of entries to be loaded by `Next()`; end will not be loaded.
513///
514/// If end <= begin, `end` is ignored (set to `-1`, i.e. will run on all entries from `begin` onwards).
515///
516/// Example:
517///
518/// ~~~ {.cpp}
519/// reader.SetEntriesRange(3, 5);
520/// while (reader.Next()) {
521/// // Will load entries 3 and 4.
522/// }
523/// ~~~
524///
525/// Note that if a TEntryList is present, beginEntry and endEntry refer to the beginEntry-th/endEntry-th entries of the
526/// TEntryList (or the main TEntryList in case it has sub-entrylists). In other words, SetEntriesRange can
527/// be used to only loop over part of the TEntryList, but not to further restrict the actual TTree/TChain entry numbers
528/// considered.
529///
530/// \param beginEntry The first entry to be loaded by `Next()`.
531/// \param endEntry The entry where `Next()` will return false, not loading it.
532
534{
535 if (beginEntry < 0)
536 return kEntryNotFound;
537 // Complain if the entries number is larger than the tree's / chain's / entry
538 // list's number of entries, unless it's a TChain and "max entries" is
539 // uninitialized (i.e. TTree::kMaxEntries).
540 if (beginEntry >= GetEntries(false) && !(IsChain() && GetEntries(false) == TTree::kMaxEntries)) {
541 Error("SetEntriesRange()", "Start entry (%lld) must be lower than the available entries (%lld).", beginEntry,
542 GetEntries(false));
543 return kEntryNotFound;
544 }
545
546 // Update data members to correctly reflect the defined range
547 if (endEntry > beginEntry)
548 fEndEntry = endEntry;
549 else
550 fEndEntry = -1;
551
552 fBeginEntry = beginEntry;
553
554 if (beginEntry - 1 < 0)
555 // Reset the cache if reading from the first entry of the tree
556 Restart();
557 else {
558 // Load the first entry in the range. SetEntry() will also call SetProxies(),
559 // thus adding all the branches to the cache and triggering the learning phase.
560 EEntryStatus es = SetEntry(beginEntry - 1);
561 if (es != kEntryValid) {
562 Error("SetEntriesRange()", "Error setting first entry %lld: %s",
563 beginEntry, fgEntryStatusText[(int)es]);
564 return es;
565 }
566 }
567
568 return kEntryValid;
569}
570
572 fDirector->SetReadEntry(-1);
573 fProxiesSet = false; // we might get more value readers, meaning new proxies.
574 fEntry = -1;
575 if (const auto curFile = fTree->GetCurrentFile()) {
576 if (auto tc = fTree->GetTree()->GetReadCache(curFile, true)) {
577 tc->DropBranch("*", true);
578 tc->ResetCache();
579 }
580 }
581}
582
583////////////////////////////////////////////////////////////////////////////////
584/// Returns the number of entries of the TEntryList if one is provided, else
585/// of the TTree / TChain, independent of a range set by SetEntriesRange()
586/// by calling TTree/TChain::%GetEntriesFast.
587
588
590 if (fEntryList)
591 return fEntryList->GetN();
592 if (!fTree)
593 return -1;
594 return fTree->GetEntriesFast();
595}
596
597
598////////////////////////////////////////////////////////////////////////////////
599/// Returns the number of entries of the TEntryList if one is provided, else
600/// of the TTree / TChain, independent of a range set by SetEntriesRange().
601///
602/// \param force If `IsChain()` and `force`, determines whether all TFiles of
603/// this TChain should be opened to determine the exact number of entries
604/// of the TChain. If `!IsChain()`, `force` is ignored.
605
607 if (fEntryList)
608 return fEntryList->GetN();
609 if (!fTree)
610 return -1;
611 if (force) {
613 auto res = fTree->GetEntries();
614 // Go back to where we were:
617 return res;
618 }
619 return fTree->GetEntriesFast();
620}
621
622
623
624////////////////////////////////////////////////////////////////////////////////
625/// Load an entry into the tree, return the status of the read.
626/// For chains, entry is the global (i.e. not tree-local) entry number, unless
627/// `local` is `true`, in which case `entry` specifies the entry number within
628/// the current tree. This is needed for instance for TSelector::Process().
629
631{
632 if (IsInvalid()) {
634 fEntry = -1;
635 return fEntryStatus;
636 }
637
638 fEntry = entry;
639
640 Long64_t entryAfterList = entry;
641 if (fEntryList) {
642 if (entry >= fEntryList->GetN()) {
643 // Passed the end of the chain, Restart() was not called:
644 // don't try to load entries anymore. Can happen in these cases:
645 // while (tr.Next()) {something()};
646 // while (tr.Next()) {somethingelse()}; // should not be calling somethingelse().
648 return fEntryStatus;
649 }
650 if (entry >= 0) {
651 if (fEntryList->GetLists()) {
653 int treenum = -1;
654 entryAfterList = fEntryList->GetEntryAndTree(entry, treenum);
655 entryAfterList += static_cast<TChain *>(fTree)->GetTreeOffset()[treenum];
656 // We always translate local entry numbers to global entry numbers for TChain+TEntryList with sublists
657 local = false;
658 } else {
659 // Could be a TTree or a TChain (TTreeReader also supports single TEntryLists for TChains).
660 // In both cases, we are using the global entry numbers coming from the single TEntryList.
661 entryAfterList = fEntryList->GetEntry(entry);
662 }
663 }
664 }
665
666 TTree* treeToCallLoadOn = local ? fTree->GetTree() : fTree;
667
669 const Long64_t loadResult = treeToCallLoadOn->LoadTree(entryAfterList);
671
672 if (loadResult < 0) {
673 // ROOT-9628 We cover here the case when:
674 // - We deal with a TChain
675 // - The last file is opened
676 // - The TTree is not correctly loaded
677 // The system is robust against issues with TTrees associated to the chain
678 // when they are not at the end of it.
679 if (loadResult == -3 && TestBit(kBitIsChain) && !fTree->GetTree()) {
680 fDirector->Notify();
681 if (fProxiesSet) {
682 for (auto value: fValues) {
683 value->NotifyNewTree(fTree->GetTree());
684 }
685 }
686 Warning("SetEntryBase()",
687 "There was an issue opening the last file associated to the TChain "
688 "being processed.");
690 return fEntryStatus;
691 }
692
693 if (loadResult == -2) {
694 fDirector->Notify();
695 if (fProxiesSet) {
696 for (auto value: fValues) {
697 value->NotifyNewTree(fTree->GetTree());
698 }
699 }
702 return fEntryStatus;
703 }
704
705 if (loadResult == -1) {
706 // The chain is empty
708 return fEntryStatus;
709 }
710
711 if (loadResult == -4) {
712 // The TChainElement corresponding to the entry is missing or
713 // the TTree is missing from the file.
714 fDirector->Notify();
715 if (fProxiesSet) {
716 for (auto value: fValues) {
717 value->NotifyNewTree(fTree->GetTree());
718 }
719 }
721 return fEntryStatus;
722 }
723
724 if (loadResult == -6) {
725 // An expected branch was not found when switching to a new tree.
726 fDirector->Notify();
727 if (fProxiesSet) {
728 for (auto value : fValues) {
729 value->NotifyNewTree(fTree->GetTree());
730 }
731 }
732 // Even though one (or more) branches might be missing from the new
733 // tree, other branches might still be there. We know we are switching
734 // into the tree at this point, so we want the director to start
735 // reading again from local entry 0, for those branches that are
736 // available
737 fDirector->SetReadEntry(0);
739 return fEntryStatus;
740 }
741
742 Warning("SetEntryBase()",
743 "Unexpected error '%lld' in %s::LoadTree", loadResult,
744 treeToCallLoadOn->IsA()->GetName());
745
747 return fEntryStatus;
748 }
749
750 if (!fProxiesSet) {
751 if (!SetProxies()) {
753 return fEntryStatus;
754 }
755 }
756
757 if ((fEndEntry >= 0 && entry >= fEndEntry) || (fEntry >= fTree->GetEntriesFast())) {
760 return fEntryStatus;
761 }
762
763 fDirector->SetReadEntry(loadResult);
765
766 // Convey the information that a branch was not found either when
767 // switching to a new tree (i.e. when trying to load its first entry) or
768 // even if we are in the middle of the tree (e.g. by calling SetEntriesRange
769 // beforehand) but a proxy was not created because of the missing branch
772 }
773
774 for (auto &&fp : fFriendProxies) {
775 if (!fp)
776 continue;
777 if (fp->GetReadEntry() >= 0)
778 continue;
779 // We are going to read an invalid entry from a friend, propagate
780 // this information to the user.
781 const auto *frTree = fp->GetDirector()->GetTree();
782 if (!frTree)
783 continue;
784 const std::string frTreeName = dynamic_cast<const TChain *>(frTree)
785 ? frTree->GetName()
787 // If the friend does not have a TTreeIndex, the cause of a failure reading an entry
788 // is most probably a difference in number of entries between main tree and friend tree
789 if (!fp->HasIndex()) {
790 std::string msg = "Cannot read entry " + std::to_string(entry) + " from friend tree '" + frTreeName +
791 "'. The friend tree has less entries than the main tree. Make sure all trees "
792 "of the dataset have the same number of entries.";
793 throw std::runtime_error{msg};
794 } else {
796 }
797 }
798
799 return fEntryStatus;
800}
801
802////////////////////////////////////////////////////////////////////////////////
803/// Set (or update) the which tree to read from. `tree` can be
804/// a TTree or a TChain.
805
806void TTreeReader::SetTree(TTree* tree, TEntryList* entryList /*= nullptr*/)
807{
809 // a plain TTree is automatically added to the current directory,
810 // do not delete it here
811 if (IsChain()) {
812 delete fTree;
813 }
814 }
815
816 fTree = tree;
817 fEntryList = entryList;
818 fEntry = -1;
819
822 if (fTree) {
825 } else {
827 }
828
829 if (!fDirector) {
830 Initialize();
831 }
832 else {
833 fDirector->SetTree(fTree);
834 fDirector->SetReadEntry(-1);
835 }
836}
837
838////////////////////////////////////////////////////////////////////////////////
839/// Set (or update) the which tree to read from, passing the name of a tree in a
840/// directory.
841///
842/// \param keyname - name of the tree in `dir`
843/// \param dir - the `TDirectory` to load `keyname` from (or gDirectory if `nullptr`)
844/// \param entryList - the `TEntryList` to attach to the `TTreeReader`.
845
846void TTreeReader::SetTree(const char* keyname, TDirectory* dir, TEntryList* entryList /*= nullptr*/)
847{
848 TTree* tree = nullptr;
849 if (!dir)
850 dir = gDirectory;
851 dir->GetObject(keyname, tree);
852 SetTree(tree, entryList);
853}
854
855////////////////////////////////////////////////////////////////////////////////
856/// Add a value reader for this tree.
857
859{
860 if (fProxiesSet) {
861 Error("RegisterValueReader",
862 "Error registering reader for %s: TTreeReaderValue/Array objects must be created before the call to Next() / SetEntry() / SetLocalEntry(), or after TTreeReader::Restart()!",
863 reader->GetBranchName());
864 return false;
865 }
866 fValues.push_back(reader);
867 return true;
868}
869
870////////////////////////////////////////////////////////////////////////////////
871/// Remove a value reader for this tree.
872
874{
875 std::deque<ROOT::Internal::TTreeReaderValueBase*>::iterator iReader
876 = std::find(fValues.begin(), fValues.end(), reader);
877 if (iReader == fValues.end()) {
878 Error("DeregisterValueReader", "Cannot find reader of type %s for branch %s", reader->GetDerivedTypeName(), reader->fBranchName.Data());
879 return;
880 }
881 fValues.erase(iReader);
882}
#define e(i)
Definition RSha256.hxx:103
long long Long64_t
Definition RtypesCore.h:69
#define ClassImp(name)
Definition Rtypes.h:382
#define gDirectory
Definition TDirectory.h:384
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Base class of TTreeReaderValue.
@ kSetupMissingBranch
The specified branch cannot be found.
ESetupStatus GetSetupStatus() const
Return this TTreeReaderValue's setup status.
Detail::TBranchProxy * GetProxy() const
virtual const char * GetDerivedTypeName() const =0
TString fBranchName
Name of the branch to read data from.
virtual void CreateProxy()
Create the proxy object for our branch.
A chain is a collection of files containing TTree objects.
Definition TChain.h:33
static TClass * Class()
Describe directory structure in memory.
Definition TDirectory.h:45
void GetObject(const char *namecycle, T *&ptr)
Get an object with proper type checking.
Definition TDirectory.h:212
A List of entry numbers in a TTree or TChain.
Definition TEntryList.h:26
virtual TList * GetLists() const
Definition TEntryList.h:76
virtual Long64_t GetEntryAndTree(Long64_t index, Int_t &treenum)
Return the index of "index"-th non-zero entry in the TTree or TChain and the # of the corresponding t...
virtual Long64_t GetEntry(Long64_t index)
Return the number of the entry #index of this TEntryList in the TTree or TChain See also Next().
virtual Long64_t GetN() const
Definition TEntryList.h:78
A TFriendElement TF describes a TTree object TF in a file.
virtual TTree * GetTree()
Return pointer to friend TTree.
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
void PrependLink(Chain &chain)
Set this link as the head of the chain's list of notify subscribers.
Definition TNotifyLink.h:82
void RemoveLink(Chain &chain)
Remove this link from a chain's list of notify subscribers.
Bool_t IsLinked()
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:199
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:979
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:786
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:530
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:993
void ResetBit(UInt_t f)
Definition TObject.h:198
const char * Data() const
Definition TString.h:376
std::string_view View() const
Definition TString.h:452
A simple, robust and fast interface to read values from ROOT columnar datasets such as TTree,...
Definition TTreeReader.h:46
TTreeReader()
Default constructor. Call SetTree to connect to a TTree.
std::vector< std::string > fMissingProxies
ELoadTreeStatus fLoadTreeStatus
Indicator on how LoadTree was called 'last' time.
bool IsInvalid() const
Long64_t GetEntries() const
Returns the number of entries of the TEntryList if one is provided, else of the TTree / TChain,...
EEntryStatus fEntryStatus
status of most recent read request
std::vector< std::string > fSuppressErrorsForMissingBranches
void SetTree(TTree *tree, TEntryList *entryList=nullptr)
Set (or update) the which tree to read from.
~TTreeReader() override
Tell all value readers that the tree reader does not exist anymore.
TNotifyLink< TTreeReader > fNotify
TTree and TChain will notify this object upon LoadTree, leading to a call to TTreeReader::Notify().
bool fProxiesSet
True if the proxies have been set, false otherwise.
bool IsChain() const
@ kEntryNotFound
the tree entry number does not exist
@ kIndexedFriendNoMatch
A friend with TTreeIndex doesn't have an entry for this index.
@ kEntryUnknownError
LoadTree return less than -6, likely a 'newer' error code.
@ kEntryDictionaryError
problem reading dictionary info from tree
@ kMissingBranchWhenSwitchingTree
A branch was not found when switching to the next TTree in the chain.
@ kEntryBeyondEnd
last entry loop has reached its end
@ kEntryChainFileError
problem in opening a chain's file
@ kEntryNoTree
the tree does not exist
@ kEntryValid
data read okay
bool fSetEntryBaseCallingLoadTree
True if during the LoadTree execution triggered by SetEntryBase.
std::deque< ROOT::Internal::TTreeReaderValueBase * > fValues
readers that use our director
bool RegisterValueReader(ROOT::Internal::TTreeReaderValueBase *reader)
Add a value reader for this tree.
TTree * fTree
tree that's read
bool fWarnAboutLongerFriends
EEntryStatus SetEntriesRange(Long64_t beginEntry, Long64_t endEntry)
Set the range of entries to be loaded by Next(); end will not be loaded.
EEntryStatus SetEntryBase(Long64_t entry, bool local)
Load an entry into the tree, return the status of the read.
void WarnIfFriendsHaveMoreEntries()
@ kInternalLoadTree
Notify/LoadTree was last called from SetEntryBase.
@ kMissingBranchFromTree
Missing expected branch when loading new tree.
@ kNoTree
default state, no TTree is connected (formerly 'Zombie' state)
@ kExternalLoadTree
User code called LoadTree directly.
@ kLoadTreeNone
Notify has not been called yet.
void Initialize()
Initialization of the director.
void Restart()
Restart a Next() loop from entry 0 (of TEntryList index 0 of fEntryList is set).
TEntryList * fEntryList
entry list to be used
Long64_t fEntry
Current (non-local) entry of fTree or of fEntryList if set.
bool Notify() override
Notify director and values of a change in tree.
Long64_t fBeginEntry
This allows us to propagate the range to the TTreeCache.
void DeregisterValueReader(ROOT::Internal::TTreeReaderValueBase *reader)
Remove a value reader for this tree.
@ kBitIsExternalTree
we do not own the tree
@ kBitHaveWarnedAboutEntryListAttachedToTTree
the tree had a TEntryList and we have warned about that
@ kBitIsChain
our tree is a chain
bool SetProxies()
Tell readers we now have a tree.
ROOT::Internal::TFriendProxy & AddFriendProxy(std::size_t friendIdx)
std::vector< std::unique_ptr< ROOT::Internal::TFriendProxy > > fFriendProxies
Proxies to friend trees, created in TTreeReader[Value,Array]::CreateProxy.
std::unique_ptr< ROOT::Internal::TBranchProxyDirector > fDirector
proxying director
Long64_t fEndEntry
The end of the entry loop.
EEntryStatus SetEntry(Long64_t entry)
Set the next entry (or index of the TEntryList if that is set).
static constexpr const char *const fgEntryStatusText[kEntryUnknownError+1]
Long64_t GetCurrentEntry() const
Returns the index of the current entry being read.
A TTree represents a columnar dataset.
Definition TTree.h:79
virtual Int_t StopCacheLearningPhase()
Stop the cache learning phase.
Definition TTree.cxx:9474
virtual Int_t AddBranchToCache(const char *bname, bool subbranches=false)
Add branch with name bname to the Tree cache.
Definition TTree.cxx:1059
TFile * GetCurrentFile() const
Return pointer to the current file.
Definition TTree.cxx:5479
TTreeCache * GetReadCache(TFile *file) const
Find and return the TTreeCache registered with the file and which may contain branches for us.
Definition TTree.cxx:6318
virtual TEntryList * GetEntryList()
Returns the entry list assigned to this tree.
Definition TTree.cxx:5854
virtual Long64_t GetEntries() const
Definition TTree.h:463
virtual TTree * GetTree() const
Definition TTree.h:557
virtual Long64_t LoadTree(Long64_t entry)
Set current entry.
Definition TTree.cxx:6473
virtual Long64_t GetEntriesFast() const
Return a number greater or equal to the total number of entries in the dataset.
Definition TTree.h:505
TClass * IsA() const override
Definition TTree.h:705
virtual Int_t SetCacheEntryRange(Long64_t first, Long64_t last)
interface to TTreeCache to set the cache entry range
Definition TTree.cxx:8831
virtual TList * GetListOfFriends() const
Definition TTree.h:530
static constexpr Long64_t kMaxEntries
Definition TTree.h:229
std::vector< std::string > GetTreeFullPaths(const TTree &tree)