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
177
178using namespace ROOT::Internal;
179
180// Provide some storage for the poor little symbol.
182
183////////////////////////////////////////////////////////////////////////////////
184/// Default constructor. Call SetTree to connect to a TTree.
185
186TTreeReader::TTreeReader() : fNotify(this), fFriendProxies() {}
187
188////////////////////////////////////////////////////////////////////////////////
189/// Access data from tree.
190///
191/// \param tree The TTree or TChain to read from
192/// \param entryList It can be a single TEntryList with global entry numbers (supported, as
193/// an extension, also in the case of a TChain) or, if the first parameter
194/// is a TChain, a TEntryList with sub-TEntryLists with local entry numbers.
195/// In the latter case, the TEntryList must be associated to the TChain, as
196/// per chain.SetEntryList(&entryList).
197
199 const std::set<std::string> &suppressErrorsForMissingBranches)
200 : fTree(tree),
201 fEntryList(entryList),
202 fNotify(this),
203 fFriendProxies(),
204 fWarnAboutLongerFriends(warnAboutLongerFriends),
205 fSuppressErrorsForMissingBranches(suppressErrorsForMissingBranches)
206{
207 if (!fTree) {
208 ::Error("TTreeReader::TTreeReader", "TTree is NULL!");
209 } else {
210 // We do not own the tree
212 Initialize();
213 }
214}
215
216////////////////////////////////////////////////////////////////////////////////
217/// Access data from the tree called keyname in the directory (e.g. TFile)
218/// dir, or the current directory if dir is NULL. If keyname cannot be
219/// found, or if it is not a TTree, IsInvalid() will return true.
220///
221/// \param keyname The name of the TTree to read from file
222/// \param dir The TDirectory to read keyname from
223/// \param entryList It can be a single TEntryList with global entry numbers (supported, as
224/// an extension, also in the case of a TChain) or, if the first parameter
225/// is a TChain, a TEntryList with sub-TEntryLists with local entry numbers.
226/// In the latter case, the TEntryList must be associated to the TChain, as
227/// per chain.SetEntryList(&entryList).
228
230 : fEntryList(entryList), fNotify(this), fFriendProxies()
231{
232 if (!dir)
233 dir = gDirectory;
234 dir->GetObject(keyname, fTree);
235 if (!fTree) {
236 std::string msg = "No TTree called ";
237 msg += keyname;
238 msg += " was found in the selected TDirectory.";
239 Error("TTreeReader", "%s", msg.c_str());
240 }
241 Initialize();
242}
243
244////////////////////////////////////////////////////////////////////////////////
245/// Tell all value readers that the tree reader does not exist anymore.
246
248{
249 for (std::deque<ROOT::Internal::TTreeReaderValueBase *>::const_iterator i = fValues.begin(), e = fValues.end();
250 i != e; ++i) {
251 (*i)->MarkTreeReaderUnavailable();
252 }
253 if (fTree && fNotify.IsLinked())
255
257 // a plain TTree is automatically added to the current directory,
258 // do not delete it here
259 if (IsChain()) {
260 delete fTree;
261 }
262 }
263}
264
265////////////////////////////////////////////////////////////////////////////////
266/// Initialization of the director.
267
269{
270 fEntry = -1;
271 if (!fTree) {
274 return;
275 }
276
280 } else if (fEntryList && fEntryList->GetLists()) {
281 Error("Initialize", "We are not processing a TChain but the TEntryList contains sublists. Please "
282 "provide a simple TEntryList with no sublists instead.");
285 return;
286 }
287
288 fDirector = std::make_unique<ROOT::Internal::TBranchProxyDirector>(fTree, -1);
289
290 if (!fNotify.IsLinked()) {
292
293 if (fTree->GetTree()) {
294 // The current TTree is already available.
296 Notify();
298 }
299 }
300}
301
303{
304 if (friendIdx >= fFriendProxies.size()) {
305 fFriendProxies.resize(friendIdx + 1);
306 }
307
309 fFriendProxies[friendIdx] = std::make_unique<ROOT::Internal::TFriendProxy>(fDirector.get(), fTree, friendIdx);
310 }
311
312 return *fFriendProxies[friendIdx];
313}
314
315////////////////////////////////////////////////////////////////////////////////
316/// Notify director and values of a change in tree. Called from TChain and TTree's LoadTree.
317/// TTreeReader registers its fNotify data member with the TChain/TTree which
318/// in turn leads to this method being called upon the execution of LoadTree.
320{
321
322 // We are missing at least one proxy, retry creating them when switching
323 // to the next tree
324 if (!fMissingProxies.empty())
325 SetProxies();
326
329 // This can happen if someone switched trees behind us.
330 // Likely cause: a TChain::LoadTree() e.g. from TTree::Process().
331 // This means that "local" should be set!
332 // There are two entities switching trees which is bad.
333 Warning("SetEntryBase()",
334 "The current tree in the TChain %s has changed (e.g. by TTree::Process) "
335 "even though TTreeReader::SetEntry() was called, which switched the tree "
336 "again. Did you mean to call TTreeReader::SetLocalEntry()?",
337 fTree->GetName());
338 }
340 } else {
342 }
343
345 Warning("SetEntryBase()",
346 "The TTree / TChain has an associated TEntryList. "
347 "TTreeReader ignores TEntryLists unless you construct the TTreeReader passing a TEntryList.");
349 }
350
351 if (!fDirector->Notify()) {
353 Error("SetEntryBase()", "There was an error while notifying the proxies.");
355 return false;
356 }
357
358 if (fProxiesSet) {
359 for (auto value : fValues) {
360 value->NotifyNewTree(fTree->GetTree());
361 }
362 }
363
364 return true;
365}
366
367////////////////////////////////////////////////////////////////////////////////
368/// Tell readers we now have a tree.
369/// fValues gets insertions during this loop (when parametrized arrays are read),
370/// invalidating iterators. Use old-school counting instead.
371
373{
374 fMissingProxies.clear();
375 fProxiesSet = false; // In the loop below, we cannot recreate proxies if this is true
376
377 for (size_t i = 0; i < fValues.size(); ++i) {
379 // Check whether the user wants to suppress errors for this specific branch
380 // if it is missing. This information is used here to act in the situation
381 // where the first tree of the chain does not contain that branch. In such
382 // case, we need to postpone the creation of the corresponding proxy until
383 // we find the branch in a following tree of the chain.
384 const bool suppressErrorsForThisBranch = (fSuppressErrorsForMissingBranches.find(reader->fBranchName.Data()) !=
386 // Because of the situation described above, we may have some proxies
387 // already created and some not, if their branch was not available so far.
388 // Make sure we do not recreate the proxy unnecessarily, unless the
389 // data member was set outside of this function (e.g. in Restart).
390 if (!reader->GetProxy() || !fProxiesSet)
391 reader->CreateProxy();
392
393 // The creation of the proxy failed again. If it was due to a missing
394 // branch, we propagate this information upstream, otherwise we return
395 // false to signify there was some other problem.
396 if (!reader->GetProxy()) {
399 fMissingProxies.insert(reader->fBranchName.Data());
400 else
401 return false;
402 }
403 }
404 // If at least one proxy was there and no error occurred, we assume the proxies to be set.
405 fProxiesSet = !fValues.empty();
406
407 // Now we need to properly set the TTreeCache. We do this in steps:
408 // 1. We set the entry range according to the entry range of the TTreeReader
409 // 2. We add to the cache the branches identifying them by the name the user provided
410 // upon creation of the TTreeReader{Value, Array}s
411 // 3. We stop the learning phase.
412 // Operations 1, 2 and 3 need to happen in this order. See:
413 // https://sft.its.cern.ch/jira/browse/ROOT-9773?focusedCommentId=87837
414 if (fProxiesSet) {
415 const auto curFile = fTree->GetCurrentFile();
416 if (curFile && fTree->GetTree()->GetReadCache(curFile, true)) {
417 if (!(-1LL == fEndEntry && 0ULL == fBeginEntry)) {
418 // We need to avoid to pass -1 as end entry to the SetCacheEntryRange method
419 const auto lastEntry = (-1LL == fEndEntry) ? fTree->GetEntriesFast() : fEndEntry;
421 }
422 for (auto value : fValues) {
423 if (value->GetProxy())
424 fTree->AddBranchToCache(value->GetProxy()->GetBranchName(), true);
425 }
427 }
428 }
429
430 return true;
431}
432
434{
436 return;
437 if (!fTree)
438 return;
439 // Make sure all proxies are set, as in certain situations we might get to this
440 // point without having set the proxies first. For example, when processing a
441 // TChain and calling `SetEntry(N)` with N beyond the real number of entries.
442 // If the proxies can't be set return from the function and give up the warning.
443 if (!fProxiesSet && !SetProxies())
444 return;
445
446 // If we are stopping the reading because we reached the last entry specified
447 // explicitly via SetEntriesRange, do not bother the user with a warning
448 if (fEntry == fEndEntry)
449 return;
450
451 const std::string mainTreeName =
453
454 const auto *friendsList = fTree->GetListOfFriends();
455 if (!friendsList || friendsList->GetEntries() == 0)
456 return;
457
458 for (decltype(fFriendProxies.size()) idx = 0; idx < fFriendProxies.size(); idx++) {
459 auto &&fp = fFriendProxies[idx];
460 if (!fp)
461 continue;
462 // In case the friend is indexed it may very well be that it has a different number of events
463 // e.g. the friend contains information about luminosity block and
464 // all the entries in the main tree are from the same luminosity block
465 if (fp->HasIndex())
466 continue;
467 const auto *frTree = fp->GetDirector()->GetTree();
468 if (!frTree)
469 continue;
470
471 // Need to retrieve the real friend tree from the main tree
472 // because the current friend proxy points to the tree it is currently processing
473 // i.e. the current tree in a chain in case the real friend is a TChain
474 auto *frEl = static_cast<TFriendElement *>(friendsList->At(idx));
475 if (!frEl)
476 continue;
477 auto *frTreeFromMain = frEl->GetTree();
478 if (!frTreeFromMain)
479 continue;
480 // We are looking for the situation where there are actually still more
481 // entries to read in the friend. The following checks if the current entry to read
482 // is greater than the available entries in the dataset. If not, then we know there
483 // are more entries left in the friend.
484 //
485 // GetEntriesFast gives us a single handle to assess all the following:
486 // * If the friend is a TTree, it returns the total number of entries
487 // * If it is a TChain, then two more scenarios may occur:
488 // - If we have processed until the last file, then it returns the total
489 // number of entries.
490 // - If we have not processed all files yet, then it returns TTree::kMaxEntries.
491 // Thus, fEntry will always be smaller and the warning will be issued.
492 if (fEntry >= frTreeFromMain->GetEntriesFast())
493 continue;
494 // The friend tree still has entries beyond the last one of the main
495 // tree, warn the user about it.
496 const std::string frTreeName = dynamic_cast<const TChain *>(frTree)
497 ? frTree->GetName()
499 std::string msg = "Last entry available from main tree '" + mainTreeName + "' was " + std::to_string(fEntry - 1) +
500 " but friend tree '" + frTreeName + "' has more entries beyond the end of the main tree.";
501 Warning("SetEntryBase()", "%s", msg.c_str());
502 }
503}
504////////////////////////////////////////////////////////////////////////////////
505/// Set the range of entries to be loaded by `Next()`; end will not be loaded.
506///
507/// If end <= begin, `end` is ignored (set to `-1`, i.e. will run on all entries from `begin` onwards).
508///
509/// Example:
510///
511/// ~~~ {.cpp}
512/// reader.SetEntriesRange(3, 5);
513/// while (reader.Next()) {
514/// // Will load entries 3 and 4.
515/// }
516/// ~~~
517///
518/// Note that if a TEntryList is present, beginEntry and endEntry refer to the beginEntry-th/endEntry-th entries of the
519/// TEntryList (or the main TEntryList in case it has sub-entrylists). In other words, SetEntriesRange can
520/// be used to only loop over part of the TEntryList, but not to further restrict the actual TTree/TChain entry numbers
521/// considered.
522///
523/// \param beginEntry The first entry to be loaded by `Next()`.
524/// \param endEntry The entry where `Next()` will return false, not loading it.
525
527{
528 if (beginEntry < 0)
529 return kEntryNotFound;
530 // Complain if the entries number is larger than the tree's / chain's / entry
531 // list's number of entries, unless it's a TChain and "max entries" is
532 // uninitialized (i.e. TTree::kMaxEntries).
533 if (beginEntry >= GetEntries(false) && !(IsChain() && GetEntries(false) == TTree::kMaxEntries)) {
534 Error("SetEntriesRange()", "Start entry (%lld) must be lower than the available entries (%lld).", beginEntry,
535 GetEntries(false));
536 return kEntryNotFound;
537 }
538
539 // Update data members to correctly reflect the defined range
540 if (endEntry > beginEntry)
542 else
543 fEndEntry = -1;
544
546
547 if (beginEntry - 1 < 0)
548 // Reset the cache if reading from the first entry of the tree
549 Restart();
550 else {
551 // Load the first entry in the range. SetEntry() will also call SetProxies(),
552 // thus adding all the branches to the cache and triggering the learning phase.
554 if (es != kEntryValid) {
555 Error("SetEntriesRange()", "Error setting first entry %lld: %s", beginEntry, fgEntryStatusText[(int)es]);
556 return es;
557 }
558 }
559
560 return kEntryValid;
561}
562
564{
565 fDirector->SetReadEntry(-1);
566 fProxiesSet = false; // we might get more value readers, meaning new proxies.
567 fEntry = -1;
568 // Find if there is an active TTreeCache and reset it if so
569 if (!fTree)
570 return;
571 const auto curFile = fTree->GetCurrentFile();
572 if (!curFile)
573 return;
574 auto curTree = fTree->GetTree();
575 if (!curTree)
576 return;
577 auto tc = curTree->GetReadCache(curFile, true);
578 if (!tc)
579 return;
580 tc->DropBranch("*", true);
581 tc->ResetCache();
582}
583
584////////////////////////////////////////////////////////////////////////////////
585/// Returns the number of entries of the TEntryList if one is provided, else
586/// of the TTree / TChain, independent of a range set by SetEntriesRange()
587/// by calling TTree/TChain::%GetEntriesFast.
588
590{
591 if (fEntryList)
592 return fEntryList->GetN();
593 if (!fTree)
594 return -1;
595 return fTree->GetEntriesFast();
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{
608 if (fEntryList)
609 return fEntryList->GetN();
610 if (!fTree)
611 return -1;
612 if (force) {
614 auto res = fTree->GetEntries();
615 // Go back to where we were:
618 return res;
619 }
620 return fTree->GetEntriesFast();
621}
622
623////////////////////////////////////////////////////////////////////////////////
624/// Load an entry into the tree, return the status of the read.
625/// For chains, entry is the global (i.e. not tree-local) entry number, unless
626/// `local` is `true`, in which case `entry` specifies the entry number within
627/// the current tree. This is needed for instance for TSelector::Process().
628
630{
631 if (IsInvalid()) {
633 fEntry = -1;
634 return fEntryStatus;
635 }
636
637 fEntry = entry;
638
640 if (fEntryList) {
641 if (entry >= fEntryList->GetN()) {
642 // Passed the end of the chain, Restart() was not called:
643 // don't try to load entries anymore. Can happen in these cases:
644 // while (tr.Next()) {something()};
645 // while (tr.Next()) {somethingelse()}; // should not be calling somethingelse().
647 return fEntryStatus;
648 }
649 if (entry >= 0) {
650 if (fEntryList->GetLists()) {
652 int treenum = -1;
654 entryAfterList += static_cast<TChain *>(fTree)->GetTreeOffset()[treenum];
655 // We always translate local entry numbers to global entry numbers for TChain+TEntryList with sublists
656 local = false;
657 } else {
658 // Could be a TTree or a TChain (TTreeReader also supports single TEntryLists for TChains).
659 // In both cases, we are using the global entry numbers coming from the single TEntryList.
661 }
662 }
663 }
664
666
670
671 if (loadResult < 0) {
672 // ROOT-9628 We cover here the case when:
673 // - We deal with a TChain
674 // - The last file is opened
675 // - The TTree is not correctly loaded
676 // The system is robust against issues with TTrees associated to the chain
677 // when they are not at the end of it.
678 if (loadResult == -3 && TestBit(kBitIsChain) && !fTree->GetTree()) {
679 fDirector->Notify();
680 if (fProxiesSet) {
681 for (auto value : fValues) {
682 value->NotifyNewTree(fTree->GetTree());
683 }
684 }
685 Warning("SetEntryBase()", "There was an issue opening the last file associated to the TChain "
686 "being processed.");
688 return fEntryStatus;
689 }
690
691 if (loadResult == -2) {
692 fDirector->Notify();
693 if (fProxiesSet) {
694 for (auto value : fValues) {
695 value->NotifyNewTree(fTree->GetTree());
696 }
697 }
698 auto &&nEntries = treeToCallLoadOn->GetEntriesFast();
699 if (fBeginEntry >= nEntries && nEntries > 0) {
700 // The beginning entry specified via SetEntriesRange was beyond the total number of entries in the dataset
701 Error("SetEntryBase()",
702 "The beginning entry specified via SetEntriesRange (%lld) is equal to or beyond the "
703 "total number of entries in the dataset (%lld). Make sure to specify a "
704 "beginning entry lower than the number of available entries.",
707 } else
710 return fEntryStatus;
711 }
712
713 if (loadResult == -1) {
714 // The chain is empty
716 return fEntryStatus;
717 }
718
719 if (loadResult == -4) {
720 // The TChainElement corresponding to the entry is missing or
721 // the TTree is missing from the file.
722 fDirector->Notify();
723 if (fProxiesSet) {
724 for (auto value : fValues) {
725 value->NotifyNewTree(fTree->GetTree());
726 }
727 }
729 return fEntryStatus;
730 }
731
732 if (loadResult == -6) {
733 // An expected branch was not found when switching to a new tree.
734 fDirector->Notify();
735 if (fProxiesSet) {
736 for (auto value : fValues) {
737 value->NotifyNewTree(fTree->GetTree());
738 }
739 }
740 // Even though one (or more) branches might be missing from the new
741 // tree, other branches might still be there. We know we are switching
742 // into the tree at this point, so we want the director to start
743 // reading again from local entry 0, for those branches that are
744 // available
745 fDirector->SetReadEntry(0);
747 return fEntryStatus;
748 }
749
750 Warning("SetEntryBase()", "Unexpected error '%lld' in %s::LoadTree", loadResult,
751 treeToCallLoadOn->IsA()->GetName());
752
754 return fEntryStatus;
755 }
756
757 if (!fProxiesSet) {
758 if (!SetProxies()) {
760 return fEntryStatus;
761 }
762 }
763
764 if ((fEndEntry >= 0 && entry >= fEndEntry) || (fEntry >= fTree->GetEntriesFast())) {
767 return fEntryStatus;
768 }
769
770 fDirector->SetReadEntry(loadResult);
772
773 // Convey the information that a branch was not found either when
774 // switching to a new tree (i.e. when trying to load its first entry) or
775 // even if we are in the middle of the tree (e.g. by calling SetEntriesRange
776 // beforehand) but a proxy was not created because of the missing branch
779 }
780
781 for (auto &&fp : fFriendProxies) {
782 if (!fp)
783 continue;
784 if (fp->GetReadEntry() >= 0)
785 continue;
786 // We are going to read an invalid entry from a friend, propagate
787 // this information to the user.
788 const auto *frTree = fp->GetDirector()->GetTree();
789 if (!frTree)
790 continue;
791 const std::string frTreeName = dynamic_cast<const TChain *>(frTree)
792 ? frTree->GetName()
794 // If the friend does not have a TTreeIndex, the cause of a failure reading an entry
795 // is most probably a difference in number of entries between main tree and friend tree
796 if (!fp->HasIndex()) {
797 std::string msg = "Cannot read entry " + std::to_string(entry) + " from friend tree '" + frTreeName +
798 "'. The friend tree has less entries than the main tree. Make sure all trees "
799 "of the dataset have the same number of entries.";
800 throw std::runtime_error{msg};
801 } else {
803 }
804 }
805
806 return fEntryStatus;
807}
808
809////////////////////////////////////////////////////////////////////////////////
810/// Set (or update) the which tree to read from. `tree` can be
811/// a TTree or a TChain.
812
814{
816 // a plain TTree is automatically added to the current directory,
817 // do not delete it here
818 if (IsChain()) {
819 delete fTree;
820 }
821 }
822
823 fTree = tree;
825 fEntry = -1;
826
829 if (fTree) {
832 } else {
834 }
835
836 if (!fDirector) {
837 Initialize();
838 } else {
839 fDirector->SetTree(fTree);
840 fDirector->SetReadEntry(-1);
841 }
842}
843
844////////////////////////////////////////////////////////////////////////////////
845/// Set (or update) the which tree to read from, passing the name of a tree in a
846/// directory.
847///
848/// \param keyname - name of the tree in `dir`
849/// \param dir - the `TDirectory` to load `keyname` from (or gDirectory if `nullptr`)
850/// \param entryList - the `TEntryList` to attach to the `TTreeReader`.
851
852void TTreeReader::SetTree(const char *keyname, TDirectory *dir, TEntryList *entryList /*= nullptr*/)
853{
854 TTree *tree = nullptr;
855 if (!dir)
856 dir = gDirectory;
857 dir->GetObject(keyname, tree);
858 SetTree(tree, entryList);
859}
860
861////////////////////////////////////////////////////////////////////////////////
862/// Add a value reader for this tree.
863
865{
866 if (fProxiesSet) {
867 Error("RegisterValueReader",
868 "Error registering reader for %s: TTreeReaderValue/Array objects must be created before the call to Next() "
869 "/ SetEntry() / SetLocalEntry(), or after TTreeReader::Restart()!",
870 reader->GetBranchName());
871 return false;
872 }
873 fValues.push_back(reader);
874 return true;
875}
876
877////////////////////////////////////////////////////////////////////////////////
878/// Remove a value reader for this tree.
879
881{
882 std::deque<ROOT::Internal::TTreeReaderValueBase *>::iterator iReader =
883 std::find(fValues.begin(), fValues.end(), reader);
884 if (iReader == fValues.end()) {
885 Error("DeregisterValueReader", "Cannot find reader of type %s for branch %s", reader->GetDerivedTypeName(),
886 reader->fBranchName.Data());
887 return;
888 }
889 fValues.erase(iReader);
890}
#define e(i)
Definition RSha256.hxx:103
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define gDirectory
Definition TDirectory.h:385
#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:213
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
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:89
virtual Int_t StopCacheLearningPhase()
Stop the cache learning phase.
Definition TTree.cxx:9692
virtual Int_t AddBranchToCache(const char *bname, bool subbranches=false)
Add branch with name bname to the Tree cache.
Definition TTree.cxx:1086
TFile * GetCurrentFile() const
Return pointer to the current file.
Definition TTree.cxx:5555
virtual TEntryList * GetEntryList()
Returns the entry list assigned to this tree.
Definition TTree.cxx:5934
virtual Long64_t GetEntries() const
Definition TTree.h:502
virtual TTree * GetTree() const
Definition TTree.h:596
virtual Long64_t LoadTree(Long64_t entry)
Set current entry.
Definition TTree.cxx:6554
virtual Long64_t GetEntriesFast() const
Return a number greater or equal to the total number of entries in the dataset.
Definition TTree.h:544
virtual Int_t SetCacheEntryRange(Long64_t first, Long64_t last)
interface to TTreeCache to set the cache entry range
Definition TTree.cxx:9038
virtual TList * GetListOfFriends() const
Definition TTree.h:569
static constexpr Long64_t kMaxEntries
Used as the max value for any TTree range operation.
Definition TTree.h:265
std::vector< std::string > GetTreeFullPaths(const TTree &tree)