Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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/io/tree/hsimpleReader.C
34 - tutorials/io/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
204 const std::set<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
235 : fEntryList(entryList), fNotify(this), fFriendProxies()
236{
237 if (!dir)
238 dir = gDirectory;
239 dir->GetObject(keyname, fTree);
240 if (!fTree) {
241 std::string msg = "No TTree called ";
242 msg += keyname;
243 msg += " was found in the selected TDirectory.";
244 Error("TTreeReader", "%s", msg.c_str());
245 }
246 Initialize();
247}
248
249////////////////////////////////////////////////////////////////////////////////
250/// Tell all value readers that the tree reader does not exist anymore.
251
253{
254 for (std::deque<ROOT::Internal::TTreeReaderValueBase *>::const_iterator i = fValues.begin(), e = fValues.end();
255 i != e; ++i) {
256 (*i)->MarkTreeReaderUnavailable();
257 }
258 if (fTree && fNotify.IsLinked())
260
262 // a plain TTree is automatically added to the current directory,
263 // do not delete it here
264 if (IsChain()) {
265 delete fTree;
266 }
267 }
268}
269
270////////////////////////////////////////////////////////////////////////////////
271/// Initialization of the director.
272
274{
275 fEntry = -1;
276 if (!fTree) {
279 return;
280 }
281
285 } else if (fEntryList && fEntryList->GetLists()) {
286 Error("Initialize", "We are not processing a TChain but the TEntryList contains sublists. Please "
287 "provide a simple TEntryList with no sublists instead.");
290 return;
291 }
292
293 fDirector = std::make_unique<ROOT::Internal::TBranchProxyDirector>(fTree, -1);
294
295 if (!fNotify.IsLinked()) {
297
298 if (fTree->GetTree()) {
299 // The current TTree is already available.
301 Notify();
303 }
304 }
305}
306
308{
309 if (friendIdx >= fFriendProxies.size()) {
310 fFriendProxies.resize(friendIdx + 1);
311 }
312
314 fFriendProxies[friendIdx] = std::make_unique<ROOT::Internal::TFriendProxy>(fDirector.get(), fTree, friendIdx);
315 }
316
317 return *fFriendProxies[friendIdx];
318}
319
320////////////////////////////////////////////////////////////////////////////////
321/// Notify director and values of a change in tree. Called from TChain and TTree's LoadTree.
322/// TTreeReader registers its fNotify data member with the TChain/TTree which
323/// in turn leads to this method being called upon the execution of LoadTree.
325{
326
327 // We are missing at least one proxy, retry creating them when switching
328 // to the next tree
329 if (!fMissingProxies.empty())
330 SetProxies();
331
334 // This can happen if someone switched trees behind us.
335 // Likely cause: a TChain::LoadTree() e.g. from TTree::Process().
336 // This means that "local" should be set!
337 // There are two entities switching trees which is bad.
338 Warning("SetEntryBase()",
339 "The current tree in the TChain %s has changed (e.g. by TTree::Process) "
340 "even though TTreeReader::SetEntry() was called, which switched the tree "
341 "again. Did you mean to call TTreeReader::SetLocalEntry()?",
342 fTree->GetName());
343 }
345 } else {
347 }
348
350 Warning("SetEntryBase()",
351 "The TTree / TChain has an associated TEntryList. "
352 "TTreeReader ignores TEntryLists unless you construct the TTreeReader passing a TEntryList.");
354 }
355
356 if (!fDirector->Notify()) {
358 Error("SetEntryBase()", "There was an error while notifying the proxies.");
360 return false;
361 }
362
363 if (fProxiesSet) {
364 for (auto value : fValues) {
365 value->NotifyNewTree(fTree->GetTree());
366 }
367 }
368
369 return true;
370}
371
372////////////////////////////////////////////////////////////////////////////////
373/// Tell readers we now have a tree.
374/// fValues gets insertions during this loop (when parametrized arrays are read),
375/// invalidating iterators. Use old-school counting instead.
376
378{
379 fMissingProxies.clear();
380 fProxiesSet = false; // In the loop below, we cannot recreate proxies if this is true
381
382 for (size_t i = 0; i < fValues.size(); ++i) {
384 // Check whether the user wants to suppress errors for this specific branch
385 // if it is missing. This information is used here to act in the situation
386 // where the first tree of the chain does not contain that branch. In such
387 // case, we need to postpone the creation of the corresponding proxy until
388 // we find the branch in a following tree of the chain.
389 const bool suppressErrorsForThisBranch = (fSuppressErrorsForMissingBranches.find(reader->fBranchName.Data()) !=
391 // Because of the situation described above, we may have some proxies
392 // already created and some not, if their branch was not available so far.
393 // Make sure we do not recreate the proxy unnecessarily, unless the
394 // data member was set outside of this function (e.g. in Restart).
395 if (!reader->GetProxy() || !fProxiesSet)
396 reader->CreateProxy();
397
398 // The creation of the proxy failed again. If it was due to a missing
399 // branch, we propagate this information upstream, otherwise we return
400 // false to signify there was some other problem.
401 if (!reader->GetProxy()) {
404 fMissingProxies.insert(reader->fBranchName.Data());
405 else
406 return false;
407 }
408 }
409 // If at least one proxy was there and no error occurred, we assume the proxies to be set.
410 fProxiesSet = !fValues.empty();
411
412 // Now we need to properly set the TTreeCache. We do this in steps:
413 // 1. We set the entry range according to the entry range of the TTreeReader
414 // 2. We add to the cache the branches identifying them by the name the user provided
415 // upon creation of the TTreeReader{Value, Array}s
416 // 3. We stop the learning phase.
417 // Operations 1, 2 and 3 need to happen in this order. See:
418 // https://sft.its.cern.ch/jira/browse/ROOT-9773?focusedCommentId=87837
419 if (fProxiesSet) {
420 const auto curFile = fTree->GetCurrentFile();
421 if (curFile && fTree->GetTree()->GetReadCache(curFile, true)) {
422 if (!(-1LL == fEndEntry && 0ULL == fBeginEntry)) {
423 // We need to avoid to pass -1 as end entry to the SetCacheEntryRange method
424 const auto lastEntry = (-1LL == fEndEntry) ? fTree->GetEntriesFast() : fEndEntry;
426 }
427 for (auto value : fValues) {
428 if (value->GetProxy())
429 fTree->AddBranchToCache(value->GetProxy()->GetBranchName(), true);
430 }
432 }
433 }
434
435 return true;
436}
437
439{
441 return;
442 if (!fTree)
443 return;
444 // Make sure all proxies are set, as in certain situations we might get to this
445 // point without having set the proxies first. For example, when processing a
446 // TChain and calling `SetEntry(N)` with N beyond the real number of entries.
447 // If the proxies can't be set return from the function and give up the warning.
448 if (!fProxiesSet && !SetProxies())
449 return;
450
451 // If we are stopping the reading because we reached the last entry specified
452 // explicitly via SetEntriesRange, do not bother the user with a warning
453 if (fEntry == fEndEntry)
454 return;
455
456 const std::string mainTreeName =
458
459 const auto *friendsList = fTree->GetListOfFriends();
460 if (!friendsList || friendsList->GetEntries() == 0)
461 return;
462
463 for (decltype(fFriendProxies.size()) idx = 0; idx < fFriendProxies.size(); idx++) {
464 auto &&fp = fFriendProxies[idx];
465 if (!fp)
466 continue;
467 // In case the friend is indexed it may very well be that it has a different number of events
468 // e.g. the friend contains information about luminosity block and
469 // all the entries in the main tree are from the same luminosity block
470 if (fp->HasIndex())
471 continue;
472 const auto *frTree = fp->GetDirector()->GetTree();
473 if (!frTree)
474 continue;
475
476 // Need to retrieve the real friend tree from the main tree
477 // because the current friend proxy points to the tree it is currently processing
478 // i.e. the current tree in a chain in case the real friend is a TChain
479 auto *frEl = static_cast<TFriendElement *>(friendsList->At(idx));
480 if (!frEl)
481 continue;
482 auto *frTreeFromMain = frEl->GetTree();
483 if (!frTreeFromMain)
484 continue;
485 // We are looking for the situation where there are actually still more
486 // entries to read in the friend. The following checks if the current entry to read
487 // is greater than the available entries in the dataset. If not, then we know there
488 // are more entries left in the friend.
489 //
490 // GetEntriesFast gives us a single handle to assess all the following:
491 // * If the friend is a TTree, it returns the total number of entries
492 // * If it is a TChain, then two more scenarios may occur:
493 // - If we have processed until the last file, then it returns the total
494 // number of entries.
495 // - If we have not processed all files yet, then it returns TTree::kMaxEntries.
496 // Thus, fEntry will always be smaller and the warning will be issued.
497 if (fEntry >= frTreeFromMain->GetEntriesFast())
498 continue;
499 // The friend tree still has entries beyond the last one of the main
500 // tree, warn the user about it.
501 const std::string frTreeName = dynamic_cast<const TChain *>(frTree)
502 ? frTree->GetName()
504 std::string msg = "Last entry available from main tree '" + mainTreeName + "' was " + std::to_string(fEntry - 1) +
505 " but friend tree '" + frTreeName + "' has more entries beyond the end of the main tree.";
506 Warning("SetEntryBase()", "%s", msg.c_str());
507 }
508}
509////////////////////////////////////////////////////////////////////////////////
510/// Set the range of entries to be loaded by `Next()`; end will not be loaded.
511///
512/// If end <= begin, `end` is ignored (set to `-1`, i.e. will run on all entries from `begin` onwards).
513///
514/// Example:
515///
516/// ~~~ {.cpp}
517/// reader.SetEntriesRange(3, 5);
518/// while (reader.Next()) {
519/// // Will load entries 3 and 4.
520/// }
521/// ~~~
522///
523/// Note that if a TEntryList is present, beginEntry and endEntry refer to the beginEntry-th/endEntry-th entries of the
524/// TEntryList (or the main TEntryList in case it has sub-entrylists). In other words, SetEntriesRange can
525/// be used to only loop over part of the TEntryList, but not to further restrict the actual TTree/TChain entry numbers
526/// considered.
527///
528/// \param beginEntry The first entry to be loaded by `Next()`.
529/// \param endEntry The entry where `Next()` will return false, not loading it.
530
532{
533 if (beginEntry < 0)
534 return kEntryNotFound;
535 // Complain if the entries number is larger than the tree's / chain's / entry
536 // list's number of entries, unless it's a TChain and "max entries" is
537 // uninitialized (i.e. TTree::kMaxEntries).
538 if (beginEntry >= GetEntries(false) && !(IsChain() && GetEntries(false) == TTree::kMaxEntries)) {
539 Error("SetEntriesRange()", "Start entry (%lld) must be lower than the available entries (%lld).", beginEntry,
540 GetEntries(false));
541 return kEntryNotFound;
542 }
543
544 // Update data members to correctly reflect the defined range
545 if (endEntry > beginEntry)
547 else
548 fEndEntry = -1;
549
551
552 if (beginEntry - 1 < 0)
553 // Reset the cache if reading from the first entry of the tree
554 Restart();
555 else {
556 // Load the first entry in the range. SetEntry() will also call SetProxies(),
557 // thus adding all the branches to the cache and triggering the learning phase.
559 if (es != kEntryValid) {
560 Error("SetEntriesRange()", "Error setting first entry %lld: %s", beginEntry, fgEntryStatusText[(int)es]);
561 return es;
562 }
563 }
564
565 return kEntryValid;
566}
567
569{
570 fDirector->SetReadEntry(-1);
571 fProxiesSet = false; // we might get more value readers, meaning new proxies.
572 fEntry = -1;
573 if (const auto curFile = fTree->GetCurrentFile()) {
574 if (auto tc = fTree->GetTree()->GetReadCache(curFile, true)) {
575 tc->DropBranch("*", true);
576 tc->ResetCache();
577 }
578 }
579}
580
581////////////////////////////////////////////////////////////////////////////////
582/// Returns the number of entries of the TEntryList if one is provided, else
583/// of the TTree / TChain, independent of a range set by SetEntriesRange()
584/// by calling TTree/TChain::%GetEntriesFast.
585
587{
588 if (fEntryList)
589 return fEntryList->GetN();
590 if (!fTree)
591 return -1;
592 return fTree->GetEntriesFast();
593}
594
595////////////////////////////////////////////////////////////////////////////////
596/// Returns the number of entries of the TEntryList if one is provided, else
597/// of the TTree / TChain, independent of a range set by SetEntriesRange().
598///
599/// \param force If `IsChain()` and `force`, determines whether all TFiles of
600/// this TChain should be opened to determine the exact number of entries
601/// of the TChain. If `!IsChain()`, `force` is ignored.
602
604{
605 if (fEntryList)
606 return fEntryList->GetN();
607 if (!fTree)
608 return -1;
609 if (force) {
611 auto res = fTree->GetEntries();
612 // Go back to where we were:
615 return res;
616 }
617 return fTree->GetEntriesFast();
618}
619
620////////////////////////////////////////////////////////////////////////////////
621/// Load an entry into the tree, return the status of the read.
622/// For chains, entry is the global (i.e. not tree-local) entry number, unless
623/// `local` is `true`, in which case `entry` specifies the entry number within
624/// the current tree. This is needed for instance for TSelector::Process().
625
627{
628 if (IsInvalid()) {
630 fEntry = -1;
631 return fEntryStatus;
632 }
633
634 fEntry = entry;
635
637 if (fEntryList) {
638 if (entry >= fEntryList->GetN()) {
639 // Passed the end of the chain, Restart() was not called:
640 // don't try to load entries anymore. Can happen in these cases:
641 // while (tr.Next()) {something()};
642 // while (tr.Next()) {somethingelse()}; // should not be calling somethingelse().
644 return fEntryStatus;
645 }
646 if (entry >= 0) {
647 if (fEntryList->GetLists()) {
649 int treenum = -1;
651 entryAfterList += static_cast<TChain *>(fTree)->GetTreeOffset()[treenum];
652 // We always translate local entry numbers to global entry numbers for TChain+TEntryList with sublists
653 local = false;
654 } else {
655 // Could be a TTree or a TChain (TTreeReader also supports single TEntryLists for TChains).
656 // In both cases, we are using the global entry numbers coming from the single TEntryList.
658 }
659 }
660 }
661
663
667
668 if (loadResult < 0) {
669 // ROOT-9628 We cover here the case when:
670 // - We deal with a TChain
671 // - The last file is opened
672 // - The TTree is not correctly loaded
673 // The system is robust against issues with TTrees associated to the chain
674 // when they are not at the end of it.
675 if (loadResult == -3 && TestBit(kBitIsChain) && !fTree->GetTree()) {
676 fDirector->Notify();
677 if (fProxiesSet) {
678 for (auto value : fValues) {
679 value->NotifyNewTree(fTree->GetTree());
680 }
681 }
682 Warning("SetEntryBase()", "There was an issue opening the last file associated to the TChain "
683 "being processed.");
685 return fEntryStatus;
686 }
687
688 if (loadResult == -2) {
689 fDirector->Notify();
690 if (fProxiesSet) {
691 for (auto value : fValues) {
692 value->NotifyNewTree(fTree->GetTree());
693 }
694 }
695 auto &&nEntries = treeToCallLoadOn->GetEntriesFast();
696 if (fBeginEntry >= nEntries && nEntries > 0) {
697 // The beginning entry specified via SetEntriesRange was beyond the total number of entries in the dataset
698 Error("SetEntryBase()",
699 "The beginning entry specified via SetEntriesRange (%lld) is equal to or beyond the "
700 "total number of entries in the dataset (%lld). Make sure to specify a "
701 "beginning entry lower than the number of available entries.",
704 } else
707 return fEntryStatus;
708 }
709
710 if (loadResult == -1) {
711 // The chain is empty
713 return fEntryStatus;
714 }
715
716 if (loadResult == -4) {
717 // The TChainElement corresponding to the entry is missing or
718 // the TTree is missing from the file.
719 fDirector->Notify();
720 if (fProxiesSet) {
721 for (auto value : fValues) {
722 value->NotifyNewTree(fTree->GetTree());
723 }
724 }
726 return fEntryStatus;
727 }
728
729 if (loadResult == -6) {
730 // An expected branch was not found when switching to a new tree.
731 fDirector->Notify();
732 if (fProxiesSet) {
733 for (auto value : fValues) {
734 value->NotifyNewTree(fTree->GetTree());
735 }
736 }
737 // Even though one (or more) branches might be missing from the new
738 // tree, other branches might still be there. We know we are switching
739 // into the tree at this point, so we want the director to start
740 // reading again from local entry 0, for those branches that are
741 // available
742 fDirector->SetReadEntry(0);
744 return fEntryStatus;
745 }
746
747 Warning("SetEntryBase()", "Unexpected error '%lld' in %s::LoadTree", loadResult,
748 treeToCallLoadOn->IsA()->GetName());
749
751 return fEntryStatus;
752 }
753
754 if (!fProxiesSet) {
755 if (!SetProxies()) {
757 return fEntryStatus;
758 }
759 }
760
761 if ((fEndEntry >= 0 && entry >= fEndEntry) || (fEntry >= fTree->GetEntriesFast())) {
764 return fEntryStatus;
765 }
766
767 fDirector->SetReadEntry(loadResult);
769
770 // Convey the information that a branch was not found either when
771 // switching to a new tree (i.e. when trying to load its first entry) or
772 // even if we are in the middle of the tree (e.g. by calling SetEntriesRange
773 // beforehand) but a proxy was not created because of the missing branch
776 }
777
778 for (auto &&fp : fFriendProxies) {
779 if (!fp)
780 continue;
781 if (fp->GetReadEntry() >= 0)
782 continue;
783 // We are going to read an invalid entry from a friend, propagate
784 // this information to the user.
785 const auto *frTree = fp->GetDirector()->GetTree();
786 if (!frTree)
787 continue;
788 const std::string frTreeName = dynamic_cast<const TChain *>(frTree)
789 ? frTree->GetName()
791 // If the friend does not have a TTreeIndex, the cause of a failure reading an entry
792 // is most probably a difference in number of entries between main tree and friend tree
793 if (!fp->HasIndex()) {
794 std::string msg = "Cannot read entry " + std::to_string(entry) + " from friend tree '" + frTreeName +
795 "'. The friend tree has less entries than the main tree. Make sure all trees "
796 "of the dataset have the same number of entries.";
797 throw std::runtime_error{msg};
798 } else {
800 }
801 }
802
803 return fEntryStatus;
804}
805
806////////////////////////////////////////////////////////////////////////////////
807/// Set (or update) the which tree to read from. `tree` can be
808/// a TTree or a TChain.
809
811{
813 // a plain TTree is automatically added to the current directory,
814 // do not delete it here
815 if (IsChain()) {
816 delete fTree;
817 }
818 }
819
820 fTree = tree;
822 fEntry = -1;
823
826 if (fTree) {
829 } else {
831 }
832
833 if (!fDirector) {
834 Initialize();
835 } else {
836 fDirector->SetTree(fTree);
837 fDirector->SetReadEntry(-1);
838 }
839}
840
841////////////////////////////////////////////////////////////////////////////////
842/// Set (or update) the which tree to read from, passing the name of a tree in a
843/// directory.
844///
845/// \param keyname - name of the tree in `dir`
846/// \param dir - the `TDirectory` to load `keyname` from (or gDirectory if `nullptr`)
847/// \param entryList - the `TEntryList` to attach to the `TTreeReader`.
848
849void TTreeReader::SetTree(const char *keyname, TDirectory *dir, TEntryList *entryList /*= nullptr*/)
850{
851 TTree *tree = nullptr;
852 if (!dir)
853 dir = gDirectory;
854 dir->GetObject(keyname, tree);
855 SetTree(tree, entryList);
856}
857
858////////////////////////////////////////////////////////////////////////////////
859/// Add a value reader for this tree.
860
862{
863 if (fProxiesSet) {
864 Error("RegisterValueReader",
865 "Error registering reader for %s: TTreeReaderValue/Array objects must be created before the call to Next() "
866 "/ SetEntry() / SetLocalEntry(), or after TTreeReader::Restart()!",
867 reader->GetBranchName());
868 return false;
869 }
870 fValues.push_back(reader);
871 return true;
872}
873
874////////////////////////////////////////////////////////////////////////////////
875/// Remove a value reader for this tree.
876
878{
879 std::deque<ROOT::Internal::TTreeReaderValueBase *>::iterator iReader =
880 std::find(fValues.begin(), fValues.end(), reader);
881 if (iReader == fValues.end()) {
882 Error("DeregisterValueReader", "Cannot find reader of type %s for branch %s", reader->GetDerivedTypeName(),
883 reader->fBranchName.Data());
884 return;
885 }
886 fValues.erase(iReader);
887}
#define e(i)
Definition RSha256.hxx:103
long long Long64_t
Definition RtypesCore.h:69
#define ClassImp(name)
Definition Rtypes.h:374
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#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.
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.
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
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:205
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1057
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:864
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:543
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1071
void ResetBit(UInt_t f)
Definition TObject.h:204
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.
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,...
std::deque< ROOT::Internal::TTreeReaderValueBase * > fValues
readers that use our director
EEntryStatus fEntryStatus
status of most recent read request
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.
bool RegisterValueReader(ROOT::Internal::TTreeReaderValueBase *reader)
Add a value reader for this tree.
TTree * fTree
tree that's read
bool fWarnAboutLongerFriends
std::set< std::string > fMissingProxies
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.
std::set< std::string > fSuppressErrorsForMissingBranches
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:9583
virtual Int_t AddBranchToCache(const char *bname, bool subbranches=false)
Add branch with name bname to the Tree cache.
Definition TTree.cxx:1053
TFile * GetCurrentFile() const
Return pointer to the current file.
Definition TTree.cxx:5484
virtual TEntryList * GetEntryList()
Returns the entry list assigned to this tree.
Definition TTree.cxx:5861
virtual Long64_t GetEntries() const
Definition TTree.h:464
virtual TTree * GetTree() const
Definition TTree.h:558
virtual Long64_t LoadTree(Long64_t entry)
Set current entry.
Definition TTree.cxx:6480
virtual Long64_t GetEntriesFast() const
Return a number greater or equal to the total number of entries in the dataset.
Definition TTree.h:506
virtual Int_t SetCacheEntryRange(Long64_t first, Long64_t last)
interface to TTreeCache to set the cache entry range
Definition TTree.cxx:8929
virtual TList * GetListOfFriends() const
Definition TTree.h:531
static constexpr Long64_t kMaxEntries
Definition TTree.h:230
std::vector< std::string > GetTreeFullPaths(const TTree &tree)