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/io/tree/hsimpleReader.C
34 - tutorials/analysis/tree/h1analysisTreeReader.C
35 - An example in roottest showing the full power <a href="https://github.com/root-project/root/tree/master/roottest/root/tree/reader">here</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
40A simpler analysis example can be found below: it histograms a function of the px and py branches.
41
42~~~{.cpp}
43// A simple TTreeReader use: read data from hsimple.root (written by hsimple.C)
44
45#include "TFile.h"
46#include "TH1F.h"
47#include "TTreeReader.h"
48#include "TTreeReaderValue.h"
49
50void hsimpleReader() {
51 // Create a histogram for the values we read.
52 TH1F("h1", "ntuple", 100, -4, 4);
53
54 // Open the file containing the tree.
55 TFile *myFile = TFile::Open("$ROOTSYS/tutorials/hsimple.root");
56
57 // Create a TTreeReader for the tree, for instance by passing the
58 // TTree's name and the TDirectory / TFile it is in.
59 TTreeReader myReader("ntuple", myFile);
60
61 // The branch "px" contains floats; access them as myPx.
62 TTreeReaderValue<Float_t> myPx(myReader, "px");
63 // The branch "py" contains floats, too; access those as myPy.
64 TTreeReaderValue<Float_t> myPy(myReader, "py");
65
66 // Loop over all entries of the TTree or TChain.
67 while (myReader.Next()) {
68 // Just access the data as if myPx and myPy were iterators (note the '*'
69 // in front of them):
70 myHist->Fill(*myPx + *myPy);
71 }
72
73 myHist->Draw();
74}
75~~~
76
77A more complete example including error handling and a few combinations of
78TTreeReaderValue and TTreeReaderArray would look like this:
79
80~~~{.cpp}
81#include <TFile.h>
82#include <TH1.h>
83#include <TTreeReader.h>
84#include <TTreeReaderValue.h>
85#include <TTreeReaderArray.h>
86
87#include "TriggerInfo.h"
88#include "Muon.h"
89#include "Tau.h"
90
91#include <vector>
92#include <iostream>
93
94bool CheckValue(ROOT::Internal::TTreeReaderValueBase& value) {
95 if (value.GetSetupStatus() < 0) {
96 std::cerr << "Error " << value.GetSetupStatus()
97 << "setting up reader for " << value.GetBranchName() << '\n';
98 return false;
99 }
100 return true;
101}
102
103
104// Analyze the tree "MyTree" in the file passed into the function.
105// Returns false in case of errors.
106bool analyze(TFile* file) {
107 // Create a TTreeReader named "MyTree" from the given TDirectory.
108 // The TTreeReader gives access to the TTree to the TTreeReaderValue and
109 // TTreeReaderArray objects. It knows the current entry number and knows
110 // how to iterate through the TTree.
111 TTreeReader reader("MyTree", file);
112
113 // Read a single float value in each tree entries:
114 TTreeReaderValue<float> weight(reader, "event.weight");
115
116 // Read a TriggerInfo object from the tree entries:
117 TTreeReaderValue<TriggerInfo> triggerInfo(reader, "triggerInfo");
118
119 //Read a vector of Muon objects from the tree entries:
120 TTreeReaderValue<std::vector<Muon>> muons(reader, "muons");
121
122 //Read the pT for all jets in the tree entry:
123 TTreeReaderArray<double> jetPt(reader, "jets.pT");
124
125 // Read the taus in the tree entry:
126 TTreeReaderArray<Tau> taus(reader, "taus");
127
128
129 // Now iterate through the TTree entries and fill a histogram.
130
131 TH1F("hist", "TTreeReader example histogram", 10, 0., 100.);
132
133 bool firstEntry = true;
134 while (reader.Next()) {
135 if (firstEntry) {
136 // Check that branches exist and their types match our expectation.
137 if (!CheckValue(weight)) return false;
138 if (!CheckValue(triggerInfo)) return false;
139 if (!CheckValue(muons)) return false;
140 if (!CheckValue(jetPt)) return false;
141 if (!CheckValue(taus)) return false;
142 firstentry = false;
143 }
144
145 // Access the TriggerInfo object as if it's a pointer.
146 if (!triggerInfo->hasMuonL1())
147 continue;
148
149 // Ditto for the vector<Muon>.
150 if (!muons->size())
151 continue;
152
153 // Access the jetPt as an array, whether the TTree stores this as
154 // a std::vector, std::list, TClonesArray or Jet* C-style array, with
155 // fixed or variable array size.
156 if (jetPt.GetSize() < 2 || jetPt[0] < 100)
157 continue;
158
159 // Access the array of taus.
160 if (!taus.IsEmpty()) {
161 // Access a float value - need to dereference as TTreeReaderValue
162 // behaves like an iterator
163 float currentWeight = *weight;
164 for (const Tau& tau: taus) {
165 hist->Fill(tau.eta(), currentWeight);
166 }
167 }
168 } // TTree entry / event loop
169
170 // Return true if we have iterated through all entries.
171 return reader.GetEntryStatus() == TTreeReader::kEntryBeyondEnd;
172}
173~~~
174*/
175// clang-format on
176
178
179using namespace ROOT::Internal;
180
181// Provide some storage for the poor little symbol.
183
184////////////////////////////////////////////////////////////////////////////////
185/// Default constructor. Call SetTree to connect to a TTree.
186
187TTreeReader::TTreeReader() : fNotify(this), fFriendProxies() {}
188
189////////////////////////////////////////////////////////////////////////////////
190/// Access data from tree.
191///
192/// \param tree The TTree or TChain to read from
193/// \param entryList It can be a single TEntryList with global entry numbers (supported, as
194/// an extension, also in the case of a TChain) or, if the first parameter
195/// is a TChain, a TEntryList with sub-TEntryLists with local entry numbers.
196/// In the latter case, the TEntryList must be associated to the TChain, as
197/// per chain.SetEntryList(&entryList).
198
200 const std::set<std::string> &suppressErrorsForMissingBranches)
201 : fTree(tree),
202 fEntryList(entryList),
203 fNotify(this),
204 fFriendProxies(),
205 fWarnAboutLongerFriends(warnAboutLongerFriends),
206 fSuppressErrorsForMissingBranches(suppressErrorsForMissingBranches)
207{
208 if (!fTree) {
209 ::Error("TTreeReader::TTreeReader", "TTree is NULL!");
210 } else {
211 // We do not own the tree
213 Initialize();
214 }
215}
216
217////////////////////////////////////////////////////////////////////////////////
218/// Access data from the tree called keyname in the directory (e.g. TFile)
219/// dir, or the current directory if dir is NULL. If keyname cannot be
220/// found, or if it is not a TTree, IsInvalid() will return true.
221///
222/// \param keyname The name of the TTree to read from file
223/// \param dir The TDirectory to read keyname from
224/// \param entryList It can be a single TEntryList with global entry numbers (supported, as
225/// an extension, also in the case of a TChain) or, if the first parameter
226/// is a TChain, a TEntryList with sub-TEntryLists with local entry numbers.
227/// In the latter case, the TEntryList must be associated to the TChain, as
228/// per chain.SetEntryList(&entryList).
229
231 : fEntryList(entryList), fNotify(this), fFriendProxies()
232{
233 if (!dir)
234 dir = gDirectory;
235 dir->GetObject(keyname, fTree);
236 if (!fTree) {
237 std::string msg = "No TTree called ";
238 msg += keyname;
239 msg += " was found in the selected TDirectory.";
240 Error("TTreeReader", "%s", msg.c_str());
241 }
242 Initialize();
243}
244
245////////////////////////////////////////////////////////////////////////////////
246/// Tell all value readers that the tree reader does not exist anymore.
247
249{
250 for (std::deque<ROOT::Internal::TTreeReaderValueBase *>::const_iterator i = fValues.begin(), e = fValues.end();
251 i != e; ++i) {
252 (*i)->MarkTreeReaderUnavailable();
253 }
254 if (fTree && fNotify.IsLinked())
256
258 // a plain TTree is automatically added to the current directory,
259 // do not delete it here
260 if (IsChain()) {
261 delete fTree;
262 }
263 }
264}
265
266////////////////////////////////////////////////////////////////////////////////
267/// Initialization of the director.
268
270{
271 fEntry = -1;
272 if (!fTree) {
275 return;
276 }
277
281 } else if (fEntryList && fEntryList->GetLists()) {
282 Error("Initialize", "We are not processing a TChain but the TEntryList contains sublists. Please "
283 "provide a simple TEntryList with no sublists instead.");
286 return;
287 }
288
289 fDirector = std::make_unique<ROOT::Internal::TBranchProxyDirector>(fTree, -1);
290
291 if (!fNotify.IsLinked()) {
293
294 if (fTree->GetTree()) {
295 // The current TTree is already available.
297 Notify();
299 }
300 }
301}
302
304{
305 if (friendIdx >= fFriendProxies.size()) {
306 fFriendProxies.resize(friendIdx + 1);
307 }
308
310 fFriendProxies[friendIdx] = std::make_unique<ROOT::Internal::TFriendProxy>(fDirector.get(), fTree, friendIdx);
311 }
312
313 return *fFriendProxies[friendIdx];
314}
315
316////////////////////////////////////////////////////////////////////////////////
317/// Notify director and values of a change in tree. Called from TChain and TTree's LoadTree.
318/// TTreeReader registers its fNotify data member with the TChain/TTree which
319/// in turn leads to this method being called upon the execution of LoadTree.
321{
322
323 // We are missing at least one proxy, retry creating them when switching
324 // to the next tree
325 if (!fMissingProxies.empty())
326 SetProxies();
327
330 // This can happen if someone switched trees behind us.
331 // Likely cause: a TChain::LoadTree() e.g. from TTree::Process().
332 // This means that "local" should be set!
333 // There are two entities switching trees which is bad.
334 Warning("SetEntryBase()",
335 "The current tree in the TChain %s has changed (e.g. by TTree::Process) "
336 "even though TTreeReader::SetEntry() was called, which switched the tree "
337 "again. Did you mean to call TTreeReader::SetLocalEntry()?",
338 fTree->GetName());
339 }
341 } else {
343 }
344
346 Warning("SetEntryBase()",
347 "The TTree / TChain has an associated TEntryList. "
348 "TTreeReader ignores TEntryLists unless you construct the TTreeReader passing a TEntryList.");
350 }
351
352 if (!fDirector->Notify()) {
354 Error("SetEntryBase()", "There was an error while notifying the proxies.");
356 return false;
357 }
358
359 if (fProxiesSet) {
360 for (auto value : fValues) {
361 value->NotifyNewTree(fTree->GetTree());
362 }
363 }
364
365 return true;
366}
367
368////////////////////////////////////////////////////////////////////////////////
369/// Tell readers we now have a tree.
370/// fValues gets insertions during this loop (when parametrized arrays are read),
371/// invalidating iterators. Use old-school counting instead.
372
374{
375 fMissingProxies.clear();
376 fProxiesSet = false; // In the loop below, we cannot recreate proxies if this is true
377
378 for (size_t i = 0; i < fValues.size(); ++i) {
380 // Check whether the user wants to suppress errors for this specific branch
381 // if it is missing. This information is used here to act in the situation
382 // where the first tree of the chain does not contain that branch. In such
383 // case, we need to postpone the creation of the corresponding proxy until
384 // we find the branch in a following tree of the chain.
385 const bool suppressErrorsForThisBranch = (fSuppressErrorsForMissingBranches.find(reader->fBranchName.Data()) !=
387 // Because of the situation described above, we may have some proxies
388 // already created and some not, if their branch was not available so far.
389 // Make sure we do not recreate the proxy unnecessarily, unless the
390 // data member was set outside of this function (e.g. in Restart).
391 if (!reader->GetProxy() || !fProxiesSet)
392 reader->CreateProxy();
393
394 // The creation of the proxy failed again. If it was due to a missing
395 // branch, we propagate this information upstream, otherwise we return
396 // false to signify there was some other problem.
397 if (!reader->GetProxy()) {
400 fMissingProxies.insert(reader->fBranchName.Data());
401 else
402 return false;
403 }
404 }
405 // If at least one proxy was there and no error occurred, we assume the proxies to be set.
406 fProxiesSet = !fValues.empty();
407
408 // Now we need to properly set the TTreeCache. We do this in steps:
409 // 1. We set the entry range according to the entry range of the TTreeReader
410 // 2. We add to the cache the branches identifying them by the name the user provided
411 // upon creation of the TTreeReader{Value, Array}s
412 // 3. We stop the learning phase.
413 // Operations 1, 2 and 3 need to happen in this order. See:
414 // https://sft.its.cern.ch/jira/browse/ROOT-9773?focusedCommentId=87837
415 if (fProxiesSet) {
416 const auto curFile = fTree->GetCurrentFile();
417 if (curFile && fTree->GetTree()->GetReadCache(curFile, true)) {
418 if (!(-1LL == fEndEntry && 0ULL == fBeginEntry)) {
419 // We need to avoid to pass -1 as end entry to the SetCacheEntryRange method
420 const auto lastEntry = (-1LL == fEndEntry) ? fTree->GetEntriesFast() : fEndEntry;
422 }
423 for (auto value : fValues) {
424 if (value->GetProxy())
425 fTree->AddBranchToCache(value->GetProxy()->GetBranchName(), true);
426 }
428 }
429 }
430
431 return true;
432}
433
435{
437 return;
438 if (!fTree)
439 return;
440 // Make sure all proxies are set, as in certain situations we might get to this
441 // point without having set the proxies first. For example, when processing a
442 // TChain and calling `SetEntry(N)` with N beyond the real number of entries.
443 // If the proxies can't be set return from the function and give up the warning.
444 if (!fProxiesSet && !SetProxies())
445 return;
446
447 // If we are stopping the reading because we reached the last entry specified
448 // explicitly via SetEntriesRange, do not bother the user with a warning
449 if (fEntry == fEndEntry)
450 return;
451
452 const std::string mainTreeName =
454
455 const auto *friendsList = fTree->GetListOfFriends();
456 if (!friendsList || friendsList->GetEntries() == 0)
457 return;
458
459 for (decltype(fFriendProxies.size()) idx = 0; idx < fFriendProxies.size(); idx++) {
460 auto &&fp = fFriendProxies[idx];
461 if (!fp)
462 continue;
463 // In case the friend is indexed it may very well be that it has a different number of events
464 // e.g. the friend contains information about luminosity block and
465 // all the entries in the main tree are from the same luminosity block
466 if (fp->HasIndex())
467 continue;
468 const auto *frTree = fp->GetDirector()->GetTree();
469 if (!frTree)
470 continue;
471
472 // Need to retrieve the real friend tree from the main tree
473 // because the current friend proxy points to the tree it is currently processing
474 // i.e. the current tree in a chain in case the real friend is a TChain
475 auto *frEl = static_cast<TFriendElement *>(friendsList->At(idx));
476 if (!frEl)
477 continue;
478 auto *frTreeFromMain = frEl->GetTree();
479 if (!frTreeFromMain)
480 continue;
481 // We are looking for the situation where there are actually still more
482 // entries to read in the friend. The following checks if the current entry to read
483 // is greater than the available entries in the dataset. If not, then we know there
484 // are more entries left in the friend.
485 //
486 // GetEntriesFast gives us a single handle to assess all the following:
487 // * If the friend is a TTree, it returns the total number of entries
488 // * If it is a TChain, then two more scenarios may occur:
489 // - If we have processed until the last file, then it returns the total
490 // number of entries.
491 // - If we have not processed all files yet, then it returns TTree::kMaxEntries.
492 // Thus, fEntry will always be smaller and the warning will be issued.
493 if (fEntry >= frTreeFromMain->GetEntriesFast())
494 continue;
495 // The friend tree still has entries beyond the last one of the main
496 // tree, warn the user about it.
497 const std::string frTreeName = dynamic_cast<const TChain *>(frTree)
498 ? frTree->GetName()
500 std::string msg = "Last entry available from main tree '" + mainTreeName + "' was " + std::to_string(fEntry - 1) +
501 " but friend tree '" + frTreeName + "' has more entries beyond the end of the main tree.";
502 Warning("SetEntryBase()", "%s", msg.c_str());
503 }
504}
505////////////////////////////////////////////////////////////////////////////////
506/// Set the range of entries to be loaded by `Next()`; end will not be loaded.
507///
508/// If end <= begin, `end` is ignored (set to `-1`, i.e. will run on all entries from `begin` onwards).
509///
510/// Example:
511///
512/// ~~~ {.cpp}
513/// reader.SetEntriesRange(3, 5);
514/// while (reader.Next()) {
515/// // Will load entries 3 and 4.
516/// }
517/// ~~~
518///
519/// Note that if a TEntryList is present, beginEntry and endEntry refer to the beginEntry-th/endEntry-th entries of the
520/// TEntryList (or the main TEntryList in case it has sub-entrylists). In other words, SetEntriesRange can
521/// be used to only loop over part of the TEntryList, but not to further restrict the actual TTree/TChain entry numbers
522/// considered.
523///
524/// \param beginEntry The first entry to be loaded by `Next()`.
525/// \param endEntry The entry where `Next()` will return false, not loading it.
526
528{
529 if (beginEntry < 0)
530 return kEntryNotFound;
531 // Complain if the entries number is larger than the tree's / chain's / entry
532 // list's number of entries, unless it's a TChain and "max entries" is
533 // uninitialized (i.e. TTree::kMaxEntries).
534 if (beginEntry >= GetEntries(false) && !(IsChain() && GetEntries(false) == TTree::kMaxEntries)) {
535 Error("SetEntriesRange()", "Start entry (%lld) must be lower than the available entries (%lld).", beginEntry,
536 GetEntries(false));
537 return kEntryNotFound;
538 }
539
540 // Update data members to correctly reflect the defined range
541 if (endEntry > beginEntry)
543 else
544 fEndEntry = -1;
545
547
548 if (beginEntry - 1 < 0)
549 // Reset the cache if reading from the first entry of the tree
550 Restart();
551 else {
552 // Load the first entry in the range. SetEntry() will also call SetProxies(),
553 // thus adding all the branches to the cache and triggering the learning phase.
555 if (es != kEntryValid) {
556 Error("SetEntriesRange()", "Error setting first entry %lld: %s", beginEntry, fgEntryStatusText[(int)es]);
557 return es;
558 }
559 }
560
561 return kEntryValid;
562}
563
565{
566 fDirector->SetReadEntry(-1);
567 fProxiesSet = false; // we might get more value readers, meaning new proxies.
568 fEntry = -1;
569 if (const auto curFile = fTree->GetCurrentFile()) {
570 if (auto tc = fTree->GetTree()->GetReadCache(curFile, true)) {
571 tc->DropBranch("*", true);
572 tc->ResetCache();
573 }
574 }
575}
576
577////////////////////////////////////////////////////////////////////////////////
578/// Returns the number of entries of the TEntryList if one is provided, else
579/// of the TTree / TChain, independent of a range set by SetEntriesRange()
580/// by calling TTree/TChain::%GetEntriesFast.
581
583{
584 if (fEntryList)
585 return fEntryList->GetN();
586 if (!fTree)
587 return -1;
588 return fTree->GetEntriesFast();
589}
590
591////////////////////////////////////////////////////////////////////////////////
592/// Returns the number of entries of the TEntryList if one is provided, else
593/// of the TTree / TChain, independent of a range set by SetEntriesRange().
594///
595/// \param force If `IsChain()` and `force`, determines whether all TFiles of
596/// this TChain should be opened to determine the exact number of entries
597/// of the TChain. If `!IsChain()`, `force` is ignored.
598
600{
601 if (fEntryList)
602 return fEntryList->GetN();
603 if (!fTree)
604 return -1;
605 if (force) {
607 auto res = fTree->GetEntries();
608 // Go back to where we were:
611 return res;
612 }
613 return fTree->GetEntriesFast();
614}
615
616////////////////////////////////////////////////////////////////////////////////
617/// Load an entry into the tree, return the status of the read.
618/// For chains, entry is the global (i.e. not tree-local) entry number, unless
619/// `local` is `true`, in which case `entry` specifies the entry number within
620/// the current tree. This is needed for instance for TSelector::Process().
621
623{
624 if (IsInvalid()) {
626 fEntry = -1;
627 return fEntryStatus;
628 }
629
630 fEntry = entry;
631
633 if (fEntryList) {
634 if (entry >= fEntryList->GetN()) {
635 // Passed the end of the chain, Restart() was not called:
636 // don't try to load entries anymore. Can happen in these cases:
637 // while (tr.Next()) {something()};
638 // while (tr.Next()) {somethingelse()}; // should not be calling somethingelse().
640 return fEntryStatus;
641 }
642 if (entry >= 0) {
643 if (fEntryList->GetLists()) {
645 int treenum = -1;
647 entryAfterList += static_cast<TChain *>(fTree)->GetTreeOffset()[treenum];
648 // We always translate local entry numbers to global entry numbers for TChain+TEntryList with sublists
649 local = false;
650 } else {
651 // Could be a TTree or a TChain (TTreeReader also supports single TEntryLists for TChains).
652 // In both cases, we are using the global entry numbers coming from the single TEntryList.
654 }
655 }
656 }
657
659
663
664 if (loadResult < 0) {
665 // ROOT-9628 We cover here the case when:
666 // - We deal with a TChain
667 // - The last file is opened
668 // - The TTree is not correctly loaded
669 // The system is robust against issues with TTrees associated to the chain
670 // when they are not at the end of it.
671 if (loadResult == -3 && TestBit(kBitIsChain) && !fTree->GetTree()) {
672 fDirector->Notify();
673 if (fProxiesSet) {
674 for (auto value : fValues) {
675 value->NotifyNewTree(fTree->GetTree());
676 }
677 }
678 Warning("SetEntryBase()", "There was an issue opening the last file associated to the TChain "
679 "being processed.");
681 return fEntryStatus;
682 }
683
684 if (loadResult == -2) {
685 fDirector->Notify();
686 if (fProxiesSet) {
687 for (auto value : fValues) {
688 value->NotifyNewTree(fTree->GetTree());
689 }
690 }
691 auto &&nEntries = treeToCallLoadOn->GetEntriesFast();
692 if (fBeginEntry >= nEntries && nEntries > 0) {
693 // The beginning entry specified via SetEntriesRange was beyond the total number of entries in the dataset
694 Error("SetEntryBase()",
695 "The beginning entry specified via SetEntriesRange (%lld) is equal to or beyond the "
696 "total number of entries in the dataset (%lld). Make sure to specify a "
697 "beginning entry lower than the number of available entries.",
700 } else
703 return fEntryStatus;
704 }
705
706 if (loadResult == -1) {
707 // The chain is empty
709 return fEntryStatus;
710 }
711
712 if (loadResult == -4) {
713 // The TChainElement corresponding to the entry is missing or
714 // the TTree is missing from the file.
715 fDirector->Notify();
716 if (fProxiesSet) {
717 for (auto value : fValues) {
718 value->NotifyNewTree(fTree->GetTree());
719 }
720 }
722 return fEntryStatus;
723 }
724
725 if (loadResult == -6) {
726 // An expected branch was not found when switching to a new tree.
727 fDirector->Notify();
728 if (fProxiesSet) {
729 for (auto value : fValues) {
730 value->NotifyNewTree(fTree->GetTree());
731 }
732 }
733 // Even though one (or more) branches might be missing from the new
734 // tree, other branches might still be there. We know we are switching
735 // into the tree at this point, so we want the director to start
736 // reading again from local entry 0, for those branches that are
737 // available
738 fDirector->SetReadEntry(0);
740 return fEntryStatus;
741 }
742
743 Warning("SetEntryBase()", "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
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;
818 fEntry = -1;
819
822 if (fTree) {
825 } else {
827 }
828
829 if (!fDirector) {
830 Initialize();
831 } else {
832 fDirector->SetTree(fTree);
833 fDirector->SetReadEntry(-1);
834 }
835}
836
837////////////////////////////////////////////////////////////////////////////////
838/// Set (or update) the which tree to read from, passing the name of a tree in a
839/// directory.
840///
841/// \param keyname - name of the tree in `dir`
842/// \param dir - the `TDirectory` to load `keyname` from (or gDirectory if `nullptr`)
843/// \param entryList - the `TEntryList` to attach to the `TTreeReader`.
844
845void TTreeReader::SetTree(const char *keyname, TDirectory *dir, TEntryList *entryList /*= nullptr*/)
846{
847 TTree *tree = nullptr;
848 if (!dir)
849 dir = gDirectory;
850 dir->GetObject(keyname, tree);
851 SetTree(tree, entryList);
852}
853
854////////////////////////////////////////////////////////////////////////////////
855/// Add a value reader for this tree.
856
858{
859 if (fProxiesSet) {
860 Error("RegisterValueReader",
861 "Error registering reader for %s: TTreeReaderValue/Array objects must be created before the call to Next() "
862 "/ 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(),
879 reader->fBranchName.Data());
880 return;
881 }
882 fValues.erase(iReader);
883}
#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:202
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:201
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:84
virtual Int_t StopCacheLearningPhase()
Stop the cache learning phase.
Definition TTree.cxx:9632
virtual Int_t AddBranchToCache(const char *bname, bool subbranches=false)
Add branch with name bname to the Tree cache.
Definition TTree.cxx:1087
TFile * GetCurrentFile() const
Return pointer to the current file.
Definition TTree.cxx:5531
virtual TEntryList * GetEntryList()
Returns the entry list assigned to this tree.
Definition TTree.cxx:5910
virtual Long64_t GetEntries() const
Definition TTree.h:475
virtual TTree * GetTree() const
Definition TTree.h:569
virtual Long64_t LoadTree(Long64_t entry)
Set current entry.
Definition TTree.cxx:6529
virtual Long64_t GetEntriesFast() const
Return a number greater or equal to the total number of entries in the dataset.
Definition TTree.h:517
virtual Int_t SetCacheEntryRange(Long64_t first, Long64_t last)
interface to TTreeCache to set the cache entry range
Definition TTree.cxx:8978
virtual TList * GetListOfFriends() const
Definition TTree.h:542
static constexpr Long64_t kMaxEntries
Definition TTree.h:241
std::vector< std::string > GetTreeFullPaths(const TTree &tree)