Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TTree.cxx
Go to the documentation of this file.
1// @(#)root/tree:$Id$
2// Author: Rene Brun 12/01/96
3
4/*************************************************************************
5 * Copyright (C) 1995-2024, Rene Brun and Fons Rademakers. *
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 \defgroup tree TTree
13
14 RNTuple is the modern way of storing columnar datasets: please consider to use it
15 before starting new projects based on TTree and related classes.
16
17 In order to store columnar datasets, ROOT historically provides the TTree, TChain,
18 TNtuple and TNtupleD classes.
19 The TTree class represents a columnar dataset. Any C++ type can be stored in the
20 columns. The TTree has allowed to store about **1 EB** of data coming from the LHC alone:
21 it is demonstrated to scale and it's battle tested. It has been optimized during the years
22 to reduce dataset sizes on disk and to deliver excellent runtime performance.
23 It allows to access only part of the columns of the datasets, too.
24 The TNtuple and TNtupleD classes are specialisations of the TTree class which can
25 only hold single precision and double precision floating-point numbers respectively;
26 The TChain is a collection of TTrees, which can be located also in different files.
27
28*/
29
30/** \class TTree
31\ingroup tree
32
33A TTree represents a columnar dataset. Any C++ type can be stored in its columns. The modern
34version of TTree is RNTuple: please consider using it before opting for TTree.
35
36A TTree, often called in jargon *tree*, consists of a list of independent columns or *branches*,
37represented by the TBranch class.
38Behind each branch, buffers are allocated automatically by ROOT.
39Such buffers are automatically written to disk or kept in memory until the size stored in the
40attribute fMaxVirtualSize is reached.
41Variables of one branch are written to the same buffer. A branch buffer is
42automatically compressed if the file compression attribute is set (default).
43Branches may be written to different files (see TBranch::SetFile).
44
45The ROOT user can decide to make one single branch and serialize one object into
46one single I/O buffer or to make several branches.
47Making several branches is particularly interesting in the data analysis phase,
48when it is desirable to have a high reading rate and not all columns are equally interesting
49
50\anchor creatingattreetoc
51## Create a TTree to store columnar data
52- [Construct a TTree](\ref creatingattree)
53- [Add a column of Fundamental Types and Arrays thereof](\ref addcolumnoffundamentaltypes)
54- [Add a column of a STL Collection instances](\ref addingacolumnofstl)
55- [Add a column holding an object](\ref addingacolumnofobjs)
56- [Add a column holding a TClonesArray](\ref addingacolumnoftclonesarray)
57- [Fill the tree](\ref fillthetree)
58- [Add a column to an already existing Tree](\ref addcoltoexistingtree)
59- [An Example](\ref fullexample)
60
61\anchor creatingattree
62## Construct a TTree
63
64~~~ {.cpp}
65 TTree tree(name, title)
66~~~
67Creates a Tree with name and title.
68
69Various kinds of branches can be added to a tree:
70- Variables representing fundamental types, simple classes/structures or list of variables: for example for C or Fortran
71structures.
72- Any C++ object or collection, provided by the STL or ROOT.
73
74In the following, the details about the creation of different types of branches are given.
75
76\anchor addcolumnoffundamentaltypes
77## Add a column ("branch") holding fundamental types and arrays thereof
78This strategy works also for lists of variables, e.g. to describe simple structures.
79It is strongly recommended to persistify those as objects rather than lists of leaves.
80
81~~~ {.cpp}
82 auto branch = tree.Branch(branchname, address, leaflist, bufsize)
83~~~
84- `address` is the address of the first item of a structure
85- `leaflist` is the concatenation of all the variable names and types
86 separated by a colon character :
87 The variable name and the variable type are separated by a
88 slash (/). The variable type must be 1 character. (Characters
89 after the first are legal and will be appended to the visible
90 name of the leaf, but have no effect.) If no type is given, the
91 type of the variable is assumed to be the same as the previous
92 variable. If the first variable does not have a type, it is
93 assumed of type `F` by default. The list of currently supported
94 types is given below:
95 - `C` : a character string terminated by the 0 character
96 - `B` : an 8 bit integer (`Char_t`); Mostly signed, might be unsigned in special platforms or depending on compiler flags, thus do not use std::int8_t as underlying variable since they are not equivalent; Treated as a character when in an array.
97 - `b` : an 8 bit unsigned integer (`UChar_t`)
98 - `S` : a 16 bit signed integer (`Short_t`)
99 - `s` : a 16 bit unsigned integer (`UShort_t`)
100 - `I` : a 32 bit signed integer (`Int_t`)
101 - `i` : a 32 bit unsigned integer (`UInt_t`)
102 - `F` : a 32 bit floating point (`Float_t`)
103 - `f` : a 24 bit (or 32) floating point with truncated mantissa (`Float16_t`, stored as 3 bytes by default or as fixed-point arithmetic 4 bytes Int_t if range is customized; occupies 4 bytes in memory): By default, in disk, only 21 bits are used: 1 for the sign, 8 for the exponent and 12 for the mantissa. Can be customized with suffix `[min,max(,nbits)] `where `nbits` is for the mantissa.
104 - `D` : a 64 bit floating point (`Double_t`)
105 - `d` : a 32 (or 24) bit floating point with truncated mantissa (`Double32_t`, stored as a 4 bytes Float_t by default or as 3 bytes if range is customized; occupies 8 bytes in memory): By default, in disk, 1 bit is used for the sign, 8 for the exponent and 23 for the mantissa. Can be customized to 3 bytes (24 bits) with suffix `[min,max(,nbits)]` where `nbits` is for the mantissa.
106 - `L` : a 64 bit signed integer (`Long64_t`)
107 - `l` : a 64 bit unsigned integer (`ULong64_t`)
108 - `G` : a long signed integer, stored as 64 bit (`Long_t`)
109 - `g` : a long unsigned integer, stored as 64 bit (`ULong_t`)
110 - `O` : [the letter `o`, not a zero] a boolean (`bool`)
111
112 Examples:
113 - A int: "myVar/I"
114 - A float array with fixed size: "myArrfloat[42]/F"
115 - An double array with variable size, held by the `myvar` column: "myArrdouble[myvar]/D"
116 - An Double32_t array with variable size, held by the `myvar` column , with values between 0 and 16: "myArr[myvar]/d[0,10]"
117 - The `myvar` column, which holds the variable size, **MUST** be an `Int_t` (/I).
118
119- If the address points to a single numerical variable, the leaflist is optional:
120~~~ {.cpp}
121 int value;
122 tree->Branch(branchname, &value);
123~~~
124- If the address points to more than one numerical variable, we strongly recommend
125 that the variable be sorted in decreasing order of size. Any other order will
126 result in a non-portable TTree (i.e. you will not be able to read it back on a
127 platform with a different padding strategy).
128 We recommend to persistify objects rather than composite leaflists.
129- In case of the truncated floating point types (`Float16_t` and `Double32_t`) you can
130 also specify the range in the style `[xmin,xmax]` or `[xmin,xmax,nbits]` after
131 the type character. For example, for storing a variable size array `myArr` of
132 `Double32_t` with values within a range of `[0, 2*pi]` and the size of which is stored
133 in an `Int_t` (/I) branch called `myArrSize`, the syntax for the `leaflist` string would
134 be: `myArr[myArrSize]/d[0,twopi]`. Of course the number of bits could be specified,
135 the standard rules of opaque typedefs annotation are valid. For example, if only
136 18 bits were sufficient, the syntax would become: `myArr[myArrSize]/d[0,twopi,18]`.
137 See TStreamerElement::GetRange for further details.
138
139 Examples of writing/reading plain C arrays with fixed or variable length into/from TTrees:
140
141~~~ {.cpp}
142 TTree *t = new TTree("t", "t");
143 int n;
144 Double32_t arr[64];
145 // Double32_t* arr = new Double32_t[64]; // equivalent, later just remember delete[]
146 t->Branch("n", &n);
147 t->Branch("arr", arr, "arr[n]/d[0,1,32]");
148 t->Branch("arr_def", arr, "arr_def[n]/d");
149 t->Branch("arr_fix", arr, "arr_fix[64]/d[0,1,32]");
150 t->Branch("arr_fix_def", arr, "arr_fix_def[64]/d");
151 t->Branch("single", arr, "single/d[0,1,32]");
152 t->Branch("single_def", arr, "single_def/d");
153 for (int j = 0; j < 64; ++j) {
154 arr[j] = 0.01 * j;
155 }
156 n = 3;
157 t->Fill();
158 // Reading now:
159 const auto nEntries = t->GetEntries();
160 t->Scan();
161 for (auto name : {"arr", "arr_def", "arr_fix", "arr_fix_def", "single", "single_def"}) {
162 t->ResetBranchAddresses();
163 t->SetBranchAddress("n", &n);
164 t->SetBranchAddress(name, arr);
165 for (Long64_t i = 0; i < nEntries; ++i) {
166 t->GetEntry(i);
167 // Work with arr
168 }
169 }
170~~~
171
172\anchor addingacolumnofstl
173## Adding a column holding STL collection instances (e.g. std::vector or std::list)
174
175~~~ {.cpp}
176 auto branch = tree.Branch( branchname, STLcollection, bufsize, splitlevel);
177~~~
178`STLcollection` is the address of a pointer to a container of the standard
179library such as `std::vector`, `std::list`, containing pointers, fundamental types
180or objects.
181If the splitlevel is a value bigger than 100 (`TTree::kSplitCollectionOfPointers`)
182then the collection will be written in split mode, i.e. transparently storing
183individual data members as arrays, therewith potentially increasing compression ratio.
184
185### Note
186In case of dynamic structures changing with each entry, see e.g.
187~~~ {.cpp}
188 branch->SetAddress(void *address)
189~~~
190one must redefine the branch address before filling the branch
191again. This is done via the `TBranch::SetAddress` member function.
192
193\anchor addingacolumnofobjs
194## Add a column holding objects (or a TObjArray)
195
196~~~ {.cpp}
197 MyClass object;
198 auto branch = tree.Branch(branchname, &object, bufsize, splitlevel)
199~~~
200Note: The 2nd parameter must be the address of a valid object.
201 The object must not be destroyed (i.e. be deleted) until the TTree
202 is deleted or TTree::ResetBranchAddress is called.
203
204- if splitlevel=0, the object is serialized in the branch buffer.
205- if splitlevel=1 (default), this branch will automatically be split
206 into subbranches, with one subbranch for each data member or object
207 of the object itself. In case the object member is a TClonesArray,
208 the mechanism described in case C is applied to this array.
209- if splitlevel=2 ,this branch will automatically be split
210 into subbranches, with one subbranch for each data member or object
211 of the object itself. In case the object member is a TClonesArray,
212 it is processed as a TObject*, only one branch.
213
214Another available syntax is the following:
215
216~~~ {.cpp}
217 auto branch_a = tree.Branch(branchname, &p_object, bufsize, splitlevel)
218 auto branch_b = tree.Branch(branchname, className, &p_object, bufsize, splitlevel)
219~~~
220- `p_object` is a pointer to an object.
221- If `className` is not specified, the `Branch` method uses the type of `p_object`
222 to determine the type of the object.
223- If `className` is used to specify explicitly the object type, the `className`
224 must be of a type related to the one pointed to by the pointer. It should be
225 either a parent or derived class.
226
227Note: The pointer whose address is passed to `TTree::Branch` must not
228 be destroyed (i.e. go out of scope) until the TTree is deleted or
229 TTree::ResetBranchAddress is called.
230
231Note: The pointer `p_object` can be initialized before calling `TTree::Branch`
232~~~ {.cpp}
233 auto p_object = new MyDataClass;
234 tree.Branch(branchname, &p_object);
235~~~
236or not
237~~~ {.cpp}
238 MyDataClass* p_object = nullptr;
239 tree.Branch(branchname, &p_object);
240~~~
241In either case, the ownership of the object is not taken over by the `TTree`.
242Even though in the first case an object is be allocated by `TTree::Branch`,
243the object will <b>not</b> be deleted when the `TTree` is deleted.
244
245\anchor addingacolumnoftclonesarray
246## Add a column holding TClonesArray instances
247
248*The usage of `TClonesArray` should be abandoned in favour of `std::vector`,
249for which `TTree` has been heavily optimised, as well as `RNTuple`.*
250
251~~~ {.cpp}
252 // clonesarray is the address of a pointer to a TClonesArray.
253 auto branch = tree.Branch(branchname, clonesarray, bufsize, splitlevel)
254~~~
255The TClonesArray is a direct access list of objects of the same class.
256For example, if the TClonesArray is an array of TTrack objects,
257this function will create one subbranch for each data member of
258the object TTrack.
259
260\anchor fillthetree
261## Fill the Tree
262
263A TTree instance is filled with the invocation of the TTree::Fill method:
264~~~ {.cpp}
265 tree.Fill()
266~~~
267Upon its invocation, a loop on all defined branches takes place that for each branch invokes
268the TBranch::Fill method.
269
270\anchor addcoltoexistingtree
271## Add a column to an already existing Tree
272
273You may want to add a branch to an existing tree. For example,
274if one variable in the tree was computed with a certain algorithm,
275you may want to try another algorithm and compare the results.
276One solution is to add a new branch, fill it, and save the tree.
277The code below adds a simple branch to an existing tree.
278Note the `kOverwrite` option in the `Write` method: it overwrites the
279existing tree. If it is not specified, two copies of the tree headers
280are saved.
281~~~ {.cpp}
282 void addBranchToTree() {
283 TFile f("tree.root", "update");
284
285 Float_t new_v;
286 auto mytree = f->Get<TTree>("mytree");
287 auto newBranch = mytree->Branch("new_v", &new_v, "new_v/F");
288
289 auto nentries = mytree->GetEntries(); // read the number of entries in the mytree
290
291 for (Long64_t i = 0; i < nentries; i++) {
292 new_v = gRandom->Gaus(0, 1);
293 newBranch->Fill();
294 }
295
296 mytree->Write("", TObject::kOverwrite); // save only the new version of the tree
297 }
298~~~
299It is not always possible to add branches to existing datasets stored in TFiles: for example,
300these files might not be writeable, just readable. In addition, modifying in place a TTree
301causes a new TTree instance to be written and the previous one to be deleted.
302For this reasons, ROOT offers the concept of friends for TTree and TChain.
303
304\anchor fullexample
305## A Complete Example
306
307~~~ {.cpp}
308// A simple example creating a tree
309// Compile it with: `g++ myTreeExample.cpp -o myTreeExample `root-config --cflags --libs`
310
311#include "TFile.h"
312#include "TH1D.h"
313#include "TRandom3.h"
314#include "TTree.h"
315
316int main()
317{
318 // Create a new ROOT binary machine independent file.
319 // Note that this file may contain any kind of ROOT objects, histograms,trees
320 // pictures, graphics objects, detector geometries, tracks, events, etc..
321 TFile hfile("htree.root", "RECREATE", "Demo ROOT file with trees");
322
323 // Define a histogram and some simple structures
324 TH1D hpx("hpx", "This is the px distribution", 100, -4, 4);
325
326 typedef struct {
327 Float_t x, y, z;
328 } Point;
329
330 typedef struct {
331 Int_t ntrack, nseg, nvertex;
332 UInt_t flag;
333 Float_t temperature;
334 } Event;
335 Point point;
336 Event event;
337
338 // Create a ROOT Tree
339 TTree tree("T", "An example of ROOT tree with a few branches");
340 tree.Branch("point", &point, "x:y:z");
341 tree.Branch("event", &event, "ntrack/I:nseg:nvertex:flag/i:temperature/F");
342 tree.Branch("hpx", &hpx);
343
344 float px, py;
345
346 TRandom3 myGenerator;
347
348 // Here we start a loop on 1000 events
349 for (Int_t i = 0; i < 1000; i++) {
350 myGenerator.Rannor(px, py);
351 const auto random = myGenerator.Rndm(1);
352
353 // Fill histogram
354 hpx.Fill(px);
355
356 // Fill structures
357 point.x = 10 * (random - 1);
358 point.y = 5 * random;
359 point.z = 20 * random;
360 event.ntrack = int(100 * random);
361 event.nseg = int(2 * event.ntrack);
362 event.nvertex = 1;
363 event.flag = int(random + 0.5);
364 event.temperature = 20 + random;
365
366 // Fill the tree. For each event, save the 2 structures and object.
367 // In this simple example, the objects hpx, hprof and hpxpy are only slightly
368 // different from event to event. We expect a big compression factor!
369 tree.Fill();
370 }
371
372 // Save all objects in this file
373 hfile.Write();
374
375 // Close the file. Note that this is automatically done when you leave
376 // the application upon file destruction.
377 hfile.Close();
378
379 return 0;
380}
381~~~
382## TTree Diagram
383
384The following diagram shows the organisation of the federation of classes related to TTree.
385
386Begin_Macro
387../../../tutorials/legacy/tree/tree.C
388End_Macro
389*/
390
391#include <ROOT/RConfig.hxx>
392#include "TTree.h"
393
394#include "ROOT/TIOFeatures.hxx"
395#include "TArrayC.h"
396#include "TBufferFile.h"
397#include "TBaseClass.h"
398#include "TBasket.h"
399#include "TBranchClones.h"
400#include "TBranchElement.h"
401#include "TBranchObject.h"
402#include "TBranchRef.h"
403#include "TBrowser.h"
404#include "TClass.h"
405#include "TClassEdit.h"
406#include "TClonesArray.h"
407#include "TCut.h"
408#include "TDataMember.h"
409#include "TDataType.h"
410#include "TDirectory.h"
411#include "TError.h"
412#include "TEntryList.h"
413#include "TEnv.h"
414#include "TEventList.h"
415#include "TFile.h"
416#include "TFolder.h"
417#include "TFriendElement.h"
418#include "TInterpreter.h"
419#include "TLeaf.h"
420#include "TLeafB.h"
421#include "TLeafC.h"
422#include "TLeafD.h"
423#include "TLeafElement.h"
424#include "TLeafF.h"
425#include "TLeafI.h"
426#include "TLeafL.h"
427#include "TLeafObject.h"
428#include "TLeafS.h"
429#include "TList.h"
430#include "TMath.h"
431#include "TMemFile.h"
432#include "TROOT.h"
433#include "TRealData.h"
434#include "TRegexp.h"
435#include "TRefTable.h"
436#include "TStreamerElement.h"
437#include "TStreamerInfo.h"
438#include "TStyle.h"
439#include "TSystem.h"
440#include "TTreeCloner.h"
441#include "TTreeCache.h"
442#include "TTreeCacheUnzip.h"
445#include "TVirtualIndex.h"
446#include "TVirtualPerfStats.h"
447#include "TVirtualPad.h"
448#include "TBranchSTL.h"
449#include "TSchemaRuleSet.h"
450#include "TFileMergeInfo.h"
451#include "ROOT/StringConv.hxx"
452#include "TVirtualMutex.h"
453#include "strlcpy.h"
454
455#include "TBranchIMTHelper.h"
456#include "TNotifyLink.h"
457
458#include <chrono>
459#include <cstddef>
460#include <iostream>
461#include <fstream>
462#include <sstream>
463#include <string>
464#include <cstdio>
465#include <climits>
466#include <algorithm>
467#include <set>
468
469#ifdef R__USE_IMT
471#include <thread>
472#endif
474constexpr Int_t kNEntriesResort = 100;
476
477Int_t TTree::fgBranchStyle = 1; // Use new TBranch style with TBranchElement.
478Long64_t TTree::fgMaxTreeSize = 100000000000LL;
479
480
481////////////////////////////////////////////////////////////////////////////////
482////////////////////////////////////////////////////////////////////////////////
483////////////////////////////////////////////////////////////////////////////////
486{
487 // Return the leaflist 'char' for a given datatype.
488
489 switch(datatype) {
490 case kChar_t: return 'B';
491 case kUChar_t: return 'b';
492 case kBool_t: return 'O';
493 case kShort_t: return 'S';
494 case kUShort_t: return 's';
495 case kCounter:
496 case kInt_t: return 'I';
497 case kUInt_t: return 'i';
498 case kDouble_t: return 'D';
499 case kDouble32_t: return 'd';
500 case kFloat_t: return 'F';
501 case kFloat16_t: return 'f';
502 case kLong_t: return 'G';
503 case kULong_t: return 'g';
504 case kchar: return 0; // unsupported
505 case kLong64_t: return 'L';
506 case kULong64_t: return 'l';
507
508 case kCharStar: return 'C';
509 case kBits: return 0; //unsupported
510
511 case kOther_t:
512 case kNoType_t:
513 default:
514 return 0;
515 }
516 return 0;
517}
518
519////////////////////////////////////////////////////////////////////////////////
520/// \class TTree::TFriendLock
521/// Helper class to prevent infinite recursion in the usage of TTree Friends.
522
523////////////////////////////////////////////////////////////////////////////////
524/// Record in tree that it has been used while recursively looks through the friends.
527: fTree(tree)
528{
529 // We could also add some code to acquire an actual
530 // lock to prevent multi-thread issues
532 if (fTree) {
535 } else {
536 fPrevious = false;
537 }
538}
539
540////////////////////////////////////////////////////////////////////////////////
541/// Copy constructor.
544 fTree(tfl.fTree),
545 fMethodBit(tfl.fMethodBit),
546 fPrevious(tfl.fPrevious)
547{
548}
549
550////////////////////////////////////////////////////////////////////////////////
551/// Assignment operator.
554{
555 if(this!=&tfl) {
556 fTree=tfl.fTree;
557 fMethodBit=tfl.fMethodBit;
558 fPrevious=tfl.fPrevious;
559 }
560 return *this;
561}
562
563////////////////////////////////////////////////////////////////////////////////
564/// Restore the state of tree the same as before we set the lock.
567{
568 if (fTree) {
569 if (!fPrevious) {
570 fTree->fFriendLockStatus &= ~(fMethodBit & kBitMask);
571 }
572 }
573}
574
575////////////////////////////////////////////////////////////////////////////////
576/// \class TTree::TClusterIterator
577/// Helper class to iterate over cluster of baskets.
578/// \note In contrast to class TListIter, looping here must NOT be done using
579/// `while (iter())` or `while (iter.Next())` that would lead to an infinite loop, but rather using
580/// `while( (auto clusterStart = iter()) < tree->GetEntries() )`.
581/// \see TTree::GetClusterIterator
582
583////////////////////////////////////////////////////////////////////////////////
584/// Regular constructor.
585/// TTree is not set as const, since we might modify if it is a TChain.
587TTree::TClusterIterator::TClusterIterator(TTree *tree, Long64_t firstEntry) : fTree(tree), fClusterRange(0), fStartEntry(0), fNextEntry(0), fEstimatedSize(-1)
588{
589 if (fTree->fNClusterRange) {
590 // Find the correct cluster range.
591 //
592 // Since fClusterRangeEnd contains the inclusive upper end of the range, we need to search for the
593 // range that was containing the previous entry and add 1 (because BinarySearch consider the values
594 // to be the inclusive start of the bucket).
596
599 if (fClusterRange == 0) {
600 pedestal = 0;
602 } else {
605 }
609 } else {
611 }
612 if (autoflush <= 0) {
614 }
616 } else if ( fTree->GetAutoFlush() <= 0 ) {
617 // Case of old files before November 9 2009 *or* small tree where AutoFlush was never set.
619 } else {
621 }
622 fNextEntry = fStartEntry; // Position correctly for the first call to Next()
623}
624
625////////////////////////////////////////////////////////////////////////////////
626/// Estimate the cluster size.
627///
628/// In almost all cases, this quickly returns the size of the auto-flush
629/// in the TTree.
630///
631/// However, in the case where the cluster size was not fixed (old files and
632/// case where autoflush was explicitly set to zero), we need estimate
633/// a cluster size in relation to the size of the cache.
634///
635/// After this value is calculated once for the TClusterIterator, it is
636/// cached and reused in future calls.
639{
640 auto autoFlush = fTree->GetAutoFlush();
641 if (autoFlush > 0) return autoFlush;
642 if (fEstimatedSize > 0) return fEstimatedSize;
643
644 Long64_t zipBytes = fTree->GetZipBytes();
645 if (zipBytes == 0) {
646 fEstimatedSize = fTree->GetEntries() - 1;
647 if (fEstimatedSize <= 0)
648 fEstimatedSize = 1;
649 } else {
651 Long64_t cacheSize = fTree->GetCacheSize();
652 if (cacheSize == 0) {
653 // Humm ... let's double check on the file.
654 TFile *file = fTree->GetCurrentFile();
655 if (file) {
656 TFileCacheRead *cache = fTree->GetReadCache(file);
657 if (cache) {
658 cacheSize = cache->GetBufferSize();
659 }
660 }
661 }
662 // If neither file nor tree has a cache, use the current default.
663 if (cacheSize <= 0) {
664 cacheSize = 30000000;
665 }
666 clusterEstimate = fTree->GetEntries() * cacheSize / zipBytes;
667 // If there are no entries, then just default to 1.
668 fEstimatedSize = clusterEstimate ? clusterEstimate : 1;
669 }
670 return fEstimatedSize;
671}
672
673////////////////////////////////////////////////////////////////////////////////
674/// Move on to the next cluster and return the starting entry
675/// of this next cluster
678{
679 fStartEntry = fNextEntry;
680 if (fTree->fNClusterRange || fTree->GetAutoFlush() > 0) {
681 if (fClusterRange == fTree->fNClusterRange) {
682 // We are looking at a range which size
683 // is defined by AutoFlush itself and goes to the GetEntries.
684 fNextEntry += GetEstimatedClusterSize();
685 } else {
686 if (fStartEntry > fTree->fClusterRangeEnd[fClusterRange]) {
687 ++fClusterRange;
688 }
689 if (fClusterRange == fTree->fNClusterRange) {
690 // We are looking at the last range which size
691 // is defined by AutoFlush itself and goes to the GetEntries.
692 fNextEntry += GetEstimatedClusterSize();
693 } else {
694 Long64_t clusterSize = fTree->fClusterSize[fClusterRange];
695 if (clusterSize == 0) {
696 clusterSize = GetEstimatedClusterSize();
697 }
698 fNextEntry += clusterSize;
699 if (fNextEntry > fTree->fClusterRangeEnd[fClusterRange]) {
700 // The last cluster of the range was a partial cluster,
701 // so the next cluster starts at the beginning of the
702 // next range.
703 fNextEntry = fTree->fClusterRangeEnd[fClusterRange] + 1;
704 }
705 }
706 }
707 } else {
708 // Case of old files before November 9 2009
709 fNextEntry = fStartEntry + GetEstimatedClusterSize();
710 }
711 if (fNextEntry > fTree->GetEntries()) {
712 fNextEntry = fTree->GetEntries();
713 }
714 return fStartEntry;
715}
716
717////////////////////////////////////////////////////////////////////////////////
718/// Move on to the previous cluster and return the starting entry
719/// of this previous cluster
722{
723 fNextEntry = fStartEntry;
724 if (fTree->fNClusterRange || fTree->GetAutoFlush() > 0) {
725 if (fClusterRange == 0 || fTree->fNClusterRange == 0) {
726 // We are looking at a range which size
727 // is defined by AutoFlush itself.
728 fStartEntry -= GetEstimatedClusterSize();
729 } else {
730 if (fNextEntry <= fTree->fClusterRangeEnd[fClusterRange]) {
731 --fClusterRange;
732 }
733 if (fClusterRange == 0) {
734 // We are looking at the first range.
735 fStartEntry = 0;
736 } else {
737 Long64_t clusterSize = fTree->fClusterSize[fClusterRange];
738 if (clusterSize == 0) {
739 clusterSize = GetEstimatedClusterSize();
740 }
741 fStartEntry -= clusterSize;
742 }
743 }
744 } else {
745 // Case of old files before November 9 2009 or trees that never auto-flushed.
746 fStartEntry = fNextEntry - GetEstimatedClusterSize();
747 }
748 if (fStartEntry < 0) {
749 fStartEntry = 0;
750 }
751 return fStartEntry;
752}
753
754////////////////////////////////////////////////////////////////////////////////
755////////////////////////////////////////////////////////////////////////////////
756////////////////////////////////////////////////////////////////////////////////
757
758////////////////////////////////////////////////////////////////////////////////
759/// Default constructor and I/O constructor.
760///
761/// Note: We do *not* insert ourself into the current directory.
762///
765: TNamed()
766, TAttLine()
767, TAttFill()
768, TAttMarker()
769, fEntries(0)
770, fTotBytes(0)
771, fZipBytes(0)
772, fSavedBytes(0)
773, fFlushedBytes(0)
774, fWeight(1)
776, fScanField(25)
777, fUpdate(0)
781, fMaxEntries(0)
782, fMaxEntryLoop(0)
784, fAutoSave( -300000000)
785, fAutoFlush(-30000000)
786, fEstimate(1000000)
787, fClusterRangeEnd(nullptr)
788, fClusterSize(nullptr)
789, fCacheSize(0)
790, fChainOffset(0)
791, fReadEntry(-1)
792, fTotalBuffers(0)
793, fPacketSize(100)
794, fNfill(0)
795, fDebug(0)
796, fDebugMin(0)
797, fDebugMax(9999999)
798, fMakeClass(0)
799, fFileNumber(0)
800, fNotify(nullptr)
801, fDirectory(nullptr)
802, fBranches()
803, fLeaves()
804, fAliases(nullptr)
805, fEventList(nullptr)
806, fEntryList(nullptr)
807, fIndexValues()
808, fIndex()
809, fTreeIndex(nullptr)
810, fFriends(nullptr)
811, fExternalFriends(nullptr)
812, fPerfStats(nullptr)
813, fUserInfo(nullptr)
814, fPlayer(nullptr)
815, fClones(nullptr)
816, fBranchRef(nullptr)
818, fTransientBuffer(nullptr)
822, fIMTEnabled(ROOT::IsImplicitMTEnabled())
824{
825 fMaxEntries = 1000000000;
826 fMaxEntries *= 1000;
827
828 fMaxEntryLoop = 1000000000;
829 fMaxEntryLoop *= 1000;
830
831 fBranches.SetOwner(true);
832}
833
834////////////////////////////////////////////////////////////////////////////////
835/// Normal tree constructor.
836///
837/// The tree is created in the current directory.
838/// Use the various functions Branch below to add branches to this tree.
839///
840/// If the first character of title is a "/", the function assumes a folder name.
841/// In this case, it creates automatically branches following the folder hierarchy.
842/// splitlevel may be used in this case to control the split level.
844TTree::TTree(const char* name, const char* title, Int_t splitlevel /* = 99 */,
845 TDirectory* dir /* = gDirectory*/)
846: TNamed(name, title)
847, TAttLine()
848, TAttFill()
849, TAttMarker()
850, fEntries(0)
851, fTotBytes(0)
852, fZipBytes(0)
853, fSavedBytes(0)
854, fFlushedBytes(0)
855, fWeight(1)
856, fTimerInterval(0)
857, fScanField(25)
858, fUpdate(0)
859, fDefaultEntryOffsetLen(1000)
860, fNClusterRange(0)
861, fMaxClusterRange(0)
862, fMaxEntries(0)
863, fMaxEntryLoop(0)
864, fMaxVirtualSize(0)
865, fAutoSave( -300000000)
866, fAutoFlush(-30000000)
867, fEstimate(1000000)
868, fClusterRangeEnd(nullptr)
869, fClusterSize(nullptr)
870, fCacheSize(0)
871, fChainOffset(0)
872, fReadEntry(-1)
873, fTotalBuffers(0)
874, fPacketSize(100)
875, fNfill(0)
876, fDebug(0)
877, fDebugMin(0)
878, fDebugMax(9999999)
879, fMakeClass(0)
880, fFileNumber(0)
881, fNotify(nullptr)
882, fDirectory(dir)
883, fBranches()
884, fLeaves()
885, fAliases(nullptr)
886, fEventList(nullptr)
887, fEntryList(nullptr)
888, fIndexValues()
889, fIndex()
890, fTreeIndex(nullptr)
891, fFriends(nullptr)
892, fExternalFriends(nullptr)
893, fPerfStats(nullptr)
894, fUserInfo(nullptr)
895, fPlayer(nullptr)
896, fClones(nullptr)
897, fBranchRef(nullptr)
898, fFriendLockStatus(0)
899, fTransientBuffer(nullptr)
900, fCacheDoAutoInit(true)
901, fCacheDoClusterPrefetch(false)
902, fCacheUserSet(false)
903, fIMTEnabled(ROOT::IsImplicitMTEnabled())
904, fNEntriesSinceSorting(0)
905{
906 // TAttLine state.
910
911 // TAttFill state.
914
915 // TAttMarkerState.
919
920 fMaxEntries = 1000000000;
921 fMaxEntries *= 1000;
922
923 fMaxEntryLoop = 1000000000;
924 fMaxEntryLoop *= 1000;
925
926 // Insert ourself into the current directory.
927 // FIXME: This is very annoying behaviour, we should
928 // be able to choose to not do this like we
929 // can with a histogram.
930 if (fDirectory) fDirectory->Append(this);
931
932 fBranches.SetOwner(true);
933
934 // If title starts with "/" and is a valid folder name, a superbranch
935 // is created.
936 // FIXME: Why?
937 if (strlen(title) > 2) {
938 if (title[0] == '/') {
939 Branch(title+1,32000,splitlevel);
940 }
941 }
942}
943
944////////////////////////////////////////////////////////////////////////////////
945/// Destructor.
948{
949 if (auto link = dynamic_cast<TNotifyLinkBase*>(fNotify)) {
950 link->Clear();
951 }
952 if (fAllocationCount && (gDebug > 0)) {
953 Info("TTree::~TTree", "For tree %s, allocation count is %u.", GetName(), fAllocationCount.load());
954#ifdef R__TRACK_BASKET_ALLOC_TIME
955 Info("TTree::~TTree", "For tree %s, allocation time is %lluus.", GetName(), fAllocationTime.load());
956#endif
957 }
958
959 if (fDirectory) {
960 // We are in a directory, which may possibly be a file.
961 if (fDirectory->GetList()) {
962 // Remove us from the directory listing.
963 fDirectory->Remove(this);
964 }
965 //delete the file cache if it points to this Tree
966 TFile *file = fDirectory->GetFile();
967 MoveReadCache(file,nullptr);
968 }
969
970 // Remove the TTree from any list (linked to to the list of Cleanups) to avoid the unnecessary call to
971 // this RecursiveRemove while we delete our content.
973 ResetBit(kMustCleanup); // Don't redo it.
974
975 // We don't own the leaves in fLeaves, the branches do.
976 fLeaves.Clear();
977 // I'm ready to destroy any objects allocated by
978 // SetAddress() by my branches. If I have clones,
979 // tell them to zero their pointers to this shared
980 // memory.
981 if (fClones && fClones->GetEntries()) {
982 // I have clones.
983 // I am about to delete the objects created by
984 // SetAddress() which we are sharing, so tell
985 // the clones to release their pointers to them.
986 for (TObjLink* lnk = fClones->FirstLink(); lnk; lnk = lnk->Next()) {
987 TTree* clone = (TTree*) lnk->GetObject();
988 // clone->ResetBranchAddresses();
989
990 // Reset only the branch we have set the address of.
991 CopyAddresses(clone,true);
992 }
993 }
994 // Get rid of our branches, note that this will also release
995 // any memory allocated by TBranchElement::SetAddress().
997
998 // The TBranch destructor is using fDirectory to detect whether it
999 // owns the TFile that contains its data (See TBranch::~TBranch)
1000 fDirectory = nullptr;
1001
1002 // FIXME: We must consider what to do with the reset of these if we are a clone.
1003 delete fPlayer;
1004 fPlayer = nullptr;
1005 if (fExternalFriends) {
1006 using namespace ROOT::Detail;
1008 fetree->Reset();
1009 fExternalFriends->Clear("nodelete");
1011 }
1012 if (fFriends) {
1013 fFriends->Delete();
1014 delete fFriends;
1015 fFriends = nullptr;
1016 }
1017 if (fAliases) {
1018 fAliases->Delete();
1019 delete fAliases;
1020 fAliases = nullptr;
1021 }
1022 if (fUserInfo) {
1023 fUserInfo->Delete();
1024 delete fUserInfo;
1025 fUserInfo = nullptr;
1026 }
1027 if (fClones) {
1028 // Clone trees should no longer be removed from fClones when they are deleted.
1029 {
1031 gROOT->GetListOfCleanups()->Remove(fClones);
1032 }
1033 // Note: fClones does not own its content.
1034 delete fClones;
1035 fClones = nullptr;
1036 }
1037 if (fEntryList) {
1038 if (fEntryList->TestBit(kCanDelete) && fEntryList->GetDirectory()==nullptr) {
1039 // Delete the entry list if it is marked to be deleted and it is not also
1040 // owned by a directory. (Otherwise we would need to make sure that a
1041 // TDirectoryFile that has a TTree in it does a 'slow' TList::Delete.
1042 delete fEntryList;
1043 fEntryList=nullptr;
1044 }
1045 }
1046 delete fTreeIndex;
1047 fTreeIndex = nullptr;
1048 delete fBranchRef;
1049 fBranchRef = nullptr;
1050 delete [] fClusterRangeEnd;
1051 fClusterRangeEnd = nullptr;
1052 delete [] fClusterSize;
1053 fClusterSize = nullptr;
1054
1055 if (fTransientBuffer) {
1056 delete fTransientBuffer;
1057 fTransientBuffer = nullptr;
1058 }
1059}
1060
1061////////////////////////////////////////////////////////////////////////////////
1062/// Returns the transient buffer currently used by this TTree for reading/writing baskets.
1074}
1075
1076////////////////////////////////////////////////////////////////////////////////
1077/// Add branch with name bname to the Tree cache.
1078/// If bname="*" all branches are added to the cache.
1079/// if subbranches is true all the branches of the subbranches are
1080/// also put to the cache.
1081///
1082/// Returns:
1083/// - 0 branch added or already included
1084/// - -1 on error
1086Int_t TTree::AddBranchToCache(const char*bname, bool subbranches)
1087{
1088 if (!GetTree()) {
1089 if (LoadTree(0)<0) {
1090 Error("AddBranchToCache","Could not load a tree");
1091 return -1;
1092 }
1093 }
1094 if (GetTree()) {
1095 if (GetTree() != this) {
1096 return GetTree()->AddBranchToCache(bname, subbranches);
1097 }
1098 } else {
1099 Error("AddBranchToCache", "No tree is available. Branch was not added to the cache");
1100 return -1;
1101 }
1102
1103 TFile *f = GetCurrentFile();
1104 if (!f) {
1105 Error("AddBranchToCache", "No file is available. Branch was not added to the cache");
1106 return -1;
1107 }
1108 TTreeCache *tc = GetReadCache(f,true);
1109 if (!tc) {
1110 Error("AddBranchToCache", "No cache is available, branch not added");
1111 return -1;
1112 }
1113 return tc->AddBranch(bname,subbranches);
1114}
1115
1116////////////////////////////////////////////////////////////////////////////////
1117/// Add branch b to the Tree cache.
1118/// if subbranches is true all the branches of the subbranches are
1119/// also put to the cache.
1120///
1121/// Returns:
1122/// - 0 branch added or already included
1123/// - -1 on error
1126{
1127 if (!GetTree()) {
1128 if (LoadTree(0)<0) {
1129 Error("AddBranchToCache","Could not load a tree");
1130 return -1;
1131 }
1132 }
1133 if (GetTree()) {
1134 if (GetTree() != this) {
1135 Int_t res = GetTree()->AddBranchToCache(b, subbranches);
1136 if (res<0) {
1137 Error("AddBranchToCache", "Error adding branch");
1138 }
1139 return res;
1140 }
1141 } else {
1142 Error("AddBranchToCache", "No tree is available. Branch was not added to the cache");
1143 return -1;
1144 }
1145
1146 TFile *f = GetCurrentFile();
1147 if (!f) {
1148 Error("AddBranchToCache", "No file is available. Branch was not added to the cache");
1149 return -1;
1150 }
1151 TTreeCache *tc = GetReadCache(f,true);
1152 if (!tc) {
1153 Error("AddBranchToCache", "No cache is available, branch not added");
1154 return -1;
1155 }
1156 return tc->AddBranch(b,subbranches);
1157}
1158
1159////////////////////////////////////////////////////////////////////////////////
1160/// Remove the branch with name 'bname' from the Tree cache.
1161/// If bname="*" all branches are removed from the cache.
1162/// if subbranches is true all the branches of the subbranches are
1163/// also removed from the cache.
1164///
1165/// Returns:
1166/// - 0 branch dropped or not in cache
1167/// - -1 on error
1169Int_t TTree::DropBranchFromCache(const char*bname, bool subbranches)
1170{
1171 if (!GetTree()) {
1172 if (LoadTree(0)<0) {
1173 Error("DropBranchFromCache","Could not load a tree");
1174 return -1;
1175 }
1176 }
1177 if (GetTree()) {
1178 if (GetTree() != this) {
1179 return GetTree()->DropBranchFromCache(bname, subbranches);
1180 }
1181 } else {
1182 Error("DropBranchFromCache", "No tree is available. Branch was not dropped from the cache");
1183 return -1;
1184 }
1185
1186 TFile *f = GetCurrentFile();
1187 if (!f) {
1188 Error("DropBranchFromCache", "No file is available. Branch was not dropped from the cache");
1189 return -1;
1190 }
1191 TTreeCache *tc = GetReadCache(f,true);
1192 if (!tc) {
1193 Error("DropBranchFromCache", "No cache is available, branch not dropped");
1194 return -1;
1195 }
1196 return tc->DropBranch(bname,subbranches);
1197}
1198
1199////////////////////////////////////////////////////////////////////////////////
1200/// Remove the branch b from the Tree cache.
1201/// if subbranches is true all the branches of the subbranches are
1202/// also removed from the cache.
1203///
1204/// Returns:
1205/// - 0 branch dropped or not in cache
1206/// - -1 on error
1209{
1210 if (!GetTree()) {
1211 if (LoadTree(0)<0) {
1212 Error("DropBranchFromCache","Could not load a tree");
1213 return -1;
1214 }
1215 }
1216 if (GetTree()) {
1217 if (GetTree() != this) {
1218 Int_t res = GetTree()->DropBranchFromCache(b, subbranches);
1219 if (res<0) {
1220 Error("DropBranchFromCache", "Error dropping branch");
1221 }
1222 return res;
1223 }
1224 } else {
1225 Error("DropBranchFromCache", "No tree is available. Branch was not dropped from the cache");
1226 return -1;
1227 }
1228
1229 TFile *f = GetCurrentFile();
1230 if (!f) {
1231 Error("DropBranchFromCache", "No file is available. Branch was not dropped from the cache");
1232 return -1;
1233 }
1234 TTreeCache *tc = GetReadCache(f,true);
1235 if (!tc) {
1236 Error("DropBranchFromCache", "No cache is available, branch not dropped");
1237 return -1;
1238 }
1239 return tc->DropBranch(b,subbranches);
1240}
1241
1242////////////////////////////////////////////////////////////////////////////////
1243/// Add a cloned tree to our list of trees to be notified whenever we change
1244/// our branch addresses or when we are deleted.
1246void TTree::AddClone(TTree* clone)
1247{
1248 if (!fClones) {
1249 fClones = new TList();
1250 fClones->SetOwner(false);
1251 // So that the clones are automatically removed from the list when
1252 // they are deleted.
1253 {
1255 gROOT->GetListOfCleanups()->Add(fClones);
1256 }
1257 }
1258 if (!fClones->FindObject(clone)) {
1259 fClones->Add(clone);
1260 }
1261}
1262
1263// Check whether mainTree and friendTree can be friends w.r.t. the kEntriesReshuffled bit.
1264// In particular, if any has the bit set, then friendTree must have a TTreeIndex and the
1265// branches used for indexing must be present in mainTree.
1266// Return true if the trees can be friends, false otherwise.
1268{
1271 const auto friendHasValidIndex = [&] {
1272 auto idx = friendTree.GetTreeIndex();
1273 return idx ? idx->IsValidFor(&mainTree) : false;
1274 }();
1275
1277 const auto reshuffledTreeName = isMainReshuffled ? mainTree.GetName() : friendTree.GetName();
1278 const auto msg =
1279 "Tree '%s' has the kEntriesReshuffled bit set and cannot have friends nor can be added as a friend unless the "
1280 "main tree has a TTreeIndex on the friend tree '%s'. You can also unset the bit manually if you know what you "
1281 "are doing; note that you risk associating wrong TTree entries of the friend with those of the main TTree!";
1282 Error("AddFriend", msg, reshuffledTreeName, friendTree.GetName());
1283 return false;
1284 }
1285 return true;
1286}
1287
1288////////////////////////////////////////////////////////////////////////////////
1289/// Add a TFriendElement to the list of friends.
1290///
1291/// This function:
1292/// - opens a file if filename is specified
1293/// - reads a Tree with name treename from the file (current directory)
1294/// - adds the Tree to the list of friends
1295/// see other AddFriend functions
1296///
1297/// A TFriendElement TF describes a TTree object TF in a file.
1298/// When a TFriendElement TF is added to the list of friends of an
1299/// existing TTree T, any variable from TF can be referenced in a query
1300/// to T.
1301///
1302/// A tree keeps a list of friends. In the context of a tree (or a chain),
1303/// friendship means unrestricted access to the friends data. In this way
1304/// it is much like adding another branch to the tree without taking the risk
1305/// of damaging it. To add a friend to the list, you can use the TTree::AddFriend
1306/// method. The tree in the diagram below has two friends (friend_tree1 and
1307/// friend_tree2) and now has access to the variables a,b,c,i,j,k,l and m.
1308///
1309/// \image html ttree_friend1.png
1310///
1311/// The AddFriend method has two parameters, the first is the tree name and the
1312/// second is the name of the ROOT file where the friend tree is saved.
1313/// AddFriend automatically opens the friend file. If no file name is given,
1314/// the tree called ft1 is assumed to be in the same file as the original tree.
1315///
1316/// tree.AddFriend("ft1","friendfile1.root");
1317/// If the friend tree has the same name as the original tree, you can give it
1318/// an alias in the context of the friendship:
1319///
1320/// tree.AddFriend("tree1 = tree","friendfile1.root");
1321/// Once the tree has friends, we can use TTree::Draw as if the friend's
1322/// variables were in the original tree. To specify which tree to use in
1323/// the Draw method, use the syntax:
1324/// ~~~ {.cpp}
1325/// <treeName>.<branchname>.<varname>
1326/// ~~~
1327/// If the variablename is enough to uniquely identify the variable, you can
1328/// leave out the tree and/or branch name.
1329/// For example, these commands generate a 3-d scatter plot of variable "var"
1330/// in the TTree tree versus variable v1 in TTree ft1 versus variable v2 in
1331/// TTree ft2.
1332/// ~~~ {.cpp}
1333/// tree.AddFriend("ft1","friendfile1.root");
1334/// tree.AddFriend("ft2","friendfile2.root");
1335/// tree.Draw("var:ft1.v1:ft2.v2");
1336/// ~~~
1337/// \image html ttree_friend2.png
1338///
1339/// The picture illustrates the access of the tree and its friends with a
1340/// Draw command.
1341/// When AddFriend is called, the ROOT file is automatically opened and the
1342/// friend tree (ft1) is read into memory. The new friend (ft1) is added to
1343/// the list of friends of tree.
1344/// The number of entries in the friend must be equal or greater to the number
1345/// of entries of the original tree. If the friend tree has fewer entries a
1346/// warning is given and the missing entries are not included in the histogram.
1347/// To retrieve the list of friends from a tree use TTree::GetListOfFriends.
1348/// When the tree is written to file (TTree::Write), the friends list is saved
1349/// with it. And when the tree is retrieved, the trees on the friends list are
1350/// also retrieved and the friendship restored.
1351/// When a tree is deleted, the elements of the friend list are also deleted.
1352/// It is possible to declare a friend tree that has the same internal
1353/// structure (same branches and leaves) as the original tree, and compare the
1354/// same values by specifying the tree.
1355/// ~~~ {.cpp}
1356/// tree.Draw("var:ft1.var:ft2.var")
1357/// ~~~
1359TFriendElement *TTree::AddFriend(const char *treename, const char *filename)
1360{
1361 if (!fFriends) {
1362 fFriends = new TList();
1363 }
1365
1366 TTree *t = fe->GetTree();
1367 bool canAddFriend = true;
1368 if (t) {
1369 canAddFriend = CheckReshuffling(*this, *t);
1370 if (!t->GetTreeIndex() && (t->GetEntries() < fEntries)) {
1371 Warning("AddFriend", "FriendElement %s in file %s has less entries %lld than its parent Tree: %lld", treename,
1373 }
1374 } else {
1375 Error("AddFriend", "Cannot find tree '%s' in file '%s', friend not added", treename, filename);
1376 canAddFriend = false;
1377 }
1378
1379 if (canAddFriend)
1380 fFriends->Add(fe);
1381 return fe;
1382}
1383
1384////////////////////////////////////////////////////////////////////////////////
1385/// Add a TFriendElement to the list of friends.
1386///
1387/// The TFile is managed by the user (e.g. the user must delete the file).
1388/// For complete description see AddFriend(const char *, const char *).
1389/// This function:
1390/// - reads a Tree with name treename from the file
1391/// - adds the Tree to the list of friends
1393TFriendElement *TTree::AddFriend(const char *treename, TFile *file)
1394{
1395 if (!fFriends) {
1396 fFriends = new TList();
1397 }
1398 TFriendElement *fe = new TFriendElement(this, treename, file);
1399 R__ASSERT(fe);
1400 TTree *t = fe->GetTree();
1401 bool canAddFriend = true;
1402 if (t) {
1403 canAddFriend = CheckReshuffling(*this, *t);
1404 if (!t->GetTreeIndex() && (t->GetEntries() < fEntries)) {
1405 Warning("AddFriend", "FriendElement %s in file %s has less entries %lld than its parent tree: %lld", treename,
1406 file->GetName(), t->GetEntries(), fEntries);
1407 }
1408 } else {
1409 Error("AddFriend", "Cannot find tree '%s' in file '%s', friend not added", treename, file->GetName());
1410 canAddFriend = false;
1411 }
1412
1413 if (canAddFriend)
1414 fFriends->Add(fe);
1415 return fe;
1416}
1417
1418////////////////////////////////////////////////////////////////////////////////
1419/// Add a TFriendElement to the list of friends.
1420///
1421/// The TTree is managed by the user (e.g., the user must delete the file).
1422/// For a complete description see AddFriend(const char *, const char *).
1424TFriendElement *TTree::AddFriend(TTree *tree, const char *alias, bool warn)
1425{
1426 if (!tree) {
1427 return nullptr;
1428 }
1429 if (!fFriends) {
1430 fFriends = new TList();
1431 }
1432 TFriendElement *fe = new TFriendElement(this, tree, alias);
1433 R__ASSERT(fe); // this assert is for historical reasons. Don't remove it unless you understand all the consequences.
1434 TTree *t = fe->GetTree();
1435 if (warn && (t->GetEntries() < fEntries)) {
1436 Warning("AddFriend", "FriendElement '%s' in file '%s' has less entries %lld than its parent tree: %lld",
1437 tree->GetName(), fe->GetFile() ? fe->GetFile()->GetName() : "(memory resident)", t->GetEntries(),
1438 fEntries);
1439 }
1440 if (CheckReshuffling(*this, *t))
1441 fFriends->Add(fe);
1442 else
1443 tree->RemoveExternalFriend(fe);
1444 return fe;
1445}
1446
1447////////////////////////////////////////////////////////////////////////////////
1448/// AutoSave tree header every fAutoSave bytes.
1449///
1450/// When large Trees are produced, it is safe to activate the AutoSave
1451/// procedure. Some branches may have buffers holding many entries.
1452/// If fAutoSave is negative, AutoSave is automatically called by
1453/// TTree::Fill when the number of bytes generated since the previous
1454/// AutoSave is greater than -fAutoSave bytes.
1455/// If fAutoSave is positive, AutoSave is automatically called by
1456/// TTree::Fill every N entries.
1457/// This function may also be invoked by the user.
1458/// Each AutoSave generates a new key on the file.
1459/// Once the key with the tree header has been written, the previous cycle
1460/// (if any) is deleted.
1461///
1462/// Note that calling TTree::AutoSave too frequently (or similarly calling
1463/// TTree::SetAutoSave with a small value) is an expensive operation.
1464/// You should make tests for your own application to find a compromise
1465/// between speed and the quantity of information you may loose in case of
1466/// a job crash.
1467///
1468/// In case your program crashes before closing the file holding this tree,
1469/// the file will be automatically recovered when you will connect the file
1470/// in UPDATE mode.
1471/// The Tree will be recovered at the status corresponding to the last AutoSave.
1472///
1473/// if option contains "SaveSelf", gDirectory->SaveSelf() is called.
1474/// This allows another process to analyze the Tree while the Tree is being filled.
1475///
1476/// if option contains "FlushBaskets", TTree::FlushBaskets is called and all
1477/// the current basket are closed-out and written to disk individually.
1478///
1479/// By default the previous header is deleted after having written the new header.
1480/// if option contains "Overwrite", the previous Tree header is deleted
1481/// before written the new header. This option is slightly faster, but
1482/// the default option is safer in case of a problem (disk quota exceeded)
1483/// when writing the new header.
1484///
1485/// The function returns the number of bytes written to the file.
1486/// if the number of bytes is null, an error has occurred while writing
1487/// the header to the file.
1488///
1489/// ## How to write a Tree in one process and view it from another process
1490///
1491/// The following two scripts illustrate how to do this.
1492/// The script treew.C is executed by process1, treer.C by process2
1493///
1494/// script treew.C:
1495/// ~~~ {.cpp}
1496/// void treew() {
1497/// TFile f("test.root","recreate");
1498/// TNtuple *ntuple = new TNtuple("ntuple","Demo","px:py:pz:random:i");
1499/// Float_t px, py, pz;
1500/// for ( Int_t i=0; i<10000000; i++) {
1501/// gRandom->Rannor(px,py);
1502/// pz = px*px + py*py;
1503/// Float_t random = gRandom->Rndm(1);
1504/// ntuple->Fill(px,py,pz,random,i);
1505/// if (i%1000 == 1) ntuple->AutoSave("SaveSelf");
1506/// }
1507/// }
1508/// ~~~
1509/// script treer.C:
1510/// ~~~ {.cpp}
1511/// void treer() {
1512/// TFile f("test.root");
1513/// TTree *ntuple = (TTree*)f.Get("ntuple");
1514/// TCanvas c1;
1515/// Int_t first = 0;
1516/// while(1) {
1517/// if (first == 0) ntuple->Draw("px>>hpx", "","",10000000,first);
1518/// else ntuple->Draw("px>>+hpx","","",10000000,first);
1519/// first = (Int_t)ntuple->GetEntries();
1520/// c1.Update();
1521/// gSystem->Sleep(1000); //sleep 1 second
1522/// ntuple->Refresh();
1523/// }
1524/// }
1525/// ~~~
1528{
1529 if (!fDirectory || fDirectory == gROOT || !fDirectory->IsWritable()) return 0;
1530 if (gDebug > 0) {
1531 Info("AutoSave", "Tree:%s after %lld bytes written\n",GetName(),GetTotBytes());
1532 }
1533 TString opt = option;
1534 opt.ToLower();
1535
1536 if (opt.Contains("flushbaskets")) {
1537 if (gDebug > 0) Info("AutoSave", "calling FlushBaskets \n");
1539 }
1540
1542
1543 TKey *key = (TKey*)fDirectory->GetListOfKeys()->FindObject(GetName());
1545 if (opt.Contains("overwrite")) {
1546 nbytes = fDirectory->WriteTObject(this,"","overwrite");
1547 } else {
1548 nbytes = fDirectory->WriteTObject(this); //nbytes will be 0 if Write failed (disk space exceeded)
1549 if (nbytes && key && strcmp(ClassName(), key->GetClassName()) == 0) {
1550 key->Delete();
1551 delete key;
1552 }
1553 }
1554 // save StreamerInfo
1555 TFile *file = fDirectory->GetFile();
1556 if (file) file->WriteStreamerInfo();
1557
1558 if (opt.Contains("saveself")) {
1560 //the following line is required in case GetUserInfo contains a user class
1561 //for which the StreamerInfo must be written. One could probably be a bit faster (Rene)
1562 if (file) file->WriteHeader();
1563 }
1564
1565 return nbytes;
1566}
1567
1568namespace {
1569 // This error message is repeated several times in the code. We write it once.
1570 const char* writeStlWithoutProxyMsg = "The class requested (%s) for the branch \"%s\""
1571 " is an instance of an stl collection and does not have a compiled CollectionProxy."
1572 " Please generate the dictionary for this collection (%s) to avoid to write corrupted data.";
1573}
1574
1575////////////////////////////////////////////////////////////////////////////////
1576/// Same as TTree::Branch() with added check that addobj matches className.
1577///
1578/// \see TTree::Branch()
1579///
1581TBranch* TTree::BranchImp(const char* branchname, const char* classname, TClass* ptrClass, void* addobj, Int_t bufsize, Int_t splitlevel)
1582{
1583 TClass* claim = TClass::GetClass(classname);
1584 if (!ptrClass) {
1585 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1587 claim->GetName(), branchname, claim->GetName());
1588 return nullptr;
1589 }
1590 return Branch(branchname, classname, (void*) addobj, bufsize, splitlevel);
1591 }
1592 TClass* actualClass = nullptr;
1593 void** addr = (void**) addobj;
1594 if (addr) {
1595 actualClass = ptrClass->GetActualClass(*addr);
1596 }
1597 if (ptrClass && claim) {
1598 if (!(claim->InheritsFrom(ptrClass) || ptrClass->InheritsFrom(claim))) {
1599 // Note we currently do not warn in case of splicing or over-expectation).
1600 if (claim->IsLoaded() && ptrClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), ptrClass->GetTypeInfo()->name() ) == 0) {
1601 // The type is the same according to the C++ type_info, we must be in the case of
1602 // a template of Double32_t. This is actually a correct case.
1603 } else {
1604 Error("Branch", "The class requested (%s) for \"%s\" is different from the type of the pointer passed (%s)",
1605 claim->GetName(), branchname, ptrClass->GetName());
1606 }
1607 } else if (actualClass && (claim != actualClass) && !actualClass->InheritsFrom(claim)) {
1608 if (claim->IsLoaded() && actualClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), actualClass->GetTypeInfo()->name() ) == 0) {
1609 // The type is the same according to the C++ type_info, we must be in the case of
1610 // a template of Double32_t. This is actually a correct case.
1611 } else {
1612 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s",
1613 actualClass->GetName(), branchname, claim->GetName());
1614 }
1615 }
1616 }
1617 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1619 claim->GetName(), branchname, claim->GetName());
1620 return nullptr;
1621 }
1622 return Branch(branchname, classname, (void*) addobj, bufsize, splitlevel);
1623}
1624
1625////////////////////////////////////////////////////////////////////////////////
1626/// Same as TTree::Branch but automatic detection of the class name.
1627/// \see TTree::Branch
1630{
1631 if (!ptrClass) {
1632 Error("Branch", "The pointer specified for %s is not of a class known to ROOT", branchname);
1633 return nullptr;
1634 }
1635 TClass* actualClass = nullptr;
1636 void** addr = (void**) addobj;
1637 if (addr && *addr) {
1638 actualClass = ptrClass->GetActualClass(*addr);
1639 if (!actualClass) {
1640 Warning("Branch", "The actual TClass corresponding to the object provided for the definition of the branch \"%s\" is missing.\n\tThe object will be truncated down to its %s part",
1641 branchname, ptrClass->GetName());
1643 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1644 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s", actualClass->GetName(), branchname, ptrClass->GetName());
1645 return nullptr;
1646 }
1647 } else {
1649 }
1650 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1652 actualClass->GetName(), branchname, actualClass->GetName());
1653 return nullptr;
1654 }
1655 return Branch(branchname, actualClass->GetName(), (void*) addobj, bufsize, splitlevel);
1656}
1657
1658////////////////////////////////////////////////////////////////////////////////
1659/// Same as TTree::Branch but automatic detection of the class name.
1660/// \see TTree::Branch
1662TBranch* TTree::BranchImpRef(const char* branchname, const char *classname, TClass* ptrClass, void *addobj, Int_t bufsize, Int_t splitlevel)
1663{
1664 TClass* claim = TClass::GetClass(classname);
1665 if (!ptrClass) {
1666 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1668 claim->GetName(), branchname, claim->GetName());
1669 return nullptr;
1670 } else if (claim == nullptr) {
1671 Error("Branch", "The pointer specified for %s is not of a class known to ROOT and %s is not a known class", branchname, classname);
1672 return nullptr;
1673 }
1674 ptrClass = claim;
1675 }
1676 TClass* actualClass = nullptr;
1677 if (!addobj) {
1678 Error("Branch", "Reference interface requires a valid object (for branch: %s)!", branchname);
1679 return nullptr;
1680 }
1681 actualClass = ptrClass->GetActualClass(addobj);
1682 if (ptrClass && claim) {
1683 if (!(claim->InheritsFrom(ptrClass) || ptrClass->InheritsFrom(claim))) {
1684 // Note we currently do not warn in case of splicing or over-expectation).
1685 if (claim->IsLoaded() && ptrClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), ptrClass->GetTypeInfo()->name() ) == 0) {
1686 // The type is the same according to the C++ type_info, we must be in the case of
1687 // a template of Double32_t. This is actually a correct case.
1688 } else {
1689 Error("Branch", "The class requested (%s) for \"%s\" is different from the type of the object passed (%s)",
1690 claim->GetName(), branchname, ptrClass->GetName());
1691 }
1692 } else if (actualClass && (claim != actualClass) && !actualClass->InheritsFrom(claim)) {
1693 if (claim->IsLoaded() && actualClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), actualClass->GetTypeInfo()->name() ) == 0) {
1694 // The type is the same according to the C++ type_info, we must be in the case of
1695 // a template of Double32_t. This is actually a correct case.
1696 } else {
1697 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s",
1698 actualClass->GetName(), branchname, claim->GetName());
1699 }
1700 }
1701 }
1702 if (!actualClass) {
1703 Warning("Branch", "The actual TClass corresponding to the object provided for the definition of the branch \"%s\" is missing.\n\tThe object will be truncated down to its %s part",
1704 branchname, ptrClass->GetName());
1706 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1707 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s", actualClass->GetName(), branchname, ptrClass->GetName());
1708 return nullptr;
1709 }
1710 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1712 actualClass->GetName(), branchname, actualClass->GetName());
1713 return nullptr;
1714 }
1715 return BronchExec(branchname, actualClass->GetName(), (void*) addobj, false, bufsize, splitlevel);
1716}
1717
1718////////////////////////////////////////////////////////////////////////////////
1719/// Same as TTree::Branch but automatic detection of the class name.
1720/// \see TTree::Branch
1723{
1724 if (!ptrClass) {
1725 if (datatype == kOther_t || datatype == kNoType_t) {
1726 Error("Branch", "The pointer specified for %s is not of a class or type known to ROOT", branchname);
1727 } else {
1729 return Branch(branchname,addobj,varname.Data(),bufsize);
1730 }
1731 return nullptr;
1732 }
1733 TClass* actualClass = nullptr;
1734 if (!addobj) {
1735 Error("Branch", "Reference interface requires a valid object (for branch: %s)!", branchname);
1736 return nullptr;
1737 }
1738 actualClass = ptrClass->GetActualClass(addobj);
1739 if (!actualClass) {
1740 Warning("Branch", "The actual TClass corresponding to the object provided for the definition of the branch \"%s\" is missing.\n\tThe object will be truncated down to its %s part",
1741 branchname, ptrClass->GetName());
1743 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1744 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s", actualClass->GetName(), branchname, ptrClass->GetName());
1745 return nullptr;
1746 }
1747 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1749 actualClass->GetName(), branchname, actualClass->GetName());
1750 return nullptr;
1751 }
1752 return BronchExec(branchname, actualClass->GetName(), (void*) addobj, false, bufsize, splitlevel);
1753}
1754
1755////////////////////////////////////////////////////////////////////////////////
1756// Wrapper to turn Branch call with an std::array into the relevant leaf list
1757// call
1758TBranch *TTree::BranchImpArr(const char *branchname, EDataType datatype, std::size_t N, void *addobj, Int_t bufsize,
1759 Int_t /* splitlevel */)
1760{
1761 if (datatype == kOther_t || datatype == kNoType_t) {
1762 Error("Branch",
1763 "The inner type of the std::array passed specified for %s is not of a class or type known to ROOT",
1764 branchname);
1765 } else {
1767 varname.Form("%s[%d]/%c", branchname, (int)N, DataTypeToChar(datatype));
1768 return Branch(branchname, addobj, varname.Data(), bufsize);
1769 }
1770 return nullptr;
1771}
1772
1773////////////////////////////////////////////////////////////////////////////////
1774/// Deprecated function. Use next function instead.
1776Int_t TTree::Branch(TList* li, Int_t bufsize /* = 32000 */ , Int_t splitlevel /* = 99 */)
1777{
1778 return Branch((TCollection*) li, bufsize, splitlevel);
1779}
1780
1781////////////////////////////////////////////////////////////////////////////////
1782/// Create one branch for each element in the collection.
1783///
1784/// Each entry in the collection becomes a top level branch if the
1785/// corresponding class is not a collection. If it is a collection, the entry
1786/// in the collection becomes in turn top level branches, etc.
1787/// The splitlevel is decreased by 1 every time a new collection is found.
1788/// For example if list is a TObjArray*
1789/// - if splitlevel = 1, one top level branch is created for each element
1790/// of the TObjArray.
1791/// - if splitlevel = 2, one top level branch is created for each array element.
1792/// if, in turn, one of the array elements is a TCollection, one top level
1793/// branch will be created for each element of this collection.
1794///
1795/// In case a collection element is a TClonesArray, the special Tree constructor
1796/// for TClonesArray is called.
1797/// The collection itself cannot be a TClonesArray.
1798///
1799/// The function returns the total number of branches created.
1800///
1801/// If name is given, all branch names will be prefixed with name_.
1802///
1803/// IMPORTANT NOTE1: This function should not be called with splitlevel < 1.
1804///
1805/// IMPORTANT NOTE2: The branches created by this function will have names
1806/// corresponding to the collection or object names. It is important
1807/// to give names to collections to avoid misleading branch names or
1808/// identical branch names. By default collections have a name equal to
1809/// the corresponding class name, e.g. the default name for a TList is "TList".
1810///
1811/// And in general, in case two or more master branches contain subbranches
1812/// with identical names, one must add a "." (dot) character at the end
1813/// of the master branch name. This will force the name of the subbranches
1814/// to be of the form `master.subbranch` instead of simply `subbranch`.
1815/// This situation happens when the top level object
1816/// has two or more members referencing the same class.
1817/// Without the dot, the prefix will not be there and that might cause ambiguities.
1818/// For example, if a Tree has two branches B1 and B2 corresponding
1819/// to objects of the same class MyClass, one can do:
1820/// ~~~ {.cpp}
1821/// tree.Branch("B1.","MyClass",&b1,8000,1);
1822/// tree.Branch("B2.","MyClass",&b2,8000,1);
1823/// ~~~
1824/// if MyClass has 3 members a,b,c, the two instructions above will generate
1825/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
1826/// In other words, the trailing dot of the branch name is semantically relevant
1827/// and recommended.
1828///
1829/// Example:
1830/// ~~~ {.cpp}
1831/// {
1832/// TTree T("T","test list");
1833/// TList *list = new TList();
1834///
1835/// TObjArray *a1 = new TObjArray();
1836/// a1->SetName("a1");
1837/// list->Add(a1);
1838/// TH1F *ha1a = new TH1F("ha1a","ha1",100,0,1);
1839/// TH1F *ha1b = new TH1F("ha1b","ha1",100,0,1);
1840/// a1->Add(ha1a);
1841/// a1->Add(ha1b);
1842/// TObjArray *b1 = new TObjArray();
1843/// b1->SetName("b1");
1844/// list->Add(b1);
1845/// TH1F *hb1a = new TH1F("hb1a","hb1",100,0,1);
1846/// TH1F *hb1b = new TH1F("hb1b","hb1",100,0,1);
1847/// b1->Add(hb1a);
1848/// b1->Add(hb1b);
1849///
1850/// TObjArray *a2 = new TObjArray();
1851/// a2->SetName("a2");
1852/// list->Add(a2);
1853/// TH1S *ha2a = new TH1S("ha2a","ha2",100,0,1);
1854/// TH1S *ha2b = new TH1S("ha2b","ha2",100,0,1);
1855/// a2->Add(ha2a);
1856/// a2->Add(ha2b);
1857///
1858/// T.Branch(list,16000,2);
1859/// T.Print();
1860/// }
1861/// ~~~
1863Int_t TTree::Branch(TCollection* li, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */, const char* name /* = "" */)
1864{
1865
1866 if (!li) {
1867 return 0;
1868 }
1869 TObject* obj = nullptr;
1870 Int_t nbranches = GetListOfBranches()->GetEntries();
1871 if (li->InheritsFrom(TClonesArray::Class())) {
1872 Error("Branch", "Cannot call this constructor for a TClonesArray");
1873 return 0;
1874 }
1875 Int_t nch = strlen(name);
1877 TIter next(li);
1878 while ((obj = next())) {
1880 TCollection* col = (TCollection*) obj;
1881 if (nch) {
1882 branchname.Form("%s_%s_", name, col->GetName());
1883 } else {
1884 branchname.Form("%s_", col->GetName());
1885 }
1887 } else {
1888 if (nch && (name[nch-1] == '_')) {
1889 branchname.Form("%s%s", name, obj->GetName());
1890 } else {
1891 if (nch) {
1892 branchname.Form("%s_%s", name, obj->GetName());
1893 } else {
1894 branchname.Form("%s", obj->GetName());
1895 }
1896 }
1897 if (splitlevel > 99) {
1898 branchname += ".";
1899 }
1900 Bronch(branchname, obj->ClassName(), li->GetObjectRef(obj), bufsize, splitlevel - 1);
1901 }
1902 }
1903 return GetListOfBranches()->GetEntries() - nbranches;
1904}
1905
1906////////////////////////////////////////////////////////////////////////////////
1907/// Create one branch for each element in the folder.
1908/// Returns the total number of branches created.
1910Int_t TTree::Branch(const char* foldername, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
1911{
1912 TObject* ob = gROOT->FindObjectAny(foldername);
1913 if (!ob) {
1914 return 0;
1915 }
1916 if (ob->IsA() != TFolder::Class()) {
1917 return 0;
1918 }
1919 Int_t nbranches = GetListOfBranches()->GetEntries();
1920 TFolder* folder = (TFolder*) ob;
1921 TIter next(folder->GetListOfFolders());
1922 TObject* obj = nullptr;
1923 char* curname = new char[1000];
1924 char occur[20];
1925 while ((obj = next())) {
1926 snprintf(curname,1000, "%s/%s", foldername, obj->GetName());
1927 if (obj->IsA() == TFolder::Class()) {
1929 } else {
1930 void* add = (void*) folder->GetListOfFolders()->GetObjectRef(obj);
1931 for (Int_t i = 0; i < 1000; ++i) {
1932 if (curname[i] == 0) {
1933 break;
1934 }
1935 if (curname[i] == '/') {
1936 curname[i] = '.';
1937 }
1938 }
1939 Int_t noccur = folder->Occurence(obj);
1940 if (noccur > 0) {
1941 snprintf(occur,20, "_%d", noccur);
1942 strlcat(curname, occur,1000);
1943 }
1945 if (br) br->SetBranchFolder();
1946 }
1947 }
1948 delete[] curname;
1949 return GetListOfBranches()->GetEntries() - nbranches;
1950}
1951
1952////////////////////////////////////////////////////////////////////////////////
1953/// Create a new TTree Branch.
1954///
1955/// This Branch constructor is provided to support non-objects in
1956/// a Tree. The variables described in leaflist may be simple
1957/// variables or structures. // See the two following
1958/// constructors for writing objects in a Tree.
1959///
1960/// By default the branch buffers are stored in the same file as the Tree.
1961/// use TBranch::SetFile to specify a different file
1962///
1963/// * address is the address of the first item of a structure.
1964/// * leaflist is the concatenation of all the variable names and types
1965/// separated by a colon character :
1966/// The variable name and the variable type are separated by a slash (/).
1967/// The variable type may be 0,1 or 2 characters. If no type is given,
1968/// the type of the variable is assumed to be the same as the previous
1969/// variable. If the first variable does not have a type, it is assumed
1970/// of type `F` by default. The list of currently supported types is given below:
1971/// - `C` : a character string terminated by the 0 character
1972/// - `B` : an 8 bit integer (`Char_t`); Mostly signed, might be unsigned in special platforms or depending on compiler flags, thus do not use std::int8_t as underlying variable since they are not equivalent; Treated as a character when in an array.
1973/// - `b` : an 8 bit unsigned integer (`UChar_t`)
1974/// - `S` : a 16 bit signed integer (`Short_t`)
1975/// - `s` : a 16 bit unsigned integer (`UShort_t`)
1976/// - `I` : a 32 bit signed integer (`Int_t`)
1977/// - `i` : a 32 bit unsigned integer (`UInt_t`)
1978/// - `F` : a 32 bit floating point (`Float_t`)
1979/// - `f` : a 24 bit floating point with truncated mantissa (`Float16_t`)
1980/// - `D` : a 64 bit floating point (`Double_t`)
1981/// - `d` : a 24 bit truncated floating point (`Double32_t`)
1982/// - `L` : a 64 bit signed integer (`Long64_t`)
1983/// - `l` : a 64 bit unsigned integer (`ULong64_t`)
1984/// - `G` : a long signed integer, stored as 64 bit (`Long_t`)
1985/// - `g` : a long unsigned integer, stored as 64 bit (`ULong_t`)
1986/// - `O` : [the letter `o`, not a zero] a boolean (`bool`)
1987///
1988/// Arrays of values are supported with the following syntax:
1989/// - If leaf name has the form var[nelem], where nelem is alphanumeric, then
1990/// if nelem is a leaf name, it is used as the variable size of the array,
1991/// otherwise return 0.
1992/// The leaf referred to by nelem **MUST** be an int (/I),
1993/// - If leaf name has the form var[nelem], where nelem is a non-negative integer, then
1994/// it is used as the fixed size of the array.
1995/// - If leaf name has the form of a multi-dimensional array (e.g. var[nelem][nelem2])
1996/// where nelem and nelem2 are non-negative integer) then
1997/// it is used as a 2 dimensional array of fixed size.
1998/// - In case of the truncated floating point types (Float16_t and Double32_t) you can
1999/// furthermore specify the range in the style [xmin,xmax] or [xmin,xmax,nbits] after
2000/// the type character. See `TStreamerElement::GetRange()` for further information.
2001///
2002/// Any of other form is not supported.
2003///
2004/// Note that the TTree will assume that all the item are contiguous in memory.
2005/// On some platform, this is not always true of the member of a struct or a class,
2006/// due to padding and alignment. Sorting your data member in order of decreasing
2007/// sizeof usually leads to their being contiguous in memory.
2008///
2009/// * bufsize is the buffer size in bytes for this branch
2010/// The default value is 32000 bytes and should be ok for most cases.
2011/// You can specify a larger value (e.g. 256000) if your Tree is not split
2012/// and each entry is large (Megabytes)
2013/// A small value for bufsize is optimum if you intend to access
2014/// the entries in the Tree randomly and your Tree is in split mode.
2016TBranch* TTree::Branch(const char* name, void* address, const char* leaflist, Int_t bufsize /* = 32000 */)
2017{
2018 TBranch* branch = new TBranch(this, name, address, leaflist, bufsize);
2019 if (branch->IsZombie()) {
2020 delete branch;
2021 branch = nullptr;
2022 return nullptr;
2023 }
2025 return branch;
2026}
2027
2028////////////////////////////////////////////////////////////////////////////////
2029/// Create a new branch with the object of class classname at address addobj.
2030///
2031/// WARNING:
2032///
2033/// Starting with Root version 3.01, the Branch function uses the new style
2034/// branches (TBranchElement). To get the old behaviour, you can:
2035/// - call BranchOld or
2036/// - call TTree::SetBranchStyle(0)
2037///
2038/// Note that with the new style, classname does not need to derive from TObject.
2039/// It must derived from TObject if the branch style has been set to 0 (old)
2040///
2041/// Note: See the comments in TBranchElement::SetAddress() for a more
2042/// detailed discussion of the meaning of the addobj parameter in
2043/// the case of new-style branches.
2044///
2045/// Use splitlevel < 0 instead of splitlevel=0 when the class
2046/// has a custom Streamer
2047///
2048/// Note: if the split level is set to the default (99), TTree::Branch will
2049/// not issue a warning if the class can not be split.
2051TBranch* TTree::Branch(const char* name, const char* classname, void* addobj, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2052{
2053 if (fgBranchStyle == 1) {
2054 return Bronch(name, classname, addobj, bufsize, splitlevel);
2055 } else {
2056 if (splitlevel < 0) {
2057 splitlevel = 0;
2058 }
2059 return BranchOld(name, classname, addobj, bufsize, splitlevel);
2060 }
2061}
2062
2063////////////////////////////////////////////////////////////////////////////////
2064/// Create a new TTree BranchObject.
2065///
2066/// Build a TBranchObject for an object of class classname.
2067/// addobj is the address of a pointer to an object of class classname.
2068/// IMPORTANT: classname must derive from TObject.
2069/// The class dictionary must be available (ClassDef in class header).
2070///
2071/// This option requires access to the library where the corresponding class
2072/// is defined. Accessing one single data member in the object implies
2073/// reading the full object.
2074/// See the next Branch constructor for a more efficient storage
2075/// in case the entry consists of arrays of identical objects.
2076///
2077/// By default the branch buffers are stored in the same file as the Tree.
2078/// use TBranch::SetFile to specify a different file
2079///
2080/// IMPORTANT NOTE about branch names:
2081///
2082/// And in general, in case two or more master branches contain subbranches
2083/// with identical names, one must add a "." (dot) character at the end
2084/// of the master branch name. This will force the name of the subbranches
2085/// to be of the form `master.subbranch` instead of simply `subbranch`.
2086/// This situation happens when the top level object
2087/// has two or more members referencing the same class.
2088/// For example, if a Tree has two branches B1 and B2 corresponding
2089/// to objects of the same class MyClass, one can do:
2090/// ~~~ {.cpp}
2091/// tree.Branch("B1.","MyClass",&b1,8000,1);
2092/// tree.Branch("B2.","MyClass",&b2,8000,1);
2093/// ~~~
2094/// if MyClass has 3 members a,b,c, the two instructions above will generate
2095/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
2096///
2097/// bufsize is the buffer size in bytes for this branch
2098/// The default value is 32000 bytes and should be ok for most cases.
2099/// You can specify a larger value (e.g. 256000) if your Tree is not split
2100/// and each entry is large (Megabytes)
2101/// A small value for bufsize is optimum if you intend to access
2102/// the entries in the Tree randomly and your Tree is in split mode.
2104TBranch* TTree::BranchOld(const char* name, const char* classname, void* addobj, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 1 */)
2105{
2106 TClass* cl = TClass::GetClass(classname);
2107 if (!cl) {
2108 Error("BranchOld", "Cannot find class: '%s'", classname);
2109 return nullptr;
2110 }
2111 if (!cl->IsTObject()) {
2112 if (fgBranchStyle == 0) {
2113 Fatal("BranchOld", "The requested class ('%s') does not inherit from TObject.\n"
2114 "\tfgBranchStyle is set to zero requesting by default to use BranchOld.\n"
2115 "\tIf this is intentional use Bronch instead of Branch or BranchOld.", classname);
2116 } else {
2117 Fatal("BranchOld", "The requested class ('%s') does not inherit from TObject.\n"
2118 "\tYou can not use BranchOld to store objects of this type.",classname);
2119 }
2120 return nullptr;
2121 }
2122 TBranch* branch = new TBranchObject(this, name, classname, addobj, bufsize, splitlevel);
2124 if (!splitlevel) {
2125 return branch;
2126 }
2127 // We are going to fully split the class now.
2128 TObjArray* blist = branch->GetListOfBranches();
2129 const char* rdname = nullptr;
2130 const char* dname = nullptr;
2132 char** apointer = (char**) addobj;
2133 TObject* obj = (TObject*) *apointer;
2134 bool delobj = false;
2135 if (!obj) {
2136 obj = (TObject*) cl->New();
2137 delobj = true;
2138 }
2139 // Build the StreamerInfo if first time for the class.
2140 BuildStreamerInfo(cl, obj);
2141 // Loop on all public data members of the class and its base classes.
2143 Int_t isDot = 0;
2144 if (name[lenName-1] == '.') {
2145 isDot = 1;
2146 }
2147 TBranch* branch1 = nullptr;
2148 TRealData* rd = nullptr;
2149 TRealData* rdi = nullptr;
2151 TIter next(cl->GetListOfRealData());
2152 // Note: This loop results in a full split because the
2153 // real data list includes all data members of
2154 // data members.
2155 while ((rd = (TRealData*) next())) {
2156 if (rd->TestBit(TRealData::kTransient)) continue;
2157
2158 // Loop over all data members creating branches for each one.
2159 TDataMember* dm = rd->GetDataMember();
2160 if (!dm->IsPersistent()) {
2161 // Do not process members with an "!" as the first character in the comment field.
2162 continue;
2163 }
2164 if (rd->IsObject()) {
2165 // We skip data members of class type.
2166 // But we do build their real data, their
2167 // streamer info, and write their streamer
2168 // info to the current directory's file.
2169 // Oh yes, and we also do this for all of
2170 // their base classes.
2172 if (clm) {
2173 BuildStreamerInfo(clm, (char*) obj + rd->GetThisOffset());
2174 }
2175 continue;
2176 }
2177 rdname = rd->GetName();
2178 dname = dm->GetName();
2179 if (cl->CanIgnoreTObjectStreamer()) {
2180 // Skip the TObject base class data members.
2181 // FIXME: This prevents a user from ever
2182 // using these names themself!
2183 if (!strcmp(dname, "fBits")) {
2184 continue;
2185 }
2186 if (!strcmp(dname, "fUniqueID")) {
2187 continue;
2188 }
2189 }
2190 TDataType* dtype = dm->GetDataType();
2191 Int_t code = 0;
2192 if (dtype) {
2193 code = dm->GetDataType()->GetType();
2194 }
2195 // Encode branch name. Use real data member name
2197 if (isDot) {
2198 if (dm->IsaPointer()) {
2199 // FIXME: This is wrong! The asterisk is not usually in the front!
2200 branchname.Form("%s%s", name, &rdname[1]);
2201 } else {
2202 branchname.Form("%s%s", name, &rdname[0]);
2203 }
2204 }
2205 // FIXME: Change this to a string stream.
2207 Int_t offset = rd->GetThisOffset();
2208 char* pointer = ((char*) obj) + offset;
2209 if (dm->IsaPointer()) {
2210 // We have a pointer to an object or a pointer to an array of basic types.
2211 TClass* clobj = nullptr;
2212 if (!dm->IsBasic()) {
2214 }
2215 if (clobj && clobj->InheritsFrom(TClonesArray::Class())) {
2216 // We have a pointer to a clones array.
2217 char* cpointer = (char*) pointer;
2218 char** ppointer = (char**) cpointer;
2220 if (splitlevel != 2) {
2221 if (isDot) {
2223 } else {
2224 // FIXME: This is wrong! The asterisk is not usually in the front!
2225 branch1 = new TBranchClones(branch,&branchname.Data()[1], pointer, bufsize);
2226 }
2227 blist->Add(branch1);
2228 } else {
2229 if (isDot) {
2230 branch1 = new TBranchObject(branch, branchname, li->ClassName(), pointer, bufsize);
2231 } else {
2232 // FIXME: This is wrong! The asterisk is not usually in the front!
2233 branch1 = new TBranchObject(branch, &branchname.Data()[1], li->ClassName(), pointer, bufsize);
2234 }
2235 blist->Add(branch1);
2236 }
2237 } else if (clobj) {
2238 // We have a pointer to an object.
2239 //
2240 // It must be a TObject object.
2241 if (!clobj->IsTObject()) {
2242 continue;
2243 }
2244 branch1 = new TBranchObject(branch, dname, clobj->GetName(), pointer, bufsize, 0);
2245 if (isDot) {
2246 branch1->SetName(branchname);
2247 } else {
2248 // FIXME: This is wrong! The asterisk is not usually in the front!
2249 // Do not use the first character (*).
2250 branch1->SetName(&branchname.Data()[1]);
2251 }
2252 blist->Add(branch1);
2253 } else {
2254 // We have a pointer to an array of basic types.
2255 //
2256 // Check the comments in the text of the code for an index specification.
2257 const char* index = dm->GetArrayIndex();
2258 if (index[0]) {
2259 // We are a pointer to a varying length array of basic types.
2260 //check that index is a valid data member name
2261 //if member is part of an object (e.g. fA and index=fN)
2262 //index must be changed from fN to fA.fN
2263 TString aindex (rd->GetName());
2264 Ssiz_t rdot = aindex.Last('.');
2265 if (rdot>=0) {
2266 aindex.Remove(rdot+1);
2267 aindex.Append(index);
2268 }
2269 nexti.Reset();
2270 while ((rdi = (TRealData*) nexti())) {
2271 if (rdi->TestBit(TRealData::kTransient)) continue;
2272
2273 if (!strcmp(rdi->GetName(), index)) {
2274 break;
2275 }
2276 if (!strcmp(rdi->GetName(), aindex)) {
2277 index = rdi->GetName();
2278 break;
2279 }
2280 }
2281
2282 char vcode = DataTypeToChar((EDataType)code);
2283 // Note that we differentiate between strings and
2284 // char array by the fact that there is NO specified
2285 // size for a string (see next if (code == 1)
2286
2287 if (vcode) {
2288 leaflist.Form("%s[%s]/%c", &rdname[0], index, vcode);
2289 } else {
2290 Error("BranchOld", "Cannot create branch for rdname: %s code: %d", branchname.Data(), code);
2291 leaflist = "";
2292 }
2293 } else {
2294 // We are possibly a character string.
2295 if (code == 1) {
2296 // We are a character string.
2297 leaflist.Form("%s/%s", dname, "C");
2298 } else {
2299 // Invalid array specification.
2300 // FIXME: We need an error message here.
2301 continue;
2302 }
2303 }
2304 // There are '*' in both the branchname and leaflist, remove them.
2305 TString bname( branchname );
2306 bname.ReplaceAll("*","");
2307 leaflist.ReplaceAll("*","");
2308 // Add the branch to the tree and indicate that the address
2309 // is that of a pointer to be dereferenced before using.
2310 branch1 = new TBranch(branch, bname, *((void**) pointer), leaflist, bufsize);
2311 TLeaf* leaf = (TLeaf*) branch1->GetListOfLeaves()->At(0);
2313 leaf->SetAddress((void**) pointer);
2314 blist->Add(branch1);
2315 }
2316 } else if (dm->IsBasic()) {
2317 // We have a basic type.
2318
2319 char vcode = DataTypeToChar((EDataType)code);
2320 if (vcode) {
2321 leaflist.Form("%s/%c", rdname, vcode);
2322 } else {
2323 Error("BranchOld", "Cannot create branch for rdname: %s code: %d", branchname.Data(), code);
2324 leaflist = "";
2325 }
2326 branch1 = new TBranch(branch, branchname, pointer, leaflist, bufsize);
2327 branch1->SetTitle(rdname);
2328 blist->Add(branch1);
2329 } else {
2330 // We have a class type.
2331 // Note: This cannot happen due to the rd->IsObject() test above.
2332 // FIXME: Put an error message here just in case.
2333 }
2334 if (branch1) {
2335 branch1->SetOffset(offset);
2336 } else {
2337 Warning("BranchOld", "Cannot process member: '%s'", rdname);
2338 }
2339 }
2340 if (delobj) {
2341 delete obj;
2342 obj = nullptr;
2343 }
2344 return branch;
2345}
2346
2347////////////////////////////////////////////////////////////////////////////////
2348/// Build the optional branch supporting the TRefTable.
2349/// This branch will keep all the information to find the branches
2350/// containing referenced objects.
2351///
2352/// At each Tree::Fill, the branch numbers containing the
2353/// referenced objects are saved to the TBranchRef basket.
2354/// When the Tree header is saved (via TTree::Write), the branch
2355/// is saved keeping the information with the pointers to the branches
2356/// having referenced objects.
2359{
2360 if (!fBranchRef) {
2361 fBranchRef = new TBranchRef(this);
2362 }
2363 return fBranchRef;
2364}
2365
2366////////////////////////////////////////////////////////////////////////////////
2367/// Create a new TTree BranchElement.
2368///
2369/// ## WARNING about this new function
2370///
2371/// This function is designed to replace the internal
2372/// implementation of the old TTree::Branch (whose implementation
2373/// has been moved to BranchOld).
2374///
2375/// NOTE: The 'Bronch' method supports only one possible calls
2376/// signature (where the object type has to be specified
2377/// explicitly and the address must be the address of a pointer).
2378/// For more flexibility use 'Branch'. Use Bronch only in (rare)
2379/// cases (likely to be legacy cases) where both the new and old
2380/// implementation of Branch needs to be used at the same time.
2381///
2382/// This function is far more powerful than the old Branch
2383/// function. It supports the full C++, including STL and has
2384/// the same behaviour in split or non-split mode. classname does
2385/// not have to derive from TObject. The function is based on
2386/// the new TStreamerInfo.
2387///
2388/// Build a TBranchElement for an object of class classname.
2389///
2390/// addr is the address of a pointer to an object of class
2391/// classname. The class dictionary must be available (ClassDef
2392/// in class header).
2393///
2394/// Note: See the comments in TBranchElement::SetAddress() for a more
2395/// detailed discussion of the meaning of the addr parameter.
2396///
2397/// This option requires access to the library where the
2398/// corresponding class is defined. Accessing one single data
2399/// member in the object implies reading the full object.
2400///
2401/// By default the branch buffers are stored in the same file as the Tree.
2402/// use TBranch::SetFile to specify a different file
2403///
2404/// IMPORTANT NOTE about branch names:
2405///
2406/// And in general, in case two or more master branches contain subbranches
2407/// with identical names, one must add a "." (dot) character at the end
2408/// of the master branch name. This will force the name of the subbranches
2409/// to be of the form `master.subbranch` instead of simply `subbranch`.
2410/// This situation happens when the top level object
2411/// has two or more members referencing the same class.
2412/// For example, if a Tree has two branches B1 and B2 corresponding
2413/// to objects of the same class MyClass, one can do:
2414/// ~~~ {.cpp}
2415/// tree.Branch("B1.","MyClass",&b1,8000,1);
2416/// tree.Branch("B2.","MyClass",&b2,8000,1);
2417/// ~~~
2418/// if MyClass has 3 members a,b,c, the two instructions above will generate
2419/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
2420///
2421/// bufsize is the buffer size in bytes for this branch
2422/// The default value is 32000 bytes and should be ok for most cases.
2423/// You can specify a larger value (e.g. 256000) if your Tree is not split
2424/// and each entry is large (Megabytes)
2425/// A small value for bufsize is optimum if you intend to access
2426/// the entries in the Tree randomly and your Tree is in split mode.
2427///
2428/// Use splitlevel < 0 instead of splitlevel=0 when the class
2429/// has a custom Streamer
2430///
2431/// Note: if the split level is set to the default (99), TTree::Branch will
2432/// not issue a warning if the class can not be split.
2434TBranch* TTree::Bronch(const char* name, const char* classname, void* addr, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2435{
2436 return BronchExec(name, classname, addr, true, bufsize, splitlevel);
2437}
2438
2439////////////////////////////////////////////////////////////////////////////////
2440/// Helper function implementing TTree::Bronch and TTree::Branch(const char *name, T &obj);
2442TBranch* TTree::BronchExec(const char* name, const char* classname, void* addr, bool isptrptr, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2443{
2444 TClass* cl = TClass::GetClass(classname);
2445 if (!cl) {
2446 Error("Bronch", "Cannot find class:%s", classname);
2447 return nullptr;
2448 }
2449
2450 //if splitlevel <= 0 and class has a custom Streamer, we must create
2451 //a TBranchObject. We cannot assume that TClass::ReadBuffer is consistent
2452 //with the custom Streamer. The penalty is that one cannot process
2453 //this Tree without the class library containing the class.
2454
2455 char* objptr = nullptr;
2456 if (!isptrptr) {
2457 objptr = (char*)addr;
2458 } else if (addr) {
2459 objptr = *((char**) addr);
2460 }
2461
2462 if (cl == TClonesArray::Class()) {
2464 if (!clones) {
2465 Error("Bronch", "Pointer to TClonesArray is null");
2466 return nullptr;
2467 }
2468 if (!clones->GetClass()) {
2469 Error("Bronch", "TClonesArray with no class defined in branch: %s", name);
2470 return nullptr;
2471 }
2472 if (!clones->GetClass()->HasDataMemberInfo()) {
2473 Error("Bronch", "TClonesArray with no dictionary defined in branch: %s", name);
2474 return nullptr;
2475 }
2476 bool hasCustomStreamer = clones->GetClass()->HasCustomStreamerMember();
2477 if (splitlevel > 0) {
2479 Warning("Bronch", "Using split mode on a class: %s with a custom Streamer", clones->GetClass()->GetName());
2480 } else {
2481 if (hasCustomStreamer) clones->BypassStreamer(false);
2482 TBranchObject *branch = new TBranchObject(this,name,classname,addr,bufsize,0,/*compress=*/ -1,isptrptr);
2484 return branch;
2485 }
2486 }
2487
2488 if (cl->GetCollectionProxy()) {
2490 //if (!collProxy) {
2491 // Error("Bronch", "%s is missing its CollectionProxy (for branch %s)", classname, name);
2492 //}
2493 TClass* inklass = collProxy->GetValueClass();
2494 if (!inklass && (collProxy->GetType() == 0)) {
2495 Error("Bronch", "%s with no class defined in branch: %s", classname, name);
2496 return nullptr;
2497 }
2498 if ((splitlevel > 0) && inklass && (inklass->GetCollectionProxy() == nullptr)) {
2500 if ((stl != ROOT::kSTLmap) && (stl != ROOT::kSTLmultimap)) {
2501 if (!inklass->HasDataMemberInfo()) {
2502 Error("Bronch", "Container with no dictionary defined in branch: %s", name);
2503 return nullptr;
2504 }
2505 if (inklass->HasCustomStreamerMember()) {
2506 Warning("Bronch", "Using split mode on a class: %s with a custom Streamer", inklass->GetName());
2507 }
2508 }
2509 }
2510 //-------------------------------------------------------------------------
2511 // If the splitting switch is enabled, the split level is big enough and
2512 // the collection contains pointers we can split it
2513 //////////////////////////////////////////////////////////////////////////
2514
2515 TBranch *branch;
2516 if( splitlevel > kSplitCollectionOfPointers && collProxy->HasPointers() )
2518 else
2521 if (isptrptr) {
2522 branch->SetAddress(addr);
2523 } else {
2524 branch->SetObject(addr);
2525 }
2526 return branch;
2527 }
2528
2529 bool hasCustomStreamer = false;
2530 if (!cl->HasDataMemberInfo() && !cl->GetCollectionProxy()) {
2531 Error("Bronch", "Cannot find dictionary for class: %s", classname);
2532 return nullptr;
2533 }
2534
2535 if (!cl->GetCollectionProxy() && cl->HasCustomStreamerMember()) {
2536 // Not an STL container and the linkdef file had a "-" after the class name.
2537 hasCustomStreamer = true;
2538 }
2539
2540 if (splitlevel < 0 || ((splitlevel == 0) && hasCustomStreamer && cl->IsTObject())) {
2543 return branch;
2544 }
2545
2546 if (cl == TClonesArray::Class()) {
2547 // Special case of TClonesArray.
2548 // No dummy object is created.
2549 // The streamer info is not rebuilt unoptimized.
2550 // No dummy top-level branch is created.
2551 // No splitting is attempted.
2554 if (isptrptr) {
2555 branch->SetAddress(addr);
2556 } else {
2557 branch->SetObject(addr);
2558 }
2559 return branch;
2560 }
2561
2562 //
2563 // If we are not given an object to use as an i/o buffer
2564 // then create a temporary one which we will delete just
2565 // before returning.
2566 //
2567
2568 bool delobj = false;
2569
2570 if (!objptr) {
2571 objptr = (char*) cl->New();
2572 delobj = true;
2573 }
2574
2575 //
2576 // Avoid splitting unsplittable classes.
2577 //
2578
2579 if ((splitlevel > 0) && !cl->CanSplit()) {
2580 if (splitlevel != 99) {
2581 Warning("Bronch", "%s cannot be split, resetting splitlevel to 0", cl->GetName());
2582 }
2583 splitlevel = 0;
2584 }
2585
2586 //
2587 // Make sure the streamer info is built and fetch it.
2588 //
2589 // If we are splitting, then make sure the streamer info
2590 // is built unoptimized (data members are not combined).
2591 //
2592
2594 if (!sinfo) {
2595 Error("Bronch", "Cannot build the StreamerInfo for class: %s", cl->GetName());
2596 return nullptr;
2597 }
2598
2599 //
2600 // Create a dummy top level branch object.
2601 //
2602
2603 Int_t id = -1;
2604 if (splitlevel > 0) {
2605 id = -2;
2606 }
2609
2610 //
2611 // Do splitting, if requested.
2612 //
2613
2615 branch->Unroll(name, cl, sinfo, objptr, bufsize, splitlevel);
2616 }
2617
2618 //
2619 // Setup our offsets into the user's i/o buffer.
2620 //
2621
2622 if (isptrptr) {
2623 branch->SetAddress(addr);
2624 } else {
2625 branch->SetObject(addr);
2626 }
2627
2628 if (delobj) {
2629 cl->Destructor(objptr);
2630 objptr = nullptr;
2631 }
2632
2633 return branch;
2634}
2635
2636////////////////////////////////////////////////////////////////////////////////
2637/// Browse content of the TTree.
2640{
2642 if (fUserInfo) {
2643 if (strcmp("TList",fUserInfo->GetName())==0) {
2644 fUserInfo->SetName("UserInfo");
2645 b->Add(fUserInfo);
2646 fUserInfo->SetName("TList");
2647 } else {
2648 b->Add(fUserInfo);
2649 }
2650 }
2651}
2652
2653////////////////////////////////////////////////////////////////////////////////
2654/// Build a Tree Index (default is TTreeIndex).
2655/// See a description of the parameters and functionality in
2656/// TTreeIndex::TTreeIndex().
2657///
2658/// The return value is the number of entries in the Index (< 0 indicates failure).
2659///
2660/// A TTreeIndex object pointed by fTreeIndex is created.
2661/// This object will be automatically deleted by the TTree destructor.
2662/// If an index is already existing, this is replaced by the new one without being
2663/// deleted. This behaviour prevents the deletion of a previously external index
2664/// assigned to the TTree via the TTree::SetTreeIndex() method.
2665/// \see TTree::SetTreeIndex()
2667Int_t TTree::BuildIndex(const char* majorname, const char* minorname /* = "0" */, bool long64major, bool long64minor)
2668{
2670 if (fTreeIndex->IsZombie()) {
2671 delete fTreeIndex;
2672 fTreeIndex = nullptr;
2673 return 0;
2674 }
2675 return fTreeIndex->GetN();
2676}
2677
2678////////////////////////////////////////////////////////////////////////////////
2679/// Build StreamerInfo for class cl.
2680/// pointer is an optional argument that may contain a pointer to an object of cl.
2682TStreamerInfo* TTree::BuildStreamerInfo(TClass* cl, void* pointer /* = 0 */, bool canOptimize /* = true */ )
2683{
2684 if (!cl) {
2685 return nullptr;
2686 }
2687 cl->BuildRealData(pointer);
2689
2690 // Create StreamerInfo for all base classes.
2691 TBaseClass* base = nullptr;
2692 TIter nextb(cl->GetListOfBases());
2693 while((base = (TBaseClass*) nextb())) {
2694 if (base->IsSTLContainer()) {
2695 continue;
2696 }
2697 TClass* clm = TClass::GetClass(base->GetName());
2699 }
2700 if (sinfo && fDirectory) {
2701 sinfo->ForceWriteInfo(fDirectory->GetFile());
2702 }
2703 return sinfo;
2704}
2705
2706////////////////////////////////////////////////////////////////////////////////
2707/// Enable the TTreeCache unless explicitly disabled for this TTree by
2708/// a prior call to `SetCacheSize(0)`.
2709/// If the environment variable `ROOT_TTREECACHE_SIZE` or the rootrc config
2710/// `TTreeCache.Size` has been set to zero, this call will over-ride them with
2711/// a value of 1.0 (i.e. use a cache size to hold 1 cluster)
2712///
2713/// Return true if there is a cache attached to the `TTree` (either pre-exisiting
2714/// or created as part of this call)
2715bool TTree::EnableCache()
2716{
2717 TFile* file = GetCurrentFile();
2718 if (!file)
2719 return false;
2720 // Check for an existing cache
2721 TTreeCache* pf = GetReadCache(file);
2722 if (pf)
2723 return true;
2724 if (fCacheUserSet && fCacheSize == 0)
2725 return false;
2726 return (0 == SetCacheSizeAux(true, -1));
2727}
2728
2729////////////////////////////////////////////////////////////////////////////////
2730/// Called by TTree::Fill() when file has reached its maximum fgMaxTreeSize.
2731/// Create a new file. If the original file is named "myfile.root",
2732/// subsequent files are named "myfile_1.root", "myfile_2.root", etc.
2733///
2734/// Returns a pointer to the new file.
2735///
2736/// Currently, the automatic change of file is restricted
2737/// to the case where the tree is in the top level directory.
2738/// The file should not contain sub-directories.
2739///
2740/// Before switching to a new file, the tree header is written
2741/// to the current file, then the current file is closed.
2742///
2743/// To process the multiple files created by ChangeFile, one must use
2744/// a TChain.
2745///
2746/// The new file name has a suffix "_N" where N is equal to fFileNumber+1.
2747/// By default a Root session starts with fFileNumber=0. One can set
2748/// fFileNumber to a different value via TTree::SetFileNumber.
2749/// In case a file named "_N" already exists, the function will try
2750/// a file named "__N", then "___N", etc.
2751///
2752/// fgMaxTreeSize can be set via the static function TTree::SetMaxTreeSize.
2753/// The default value of fgMaxTreeSize is 100 Gigabytes.
2754///
2755/// If the current file contains other objects like TH1 and TTree,
2756/// these objects are automatically moved to the new file.
2757///
2758/// \warning Be careful when writing the final Tree header to the file!
2759/// Don't do:
2760/// ~~~ {.cpp}
2761/// TFile *file = new TFile("myfile.root","recreate");
2762/// TTree *T = new TTree("T","title");
2763/// T->Fill(); // Loop
2764/// file->Write();
2765/// file->Close();
2766/// ~~~
2767/// \warning but do the following:
2768/// ~~~ {.cpp}
2769/// TFile *file = new TFile("myfile.root","recreate");
2770/// TTree *T = new TTree("T","title");
2771/// T->Fill(); // Loop
2772/// file = T->GetCurrentFile(); // To get the pointer to the current file
2773/// file->Write();
2774/// file->Close();
2775/// ~~~
2776///
2777/// \note This method is never called if the input file is a `TMemFile` or derivate.
2780{
2781 // Changing file clashes with the design of TMemFile and derivates, see #6523,
2782 // as well as with TFileMerger operations, see #6640.
2783 if ((dynamic_cast<TMemFile *>(file)) || file->TestBit(TFile::kCancelTTreeChangeRequest))
2784 return file;
2785 file->cd();
2786 Write();
2787 Reset();
2788 constexpr auto kBufSize = 2000;
2789 char* fname = new char[kBufSize];
2790 ++fFileNumber;
2791 char uscore[10];
2792 for (Int_t i = 0; i < 10; ++i) {
2793 uscore[i] = 0;
2794 }
2795 Int_t nus = 0;
2796 // Try to find a suitable file name that does not already exist.
2797 while (nus < 10) {
2798 uscore[nus] = '_';
2799 fname[0] = 0;
2800 strlcpy(fname, file->GetName(), kBufSize);
2801
2802 if (fFileNumber > 1) {
2803 char* cunder = strrchr(fname, '_');
2804 if (cunder) {
2806 const char* cdot = strrchr(file->GetName(), '.');
2807 if (cdot) {
2809 }
2810 } else {
2811 char fcount[21];
2812 snprintf(fcount,21, "%s%d", uscore, fFileNumber);
2814 }
2815 } else {
2816 char* cdot = strrchr(fname, '.');
2817 if (cdot) {
2819 strlcat(fname, strrchr(file->GetName(), '.'), kBufSize);
2820 } else {
2821 char fcount[21];
2822 snprintf(fcount,21, "%s%d", uscore, fFileNumber);
2824 }
2825 }
2827 break;
2828 }
2829 ++nus;
2830 Warning("ChangeFile", "file %s already exists, trying with %d underscores", fname, nus + 1);
2831 }
2833 TFile* newfile = TFile::Open(fname, "recreate", "chain files", compress);
2834 if (newfile == nullptr) {
2835 Error("Fill","Failed to open new file %s, continuing as a memory tree.",fname);
2836 } else {
2837 Printf("Fill: Switching to new file: %s", fname);
2838 }
2839 // The current directory may contain histograms and trees.
2840 // These objects must be moved to the new file.
2841 TBranch* branch = nullptr;
2842 TObject* obj = nullptr;
2843 while ((obj = file->GetList()->First())) {
2844 file->Remove(obj);
2845 // Histogram: just change the directory.
2846 if (obj->InheritsFrom("TH1")) {
2847 gROOT->ProcessLine(TString::Format("((%s*)0x%zx)->SetDirectory((TDirectory*)0x%zx);", obj->ClassName(), (size_t) obj, (size_t) newfile));
2848 continue;
2849 }
2850 // Tree: must save all trees in the old file, reset them.
2851 if (obj->InheritsFrom(TTree::Class())) {
2852 TTree* t = (TTree*) obj;
2853 if (t != this) {
2854 t->AutoSave();
2855 t->Reset();
2857 }
2860 while ((branch = (TBranch*)nextb())) {
2861 branch->SetFile(newfile);
2862 }
2863 if (t->GetBranchRef()) {
2864 t->GetBranchRef()->SetFile(newfile);
2865 }
2866 continue;
2867 }
2868 // Not a TH1 or a TTree, move object to new file.
2869 if (newfile) newfile->Append(obj);
2870 file->Remove(obj);
2871 }
2872 file->TObject::Delete();
2873 file = nullptr;
2874 delete[] fname;
2875 fname = nullptr;
2876 return newfile;
2877}
2878
2879////////////////////////////////////////////////////////////////////////////////
2880/// Check whether or not the address described by the last 3 parameters
2881/// matches the content of the branch. If a Data Model Evolution conversion
2882/// is involved, reset the fInfo of the branch.
2883/// The return values are:
2884//
2885/// - kMissingBranch (-5) : Missing branch
2886/// - kInternalError (-4) : Internal error (could not find the type corresponding to a data type number)
2887/// - kMissingCompiledCollectionProxy (-3) : Missing compiled collection proxy for a compiled collection
2888/// - kMismatch (-2) : Non-Class Pointer type given does not match the type expected by the branch
2889/// - kClassMismatch (-1) : Class Pointer type given does not match the type expected by the branch
2890/// - kMatch (0) : perfect match
2891/// - kMatchConversion (1) : match with (I/O) conversion
2892/// - kMatchConversionCollection (2) : match with (I/O) conversion of the content of a collection
2893/// - kMakeClass (3) : MakeClass mode so we can not check.
2894/// - kVoidPtr (4) : void* passed so no check was made.
2895/// - kNoCheck (5) : Underlying TBranch not yet available so no check was made.
2896/// In addition this can be multiplexed with the two bits:
2897/// - kNeedEnableDecomposedObj : in order for the address (type) to be 'usable' the branch needs to be in Decomposed Object (aka MakeClass) mode.
2898/// - kNeedDisableDecomposedObj : in order for the address (type) to be 'usable' the branch needs to not be in Decomposed Object (aka MakeClass) mode.
2899/// This bits can be masked out by using kDecomposedObjMask
2902{
2903 if (GetMakeClass()) {
2904 // If we are in MakeClass mode so we do not really use classes.
2905 return kMakeClass;
2906 }
2907
2908 // Let's determine what we need!
2909 TClass* expectedClass = nullptr;
2911 if (0 != branch->GetExpectedType(expectedClass,expectedType) ) {
2912 // Something went wrong, the warning message has already been issued.
2913 return kInternalError;
2914 }
2915 bool isBranchElement = branch->InheritsFrom( TBranchElement::Class() );
2916 if (expectedClass && datatype == kOther_t && ptrClass == nullptr) {
2917 if (isBranchElement) {
2919 bEl->SetTargetClass( expectedClass->GetName() );
2920 }
2921 if (expectedClass && expectedClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(expectedClass->GetCollectionProxy())) {
2922 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2923 "The class expected (%s) refers to an stl collection and do not have a compiled CollectionProxy. "
2924 "Please generate the dictionary for this class (%s)",
2925 branch->GetName(), expectedClass->GetName(), expectedClass->GetName());
2927 }
2928 if (!expectedClass->IsLoaded()) {
2929 // The originally expected class does not have a dictionary, it is then plausible that the pointer being passed is the right type
2930 // (we really don't know). So let's express that.
2931 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2932 "The class expected (%s) does not have a dictionary and needs to be emulated for I/O purposes but is being passed a compiled object."
2933 "Please generate the dictionary for this class (%s)",
2934 branch->GetName(), expectedClass->GetName(), expectedClass->GetName());
2935 } else {
2936 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2937 "This is probably due to a missing dictionary, the original data class for this branch is %s.", branch->GetName(), expectedClass->GetName());
2938 }
2939 return kClassMismatch;
2940 }
2941 if (expectedClass && ptrClass && (branch->GetMother() == branch)) {
2942 // Top Level branch
2943 if (!isptr) {
2944 Error("SetBranchAddress", "The address for \"%s\" should be the address of a pointer!", branch->GetName());
2945 }
2946 }
2947 if (expectedType == kFloat16_t) {
2949 }
2950 if (expectedType == kDouble32_t) {
2952 }
2953 if (datatype == kFloat16_t) {
2955 }
2956 if (datatype == kDouble32_t) {
2958 }
2959
2960 /////////////////////////////////////////////////////////////////////////////
2961 // Deal with the class renaming
2962 /////////////////////////////////////////////////////////////////////////////
2963
2964 if( expectedClass && ptrClass &&
2967 ptrClass->GetSchemaRules() &&
2968 ptrClass->GetSchemaRules()->HasRuleWithSourceClass( expectedClass->GetName() ) ) {
2970
2971 if ( ptrClass->GetCollectionProxy() && expectedClass->GetCollectionProxy() ) {
2972 if (gDebug > 7)
2973 Info("SetBranchAddress", "Matching STL collection (at least according to the SchemaRuleSet when "
2974 "reading a %s into a %s",expectedClass->GetName(),ptrClass->GetName());
2975
2976 bEl->SetTargetClass( ptrClass->GetName() );
2977 return kMatchConversion;
2978
2979 } else if ( !ptrClass->GetConversionStreamerInfo( expectedClass, bEl->GetClassVersion() ) &&
2980 !ptrClass->FindConversionStreamerInfo( expectedClass, bEl->GetCheckSum() ) ) {
2981 Error("SetBranchAddress", "The pointer type given \"%s\" does not correspond to the type needed \"%s\" by the branch: %s", ptrClass->GetName(), bEl->GetClassName(), branch->GetName());
2982
2983 bEl->SetTargetClass( expectedClass->GetName() );
2984 return kClassMismatch;
2985 }
2986 else {
2987
2988 bEl->SetTargetClass( ptrClass->GetName() );
2989 return kMatchConversion;
2990 }
2991
2992 } else if (expectedClass && ptrClass && !expectedClass->InheritsFrom(ptrClass)) {
2993
2994 if (expectedClass->GetCollectionProxy() && ptrClass->GetCollectionProxy() &&
2996 expectedClass->GetCollectionProxy()->GetValueClass() &&
2997 ptrClass->GetCollectionProxy()->GetValueClass() )
2998 {
2999 // In case of collection, we know how to convert them, if we know how to convert their content.
3000 // NOTE: we need to extend this to std::pair ...
3001
3002 TClass *onfileValueClass = expectedClass->GetCollectionProxy()->GetValueClass();
3003 TClass *inmemValueClass = ptrClass->GetCollectionProxy()->GetValueClass();
3004
3005 if (inmemValueClass->GetSchemaRules() &&
3006 inmemValueClass->GetSchemaRules()->HasRuleWithSourceClass(onfileValueClass->GetName() ) )
3007 {
3009 bEl->SetTargetClass( ptrClass->GetName() );
3011 }
3012 }
3013
3014 Error("SetBranchAddress", "The pointer type given (%s) does not correspond to the class needed (%s) by the branch: %s", ptrClass->GetName(), expectedClass->GetName(), branch->GetName());
3015 if (isBranchElement) {
3017 bEl->SetTargetClass( expectedClass->GetName() );
3018 }
3019 return kClassMismatch;
3020
3021 } else if ((expectedType != kOther_t) && (datatype != kOther_t) && (expectedType != kNoType_t) && (datatype != kNoType_t) && (expectedType != datatype)) {
3022 if (datatype != kChar_t) {
3023 // For backward compatibility we assume that (char*) was just a cast and/or a generic address
3024 Error("SetBranchAddress", "The pointer type given \"%s\" (%d) does not correspond to the type needed \"%s\" (%d) by the branch: %s",
3026 return kMismatch;
3027 }
3028 } else if ((expectedClass && (datatype != kOther_t && datatype != kNoType_t && datatype != kInt_t)) ||
3030 // Sometime a null pointer can look an int, avoid complaining in that case.
3031 if (expectedClass) {
3032 Error("SetBranchAddress", "The pointer type given \"%s\" (%d) does not correspond to the type needed \"%s\" by the branch: %s",
3033 TDataType::GetTypeName(datatype), datatype, expectedClass->GetName(), branch->GetName());
3034 if (isBranchElement) {
3036 bEl->SetTargetClass( expectedClass->GetName() );
3037 }
3038 } else {
3039 // In this case, it is okay if the first data member is of the right type (to support the case where we are being passed
3040 // a struct).
3041 bool found = false;
3042 if (ptrClass->IsLoaded()) {
3043 TIter next(ptrClass->GetListOfRealData());
3044 TRealData *rdm;
3045 while ((rdm = (TRealData*)next())) {
3046 if (rdm->GetThisOffset() == 0) {
3047 TDataType *dmtype = rdm->GetDataMember()->GetDataType();
3048 if (dmtype) {
3049 EDataType etype = (EDataType)dmtype->GetType();
3050 if (etype == expectedType) {
3051 found = true;
3052 }
3053 }
3054 break;
3055 }
3056 }
3057 } else {
3058 TIter next(ptrClass->GetListOfDataMembers());
3059 TDataMember *dm;
3060 while ((dm = (TDataMember*)next())) {
3061 if (dm->GetOffset() == 0) {
3062 TDataType *dmtype = dm->GetDataType();
3063 if (dmtype) {
3064 EDataType etype = (EDataType)dmtype->GetType();
3065 if (etype == expectedType) {
3066 found = true;
3067 }
3068 }
3069 break;
3070 }
3071 }
3072 }
3073 if (found) {
3074 // let's check the size.
3075 TLeaf *last = (TLeaf*)branch->GetListOfLeaves()->Last();
3076 long len = last->GetOffset() + last->GetLenType() * last->GetLen();
3077 if (len <= ptrClass->Size()) {
3078 return kMatch;
3079 }
3080 }
3081 Error("SetBranchAddress", "The pointer type given \"%s\" does not correspond to the type needed \"%s\" (%d) by the branch: %s",
3083 }
3084 return kMismatch;
3085 }
3086 if (expectedClass && expectedClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(expectedClass->GetCollectionProxy())) {
3087 Error("SetBranchAddress", writeStlWithoutProxyMsg,
3088 expectedClass->GetName(), branch->GetName(), expectedClass->GetName());
3089 if (isBranchElement) {
3091 bEl->SetTargetClass( expectedClass->GetName() );
3092 }
3094 }
3095 if (isBranchElement) {
3096 if (expectedClass) {
3098 bEl->SetTargetClass( expectedClass->GetName() );
3099 } else if (expectedType != kNoType_t && expectedType != kOther_t) {
3101 }
3102 }
3103 return kMatch;
3104}
3105
3106////////////////////////////////////////////////////////////////////////////////
3107/// Create a clone of this tree and copy nentries.
3108///
3109/// By default copy all entries.
3110/// The compression level of the cloned tree is set to the destination
3111/// file's compression level.
3112///
3113/// NOTE: Only active branches are copied. See TTree::SetBranchStatus for more
3114/// information and usage regarding the (de)activation of branches. More
3115/// examples are provided in the tutorials listed below.
3116///
3117/// NOTE: If the TTree is a TChain, the structure of the first TTree
3118/// is used for the copy.
3119///
3120/// IMPORTANT: The cloned tree stays connected with this tree until
3121/// this tree is deleted. In particular, any changes in
3122/// branch addresses in this tree are forwarded to the
3123/// clone trees, unless a branch in a clone tree has had
3124/// its address changed, in which case that change stays in
3125/// effect. When this tree is deleted, all the addresses of
3126/// the cloned tree are reset to their default values.
3127///
3128/// If 'option' contains the word 'fast' and nentries is -1, the
3129/// cloning will be done without unzipping or unstreaming the baskets
3130/// (i.e., a direct copy of the raw bytes on disk).
3131///
3132/// When 'fast' is specified, 'option' can also contain a sorting
3133/// order for the baskets in the output file.
3134///
3135/// There are currently 3 supported sorting order:
3136///
3137/// - SortBasketsByOffset (the default)
3138/// - SortBasketsByBranch
3139/// - SortBasketsByEntry
3140///
3141/// When using SortBasketsByOffset the baskets are written in the
3142/// output file in the same order as in the original file (i.e. the
3143/// baskets are sorted by their offset in the original file; Usually
3144/// this also means that the baskets are sorted by the index/number of
3145/// the _last_ entry they contain)
3146///
3147/// When using SortBasketsByBranch all the baskets of each individual
3148/// branches are stored contiguously. This tends to optimize reading
3149/// speed when reading a small number (1->5) of branches, since all
3150/// their baskets will be clustered together instead of being spread
3151/// across the file. However it might decrease the performance when
3152/// reading more branches (or the full entry).
3153///
3154/// When using SortBasketsByEntry the baskets with the lowest starting
3155/// entry are written first. (i.e. the baskets are sorted by the
3156/// index/number of the first entry they contain). This means that on
3157/// the file the baskets will be in the order in which they will be
3158/// needed when reading the whole tree sequentially.
3159///
3160/// For examples of CloneTree, see tutorials:
3161///
3162/// - copytree.C:
3163/// A macro to copy a subset of a TTree to a new TTree.
3164/// The input file has been generated by the program in
3165/// $ROOTSYS/test/Event with: Event 1000 1 1 1
3166///
3167/// - copytree2.C:
3168/// A macro to copy a subset of a TTree to a new TTree.
3169/// One branch of the new Tree is written to a separate file.
3170/// The input file has been generated by the program in
3171/// $ROOTSYS/test/Event with: Event 1000 1 1 1
3173TTree* TTree::CloneTree(Long64_t nentries /* = -1 */, Option_t* option /* = "" */)
3174{
3175 // Options
3176 bool fastClone = false;
3177
3178 TString opt = option;
3179 opt.ToLower();
3180 if (opt.Contains("fast")) {
3181 fastClone = true;
3182 }
3183
3184 // If we are a chain, switch to the first tree.
3185 if (fEntries > 0) {
3186 const auto res = LoadTree(0);
3187 if (res < -2 || res == -1) {
3188 // -1 is not accepted, it happens when no trees were defined
3189 // -2 is the only acceptable error, when the chain has zero entries, but tree(s) were defined
3190 // Other errors (-3, ...) are not accepted
3191 Error("CloneTree", "returning nullptr since LoadTree failed with code %lld.", res);
3192 return nullptr;
3193 }
3194 }
3195
3196 // Note: For a tree we get the this pointer, for
3197 // a chain we get the chain's current tree.
3198 TTree* thistree = GetTree();
3199
3200 // We will use this to override the IO features on the cloned branches.
3202 ;
3203
3204 // Note: For a chain, the returned clone will be
3205 // a clone of the chain's first tree.
3206 TTree* newtree = (TTree*) thistree->Clone();
3207 if (!newtree) {
3208 return nullptr;
3209 }
3210
3211 // The clone should not delete any objects allocated by SetAddress().
3212 TObjArray* branches = newtree->GetListOfBranches();
3213 Int_t nb = branches->GetEntriesFast();
3214 for (Int_t i = 0; i < nb; ++i) {
3215 TBranch* br = (TBranch*) branches->UncheckedAt(i);
3216 if (br->InheritsFrom(TBranchElement::Class())) {
3217 ((TBranchElement*) br)->ResetDeleteObject();
3218 }
3219 }
3220
3221 // Add the new tree to the list of clones so that
3222 // we can later inform it of changes to branch addresses.
3223 thistree->AddClone(newtree);
3224 if (thistree != this) {
3225 // In case this object is a TChain, add the clone
3226 // also to the TChain's list of clones.
3228 }
3229
3230 newtree->Reset();
3231
3232 TDirectory* ndir = newtree->GetDirectory();
3233 TFile* nfile = nullptr;
3234 if (ndir) {
3235 nfile = ndir->GetFile();
3236 }
3237 Int_t newcomp = -1;
3238 if (nfile) {
3239 newcomp = nfile->GetCompressionSettings();
3240 }
3241
3242 //
3243 // Delete non-active branches from the clone.
3244 //
3245 // Note: If we are a chain, this does nothing
3246 // since chains have no leaves.
3247 TObjArray* leaves = newtree->GetListOfLeaves();
3248 Int_t nleaves = leaves->GetEntriesFast();
3249 for (Int_t lndx = 0; lndx < nleaves; ++lndx) {
3250 TLeaf* leaf = (TLeaf*) leaves->UncheckedAt(lndx);
3251 if (!leaf) {
3252 continue;
3253 }
3254 TBranch* branch = leaf->GetBranch();
3255 if (branch && (newcomp > -1)) {
3256 branch->SetCompressionSettings(newcomp);
3257 }
3258 if (branch) branch->SetIOFeatures(features);
3259 if (!branch || !branch->TestBit(kDoNotProcess)) {
3260 continue;
3261 }
3262 // size might change at each iteration of the loop over the leaves.
3263 nb = branches->GetEntriesFast();
3264 for (Long64_t i = 0; i < nb; ++i) {
3265 TBranch* br = (TBranch*) branches->UncheckedAt(i);
3266 if (br == branch) {
3267 branches->RemoveAt(i);
3268 delete br;
3269 br = nullptr;
3270 branches->Compress();
3271 break;
3272 }
3273 TObjArray* lb = br->GetListOfBranches();
3274 Int_t nb1 = lb->GetEntriesFast();
3275 for (Int_t j = 0; j < nb1; ++j) {
3276 TBranch* b1 = (TBranch*) lb->UncheckedAt(j);
3277 if (!b1) {
3278 continue;
3279 }
3280 if (b1 == branch) {
3281 lb->RemoveAt(j);
3282 delete b1;
3283 b1 = nullptr;
3284 lb->Compress();
3285 break;
3286 }
3288 Int_t nb2 = lb1->GetEntriesFast();
3289 for (Int_t k = 0; k < nb2; ++k) {
3290 TBranch* b2 = (TBranch*) lb1->UncheckedAt(k);
3291 if (!b2) {
3292 continue;
3293 }
3294 if (b2 == branch) {
3295 lb1->RemoveAt(k);
3296 delete b2;
3297 b2 = nullptr;
3298 lb1->Compress();
3299 break;
3300 }
3301 }
3302 }
3303 }
3304 }
3305 leaves->Compress();
3306
3307 // Copy MakeClass status.
3308 newtree->SetMakeClass(fMakeClass);
3309
3310 // Copy branch addresses.
3312
3313 //
3314 // Copy entries if requested.
3315 //
3316
3317 if (nentries != 0) {
3318 if (fastClone && (nentries < 0)) {
3319 if ( newtree->CopyEntries( this, -1, option, false ) < 0 ) {
3320 // There was a problem!
3321 Error("CloneTTree", "TTree has not been cloned\n");
3322 delete newtree;
3323 newtree = nullptr;
3324 return nullptr;
3325 }
3326 } else {
3327 newtree->CopyEntries( this, nentries, option, false );
3328 }
3329 }
3330
3331 return newtree;
3332}
3333
3334////////////////////////////////////////////////////////////////////////////////
3335/// Set branch addresses of passed tree equal to ours.
3336/// If undo is true, reset the branch addresses instead of copying them.
3337/// This ensures 'separation' of a cloned tree from its original.
3339void TTree::CopyAddresses(TTree* tree, bool undo)
3340{
3341 // Copy branch addresses starting from branches.
3343 Int_t nbranches = branches->GetEntriesFast();
3344 for (Int_t i = 0; i < nbranches; ++i) {
3345 TBranch* branch = (TBranch*) branches->UncheckedAt(i);
3346 if (branch->TestBit(kDoNotProcess)) {
3347 continue;
3348 }
3349 if (undo) {
3350 TBranch* br = tree->GetBranch(branch->GetName());
3351 tree->ResetBranchAddress(br);
3352 } else {
3353 char* addr = branch->GetAddress();
3354 if (!addr) {
3355 if (branch->IsA() == TBranch::Class()) {
3356 // If the branch was created using a leaflist, the branch itself may not have
3357 // an address but the leaf might already.
3358 TLeaf *firstleaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
3359 if (!firstleaf || firstleaf->GetValuePointer()) {
3360 // Either there is no leaf (and thus no point in copying the address)
3361 // or the leaf has an address but we can not copy it via the branche
3362 // this will be copied via the next loop (over the leaf).
3363 continue;
3364 }
3365 }
3366 // Note: This may cause an object to be allocated.
3367 branch->SetAddress(nullptr);
3368 addr = branch->GetAddress();
3369 }
3370 TBranch* br = tree->GetBranch(branch->GetFullName());
3371 if (br) {
3372 if (br->GetMakeClass() != branch->GetMakeClass())
3373 br->SetMakeClass(branch->GetMakeClass());
3374 br->SetAddress(addr);
3375 // The copy does not own any object allocated by SetAddress().
3376 if (br->InheritsFrom(TBranchElement::Class())) {
3377 ((TBranchElement*) br)->ResetDeleteObject();
3378 }
3379 } else {
3380 Warning("CopyAddresses", "Could not find branch named '%s' in tree named '%s'", branch->GetName(), tree->GetName());
3381 }
3382 }
3383 }
3384
3385 // Copy branch addresses starting from leaves.
3387 Int_t ntleaves = tleaves->GetEntriesFast();
3388 std::set<TLeaf*> updatedLeafCount;
3389 for (Int_t i = 0; i < ntleaves; ++i) {
3390 TLeaf* tleaf = (TLeaf*) tleaves->UncheckedAt(i);
3391 TBranch* tbranch = tleaf->GetBranch();
3392 TBranch* branch = GetBranch(tbranch->GetName());
3393 if (!branch) {
3394 continue;
3395 }
3396 TLeaf* leaf = branch->GetLeaf(tleaf->GetName());
3397 if (!leaf) {
3398 continue;
3399 }
3400 if (branch->TestBit(kDoNotProcess)) {
3401 continue;
3402 }
3403 if (undo) {
3404 // Now we know whether the address has been transferred
3406 } else {
3407 TBranchElement *mother = dynamic_cast<TBranchElement*>(leaf->GetBranch()->GetMother());
3408 bool needAddressReset = false;
3409 if (leaf->GetLeafCount() && (leaf->TestBit(TLeaf::kNewValue) || !leaf->GetValuePointer() || (mother && mother->IsObjectOwner())) && tleaf->GetLeafCount())
3410 {
3411 // If it is an array and it was allocated by the leaf itself,
3412 // let's make sure it is large enough for the incoming data.
3413 if (leaf->GetLeafCount()->GetMaximum() < tleaf->GetLeafCount()->GetMaximum()) {
3414 leaf->GetLeafCount()->IncludeRange( tleaf->GetLeafCount() );
3415 updatedLeafCount.insert(leaf->GetLeafCount());
3416 needAddressReset = true;
3417 } else {
3418 needAddressReset = (updatedLeafCount.find(leaf->GetLeafCount()) != updatedLeafCount.end());
3419 }
3420 }
3421 if (needAddressReset && leaf->GetValuePointer()) {
3422 if (leaf->IsA() == TLeafElement::Class() && mother)
3423 mother->ResetAddress();
3424 else
3425 leaf->SetAddress(nullptr);
3426 }
3427 if (!branch->GetAddress() && !leaf->GetValuePointer()) {
3428 // We should attempts to set the address of the branch.
3429 // something like:
3430 //(TBranchElement*)branch->GetMother()->SetAddress(0)
3431 //plus a few more subtleties (see TBranchElement::GetEntry).
3432 //but for now we go the simplest route:
3433 //
3434 // Note: This may result in the allocation of an object.
3435 branch->SetupAddresses();
3436 }
3437 if (branch->GetAddress()) {
3438 tree->SetBranchAddress(branch->GetName(), (void*) branch->GetAddress());
3439 TBranch* br = tree->GetBranch(branch->GetName());
3440 if (br) {
3441 if (br->IsA() != branch->IsA()) {
3442 Error(
3443 "CopyAddresses",
3444 "Branch kind mismatch between input tree '%s' and output tree '%s' for branch '%s': '%s' vs '%s'",
3445 tree->GetName(), br->GetTree()->GetName(), br->GetName(), branch->IsA()->GetName(),
3446 br->IsA()->GetName());
3447 }
3448 // The copy does not own any object allocated by SetAddress().
3449 // FIXME: We do too much here, br may not be a top-level branch.
3450 if (br->InheritsFrom(TBranchElement::Class())) {
3451 ((TBranchElement*) br)->ResetDeleteObject();
3452 }
3453 } else {
3454 Warning("CopyAddresses", "Could not find branch named '%s' in tree named '%s'", branch->GetName(), tree->GetName());
3455 }
3456 } else {
3457 tleaf->SetAddress(leaf->GetValuePointer());
3458 }
3459 }
3460 }
3461
3462 if (undo &&
3463 ( tree->IsA()->InheritsFrom("TNtuple") || tree->IsA()->InheritsFrom("TNtupleD") )
3464 ) {
3465 tree->ResetBranchAddresses();
3466 }
3467}
3468
3469namespace {
3470
3471 enum EOnIndexError { kDrop, kKeep, kBuild };
3472
3473 bool R__HandleIndex(EOnIndexError onIndexError, TTree *newtree, TTree *oldtree)
3474 {
3475 // Return true if we should continue to handle indices, false otherwise.
3476
3477 bool withIndex = true;
3478
3479 if ( newtree->GetTreeIndex() ) {
3480 if ( oldtree->GetTree()->GetTreeIndex() == nullptr ) {
3481 switch (onIndexError) {
3482 case kDrop:
3483 delete newtree->GetTreeIndex();
3484 newtree->SetTreeIndex(nullptr);
3485 withIndex = false;
3486 break;
3487 case kKeep:
3488 // Nothing to do really.
3489 break;
3490 case kBuild:
3491 // Build the index then copy it
3492 if (oldtree->GetTree()->BuildIndex(newtree->GetTreeIndex()->GetMajorName(), newtree->GetTreeIndex()->GetMinorName())) {
3493 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3494 // Clean up
3495 delete oldtree->GetTree()->GetTreeIndex();
3496 oldtree->GetTree()->SetTreeIndex(nullptr);
3497 }
3498 break;
3499 }
3500 } else {
3501 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3502 }
3503 } else if ( oldtree->GetTree()->GetTreeIndex() != nullptr ) {
3504 // We discover the first index in the middle of the chain.
3505 switch (onIndexError) {
3506 case kDrop:
3507 // Nothing to do really.
3508 break;
3509 case kKeep: {
3510 TVirtualIndex *index = (TVirtualIndex*) oldtree->GetTree()->GetTreeIndex()->Clone();
3511 index->SetTree(newtree);
3512 newtree->SetTreeIndex(index);
3513 break;
3514 }
3515 case kBuild:
3516 if (newtree->GetEntries() == 0) {
3517 // Start an index.
3518 TVirtualIndex *index = (TVirtualIndex*) oldtree->GetTree()->GetTreeIndex()->Clone();
3519 index->SetTree(newtree);
3520 newtree->SetTreeIndex(index);
3521 } else {
3522 // Build the index so far.
3523 if (newtree->BuildIndex(oldtree->GetTree()->GetTreeIndex()->GetMajorName(), oldtree->GetTree()->GetTreeIndex()->GetMinorName())) {
3524 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3525 }
3526 }
3527 break;
3528 }
3529 } else if ( onIndexError == kDrop ) {
3530 // There is no index on this or on tree->GetTree(), we know we have to ignore any further
3531 // index
3532 withIndex = false;
3533 }
3534 return withIndex;
3535 }
3536}
3537
3538////////////////////////////////////////////////////////////////////////////////
3539/// Copy nentries from given tree to this tree.
3540/// This routines assumes that the branches that intended to be copied are
3541/// already connected. The typical case is that this tree was created using
3542/// tree->CloneTree(0).
3543///
3544/// By default copy all entries.
3545///
3546/// Returns number of bytes copied to this tree.
3547///
3548/// If 'option' contains the word 'fast' and nentries is -1, the cloning will be
3549/// done without unzipping or unstreaming the baskets (i.e., a direct copy of the
3550/// raw bytes on disk).
3551///
3552/// When 'fast' is specified, 'option' can also contains a sorting order for the
3553/// baskets in the output file.
3554///
3555/// There are currently 3 supported sorting order:
3556///
3557/// - SortBasketsByOffset (the default)
3558/// - SortBasketsByBranch
3559/// - SortBasketsByEntry
3560///
3561/// See TTree::CloneTree for a detailed explanation of the semantics of these 3 options.
3562///
3563/// If the tree or any of the underlying tree of the chain has an index, that index and any
3564/// index in the subsequent underlying TTree objects will be merged.
3565///
3566/// There are currently three 'options' to control this merging:
3567/// - NoIndex : all the TTreeIndex object are dropped.
3568/// - DropIndexOnError : if any of the underlying TTree object do no have a TTreeIndex,
3569/// they are all dropped.
3570/// - AsIsIndexOnError [default]: In case of missing TTreeIndex, the resulting TTree index has gaps.
3571/// - BuildIndexOnError : If any of the underlying TTree objects do not have a TTreeIndex,
3572/// all TTreeIndex are 'ignored' and the missing piece are rebuilt.
3574Long64_t TTree::CopyEntries(TTree* tree, Long64_t nentries /* = -1 */, Option_t* option /* = "" */, bool needCopyAddresses /* = false */)
3575{
3576 if (!tree) {
3577 return 0;
3578 }
3579 // Options
3580 TString opt = option;
3581 opt.ToLower();
3582 bool fastClone = opt.Contains("fast");
3583 bool withIndex = !opt.Contains("noindex");
3584 EOnIndexError onIndexError;
3585 if (opt.Contains("asisindex")) {
3587 } else if (opt.Contains("buildindex")) {
3589 } else if (opt.Contains("dropindex")) {
3591 } else {
3593 }
3594 Ssiz_t cacheSizeLoc = opt.Index("cachesize=");
3595 Long64_t cacheSize = -1;
3597 // If the parse faile, cacheSize stays at -1.
3598 Ssiz_t cacheSizeEnd = opt.Index(" ",cacheSizeLoc+10) - (cacheSizeLoc+10);
3602 Warning("CopyEntries","The cachesize option can not be parsed: %s. The default size will be used.",cacheSizeStr.String().Data());
3604 double m;
3605 const char *munit = nullptr;
3606 ROOT::ToHumanReadableSize(std::numeric_limits<decltype(cacheSize)>::max(),false,&m,&munit);
3607
3608 Warning("CopyEntries","The cachesize option is too large: %s (%g%s max). The default size will be used.",cacheSizeStr.String().Data(),m,munit);
3609 }
3610 }
3611 if (gDebug > 0 && cacheSize != -1) Info("CopyEntries","Using Cache size: %lld\n",cacheSize);
3612
3613 Long64_t nbytes = 0;
3615 if (nentries < 0) {
3617 } else if (nentries > treeEntries) {
3619 }
3620
3622 // Quickly copy the basket without decompression and streaming.
3624 for (Long64_t i = 0; i < nentries; i += tree->GetTree()->GetEntries()) {
3625 if (tree->LoadTree(i) < 0) {
3626 break;
3627 }
3628 if ( withIndex ) {
3629 withIndex = R__HandleIndex( onIndexError, this, tree );
3630 }
3631 if (this->GetDirectory()) {
3632 TFile* file2 = this->GetDirectory()->GetFile();
3633 if (file2 && (file2->GetEND() > TTree::GetMaxTreeSize())) {
3634 if (this->GetDirectory() == (TDirectory*) file2) {
3635 this->ChangeFile(file2);
3636 }
3637 }
3638 }
3640 if (cloner.IsValid()) {
3641 this->SetEntries(this->GetEntries() + tree->GetTree()->GetEntries());
3642 if (cacheSize != -1) cloner.SetCacheSize(cacheSize);
3643 cloner.Exec();
3644 } else {
3645 if (i == 0) {
3646 Warning("CopyEntries","%s",cloner.GetWarning());
3647 // If the first cloning does not work, something is really wrong
3648 // (since apriori the source and target are exactly the same structure!)
3649 return -1;
3650 } else {
3651 if (cloner.NeedConversion()) {
3652 TTree *localtree = tree->GetTree();
3653 Long64_t tentries = localtree->GetEntries();
3654 if (needCopyAddresses) {
3655 // Copy MakeClass status.
3656 tree->SetMakeClass(fMakeClass);
3657 // Copy branch addresses.
3658 CopyAddresses(tree);
3659 }
3660 for (Long64_t ii = 0; ii < tentries; ii++) {
3661 if (localtree->GetEntry(ii) <= 0) {
3662 break;
3663 }
3664 this->Fill();
3665 }
3666 if (needCopyAddresses)
3667 tree->ResetBranchAddresses();
3668 if (this->GetTreeIndex()) {
3669 this->GetTreeIndex()->Append(tree->GetTree()->GetTreeIndex(), true);
3670 }
3671 } else {
3672 Warning("CopyEntries","%s",cloner.GetWarning());
3673 if (tree->GetDirectory() && tree->GetDirectory()->GetFile()) {
3674 Warning("CopyEntries", "Skipped file %s\n", tree->GetDirectory()->GetFile()->GetName());
3675 } else {
3676 Warning("CopyEntries", "Skipped file number %d\n", tree->GetTreeNumber());
3677 }
3678 }
3679 }
3680 }
3681
3682 }
3683 if (this->GetTreeIndex()) {
3684 this->GetTreeIndex()->Append(nullptr,false); // Force the sorting
3685 }
3686 nbytes = GetTotBytes() - totbytes;
3687 } else {
3688 if (nentries < 0) {
3690 } else if (nentries > treeEntries) {
3692 }
3693 if (needCopyAddresses) {
3694 // Copy MakeClass status.
3695 tree->SetMakeClass(fMakeClass);
3696 // Copy branch addresses.
3697 CopyAddresses(tree);
3698 }
3699 Int_t treenumber = -1;
3700 for (Long64_t i = 0; i < nentries; i++) {
3701 if (tree->LoadTree(i) < 0) {
3702 break;
3703 }
3704 if (treenumber != tree->GetTreeNumber()) {
3705 if ( withIndex ) {
3706 withIndex = R__HandleIndex( onIndexError, this, tree );
3707 }
3708 treenumber = tree->GetTreeNumber();
3709 }
3710 if (tree->GetEntry(i) <= 0) {
3711 break;
3712 }
3713 nbytes += this->Fill();
3714 }
3715 if (needCopyAddresses)
3716 tree->ResetBranchAddresses();
3717 if (this->GetTreeIndex()) {
3718 this->GetTreeIndex()->Append(nullptr,false); // Force the sorting
3719 }
3720 }
3721 return nbytes;
3722}
3723
3724////////////////////////////////////////////////////////////////////////////////
3725/// Copy a tree with selection.
3726///
3727/// ### Important:
3728///
3729/// The returned copied tree stays connected with the original tree
3730/// until the original tree is deleted. In particular, any changes
3731/// to the branch addresses in the original tree are also made to
3732/// the copied tree. Any changes made to the branch addresses of the
3733/// copied tree are overridden anytime the original tree changes its
3734/// branch addresses. When the original tree is deleted, all the
3735/// branch addresses of the copied tree are set to zero.
3736///
3737/// For examples of CopyTree, see the tutorials:
3738///
3739/// - copytree.C:
3740/// Example macro to copy a subset of a tree to a new tree.
3741/// The input file was generated by running the program in
3742/// $ROOTSYS/test/Event in this way:
3743/// ~~~ {.cpp}
3744/// ./Event 1000 1 1 1
3745/// ~~~
3746/// - copytree2.C
3747/// Example macro to copy a subset of a tree to a new tree.
3748/// One branch of the new tree is written to a separate file.
3749/// The input file was generated by running the program in
3750/// $ROOTSYS/test/Event in this way:
3751/// ~~~ {.cpp}
3752/// ./Event 1000 1 1 1
3753/// ~~~
3754/// - copytree3.C
3755/// Example macro to copy a subset of a tree to a new tree.
3756/// Only selected entries are copied to the new tree.
3757/// NOTE that only the active branches are copied.
3759TTree* TTree::CopyTree(const char* selection, Option_t* option /* = 0 */, Long64_t nentries /* = TTree::kMaxEntries */, Long64_t firstentry /* = 0 */)
3760{
3761 GetPlayer();
3762 if (fPlayer) {
3764 }
3765 return nullptr;
3766}
3767
3768////////////////////////////////////////////////////////////////////////////////
3769/// Create a basket for this tree and given branch.
3772{
3773 if (!branch) {
3774 return nullptr;
3775 }
3776 return new TBasket(branch->GetName(), GetName(), branch);
3777}
3778
3779////////////////////////////////////////////////////////////////////////////////
3780/// Delete this tree from memory or/and disk.
3781///
3782/// - if option == "all" delete Tree object from memory AND from disk
3783/// all baskets on disk are deleted. All keys with same name
3784/// are deleted.
3785/// - if option =="" only Tree object in memory is deleted.
3787void TTree::Delete(Option_t* option /* = "" */)
3788{
3789 TFile *file = GetCurrentFile();
3790
3791 // delete all baskets and header from file
3792 if (file && option && !strcmp(option,"all")) {
3793 if (!file->IsWritable()) {
3794 Error("Delete","File : %s is not writable, cannot delete Tree:%s", file->GetName(),GetName());
3795 return;
3796 }
3797
3798 //find key and import Tree header in memory
3799 TKey *key = fDirectory->GetKey(GetName());
3800 if (!key) return;
3801
3803 file->cd();
3804
3805 //get list of leaves and loop on all the branches baskets
3806 TIter next(GetListOfLeaves());
3807 TLeaf *leaf;
3808 char header[16];
3809 Int_t ntot = 0;
3810 Int_t nbask = 0;
3812 while ((leaf = (TLeaf*)next())) {
3813 TBranch *branch = leaf->GetBranch();
3814 Int_t nbaskets = branch->GetMaxBaskets();
3815 for (Int_t i=0;i<nbaskets;i++) {
3816 Long64_t pos = branch->GetBasketSeek(i);
3817 if (!pos) continue;
3818 TFile *branchFile = branch->GetFile();
3819 if (!branchFile) continue;
3820 branchFile->GetRecordHeader(header,pos,16,nbytes,objlen,keylen);
3821 if (nbytes <= 0) continue;
3822 branchFile->MakeFree(pos,pos+nbytes-1);
3823 ntot += nbytes;
3824 nbask++;
3825 }
3826 }
3827
3828 // delete Tree header key and all keys with the same name
3829 // A Tree may have been saved many times. Previous cycles are invalid.
3830 while (key) {
3831 ntot += key->GetNbytes();
3832 key->Delete();
3833 delete key;
3834 key = fDirectory->GetKey(GetName());
3835 }
3836 if (dirsav) dirsav->cd();
3837 if (gDebug) Info("TTree::Delete", "Deleting Tree: %s: %d baskets deleted. Total space freed = %d bytes\n",GetName(),nbask,ntot);
3838 }
3839
3840 if (fDirectory) {
3841 fDirectory->Remove(this);
3842 //delete the file cache if it points to this Tree
3843 MoveReadCache(file,nullptr);
3844 fDirectory = nullptr;
3846 }
3847
3848 // Delete object from Cling symbol table so it can not be used anymore.
3849 gCling->DeleteGlobal(this);
3850
3851 // Warning: We have intentional invalidated this object while inside a member function!
3852 delete this;
3853}
3854
3855 ///////////////////////////////////////////////////////////////////////////////
3856 /// Called by TKey and TObject::Clone to automatically add us to a directory
3857 /// when we are read from a file.
3860{
3861 if (fDirectory == dir) return;
3862 if (fDirectory) {
3863 fDirectory->Remove(this);
3864 // Delete or move the file cache if it points to this Tree
3865 TFile *file = fDirectory->GetFile();
3866 MoveReadCache(file,dir);
3867 }
3868 fDirectory = dir;
3869 TBranch* b = nullptr;
3870 TIter next(GetListOfBranches());
3871 while((b = (TBranch*) next())) {
3872 b->UpdateFile();
3873 }
3874 if (fBranchRef) {
3876 }
3877 if (fDirectory) fDirectory->Append(this);
3878}
3879
3880////////////////////////////////////////////////////////////////////////////////
3881/// Draw expression varexp for specified entries.
3882///
3883/// \return -1 in case of error or number of selected events in case of success.
3884/// If `selection` involves an array variable `x[n]`, for example `x[] > 0` or
3885/// `x > 0`, then we return the number of selected instances rather than number of events.
3886/// In the output of `tree.Scan()`, instances are shown in individual printed rows, thus
3887/// each event (tree entry) is split across the various instances (lines) of the array.
3888/// In contrast, the function `GetEntries(selection)` always returns the number of entries selected.
3889///
3890/// This function accepts TCut objects as arguments.
3891/// Useful to use the string operator +
3892///
3893/// Example:
3894///
3895/// ~~~ {.cpp}
3896/// ntuple.Draw("x",cut1+cut2+cut3);
3897/// ~~~
3898
3903}
3904
3905/////////////////////////////////////////////////////////////////////////////////////////
3906/// \brief Draw expression varexp for entries and objects that pass a (optional) selection.
3907///
3908/// \return -1 in case of error or number of selected events in case of success.
3909/// If `selection` involves an array variable `x[n]`, for example `x[] > 0` or
3910/// `x > 0`, then we return the number of selected instances rather than number of events.
3911/// In the output of `tree.Scan()`, instances are shown in individual printed rows, thus
3912/// each event (tree entry) is split across the various instances (lines) of the array.
3913/// In contrast, the function `GetEntries(selection)` always returns the number of entries selected.
3914///
3915/// \param [in] varexp
3916/// \parblock
3917/// A string that takes one of these general forms:
3918/// - "e1" produces a 1-d histogram (TH1F) of expression "e1"
3919/// - "e1:e2" produces an unbinned 2-d scatter-plot (TGraph) of "e1"
3920/// on the y-axis versus "e2" on the x-axis
3921/// - "e1:e2:e3" produces an unbinned 3-d scatter-plot (TPolyMarker3D) of "e1"
3922/// vs "e2" vs "e3" on the z-, y-, x-axis, respectively
3923/// - "e1:e2:e3:e4" produces an unbinned 3-d scatter-plot (TPolyMarker3D) of "e1"
3924/// vs "e2" vs "e3" and "e4" mapped on the current color palette.
3925/// (to create histograms in the 2, 3, and 4 dimensional case,
3926/// see section "Saving the result of Draw to an histogram")
3927/// - "e1:e2:e3:e4:e5" with option "GL5D" produces a 5D plot using OpenGL. `gStyle->SetCanvasPreferGL(true)` is
3928/// needed.
3929/// - Any number of variables no fewer than two can be used with the options "CANDLE" and "PARA"
3930/// - An arbitrary number of variables can be used with the option "GOFF"
3931///
3932/// Examples:
3933/// - "x": the simplest case, it draws a 1-Dim histogram of column x
3934/// - "sqrt(x)", "x*y/z": draw histogram with the values of the specified numerical expression across TTree events
3935/// - "y:sqrt(x)": 2-Dim histogram of y versus sqrt(x)
3936/// - "px:py:pz:2.5*E": produces a 3-d scatter-plot of px vs py ps pz
3937/// and the color number of each marker will be 2.5*E.
3938/// If the color number is negative it is set to 0.
3939/// If the color number is greater than the current number of colors
3940/// it is set to the highest color number. The default number of
3941/// colors is 50. See TStyle::SetPalette for setting a new color palette.
3942///
3943/// The expressions can use all the operations and built-in functions
3944/// supported by TFormula (see TFormula::Analyze()), including free
3945/// functions taking numerical arguments (e.g. TMath::Bessel()).
3946/// In addition, you can call member functions taking numerical
3947/// arguments. For example, these are two valid expressions:
3948/// ~~~ {.cpp}
3949/// TMath::BreitWigner(fPx,3,2)
3950/// event.GetHistogram()->GetXaxis()->GetXmax()
3951/// ~~~
3952/// \endparblock
3953/// \param [in] selection
3954/// \parblock
3955/// A string containing a selection expression.
3956/// In a selection all usual C++ mathematical and logical operators are allowed.
3957/// The value corresponding to the selection expression is used as a weight
3958/// to fill the histogram (a weight of 0 is equivalent to not filling the histogram).\n
3959/// \n
3960/// Examples:
3961/// - "x<y && sqrt(z)>3.2": returns a weight = 0 or 1
3962/// - "(x+y)*(sqrt(z)>3.2)": returns a weight = x+y if sqrt(z)>3.2, 0 otherwise\n
3963/// \n
3964/// If the selection expression returns an array, it is iterated over in sync with the
3965/// array returned by the varexp argument (as described below in "Drawing expressions using arrays and array
3966/// elements"). For example, if, for a given event, varexp evaluates to
3967/// `{1., 2., 3.}` and selection evaluates to `{0, 1, 0}`, the resulting histogram is filled with the value 2. For
3968/// example, for each event here we perform a simple object selection:
3969/// ~~~{.cpp}
3970/// // Muon_pt is an array: fill a histogram with the array elements > 100 in each event
3971/// tree->Draw('Muon_pt', 'Muon_pt > 100')
3972/// ~~~
3973/// \endparblock
3974/// \param [in] option
3975/// \parblock
3976/// The drawing option.
3977/// - When an histogram is produced it can be any histogram drawing option
3978/// listed in THistPainter.
3979/// - when no option is specified:
3980/// - the default histogram drawing option is used
3981/// if the expression is of the form "e1".
3982/// - if the expression is of the form "e1:e2"or "e1:e2:e3" a cloud of
3983/// unbinned 2D or 3D points is drawn respectively.
3984/// - if the expression has four fields "e1:e2:e3:e4" a cloud of unbinned 3D
3985/// points is produced with e1 vs e2 vs e3, and e4 is mapped on the current color
3986/// palette.
3987/// - If option COL is specified when varexp has three fields:
3988/// ~~~ {.cpp}
3989/// tree.Draw("e1:e2:e3","","col");
3990/// ~~~
3991/// a 2D scatter is produced with e1 vs e2, and e3 is mapped on the current
3992/// color palette. The colors for e3 are evaluated once in linear scale before
3993/// painting. Therefore changing the pad to log scale along Z as no effect
3994/// on the colors.
3995/// - if expression has more than four fields the option "PARA"or "CANDLE"
3996/// can be used.
3997/// - If option contains the string "goff", no graphics is generated.
3998/// \endparblock
3999/// \param [in] nentries The number of entries to process (default is all)
4000/// \param [in] firstentry The first entry to process (default is 0)
4001///
4002/// ### Drawing expressions using arrays and array elements
4003///
4004/// Let assumes, a leaf fMatrix, on the branch fEvent, which is a 3 by 3 array,
4005/// or a TClonesArray.
4006/// In a TTree::Draw expression you can now access fMatrix using the following
4007/// syntaxes:
4008///
4009/// | String passed | What is used for each entry of the tree
4010/// |-----------------|--------------------------------------------------------|
4011/// | `fMatrix` | the 9 elements of fMatrix |
4012/// | `fMatrix[][]` | the 9 elements of fMatrix |
4013/// | `fMatrix[2][2]` | only the elements fMatrix[2][2] |
4014/// | `fMatrix[1]` | the 3 elements fMatrix[1][0], fMatrix[1][1] and fMatrix[1][2] |
4015/// | `fMatrix[1][]` | the 3 elements fMatrix[1][0], fMatrix[1][1] and fMatrix[1][2] |
4016/// | `fMatrix[][0]` | the 3 elements fMatrix[0][0], fMatrix[1][0] and fMatrix[2][0] |
4017///
4018/// "fEvent.fMatrix...." same as "fMatrix..." (unless there is more than one leaf named fMatrix!).
4019///
4020/// In summary, if a specific index is not specified for a dimension, TTree::Draw
4021/// will loop through all the indices along this dimension. Leaving off the
4022/// last (right most) dimension of specifying then with the two characters '[]'
4023/// is equivalent. For variable size arrays (and TClonesArray) the range
4024/// of the first dimension is recalculated for each entry of the tree.
4025/// You can also specify the index as an expression of any other variables from the
4026/// tree.
4027///
4028/// TTree::Draw also now properly handling operations involving 2 or more arrays.
4029///
4030/// Let assume a second matrix fResults[5][2], here are a sample of some
4031/// of the possible combinations, the number of elements they produce and
4032/// the loop used:
4033///
4034/// | expression | element(s) | Loop |
4035/// |----------------------------------|------------|--------------------------|
4036/// | `fMatrix[2][1] - fResults[5][2]` | one | no loop |
4037/// | `fMatrix[2][] - fResults[5][2]` | three | on 2nd dim fMatrix |
4038/// | `fMatrix[2][] - fResults[5][]` | two | on both 2nd dimensions |
4039/// | `fMatrix[][2] - fResults[][1]` | three | on both 1st dimensions |
4040/// | `fMatrix[][2] - fResults[][]` | six | on both 1st and 2nd dimensions of fResults |
4041/// | `fMatrix[][2] - fResults[3][]` | two | on 1st dim of fMatrix and 2nd of fResults (at the same time) |
4042/// | `fMatrix[][] - fResults[][]` | six | on 1st dim then on 2nd dim |
4043/// | `fMatrix[][fResult[][]]` | 30 | on 1st dim of fMatrix then on both dimensions of fResults. The
4044/// value if fResults[j][k] is used as the second index of fMatrix.|
4045///
4046///
4047/// In summary, TTree::Draw loops through all unspecified dimensions. To
4048/// figure out the range of each loop, we match each unspecified dimension
4049/// from left to right (ignoring ALL dimensions for which an index has been
4050/// specified), in the equivalent loop matched dimensions use the same index
4051/// and are restricted to the smallest range (of only the matched dimensions).
4052/// When involving variable arrays, the range can of course be different
4053/// for each entry of the tree.
4054///
4055/// So the loop equivalent to "fMatrix[][2] - fResults[3][]" is:
4056/// ~~~ {.cpp}
4057/// for (Int_t i0; i < min(3,2); i++) {
4058/// use the value of (fMatrix[i0][2] - fMatrix[3][i0])
4059/// }
4060/// ~~~
4061/// So the loop equivalent to "fMatrix[][2] - fResults[][]" is:
4062/// ~~~ {.cpp}
4063/// for (Int_t i0; i < min(3,5); i++) {
4064/// for (Int_t i1; i1 < 2; i1++) {
4065/// use the value of (fMatrix[i0][2] - fMatrix[i0][i1])
4066/// }
4067/// }
4068/// ~~~
4069/// So the loop equivalent to "fMatrix[][] - fResults[][]" is:
4070/// ~~~ {.cpp}
4071/// for (Int_t i0; i < min(3,5); i++) {
4072/// for (Int_t i1; i1 < min(3,2); i1++) {
4073/// use the value of (fMatrix[i0][i1] - fMatrix[i0][i1])
4074/// }
4075/// }
4076/// ~~~
4077/// So the loop equivalent to "fMatrix[][fResults[][]]" is:
4078/// ~~~ {.cpp}
4079/// for (Int_t i0; i0 < 3; i0++) {
4080/// for (Int_t j2; j2 < 5; j2++) {
4081/// for (Int_t j3; j3 < 2; j3++) {
4082/// i1 = fResults[j2][j3];
4083/// use the value of fMatrix[i0][i1]
4084/// }
4085/// }
4086/// ~~~
4087/// ### Retrieving the result of Draw
4088///
4089/// By default a temporary histogram called `htemp` is created. It will be:
4090///
4091/// - A TH1F* in case of a mono-dimensional distribution: `Draw("e1")`,
4092/// - A TH2F* in case of a bi-dimensional distribution: `Draw("e1:e2")`,
4093/// - A TH3F* in case of a three-dimensional distribution: `Draw("e1:e2:e3")`.
4094///
4095/// In the one dimensional case the `htemp` is filled and drawn whatever the drawing
4096/// option is.
4097///
4098/// In the two and three dimensional cases, with the default drawing option (`""`),
4099/// a cloud of points is drawn and the histogram `htemp` is not filled. For all the other
4100/// drawing options `htemp` will be filled.
4101///
4102/// In all cases `htemp` can be retrieved by calling:
4103///
4104/// ~~~ {.cpp}
4105/// auto htemp = (TH1F*)gPad->GetPrimitive("htemp"); // 1D
4106/// auto htemp = (TH2F*)gPad->GetPrimitive("htemp"); // 2D
4107/// auto htemp = (TH3F*)gPad->GetPrimitive("htemp"); // 3D
4108/// ~~~
4109///
4110/// In the two dimensional case (`Draw("e1;e2")`), with the default drawing option, the
4111/// data is filled into a TGraph named `Graph`. This TGraph can be retrieved by
4112/// calling
4113///
4114/// ~~~ {.cpp}
4115/// auto graph = (TGraph*)gPad->GetPrimitive("Graph");
4116/// ~~~
4117///
4118/// For the three and four dimensional cases, with the default drawing option, an unnamed
4119/// TPolyMarker3D is produced, and therefore cannot be retrieved.
4120///
4121/// In all cases `htemp` can be used to access the axes. For instance in the 2D case:
4122///
4123/// ~~~ {.cpp}
4124/// auto htemp = (TH2F*)gPad->GetPrimitive("htemp");
4125/// auto xaxis = htemp->GetXaxis();
4126/// ~~~
4127///
4128/// When the option `"A"` is used (with TGraph painting option) to draw a 2D
4129/// distribution:
4130/// ~~~ {.cpp}
4131/// tree.Draw("e1:e2","","A*");
4132/// ~~~
4133/// a scatter plot is produced (with stars in that case) but the axis creation is
4134/// delegated to TGraph and `htemp` is not created.
4135///
4136/// ### Saving the result of Draw to a histogram
4137///
4138/// If `varexp` contains `>>hnew` (following the variable(s) name(s)),
4139/// the new histogram called `hnew` is created and it is kept in the current
4140/// directory (and also the current pad). This works for all dimensions.
4141///
4142/// Example:
4143/// ~~~ {.cpp}
4144/// tree.Draw("sqrt(x)>>hsqrt","y>0")
4145/// ~~~
4146/// will draw `sqrt(x)` and save the histogram as "hsqrt" in the current
4147/// directory. To retrieve it do:
4148/// ~~~ {.cpp}
4149/// TH1F *hsqrt = (TH1F*)gDirectory->Get("hsqrt");
4150/// ~~~
4151/// The binning information is taken from the environment variables
4152/// ~~~ {.cpp}
4153/// Hist.Binning.?D.?
4154/// ~~~
4155/// In addition, the name of the histogram can be followed by up to 9
4156/// numbers between '(' and ')', where the numbers describe the
4157/// following:
4158///
4159/// - 1 - bins in x-direction
4160/// - 2 - lower limit in x-direction
4161/// - 3 - upper limit in x-direction
4162/// - 4-6 same for y-direction
4163/// - 7-9 same for z-direction
4164///
4165/// When a new binning is used the new value will become the default.
4166/// Values can be skipped.
4167///
4168/// Example:
4169/// ~~~ {.cpp}
4170/// tree.Draw("sqrt(x)>>hsqrt(500,10,20)")
4171/// // plot sqrt(x) between 10 and 20 using 500 bins
4172/// tree.Draw("sqrt(x):sin(y)>>hsqrt(100,10,60,50,.1,.5)")
4173/// // plot sqrt(x) against sin(y)
4174/// // 100 bins in x-direction; lower limit on x-axis is 10; upper limit is 60
4175/// // 50 bins in y-direction; lower limit on y-axis is .1; upper limit is .5
4176/// ~~~
4177/// By default, if a histogram with the same name is already registered to the current
4178/// ROOT directory, the specified histogram is reset. To continue to append data to an
4179/// existing histogram, use "+" in front of the histogram name.
4180///
4181/// A '+' in front of the histogram name is ignored, when the name is followed by
4182/// binning information as described in the previous paragraph.
4183/// ~~~ {.cpp}
4184/// tree.Draw("sqrt(x)>>+hsqrt","y>0")
4185/// ~~~
4186/// will not reset `hsqrt`, but will continue filling. This works for 1-D, 2-D
4187/// and 3-D histograms.
4188///
4189/// Note that when the automatic registration of histograms is off (see \ref DisableObjectAutoRegistration() ),
4190/// external histogram are not visible to TTree::Draw unless they are registered to the current directory explicitly.
4191/// ~~~ {.cpp}
4192/// auto histo = new TH1D("histo", ...);
4193/// histo->SetDirectory(gDirectory);
4194/// tree.Draw("sqrt(x)>>histo","y>0")
4195/// ~~~
4196/// When auto-registration is off, histograms created by TTree::Draw will still be registered to the current directory.
4197///
4198/// ### Accessing collection objects
4199///
4200/// TTree::Draw default's handling of collections is to assume that any
4201/// request on a collection pertain to it content. For example, if fTracks
4202/// is a collection of Track objects, the following:
4203/// ~~~ {.cpp}
4204/// tree->Draw("event.fTracks.fPx");
4205/// ~~~
4206/// will plot the value of fPx for each Track objects inside the collection.
4207/// Also
4208/// ~~~ {.cpp}
4209/// tree->Draw("event.fTracks.size()");
4210/// ~~~
4211/// would plot the result of the member function Track::size() for each
4212/// Track object inside the collection.
4213/// To access information about the collection itself, TTree::Draw support
4214/// the '@' notation. If a variable which points to a collection is prefixed
4215/// or postfixed with '@', the next part of the expression will pertain to
4216/// the collection object. For example:
4217/// ~~~ {.cpp}
4218/// tree->Draw("event.@fTracks.size()");
4219/// ~~~
4220/// will plot the size of the collection referred to by `fTracks` (i.e the number
4221/// of Track objects).
4222///
4223/// ### Drawing 'objects'
4224///
4225/// When a class has a member function named AsDouble or AsString, requesting
4226/// to directly draw the object will imply a call to one of the 2 functions.
4227/// If both AsDouble and AsString are present, AsDouble will be used.
4228/// AsString can return either a char*, a std::string or a TString.s
4229/// For example, the following
4230/// ~~~ {.cpp}
4231/// tree->Draw("event.myTTimeStamp");
4232/// ~~~
4233/// will draw the same histogram as
4234/// ~~~ {.cpp}
4235/// tree->Draw("event.myTTimeStamp.AsDouble()");
4236/// ~~~
4237/// In addition, when the object is a type TString or std::string, TTree::Draw
4238/// will call respectively `TString::Data` and `std::string::c_str()`
4239///
4240/// If the object is a TBits, the histogram will contain the index of the bit
4241/// that are turned on.
4242///
4243/// ### Retrieving information about the tree itself.
4244///
4245/// You can refer to the tree (or chain) containing the data by using the
4246/// string 'This'.
4247/// You can then could any TTree methods. For example:
4248/// ~~~ {.cpp}
4249/// tree->Draw("This->GetReadEntry()");
4250/// ~~~
4251/// will display the local entry numbers be read.
4252/// ~~~ {.cpp}
4253/// tree->Draw("This->GetUserInfo()->At(0)->GetName()");
4254/// ~~~
4255/// will display the name of the first 'user info' object.
4256///
4257/// ### Special functions and variables
4258///
4259/// `Entry$`: A TTree::Draw formula can use the special variable `Entry$`
4260/// to access the entry number being read. For example to draw every
4261/// other entry use:
4262/// ~~~ {.cpp}
4263/// tree.Draw("myvar","Entry$%2==0");
4264/// ~~~
4265/// - `Entry$` : return the current entry number (`== TTree::GetReadEntry()`)
4266/// - `LocalEntry$` : return the current entry number in the current tree of a
4267/// chain (`== GetTree()->GetReadEntry()`)
4268/// - `Entries$` : return the total number of entries (== TTree::GetEntries())
4269/// - `LocalEntries$` : return the total number of entries in the current tree
4270/// of a chain (== GetTree()->TTree::GetEntries())
4271/// - `Length$` : return the total number of element of this formula for this
4272/// entry (`==TTreeFormula::GetNdata()`)
4273/// - `Iteration$` : return the current iteration over this formula for this
4274/// entry (i.e. varies from 0 to `Length$ - 1`).
4275/// - `Length$(formula )` : return the total number of element of the formula
4276/// given as a parameter.
4277/// - `Sum$(formula )` : return the sum of the value of the elements of the
4278/// formula given as a parameter. For example the mean for all the elements in
4279/// one entry can be calculated with: `Sum$(formula )/Length$(formula )`
4280/// - `Min$(formula )` : return the minimum (within one TTree entry) of the value of the
4281/// elements of the formula given as a parameter.
4282/// - `Max$(formula )` : return the maximum (within one TTree entry) of the value of the
4283/// elements of the formula given as a parameter.
4284/// - `MinIf$(formula,condition)`
4285/// - `MaxIf$(formula,condition)` : return the minimum (maximum) (within one TTree entry)
4286/// of the value of the elements of the formula given as a parameter
4287/// if they match the condition. If no element matches the condition,
4288/// the result is zero. To avoid the resulting peak at zero, use the
4289/// pattern:
4290/// ~~~ {.cpp}
4291/// tree->Draw("MinIf$(formula,condition)","condition");
4292/// ~~~
4293/// which will avoid calculation `MinIf$` for the entries that have no match
4294/// for the condition.
4295/// - `Alt$(primary,alternate)` : return the value of "primary" if it is available
4296/// for the current iteration otherwise return the value of "alternate".
4297/// For example, with arr1[3] and arr2[2]
4298/// ~~~ {.cpp}
4299/// tree->Draw("arr1+Alt$(arr2,0)");
4300/// ~~~
4301/// will draw arr1[0]+arr2[0] ; arr1[1]+arr2[1] and arr1[2]+0
4302/// Or with a variable size array arr3
4303/// ~~~ {.cpp}
4304/// tree->Draw("Alt$(arr3[0],0)+Alt$(arr3[1],0)+Alt$(arr3[2],0)");
4305/// ~~~
4306/// will draw the sum arr3 for the index 0 to min(2,actual_size_of_arr3-1)
4307/// As a comparison
4308/// ~~~ {.cpp}
4309/// tree->Draw("arr3[0]+arr3[1]+arr3[2]");
4310/// ~~~
4311/// will draw the sum arr3 for the index 0 to 2 only if the
4312/// actual_size_of_arr3 is greater or equal to 3.
4313/// Note that the array in 'primary' is flattened/linearized thus using
4314/// `Alt$` with multi-dimensional arrays of different dimensions is unlikely
4315/// to yield the expected results. To visualize a bit more what elements
4316/// would be matched by TTree::Draw, TTree::Scan can be used:
4317/// ~~~ {.cpp}
4318/// tree->Scan("arr1:Alt$(arr2,0)");
4319/// ~~~
4320/// will print on one line the value of arr1 and (arr2,0) that will be
4321/// matched by
4322/// ~~~ {.cpp}
4323/// tree->Draw("arr1-Alt$(arr2,0)");
4324/// ~~~
4325/// The ternary operator is not directly supported in TTree::Draw however, to plot the
4326/// equivalent of `var2<20 ? -99 : var1`, you can use:
4327/// ~~~ {.cpp}
4328/// tree->Draw("(var2<20)*99+(var2>=20)*var1","");
4329/// ~~~
4330///
4331/// ### Drawing a user function accessing the TTree data directly
4332///
4333/// If the formula contains a file name, TTree::MakeProxy will be used
4334/// to load and execute this file. In particular it will draw the
4335/// result of a function with the same name as the file. The function
4336/// will be executed in a context where the name of the branches can
4337/// be used as a C++ variable.
4338///
4339/// For example draw px using the file hsimple.root (generated by the
4340/// hsimple.C tutorial), we need a file named hsimple.cxx:
4341/// ~~~ {.cpp}
4342/// double hsimple() {
4343/// return px;
4344/// }
4345/// ~~~
4346/// MakeProxy can then be used indirectly via the TTree::Draw interface
4347/// as follow:
4348/// ~~~ {.cpp}
4349/// new TFile("hsimple.root")
4350/// ntuple->Draw("hsimple.cxx");
4351/// ~~~
4352/// A more complete example is available in the tutorials directory:
4353/// `h1analysisProxy.cxx`, `h1analysProxy.h` and `h1analysisProxyCut.C`
4354/// which reimplement the selector found in `h1analysis.C`
4355///
4356/// The main features of this facility are:
4357///
4358/// * on-demand loading of branches
4359/// * ability to use the 'branchname' as if it was a data member
4360/// * protection against array out-of-bound
4361/// * ability to use the branch data as object (when the user code is available)
4362///
4363/// See TTree::MakeProxy for more details.
4364///
4365/// ### Making a Profile histogram
4366///
4367/// In case of a 2-Dim expression, one can generate a TProfile histogram
4368/// instead of a TH2F histogram by specifying option=prof or option=profs
4369/// or option=profi or option=profg ; the trailing letter select the way
4370/// the bin error are computed, See TProfile2D::SetErrorOption for
4371/// details on the differences.
4372/// The option=prof is automatically selected in case of y:x>>pf
4373/// where pf is an existing TProfile histogram.
4374///
4375/// ### Making a 2D Profile histogram
4376///
4377/// In case of a 3-Dim expression, one can generate a TProfile2D histogram
4378/// instead of a TH3F histogram by specifying option=prof or option=profs.
4379/// or option=profi or option=profg ; the trailing letter select the way
4380/// the bin error are computed, See TProfile2D::SetErrorOption for
4381/// details on the differences.
4382/// The option=prof is automatically selected in case of z:y:x>>pf
4383/// where pf is an existing TProfile2D histogram.
4384///
4385/// ### Making a 5D plot using GL
4386///
4387/// If option GL5D is specified together with 5 variables, a 5D plot is drawn
4388/// using OpenGL. See tree502_staff.C as example.
4389///
4390/// ### Making a parallel coordinates plot
4391///
4392/// In case of a 2-Dim or more expression with the option=para, one can generate
4393/// a parallel coordinates plot. With that option, the number of dimensions is
4394/// arbitrary. Giving more than 4 variables without the option=para or
4395/// option=candle or option=goff will produce an error.
4396///
4397/// ### Making a candle sticks chart
4398///
4399/// In case of a 2-Dim or more expression with the option=candle, one can generate
4400/// a candle sticks chart. With that option, the number of dimensions is
4401/// arbitrary. Giving more than 4 variables without the option=para or
4402/// option=candle or option=goff will produce an error.
4403///
4404/// ### Normalizing the output histogram to 1
4405///
4406/// When option contains "norm" the output histogram is normalized to 1.
4407///
4408/// ### Saving the result of Draw to a TEventList, a TEntryList or a TEntryListArray
4409///
4410/// TTree::Draw can be used to fill a TEventList object (list of entry numbers)
4411/// instead of histogramming one variable.
4412/// If varexp0 has the form >>elist , a TEventList object named "elist"
4413/// is created in the current directory. elist will contain the list
4414/// of entry numbers satisfying the current selection.
4415/// If option "entrylist" is used, a TEntryList object is created
4416/// If the selection contains arrays, vectors or any container class and option
4417/// "entrylistarray" is used, a TEntryListArray object is created
4418/// containing also the subentries satisfying the selection, i.e. the indices of
4419/// the branches which hold containers classes.
4420/// Example:
4421/// ~~~ {.cpp}
4422/// tree.Draw(">>yplus","y>0")
4423/// ~~~
4424/// will create a TEventList object named "yplus" in the current directory.
4425/// In an interactive session, one can type (after TTree::Draw)
4426/// ~~~ {.cpp}
4427/// yplus.Print("all")
4428/// ~~~
4429/// to print the list of entry numbers in the list.
4430/// ~~~ {.cpp}
4431/// tree.Draw(">>yplus", "y>0", "entrylist")
4432/// ~~~
4433/// will create a TEntryList object names "yplus" in the current directory
4434/// ~~~ {.cpp}
4435/// tree.Draw(">>yplus", "y>0", "entrylistarray")
4436/// ~~~
4437/// will create a TEntryListArray object names "yplus" in the current directory
4438///
4439/// By default, the specified entry list is reset.
4440/// To continue to append data to an existing list, use "+" in front
4441/// of the list name;
4442/// ~~~ {.cpp}
4443/// tree.Draw(">>+yplus","y>0")
4444/// ~~~
4445/// will not reset yplus, but will enter the selected entries at the end
4446/// of the existing list.
4447///
4448/// Note that when the automatic registration of event lists is off (see \ref DisableObjectAutoRegistration() ),
4449/// they are not visible to TTree::Draw unless they are registered to the current directory explicitly.
4450/// ~~~ {.cpp}
4451/// auto elist = new TEventList("elist", ...);
4452/// elist->SetDirectory(gDirectory);
4453/// tree.Draw(">>+elist","y>0")
4454/// ~~~
4455///
4456/// ### Using a TEventList, TEntryList or TEntryListArray as Input
4457///
4458/// Once a TEventList or a TEntryList object has been generated, it can be used as input
4459/// for TTree::Draw. Use TTree::SetEventList or TTree::SetEntryList to set the
4460/// current event list
4461///
4462/// Example 1:
4463/// ~~~ {.cpp}
4464/// TEventList *elist = (TEventList*)gDirectory->Get("yplus");
4465/// tree->SetEventList(elist);
4466/// tree->Draw("py");
4467/// ~~~
4468/// Example 2:
4469/// ~~~ {.cpp}
4470/// TEntryList *elist = (TEntryList*)gDirectory->Get("yplus");
4471/// tree->SetEntryList(elist);
4472/// tree->Draw("py");
4473/// ~~~
4474/// If a TEventList object is used as input, a new TEntryList object is created
4475/// inside the SetEventList function. In case of a TChain, all tree headers are loaded
4476/// for this transformation. This new object is owned by the chain and is deleted
4477/// with it, unless the user extracts it by calling GetEntryList() function.
4478/// See also comments to SetEventList() function of TTree and TChain.
4479///
4480/// If arrays are used in the selection criteria and TEntryListArray is not used,
4481/// all the entries that have at least one element of the array that satisfy the selection
4482/// are entered in the list.
4483///
4484/// Example:
4485/// ~~~ {.cpp}
4486/// tree.Draw(">>pyplus","fTracks.fPy>0");
4487/// tree->SetEventList(pyplus);
4488/// tree->Draw("fTracks.fPy");
4489/// ~~~
4490/// will draw the fPy of ALL tracks in event with at least one track with
4491/// a positive fPy.
4492///
4493/// To select only the elements that did match the original selection
4494/// use TEventList::SetReapplyCut or TEntryList::SetReapplyCut.
4495///
4496/// Example:
4497/// ~~~ {.cpp}
4498/// tree.Draw(">>pyplus","fTracks.fPy>0");
4499/// pyplus->SetReapplyCut(true);
4500/// tree->SetEventList(pyplus);
4501/// tree->Draw("fTracks.fPy");
4502/// ~~~
4503/// will draw the fPy of only the tracks that have a positive fPy.
4504///
4505/// To draw only the elements that match a selection in case of arrays,
4506/// you can also use TEntryListArray (faster in case of a more general selection).
4507///
4508/// Example:
4509/// ~~~ {.cpp}
4510/// tree.Draw(">>pyplus","fTracks.fPy>0", "entrylistarray");
4511/// tree->SetEntryList(pyplus);
4512/// tree->Draw("fTracks.fPy");
4513/// ~~~
4514/// will draw the fPy of only the tracks that have a positive fPy,
4515/// but without redoing the selection.
4516///
4517/// Note: Use tree->SetEventList(0) if you do not want use the list as input.
4518///
4519/// ### How to obtain more info from TTree::Draw
4520///
4521/// Once TTree::Draw has been called, it is possible to access useful
4522/// information still stored in the TTree object via the following functions:
4523///
4524/// - GetSelectedRows() // return the number of values accepted by the selection expression. In case where no selection
4525/// was specified, returns the number of values processed.
4526/// - GetV1() // returns a pointer to the double array of V1
4527/// - GetV2() // returns a pointer to the double array of V2
4528/// - GetV3() // returns a pointer to the double array of V3
4529/// - GetV4() // returns a pointer to the double array of V4
4530/// - GetW() // returns a pointer to the double array of Weights where weight equal the result of the
4531/// selection expression.
4532///
4533/// where V1,V2,V3 correspond to the expressions in
4534/// ~~~ {.cpp}
4535/// TTree::Draw("V1:V2:V3:V4",selection);
4536/// ~~~
4537/// If the expression has more than 4 component use GetVal(index)
4538///
4539/// Example:
4540/// ~~~ {.cpp}
4541/// Root > ntuple->Draw("py:px","pz>4");
4542/// Root > TGraph *gr = new TGraph(ntuple->GetSelectedRows(),
4543/// ntuple->GetV2(), ntuple->GetV1());
4544/// Root > gr->Draw("ap"); //draw graph in current pad
4545/// ~~~
4546///
4547/// A more complete complete tutorial (treegetval.C) shows how to use the
4548/// GetVal() method.
4549///
4550/// creates a TGraph object with a number of points corresponding to the
4551/// number of entries selected by the expression "pz>4", the x points of the graph
4552/// being the px values of the Tree and the y points the py values.
4553///
4554/// Important note: By default TTree::Draw creates the arrays obtained
4555/// with GetW, GetV1, GetV2, GetV3, GetV4, GetVal with a length corresponding
4556/// to the parameter fEstimate. The content will be the last `GetSelectedRows() % GetEstimate()`
4557/// values calculated.
4558/// By default fEstimate=1000000 and can be modified
4559/// via TTree::SetEstimate. To keep in memory all the results (in case
4560/// where there is only one result per entry), use
4561/// ~~~ {.cpp}
4562/// tree->SetEstimate(tree->GetEntries()+1); // same as tree->SetEstimate(-1);
4563/// ~~~
4564/// You must call SetEstimate if the expected number of selected rows
4565/// you need to look at is greater than 1000000.
4566///
4567/// You can use the option "goff" to turn off the graphics output
4568/// of TTree::Draw in the above example.
4569///
4570/// ### Automatic interface to TTree::Draw via the TTreeViewer
4571///
4572/// A complete graphical interface to this function is implemented
4573/// in the class TTreeViewer.
4574/// To start the TTreeViewer, three possibilities:
4575/// - select TTree context menu item "StartViewer"
4576/// - type the command "TTreeViewer TV(treeName)"
4577/// - execute statement "tree->StartViewer();"
4580{
4581 GetPlayer();
4582 if (fPlayer)
4584 return -1;
4585}
4586
4587////////////////////////////////////////////////////////////////////////////////
4588/// Remove some baskets from memory.
4590void TTree::DropBaskets()
4591{
4592 TBranch* branch = nullptr;
4594 for (Int_t i = 0; i < nb; ++i) {
4596 branch->DropBaskets("all");
4597 }
4598}
4599
4600////////////////////////////////////////////////////////////////////////////////
4601/// Drop branch buffers to accommodate nbytes below MaxVirtualsize.
4604{
4605 // Be careful not to remove current read/write buffers.
4607 for (Int_t i = 0; i < nleaves; ++i) {
4609 TBranch* branch = (TBranch*) leaf->GetBranch();
4610 Int_t nbaskets = branch->GetListOfBaskets()->GetEntries();
4611 for (Int_t j = 0; j < nbaskets - 1; ++j) {
4612 if ((j == branch->GetReadBasket()) || (j == branch->GetWriteBasket())) {
4613 continue;
4614 }
4615 TBasket* basket = (TBasket*)branch->GetListOfBaskets()->UncheckedAt(j);
4616 if (basket) {
4617 basket->DropBuffers();
4619 return;
4620 }
4621 }
4622 }
4623 }
4624}
4625
4626////////////////////////////////////////////////////////////////////////////////
4627/// Fill all branches.
4628///
4629/// This function loops on all the branches of this tree. For
4630/// each branch, it copies to the branch buffer (basket) the current
4631/// values of the leaves data types. If a leaf is a simple data type,
4632/// a simple conversion to a machine independent format has to be done.
4633///
4634/// This machine independent version of the data is copied into a
4635/// basket (each branch has its own basket). When a basket is full
4636/// (32k worth of data by default), it is then optionally compressed
4637/// and written to disk (this operation is also called committing or
4638/// 'flushing' the basket). The committed baskets are then
4639/// immediately removed from memory.
4640///
4641/// The function returns the number of bytes committed to the
4642/// individual branches.
4643///
4644/// If a write error occurs, the number of bytes returned is -1.
4645///
4646/// If no data are written, because, e.g., the branch is disabled,
4647/// the number of bytes returned is 0.
4648///
4649/// __The baskets are flushed and the Tree header saved at regular intervals__
4650///
4651/// At regular intervals, when the amount of data written so far is
4652/// greater than fAutoFlush (see SetAutoFlush) all the baskets are flushed to disk.
4653/// This makes future reading faster as it guarantees that baskets belonging to nearby
4654/// entries will be on the same disk region.
4655/// When the first call to flush the baskets happen, we also take this opportunity
4656/// to optimize the baskets buffers.
4657/// We also check if the amount of data written is greater than fAutoSave (see SetAutoSave).
4658/// In this case we also write the Tree header. This makes the Tree recoverable up to this point
4659/// in case the program writing the Tree crashes.
4660/// The decisions to FlushBaskets and Auto Save can be made based either on the number
4661/// of bytes written (fAutoFlush and fAutoSave negative) or on the number of entries
4662/// written (fAutoFlush and fAutoSave positive).
4663/// Note that the user can decide to call FlushBaskets and AutoSave in her event loop
4664/// base on the number of events written instead of the number of bytes written.
4665///
4666/// \note Calling `TTree::FlushBaskets` too often increases the IO time.
4667///
4668/// \note Calling `TTree::AutoSave` too often increases the IO time and also the
4669/// file size.
4670///
4671/// \note This method calls `TTree::ChangeFile` when the tree reaches a size
4672/// greater than `TTree::fgMaxTreeSize`. This doesn't happen if the tree is
4673/// attached to a `TMemFile` or derivate.
4676{
4677 Int_t nbytes = 0;
4678 Int_t nwrite = 0;
4679 Int_t nerror = 0;
4681
4682 // Case of one single super branch. Automatically update
4683 // all the branch addresses if a new object was created.
4684 if (nbranches == 1)
4685 ((TBranch *)fBranches.UncheckedAt(0))->UpdateAddress();
4686
4687 if (fBranchRef)
4688 fBranchRef->Clear();
4689
4690#ifdef R__USE_IMT
4693 if (useIMT) {
4694 fIMTFlush = true;
4695 fIMTZipBytes.store(0);
4696 fIMTTotBytes.store(0);
4697 }
4698#endif
4699
4700 for (Int_t i = 0; i < nbranches; ++i) {
4701 // Loop over all branches, filling and accumulating bytes written and error counts.
4703
4704 if (branch->TestBit(kDoNotProcess))
4705 continue;
4706
4707#ifndef R__USE_IMT
4708 nwrite = branch->FillImpl(nullptr);
4709#else
4710 nwrite = branch->FillImpl(useIMT ? &imtHelper : nullptr);
4711#endif
4712 if (nwrite < 0) {
4713 if (nerror < 2) {
4714 Error("Fill", "Failed filling branch:%s.%s, nbytes=%d, entry=%lld\n"
4715 " This error is symptomatic of a Tree created as a memory-resident Tree\n"
4716 " Instead of doing:\n"
4717 " TTree *T = new TTree(...)\n"
4718 " TFile *f = new TFile(...)\n"
4719 " you should do:\n"
4720 " TFile *f = new TFile(...)\n"
4721 " TTree *T = new TTree(...)\n\n",
4722 GetName(), branch->GetName(), nwrite, fEntries + 1);
4723 } else {
4724 Error("Fill", "Failed filling branch:%s.%s, nbytes=%d, entry=%lld", GetName(), branch->GetName(), nwrite,
4725 fEntries + 1);
4726 }
4727 ++nerror;
4728 } else {
4729 nbytes += nwrite;
4730 }
4731 }
4732
4733#ifdef R__USE_IMT
4734 if (fIMTFlush) {
4735 imtHelper.Wait();
4736 fIMTFlush = false;
4737 const_cast<TTree *>(this)->AddTotBytes(fIMTTotBytes);
4738 const_cast<TTree *>(this)->AddZipBytes(fIMTZipBytes);
4739 nbytes += imtHelper.GetNbytes();
4740 nerror += imtHelper.GetNerrors();
4741 }
4742#endif
4743
4744 if (fBranchRef)
4745 fBranchRef->Fill();
4746
4747 ++fEntries;
4748
4749 if (fEntries > fMaxEntries)
4750 KeepCircular();
4751
4752 if (gDebug > 0)
4753 Info("TTree::Fill", " - A: %d %lld %lld %lld %lld %lld %lld \n", nbytes, fEntries, fAutoFlush, fAutoSave,
4755
4756 bool autoFlush = false;
4757 bool autoSave = false;
4758
4759 if (fAutoFlush != 0 || fAutoSave != 0) {
4760 // Is it time to flush or autosave baskets?
4761 if (fFlushedBytes == 0) {
4762 // If fFlushedBytes == 0, it means we never flushed or saved, so
4763 // we need to check if it's time to do it and recompute the values
4764 // of fAutoFlush and fAutoSave in terms of the number of entries.
4765 // Decision can be based initially either on the number of bytes
4766 // or the number of entries written.
4768
4769 if (fAutoFlush)
4771
4772 if (fAutoSave)
4773 autoSave = fAutoSave < 0 ? (zipBytes > -fAutoSave) : fEntries % fAutoSave == 0;
4774
4775 if (autoFlush || autoSave) {
4776 // First call FlushBasket to make sure that fTotBytes is up to date.
4778 autoFlush = false; // avoid auto flushing again later
4779
4780 // When we are in one-basket-per-cluster mode, there is no need to optimize basket:
4781 // they will automatically grow to the size needed for an event cluster (with the basket
4782 // shrinking preventing them from growing too much larger than the actually-used space).
4784 OptimizeBaskets(GetTotBytes(), 1, "");
4785 if (gDebug > 0)
4786 Info("TTree::Fill", "OptimizeBaskets called at entry %lld, fZipBytes=%lld, fFlushedBytes=%lld\n",
4788 }
4790 fAutoFlush = fEntries; // Use test on entries rather than bytes
4791
4792 // subsequently in run
4793 if (fAutoSave < 0) {
4794 // Set fAutoSave to the largest integer multiple of
4795 // fAutoFlush events such that fAutoSave*fFlushedBytes
4796 // < (minus the input value of fAutoSave)
4798 if (zipBytes != 0) {
4800 } else if (totBytes != 0) {
4802 } else {
4804 TTree::Class()->WriteBuffer(b, (TTree *)this);
4805 Long64_t total = b.Length();
4807 }
4808 } else if (fAutoSave > 0) {
4810 }
4811
4812 if (fAutoSave != 0 && fEntries >= fAutoSave)
4813 autoSave = true;
4814
4815 if (gDebug > 0)
4816 Info("TTree::Fill", "First AutoFlush. fAutoFlush = %lld, fAutoSave = %lld\n", fAutoFlush, fAutoSave);
4817 }
4818 } else {
4819 // Check if we need to auto flush
4820 if (fAutoFlush) {
4821 if (fNClusterRange == 0)
4822 autoFlush = fEntries > 1 && fEntries % fAutoFlush == 0;
4823 else
4825 }
4826 // Check if we need to auto save
4827 if (fAutoSave)
4828 autoSave = fEntries % fAutoSave == 0;
4829 }
4830 }
4831
4832 if (autoFlush) {
4834 if (gDebug > 0)
4835 Info("TTree::Fill", "FlushBaskets() called at entry %lld, fZipBytes=%lld, fFlushedBytes=%lld\n", fEntries,
4838 }
4839
4840 if (autoSave) {
4841 AutoSave(); // does not call FlushBasketsImpl() again
4842 if (gDebug > 0)
4843 Info("TTree::Fill", "AutoSave called at entry %lld, fZipBytes=%lld, fSavedBytes=%lld\n", fEntries,
4845 }
4846
4847 // Check that output file is still below the maximum size.
4848 // If above, close the current file and continue on a new file.
4849 // Currently, the automatic change of file is restricted
4850 // to the case where the tree is in the top level directory.
4851 if (fDirectory)
4852 if (TFile *file = fDirectory->GetFile())
4853 if (static_cast<TDirectory *>(file) == fDirectory && (file->GetEND() > fgMaxTreeSize))
4854 ChangeFile(file);
4855
4856 return nerror == 0 ? nbytes : -1;
4857}
4858
4859////////////////////////////////////////////////////////////////////////////////
4860/// Search in the array for a branch matching the branch name,
4861/// with the branch possibly expressed as a 'full' path name (with dots).
4863static TBranch *R__FindBranchHelper(TObjArray *list, const char *branchname) {
4864 if (list==nullptr || branchname == nullptr || branchname[0] == '\0') return nullptr;
4865
4866 Int_t nbranches = list->GetEntries();
4867
4869
4870 for(Int_t index = 0; index < nbranches; ++index) {
4871 TBranch *where = (TBranch*)list->UncheckedAt(index);
4872
4873 const char *name = where->GetName();
4874 UInt_t len = strlen(name);
4875 if (len && name[len - 1] == ']' && (brlen == 0 || branchname[brlen - 1] != ']')) {
4876 const char *dim = strchr(name,'[');
4877 if (dim) {
4878 len = dim - name;
4879 }
4880 }
4881 if (brlen == len && strncmp(branchname,name,len)==0) {
4882 return where;
4883 }
4884 TBranch *next = nullptr;
4885 if ((brlen >= len) && (branchname[len] == '.')
4886 && strncmp(name, branchname, len) == 0) {
4887 // The prefix subbranch name match the branch name.
4888
4889 next = where->FindBranch(branchname);
4890 if (!next) {
4891 next = where->FindBranch(branchname+len+1);
4892 }
4893 if (next) return next;
4894 }
4895 const char *dot = strchr((char*)branchname,'.');
4896 if (dot) {
4897 if (len==(size_t)(dot-branchname) &&
4898 strncmp(branchname,name,dot-branchname)==0 ) {
4899 return R__FindBranchHelper(where->GetListOfBranches(),dot+1);
4900 }
4901 }
4902 }
4903 return nullptr;
4904}
4906TBranch *TTree::FindBranchFromSelf(const char *branchName)
4907{
4908 // If the first part of the name match the TTree name, look for the right part in the
4909 // list of branches. This will allow the branchName to be preceded by the name of this tree.
4910 if (strncmp(fName.Data(), branchName, fName.Length()) == 0 && branchName[fName.Length()] == '.')
4911 if (auto *br = R__FindBranchHelper(GetListOfBranches(), branchName + fName.Length() + 1))
4912 return br;
4913
4914 // If we did not find it, let's try to find the full name in the list of branches.
4915 if (auto *br = R__FindBranchHelper(GetListOfBranches(), branchName))
4916 return br;
4917
4918 // If we still did not find, let's try to find it within each branch assuming it does not contain the branch name.
4920 if (auto *nestedbranch = branch->FindBranch(branchName))
4921 return nestedbranch;
4922
4923 return nullptr;
4924}
4926TBranch *TTree::FindBranchFromFriends(const char *branchName)
4927{
4928 if (!fFriends) {
4929 return nullptr;
4930 }
4931
4932 TFriendLock lock(this, kFindBranch);
4934 TTree *t = frEl->GetTree();
4935 if (!t) {
4936 continue;
4937 }
4938 // If the alias is present replace it with the real name.
4939 const char *subbranch = strstr(branchName, frEl->GetName());
4940 if (subbranch != branchName) {
4941 subbranch = nullptr;
4942 }
4943 if (subbranch) {
4944 subbranch += strlen(frEl->GetName());
4945 if (*subbranch != '.') {
4946 subbranch = nullptr;
4947 } else {
4948 ++subbranch;
4949 }
4950 }
4951 std::ostringstream name;
4952 if (subbranch) {
4953 name << t->GetName() << "." << subbranch;
4954 } else {
4955 name << branchName;
4956 }
4957 if (auto *br = t->FindBranch(name.str().c_str()))
4958 return br;
4959 }
4960
4961 return nullptr;
4962}
4963
4964////////////////////////////////////////////////////////////////////////////////
4965/// Return the branch that correspond to the path 'branchname', which can
4966/// include the name of the tree or the omitted name of the parent branches.
4967/// In case of ambiguity, returns the first match.
4968/// \sa TTree::GetBranch
4971{
4972 // We already have been visited while recursively looking
4973 // through the friends tree, let return
4975 return nullptr;
4976 }
4977
4978 if (!branchname)
4979 return nullptr;
4980
4981 if (auto *br = FindBranchFromSelf(branchname))
4982 return br;
4983
4984 if (auto *br = FindBranchFromFriends(branchname))
4985 return br;
4986
4987 return nullptr;
4988}
4989
4990////////////////////////////////////////////////////////////////////////////////
4991/// Find first leaf containing searchname.
4993TLeaf* TTree::FindLeaf(const char* searchname)
4994{
4995 if (!searchname)
4996 return nullptr;
4997
4998 // We already have been visited while recursively looking
4999 // through the friends tree, let's return.
5001 return nullptr;
5002 }
5003
5004 // This will allow the branchname to be preceded by
5005 // the name of this tree.
5006 const char* subsearchname = strstr(searchname, GetName());
5007 if (subsearchname != searchname) {
5008 subsearchname = nullptr;
5009 }
5010 if (subsearchname) {
5012 if (*subsearchname != '.') {
5013 subsearchname = nullptr;
5014 } else {
5015 ++subsearchname;
5016 if (subsearchname[0] == 0) {
5017 subsearchname = nullptr;
5018 }
5019 }
5020 }
5021
5026
5027 const bool searchnameHasDot = strchr(searchname, '.') != nullptr;
5028
5029 // For leaves we allow for one level up to be prefixed to the name.
5030 TIter next(GetListOfLeaves());
5031 TLeaf* leaf = nullptr;
5032 while ((leaf = (TLeaf*) next())) {
5033 leafname = leaf->GetName();
5034 Ssiz_t dim = leafname.First('[');
5035 if (dim >= 0) leafname.Remove(dim);
5036
5037 if (leafname == searchname) {
5038 return leaf;
5039 }
5041 return leaf;
5042 }
5043 // The TLeafElement contains the branch name
5044 // in its name, let's use the title.
5045 leaftitle = leaf->GetTitle();
5046 dim = leaftitle.First('[');
5047 if (dim >= 0) leaftitle.Remove(dim);
5048
5049 if (leaftitle == searchname) {
5050 return leaf;
5051 }
5053 return leaf;
5054 }
5055 if (!searchnameHasDot)
5056 continue;
5057 TBranch* branch = leaf->GetBranch();
5058 if (branch) {
5059 longname.Form("%s.%s",branch->GetName(),leafname.Data());
5060 dim = longname.First('[');
5061 if (dim>=0) longname.Remove(dim);
5062 if (longname == searchname) {
5063 return leaf;
5064 }
5066 return leaf;
5067 }
5068 longtitle.Form("%s.%s",branch->GetName(),leaftitle.Data());
5069 dim = longtitle.First('[');
5070 if (dim>=0) longtitle.Remove(dim);
5071 if (longtitle == searchname) {
5072 return leaf;
5073 }
5075 return leaf;
5076 }
5077 // The following is for the case where the branch is only
5078 // a sub-branch. Since we do not see it through
5079 // TTree::GetListOfBranches, we need to see it indirectly.
5080 // This is the less sturdy part of this search ... it may
5081 // need refining ...
5082 if (strstr(searchname, ".") && !strcmp(searchname, branch->GetName())) {
5083 return leaf;
5084 }
5085 if (subsearchname && strstr(subsearchname, ".") && !strcmp(subsearchname, branch->GetName())) {
5086 return leaf;
5087 }
5088 }
5089 }
5090 // Search in list of friends.
5091 if (!fFriends) {
5092 return nullptr;
5093 }
5094 TFriendLock lock(this, kFindLeaf);
5096 TFriendElement* fe = nullptr;
5097 while ((fe = (TFriendElement*) nextf())) {
5098 TTree* t = fe->GetTree();
5099 if (!t) {
5100 continue;
5101 }
5102 // If the alias is present replace it with the real name.
5103 subsearchname = strstr(searchname, fe->GetName());
5104 if (subsearchname != searchname) {
5105 subsearchname = nullptr;
5106 }
5107 if (subsearchname) {
5108 subsearchname += strlen(fe->GetName());
5109 if (*subsearchname != '.') {
5110 subsearchname = nullptr;
5111 } else {
5112 ++subsearchname;
5113 }
5114 }
5115 if (subsearchname) {
5116 leafname.Form("%s.%s",t->GetName(),subsearchname);
5117 } else {
5119 }
5120 leaf = t->FindLeaf(leafname);
5121 if (leaf) {
5122 return leaf;
5123 }
5124 }
5125 return nullptr;
5126}
5127
5128////////////////////////////////////////////////////////////////////////////////
5129/// Fit a projected item(s) from a tree.
5130///
5131/// funcname is a TF1 function.
5132///
5133/// See TTree::Draw() for explanations of the other parameters.
5134///
5135/// By default the temporary histogram created is called htemp.
5136/// If varexp contains >>hnew , the new histogram created is called hnew
5137/// and it is kept in the current directory.
5138///
5139/// The function returns the number of selected entries.
5140///
5141/// Example:
5142/// ~~~ {.cpp}
5143/// tree.Fit(pol4,"sqrt(x)>>hsqrt","y>0")
5144/// ~~~
5145/// will fit sqrt(x) and save the histogram as "hsqrt" in the current
5146/// directory.
5147///
5148/// See also TTree::UnbinnedFit
5149///
5150/// ## Return status
5151///
5152/// The function returns the status of the histogram fit (see TH1::Fit)
5153/// If no entries were selected, the function returns -1;
5154/// (i.e. fitResult is null if the fit is OK)
5157{
5158 GetPlayer();
5159 if (fPlayer) {
5161 }
5162 return -1;
5163}
5164
5165namespace {
5166struct BoolRAIIToggle {
5167 bool &m_val;
5168
5169 BoolRAIIToggle(bool &val) : m_val(val) { m_val = true; }
5170 ~BoolRAIIToggle() { m_val = false; }
5171};
5172}
5173
5174////////////////////////////////////////////////////////////////////////////////
5175/// Write to disk all the basket that have not yet been individually written and
5176/// create an event cluster boundary (by default).
5177///
5178/// If the caller wishes to flush the baskets but not create an event cluster,
5179/// then set create_cluster to false.
5180///
5181/// If ROOT has IMT-mode enabled, this will launch multiple TBB tasks in parallel
5182/// via TThreadExecutor to do this operation; one per basket compression. If the
5183/// caller utilizes TBB also, care must be taken to prevent deadlocks.
5184///
5185/// For example, let's say the caller holds mutex A and calls FlushBaskets; while
5186/// TBB is waiting for the ROOT compression tasks to complete, it may decide to
5187/// run another one of the user's tasks in this thread. If the second user task
5188/// tries to acquire A, then a deadlock will occur. The example call sequence
5189/// looks like this:
5190///
5191/// - User acquires mutex A
5192/// - User calls FlushBaskets.
5193/// - ROOT launches N tasks and calls wait.
5194/// - TBB schedules another user task, T2.
5195/// - T2 tries to acquire mutex A.
5196///
5197/// At this point, the thread will deadlock: the code may function with IMT-mode
5198/// disabled if the user assumed the legacy code never would run their own TBB
5199/// tasks.
5200///
5201/// SO: users of TBB who want to enable IMT-mode should carefully review their
5202/// locking patterns and make sure they hold no coarse-grained application
5203/// locks when they invoke ROOT.
5204///
5205/// Return the number of bytes written or -1 in case of write error.
5207{
5209 if (retval == -1) return retval;
5210
5211 if (create_cluster) const_cast<TTree *>(this)->MarkEventCluster();
5212 return retval;
5213}
5214
5215////////////////////////////////////////////////////////////////////////////////
5216/// Internal implementation of the FlushBaskets algorithm.
5217/// Unlike the public interface, this does NOT create an explicit event cluster
5218/// boundary; it is up to the (internal) caller to determine whether that should
5219/// done.
5220///
5221/// Otherwise, the comments for FlushBaskets applies.
5224{
5225 if (!fDirectory) return 0;
5226 Int_t nbytes = 0;
5227 Int_t nerror = 0;
5228 TObjArray *lb = const_cast<TTree*>(this)->GetListOfBranches();
5229 Int_t nb = lb->GetEntriesFast();
5230
5231#ifdef R__USE_IMT
5233 if (useIMT) {
5234 // ROOT-9668: here we need to check if the size of fSortedBranches is different from the
5235 // size of the list of branches before triggering the initialisation of the fSortedBranches
5236 // container to cover two cases:
5237 // 1. This is the first time we flush. fSortedBranches is empty and we need to fill it.
5238 // 2. We flushed at least once already but a branch has been be added to the tree since then
5239 if (fSortedBranches.size() != unsigned(nb)) { const_cast<TTree*>(this)->InitializeBranchLists(false); }
5240
5241 BoolRAIIToggle sentry(fIMTFlush);
5242 fIMTZipBytes.store(0);
5243 fIMTTotBytes.store(0);
5244 std::atomic<Int_t> nerrpar(0);
5245 std::atomic<Int_t> nbpar(0);
5246 std::atomic<Int_t> pos(0);
5247
5248 auto mapFunction = [&]() {
5249 // The branch to process is obtained when the task starts to run.
5250 // This way, since branches are sorted, we make sure that branches
5251 // leading to big tasks are processed first. If we assigned the
5252 // branch at task creation time, the scheduler would not necessarily
5253 // respect our sorting.
5254 Int_t j = pos.fetch_add(1);
5255
5256 auto branch = fSortedBranches[j].second;
5257 if (R__unlikely(!branch)) { return; }
5258
5259 if (R__unlikely(gDebug > 0)) {
5260 std::stringstream ss;
5261 ss << std::this_thread::get_id();
5262 Info("FlushBaskets", "[IMT] Thread %s", ss.str().c_str());
5263 Info("FlushBaskets", "[IMT] Running task for branch #%d: %s", j, branch->GetName());
5264 }
5265
5266 Int_t nbtask = branch->FlushBaskets();
5267
5268 if (nbtask < 0) { nerrpar++; }
5269 else { nbpar += nbtask; }
5270 };
5271
5273 pool.Foreach(mapFunction, nb);
5274
5275 fIMTFlush = false;
5276 const_cast<TTree*>(this)->AddTotBytes(fIMTTotBytes);
5277 const_cast<TTree*>(this)->AddZipBytes(fIMTZipBytes);
5278
5279 return nerrpar ? -1 : nbpar.load();
5280 }
5281#endif
5282 for (Int_t j = 0; j < nb; j++) {
5283 TBranch* branch = (TBranch*) lb->UncheckedAt(j);
5284 if (branch) {
5285 Int_t nwrite = branch->FlushBaskets();
5286 if (nwrite<0) {
5287 ++nerror;
5288 } else {
5289 nbytes += nwrite;
5290 }
5291 }
5292 }
5293 if (nerror) {
5294 return -1;
5295 } else {
5296 return nbytes;
5297 }
5298}
5299
5300////////////////////////////////////////////////////////////////////////////////
5301/// Returns the expanded value of the alias. Search in the friends if any.
5303const char* TTree::GetAlias(const char* aliasName) const
5304{
5305 // We already have been visited while recursively looking
5306 // through the friends tree, let's return.
5308 return nullptr;
5309 }
5310 if (fAliases) {
5312 if (alias) {
5313 return alias->GetTitle();
5314 }
5315 }
5316 if (!fFriends) {
5317 return nullptr;
5318 }
5319 TFriendLock lock(const_cast<TTree*>(this), kGetAlias);
5321 TFriendElement* fe = nullptr;
5322 while ((fe = (TFriendElement*) nextf())) {
5323 TTree* t = fe->GetTree();
5324 if (t) {
5325 const char* alias = t->GetAlias(aliasName);
5326 if (alias) {
5327 return alias;
5328 }
5329 const char* subAliasName = strstr(aliasName, fe->GetName());
5330 if (subAliasName && (subAliasName[strlen(fe->GetName())] == '.')) {
5331 alias = t->GetAlias(aliasName + strlen(fe->GetName()) + 1);
5332 if (alias) {
5333 return alias;
5334 }
5335 }
5336 }
5337 }
5338 return nullptr;
5339}
5340
5341namespace {
5342/// Do a breadth first search through the implied hierarchy
5343/// of branches.
5344/// To avoid scanning through the list multiple time
5345/// we also remember the 'depth-first' match.
5346TBranch *R__GetBranch(const TObjArray &branches, const char *name)
5347{
5348 TBranch *result = nullptr;
5349 Int_t nb = branches.GetEntriesFast();
5350 for (Int_t i = 0; i < nb; i++) {
5351 TBranch* b = (TBranch*)branches.UncheckedAt(i);
5352 if (!b)
5353 continue;
5354 if (!strcmp(b->GetName(), name)) {
5355 return b;
5356 }
5357 if (!strcmp(b->GetFullName(), name)) {
5358 return b;
5359 }
5360 if (!result)
5361 result = R__GetBranch(*(b->GetListOfBranches()), name);
5362 }
5363 return result;
5364}
5365}
5366
5367////////////////////////////////////////////////////////////////////////////////
5368/// Returns a pointer to the branch with the given name, if it can be found in
5369/// this tree. Otherwise, returns nullptr.
5370TBranch *TTree::GetBranchFromSelf(const char *branchName)
5371{
5372 // Look for an exact match in the list of top level
5373 // branches.
5374 if (auto *br = static_cast<TBranch *>(fBranches.FindObject(branchName)))
5375 return br;
5376
5377 // Look for an exact match in the mapping from branch name to TBranch *
5378 // gathered when first reading the TTree from disk.
5379 if (auto it = fNamesToBranches.find(branchName); it != fNamesToBranches.end())
5380 return it->second;
5381
5382 // Search using branches, breadth first.
5383 if (auto *br = R__GetBranch(fBranches, branchName))
5384 return br;
5385
5386 // Search using leaves.
5388 Int_t nleaves = leaves->GetEntriesFast();
5389 for (Int_t i = 0; i < nleaves; i++) {
5390 TLeaf *leaf = (TLeaf *)leaves->UncheckedAt(i);
5391 TBranch *branch = leaf->GetBranch();
5392 if (!strcmp(branch->GetName(), branchName)) {
5393 return branch;
5394 }
5395 if (!strcmp(branch->GetFullName(), branchName)) {
5396 return branch;
5397 }
5398 }
5399
5400 return nullptr;
5401}
5402
5403////////////////////////////////////////////////////////////////////////////////
5404/// Returns a pointer to the branch with the given name, if it can be found in
5405/// the list of friends of this tree. Otherwise, returns nullptr.
5406TBranch *TTree::GetBranchFromFriends(const char *branchName)
5407{
5408 if (!fFriends) {
5409 return nullptr;
5410 }
5411
5412 // Search in list of friends.
5413 TFriendLock lock(this, kGetBranch);
5414 TIter next(fFriends);
5415 TFriendElement *fe = nullptr;
5416 while ((fe = (TFriendElement *)next())) {
5417 TTree *t = fe->GetTree();
5418 if (t) {
5419 TBranch *branch = t->GetBranch(branchName);
5420 if (branch) {
5421 return branch;
5422 }
5423 }
5424 }
5425
5426 // Second pass in the list of friends when
5427 // the branch name is prefixed by the tree name.
5428 next.Reset();
5429 while ((fe = (TFriendElement *)next())) {
5430 TTree *t = fe->GetTree();
5431 if (!t) {
5432 continue;
5433 }
5434 const char *subname = strstr(branchName, fe->GetName());
5435 if (subname != branchName) {
5436 continue;
5437 }
5438 Int_t l = strlen(fe->GetName());
5439 subname += l;
5440 if (*subname != '.') {
5441 continue;
5442 }
5443 subname++;
5445 if (branch) {
5446 return branch;
5447 }
5448 }
5449
5450 return nullptr;
5451}
5452
5453////////////////////////////////////////////////////////////////////////////////
5454/// Return pointer to the branch with the given name in this tree or its friends.
5455/// The search is done breadth first.
5456/// \sa TTree::FindBranch
5458TBranch *TTree::GetBranch(const char *name)
5459{
5460 // We already have been visited while recursively
5461 // looking through the friends tree, let's return.
5463 return nullptr;
5464 }
5465
5466 if (!name)
5467 return nullptr;
5468
5469 if (auto *br = GetBranchFromSelf(name))
5470 return br;
5471
5472 if (auto *br = GetBranchFromFriends(name))
5473 return br;
5474
5475 return nullptr;
5476}
5477
5478////////////////////////////////////////////////////////////////////////////////
5479/// Return status of branch with name branchname.
5480///
5481/// - 0 if branch is not activated
5482/// - 1 if branch is activated
5484bool TTree::GetBranchStatus(const char* branchname) const
5485{
5486 TBranch* br = const_cast<TTree*>(this)->GetBranch(branchname);
5487 if (br) {
5488 return br->TestBit(kDoNotProcess) == 0;
5489 }
5490 return false;
5491}
5492
5493////////////////////////////////////////////////////////////////////////////////
5494/// Static function returning the current branch style.
5495///
5496/// - style = 0 old Branch
5497/// - style = 1 new Bronch
5502}
5503
5504////////////////////////////////////////////////////////////////////////////////
5505/// Used for automatic sizing of the cache.
5506///
5507/// Estimates a suitable size in bytes for the tree cache based on AutoFlush.
5508/// A cache sizing factor is taken from the configuration. If this yields zero
5509/// and withDefault is true the historical algorithm for default size is used.
5511Long64_t TTree::GetCacheAutoSize(bool withDefault /* = false */ )
5512{
5514 {
5515 Long64_t cacheSize = 0;
5516 if (fAutoFlush < 0) {
5517 cacheSize = Long64_t(-cacheFactor * fAutoFlush);
5518 } else if (fAutoFlush == 0) {
5520 if (medianClusterSize > 0)
5521 cacheSize = Long64_t(cacheFactor * 1.5 * medianClusterSize * GetZipBytes() / (fEntries + 1));
5522 else
5523 cacheSize = Long64_t(cacheFactor * 1.5 * 30000000); // use the default value of fAutoFlush
5524 } else {
5525 cacheSize = Long64_t(cacheFactor * 1.5 * fAutoFlush * GetZipBytes() / (fEntries + 1));
5526 }
5527 if (cacheSize >= (INT_MAX / 4)) {
5528 cacheSize = INT_MAX / 4;
5529 }
5530 return cacheSize;
5531 };
5532
5533 const char *stcs;
5534 Double_t cacheFactor = 0.0;
5535 if (!(stcs = gSystem->Getenv("ROOT_TTREECACHE_SIZE")) || !*stcs) {
5536 cacheFactor = gEnv->GetValue("TTreeCache.Size", 1.0);
5537 } else {
5539 }
5540
5541 if (cacheFactor < 0.0) {
5542 // ignore negative factors
5543 cacheFactor = 0.0;
5544 }
5545
5547
5548 if (cacheSize < 0) {
5549 cacheSize = 0;
5550 }
5551
5552 if (cacheSize == 0 && withDefault) {
5553 cacheSize = calculateCacheSize(1.0);
5554 }
5555
5556 return cacheSize;
5557}
5558
5559////////////////////////////////////////////////////////////////////////////////
5560/// Return an iterator over the cluster of baskets starting at firstentry.
5561///
5562/// This iterator is not yet supported for TChain object.
5563/// ~~~ {.cpp}
5564/// TTree::TClusterIterator clusterIter = tree->GetClusterIterator(entry);
5565/// Long64_t clusterStart;
5566/// while( (clusterStart = clusterIter()) < tree->GetEntries() ) {
5567/// printf("The cluster starts at %lld and ends at %lld (inclusive)\n",clusterStart,clusterIter.GetNextEntry()-1);
5568/// }
5569/// ~~~
5572{
5573 // create cache if wanted
5574 if (fCacheDoAutoInit)
5576
5577 return TClusterIterator(this,firstentry);
5578}
5579
5580////////////////////////////////////////////////////////////////////////////////
5581/// Return pointer to the current file.
5584{
5585 if (!fDirectory || fDirectory==gROOT) {
5586 return nullptr;
5587 }
5588 return fDirectory->GetFile();
5589}
5590
5591////////////////////////////////////////////////////////////////////////////////
5592/// Return the number of entries matching the selection.
5593/// Return -1 in case of errors.
5594///
5595/// If the selection uses any arrays or containers, we return the number
5596/// of entries where at least one element match the selection.
5597/// GetEntries is implemented using the selector class TSelectorEntries,
5598/// which can be used directly (see code in TTreePlayer::GetEntries) for
5599/// additional option.
5600/// If SetEventList was used on the TTree or TChain, only that subset
5601/// of entries will be considered.
5604{
5605 GetPlayer();
5606 if (fPlayer) {
5607 return fPlayer->GetEntries(selection);
5608 }
5609 return -1;
5610}
5611
5612////////////////////////////////////////////////////////////////////////////////
5613/// Returns a number corresponding to:
5614/// - The number of entries in this tree, if greater than zero
5615/// - The number of entries in the first friend tree, if there are any friends
5616/// - 0 otherwise
5619{
5620 if (fEntries) return fEntries;
5621 if (!fFriends) return 0;
5623 if (!fr) return 0;
5624 TTree *t = fr->GetTree();
5625 if (t==nullptr) return 0;
5626 return t->GetEntriesFriend();
5627}
5628
5629////////////////////////////////////////////////////////////////////////////////
5630/// Read all branches of entry and return total number of bytes read.
5631///
5632/// - `getall = 0` : get only active branches
5633/// - `getall = 1` : get all branches
5634///
5635/// The function returns the number of bytes read from the input buffer.
5636/// If entry does not exist the function returns 0.
5637/// If an I/O error occurs, the function returns -1.
5638/// If all branches are disabled and getall == 0, it also returns 0
5639/// even if the specified entry exists in the tree, since zero bytes were read.
5640///
5641/// If the Tree has friends, also read the friends entry.
5642///
5643/// To activate/deactivate one or more branches, use TBranch::SetBranchStatus
5644/// For example, if you have a Tree with several hundred branches, and you
5645/// are interested only by branches named "a" and "b", do
5646/// ~~~ {.cpp}
5647/// mytree.SetBranchStatus("*",0); //disable all branches
5648/// mytree.SetBranchStatus("a",1);
5649/// mytree.SetBranchStatus("b",1);
5650/// ~~~
5651/// when calling mytree.GetEntry(i); only branches "a" and "b" will be read.
5652///
5653/// __WARNING!!__
5654/// If your Tree has been created in split mode with a parent branch "parent.",
5655/// ~~~ {.cpp}
5656/// mytree.SetBranchStatus("parent",1);
5657/// ~~~
5658/// will not activate the sub-branches of "parent". You should do:
5659/// ~~~ {.cpp}
5660/// mytree.SetBranchStatus("parent*",1);
5661/// ~~~
5662/// Without the trailing dot in the branch creation you have no choice but to
5663/// call SetBranchStatus explicitly for each of the sub branches.
5664///
5665/// An alternative is to call directly
5666/// ~~~ {.cpp}
5667/// brancha.GetEntry(i)
5668/// branchb.GetEntry(i);
5669/// ~~~
5670/// ## IMPORTANT NOTE
5671///
5672/// By default, GetEntry reuses the space allocated by the previous object
5673/// for each branch. You can force the previous object to be automatically
5674/// deleted if you call mybranch.SetAutoDelete(true) (default is false).
5675///
5676/// Example:
5677///
5678/// Consider the example in $ROOTSYS/test/Event.h
5679/// The top level branch in the tree T is declared with:
5680/// ~~~ {.cpp}
5681/// Event *event = 0; //event must be null or point to a valid object
5682/// //it must be initialized
5683/// T.SetBranchAddress("event",&event);
5684/// ~~~
5685/// When reading the Tree, one can choose one of these 3 options:
5686///
5687/// ## OPTION 1
5688///
5689/// ~~~ {.cpp}
5690/// for (Long64_t i=0;i<nentries;i++) {
5691/// T.GetEntry(i);
5692/// // the object event has been filled at this point
5693/// }
5694/// ~~~
5695/// The default (recommended). At the first entry an object of the class
5696/// Event will be created and pointed by event. At the following entries,
5697/// event will be overwritten by the new data. All internal members that are
5698/// TObject* are automatically deleted. It is important that these members
5699/// be in a valid state when GetEntry is called. Pointers must be correctly
5700/// initialized. However these internal members will not be deleted if the
5701/// characters "->" are specified as the first characters in the comment
5702/// field of the data member declaration.
5703///
5704/// If "->" is specified, the pointer member is read via pointer->Streamer(buf).
5705/// In this case, it is assumed that the pointer is never null (case of
5706/// pointer TClonesArray *fTracks in the Event example). If "->" is not
5707/// specified, the pointer member is read via buf >> pointer. In this case
5708/// the pointer may be null. Note that the option with "->" is faster to
5709/// read or write and it also consumes less space in the file.
5710///
5711/// ## OPTION 2
5712///
5713/// The option AutoDelete is set
5714/// ~~~ {.cpp}
5715/// TBranch *branch = T.GetBranch("event");
5716/// branch->SetAddress(&event);
5717/// branch->SetAutoDelete(true);
5718/// for (Long64_t i=0;i<nentries;i++) {
5719/// T.GetEntry(i);
5720/// // the object event has been filled at this point
5721/// }
5722/// ~~~
5723/// In this case, at each iteration, the object event is deleted by GetEntry
5724/// and a new instance of Event is created and filled.
5725///
5726/// ## OPTION 3
5727///
5728/// ~~~ {.cpp}
5729/// Same as option 1, but you delete yourself the event.
5730///
5731/// for (Long64_t i=0;i<nentries;i++) {
5732/// delete event;
5733/// event = 0; // EXTREMELY IMPORTANT
5734/// T.GetEntry(i);
5735/// // the object event has been filled at this point
5736/// }
5737/// ~~~
5738/// It is strongly recommended to use the default option 1. It has the
5739/// additional advantage that functions like TTree::Draw (internally calling
5740/// TTree::GetEntry) will be functional even when the classes in the file are
5741/// not available.
5742///
5743/// Note: See the comments in TBranchElement::SetAddress() for the
5744/// object ownership policy of the underlying (user) data.
5747{
5748 // We already have been visited while recursively looking
5749 // through the friends tree, let return
5750 if (kGetEntry & fFriendLockStatus) return 0;
5751
5752 if (entry < 0 || entry >= fEntries) return 0;
5753 Int_t i;
5754 Int_t nbytes = 0;
5755 fReadEntry = entry;
5756
5757 // create cache if wanted
5758 if (fCacheDoAutoInit)
5760
5762 Int_t nb=0;
5763
5764 auto seqprocessing = [&]() {
5765 TBranch *branch;
5766 for (i=0;i<nbranches;i++) {
5768 nb = branch->GetEntry(entry, getall);
5769 if (nb < 0) break;
5770 nbytes += nb;
5771 }
5772 };
5773
5774#ifdef R__USE_IMT
5776 if (fSortedBranches.empty())
5778
5779 // Count branches are processed first and sequentially
5780 for (auto branch : fSeqBranches) {
5781 nb = branch->GetEntry(entry, getall);
5782 if (nb < 0) break;
5783 nbytes += nb;
5784 }
5785 if (nb < 0) return nb;
5786
5787 // Enable this IMT use case (activate its locks)
5789
5790 Int_t errnb = 0;
5791 std::atomic<Int_t> pos(0);
5792 std::atomic<Int_t> nbpar(0);
5793
5794 auto mapFunction = [&]() {
5795 // The branch to process is obtained when the task starts to run.
5796 // This way, since branches are sorted, we make sure that branches
5797 // leading to big tasks are processed first. If we assigned the
5798 // branch at task creation time, the scheduler would not necessarily
5799 // respect our sorting.
5800 Int_t j = pos.fetch_add(1);
5801
5802 Int_t nbtask = 0;
5803 auto branch = fSortedBranches[j].second;
5804
5805 if (gDebug > 0) {
5806 std::stringstream ss;
5807 ss << std::this_thread::get_id();
5808 Info("GetEntry", "[IMT] Thread %s", ss.str().c_str());
5809 Info("GetEntry", "[IMT] Running task for branch #%d: %s", j, branch->GetName());
5810 }
5811
5812 std::chrono::time_point<std::chrono::system_clock> start, end;
5813
5814 start = std::chrono::system_clock::now();
5815 nbtask = branch->GetEntry(entry, getall);
5816 end = std::chrono::system_clock::now();
5817
5818 Long64_t tasktime = (Long64_t)std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
5819 fSortedBranches[j].first += tasktime;
5820
5821 if (nbtask < 0) errnb = nbtask;
5822 else nbpar += nbtask;
5823 };
5824
5826 pool.Foreach(mapFunction, fSortedBranches.size());
5827
5828 if (errnb < 0) {
5829 nb = errnb;
5830 }
5831 else {
5832 // Save the number of bytes read by the tasks
5833 nbytes += nbpar;
5834
5835 // Re-sort branches if necessary
5839 }
5840 }
5841 }
5842 else {
5843 seqprocessing();
5844 }
5845#else
5846 seqprocessing();
5847#endif
5848 if (nb < 0) return nb;
5849
5850 // GetEntry in list of friends
5851 if (!fFriends) return nbytes;
5852 TFriendLock lock(this,kGetEntry);
5855 while ((fe = (TFriendElement*)nextf())) {
5856 TTree *t = fe->GetTree();
5857 if (t) {
5858 if (fe->TestBit(TFriendElement::kFromChain)) {
5859 nb = t->GetEntry(t->GetReadEntry(),getall);
5860 } else {
5861 if ( t->LoadTreeFriend(entry,this) >= 0 ) {
5862 nb = t->GetEntry(t->GetReadEntry(),getall);
5863 } else nb = 0;
5864 }
5865 if (nb < 0) return nb;
5866 nbytes += nb;
5867 }
5868 }
5869 return nbytes;
5870}
5871
5872
5873////////////////////////////////////////////////////////////////////////////////
5874/// Divides the top-level branches into two vectors: (i) branches to be
5875/// processed sequentially and (ii) branches to be processed in parallel.
5876/// Even if IMT is on, some branches might need to be processed first and in a
5877/// sequential fashion: in the parallelization of GetEntry, those are the
5878/// branches that store the size of another branch for every entry
5879/// (e.g. the size of an array branch). If such branches were processed
5880/// in parallel with the rest, there could be two threads invoking
5881/// TBranch::GetEntry on one of them at the same time, since a branch that
5882/// depends on a size (or count) branch will also invoke GetEntry on the latter.
5883/// This method can be invoked several times during the event loop if the TTree
5884/// is being written, for example when adding new branches. In these cases, the
5885/// `checkLeafCount` parameter is false.
5886/// \param[in] checkLeafCount True if we need to check whether some branches are
5887/// count leaves.
5890{
5892
5893 // The special branch fBranchRef needs to be processed sequentially:
5894 // we add it once only.
5895 if (fBranchRef && fBranchRef != fSeqBranches[0]) {
5896 fSeqBranches.push_back(fBranchRef);
5897 }
5898
5899 // The branches to be processed sequentially are those that are the leaf count of another branch
5900 if (checkLeafCount) {
5901 for (Int_t i = 0; i < nbranches; i++) {
5903 auto leafCount = ((TLeaf*)branch->GetListOfLeaves()->At(0))->GetLeafCount();
5904 if (leafCount) {
5905 auto countBranch = leafCount->GetBranch();
5906 if (std::find(fSeqBranches.begin(), fSeqBranches.end(), countBranch) == fSeqBranches.end()) {
5907 fSeqBranches.push_back(countBranch);
5908 }
5909 }
5910 }
5911 }
5912
5913 // Any branch that is not a leaf count can be safely processed in parallel when reading
5914 // We need to reset the vector to make sure we do not re-add several times the same branch.
5915 if (!checkLeafCount) {
5916 fSortedBranches.clear();
5917 }
5918 for (Int_t i = 0; i < nbranches; i++) {
5919 Long64_t bbytes = 0;
5921 if (std::find(fSeqBranches.begin(), fSeqBranches.end(), branch) == fSeqBranches.end()) {
5922 bbytes = branch->GetTotBytes("*");
5923 fSortedBranches.emplace_back(bbytes, branch);
5924 }
5925 }
5926
5927 // Initially sort parallel branches by size
5928 std::sort(fSortedBranches.begin(),
5929 fSortedBranches.end(),
5930 [](std::pair<Long64_t,TBranch*> a, std::pair<Long64_t,TBranch*> b) {
5931 return a.first > b.first;
5932 });
5933
5934 for (size_t i = 0; i < fSortedBranches.size(); i++) {
5935 fSortedBranches[i].first = 0LL;
5936 }
5937}
5938
5939////////////////////////////////////////////////////////////////////////////////
5940/// Sorts top-level branches by the last average task time recorded per branch.
5943{
5944 for (size_t i = 0; i < fSortedBranches.size(); i++) {
5946 }
5947
5948 std::sort(fSortedBranches.begin(),
5949 fSortedBranches.end(),
5950 [](std::pair<Long64_t,TBranch*> a, std::pair<Long64_t,TBranch*> b) {
5951 return a.first > b.first;
5952 });
5953
5954 for (size_t i = 0; i < fSortedBranches.size(); i++) {
5955 fSortedBranches[i].first = 0LL;
5956 }
5957}
5958
5959////////////////////////////////////////////////////////////////////////////////
5960///Returns the entry list assigned to this tree
5963{
5964 return fEntryList;
5965}
5966
5967////////////////////////////////////////////////////////////////////////////////
5968/// Return entry number corresponding to entry.
5969///
5970/// if no TEntryList set returns entry
5971/// else returns the entry number corresponding to the list index=entry
5974{
5975 if (!fEntryList) {
5976 return entry;
5977 }
5978
5979 return fEntryList->GetEntry(entry);
5980}
5981
5982////////////////////////////////////////////////////////////////////////////////
5983/// Return entry number corresponding to major and minor number.
5984/// Note that this function returns only the entry number, not the data
5985/// To read the data corresponding to an entry number, use TTree::GetEntryWithIndex
5986/// the BuildIndex function has created a table of Long64_t* of sorted values
5987/// corresponding to val = major<<31 + minor;
5988/// The function performs binary search in this sorted table.
5989/// If it finds a pair that matches val, it returns directly the
5990/// index in the table.
5991/// If an entry corresponding to major and minor is not found, the function
5992/// returns the index of the major,minor pair immediately lower than the
5993/// requested value, ie it will return -1 if the pair is lower than
5994/// the first entry in the index.
5995///
5996/// See also GetEntryNumberWithIndex
6004}
6005
6006////////////////////////////////////////////////////////////////////////////////
6007/// Return entry number corresponding to major and minor number.
6008/// Note that this function returns only the entry number, not the data
6009/// To read the data corresponding to an entry number, use TTree::GetEntryWithIndex
6010/// the BuildIndex function has created a table of Long64_t* of sorted values
6011/// corresponding to val = major<<31 + minor;
6012/// The function performs binary search in this sorted table.
6013/// If it finds a pair that matches val, it returns directly the
6014/// index in the table, otherwise it returns -1.
6015///
6016/// See also GetEntryNumberWithBestIndex
6019{
6020 if (!fTreeIndex) {
6021 return -1;
6022 }
6024}
6025
6026////////////////////////////////////////////////////////////////////////////////
6027/// Read entry corresponding to major and minor number.
6028///
6029/// The function returns the total number of bytes read; -1 if entry not found.
6030/// If the Tree has friend trees, the corresponding entry with
6031/// the index values (major,minor) is read. Note that the master Tree
6032/// and its friend may have different entry serial numbers corresponding
6033/// to (major,minor).
6034/// \note See TTreeIndex::GetEntryNumberWithIndex for information about the maximum values accepted for major and minor
6037{
6038 // We already have been visited while recursively looking
6039 // through the friends tree, let's return.
6041 return 0;
6042 }
6044 if (serial < 0) {
6045 return -1;
6046 }
6047 // create cache if wanted
6048 if (fCacheDoAutoInit)
6050
6051 Int_t i;
6052 Int_t nbytes = 0;
6053 fReadEntry = serial;
6054 TBranch *branch;
6056 Int_t nb;
6057 for (i = 0; i < nbranches; ++i) {
6059 nb = branch->GetEntry(serial);
6060 if (nb < 0) return nb;
6061 nbytes += nb;
6062 }
6063 // GetEntry in list of friends
6064 if (!fFriends) return nbytes;
6067 TFriendElement* fe = nullptr;
6068 while ((fe = (TFriendElement*) nextf())) {
6069 TTree *t = fe->GetTree();
6070 if (t) {
6071 serial = t->GetEntryNumberWithIndex(major,minor);
6072 if (serial <0) return -nbytes;
6073 nb = t->GetEntry(serial);
6074 if (nb < 0) return nb;
6075 nbytes += nb;
6076 }
6077 }
6078 return nbytes;
6079}
6080
6081////////////////////////////////////////////////////////////////////////////////
6082/// Return a pointer to the TTree friend whose name or alias is `friendname`.
6084TTree* TTree::GetFriend(const char *friendname) const
6085{
6086
6087 // We already have been visited while recursively
6088 // looking through the friends tree, let's return.
6090 return nullptr;
6091 }
6092 if (!fFriends) {
6093 return nullptr;
6094 }
6095 TFriendLock lock(const_cast<TTree*>(this), kGetFriend);
6097 TFriendElement* fe = nullptr;
6098 while ((fe = (TFriendElement*) nextf())) {
6099 if (strcmp(friendname,fe->GetName())==0
6100 || strcmp(friendname,fe->GetTreeName())==0) {
6101 return fe->GetTree();
6102 }
6103 }
6104 // After looking at the first level,
6105 // let's see if it is a friend of friends.
6106 nextf.Reset();
6107 fe = nullptr;
6108 while ((fe = (TFriendElement*) nextf())) {
6109 TTree *res = fe->GetTree()->GetFriend(friendname);
6110 if (res) {
6111 return res;
6112 }
6113 }
6114 return nullptr;
6115}
6116
6117////////////////////////////////////////////////////////////////////////////////
6118/// If the 'tree' is a friend, this method returns its alias name.
6119///
6120/// This alias is an alternate name for the tree.
6121///
6122/// It can be used in conjunction with a branch or leaf name in a TTreeFormula,
6123/// to specify in which particular tree the branch or leaf can be found if
6124/// the friend trees have branches or leaves with the same name as the master
6125/// tree.
6126///
6127/// It can also be used in conjunction with an alias created using
6128/// TTree::SetAlias in a TTreeFormula, e.g.:
6129/// ~~~ {.cpp}
6130/// maintree->Draw("treealias.fPx - treealias.myAlias");
6131/// ~~~
6132/// where fPx is a branch of the friend tree aliased as 'treealias' and 'myAlias'
6133/// was created using TTree::SetAlias on the friend tree.
6134///
6135/// However, note that 'treealias.myAlias' will be expanded literally,
6136/// without remembering that it comes from the aliased friend and thus
6137/// the branch name might not be disambiguated properly, which means
6138/// that you may not be able to take advantage of this feature.
6139///
6141const char *TTree::GetFriendAlias(TTree *tree) const
6142{
6143 if ((tree == this) || (tree == GetTree())) {
6144 return nullptr;
6145 }
6146
6147 // We already have been visited while recursively
6148 // looking through the friends tree, let's return.
6150 return nullptr;
6151 }
6152
6153 // This is a TTree and it does not have any friends, we can return early
6154 if (GetTree() == this && !fFriends)
6155 return nullptr;
6156
6157 TFriendLock lock(const_cast<TTree *>(this), kGetFriendAlias);
6158
6159 auto lookForFriendNameInListOfFriends = [tree](const TList &friends) -> const char * {
6161 auto *frElTree = frEl->GetTree();
6162 // Simplest case: we found a friend which tree is the same as the input tree
6163 if (frElTree == tree)
6164 return frEl->GetName();
6165 // Try again: the friend tree might be actually a TChain
6166 if (frElTree && frElTree->GetTree() == tree)
6167 return frEl->GetName();
6168 }
6169 return nullptr;
6170 };
6171
6172 // First, look for the immediate friends of this tree
6173 if (fFriends) {
6175 if (friendAlias)
6176 return friendAlias;
6177 }
6178
6179 // Then, check if this is a TChain and the current tree has friends
6180 // The non-redundant scenario here is that the currently-available
6181 // inner TTree of this TChain has a list of friends which the TChain
6182 // itself doesn't know anything about.
6183 if (const auto *innerListOfFriends = GetTree()->GetListOfFriends();
6186 if (friendAlias)
6187 return friendAlias;
6188 }
6189
6190 // Recursively look into the list of friends of this tree
6191 if (fFriends) {
6193 const char *friendAlias = frEl->GetTree()->GetFriendAlias(tree);
6194 if (friendAlias)
6195 return friendAlias;
6196 }
6197 }
6198
6199 // Recursively look into the list of friends of the inner tree
6200 if (const auto *innerListOfFriends = GetTree()->GetListOfFriends();
6203 const char *friendAlias = frEl->GetTree()->GetFriendAlias(tree);
6204 if (friendAlias)
6205 return friendAlias;
6206 }
6207 }
6208 return nullptr;
6209}
6210
6211////////////////////////////////////////////////////////////////////////////////
6212/// Returns the current set of IO settings
6214{
6215 return fIOFeatures;
6216}
6217
6218////////////////////////////////////////////////////////////////////////////////
6219/// Creates a new iterator that will go through all the leaves on the tree itself and its friend.
6222{
6223 return new TTreeFriendLeafIter(this, dir);
6224}
6226TLeaf *TTree::SearchLeafInListOfLeaves(const char *branchName, const char *leafName)
6227{
6229 if (strcmp(leaf->GetFullName(), leafName) != 0 && strcmp(leaf->GetName(), leafName) != 0)
6230 continue; // leafName does not match GetName() nor GetFullName(), this is not the right leaf
6231 if (branchName) {
6232 // check the branchName is also a match
6233 TBranch *br = leaf->GetBranch();
6234 // if a quick comparison with the branch full name is a match, we are done
6235 if (!strcmp(br->GetFullName(), branchName))
6236 return leaf;
6237 UInt_t nbch = strlen(branchName);
6238 const char* brname = br->GetName();
6239 TBranch *mother = br->GetMother();
6240 if (strncmp(brname, branchName, nbch)) {
6241 if (mother != br) {
6242 const char *mothername = mother->GetName();
6244 if (!strcmp(mothername, branchName)) {
6245 return leaf;
6246 } else if (nbch > motherlen && strncmp(mothername, branchName, motherlen) == 0 &&
6247 (mothername[motherlen - 1] == '.' || branchName[motherlen] == '.')) {
6248 // The left part of the requested name match the name of the mother, let's see if the right part match the name of the branch.
6249 if (strncmp(brname, branchName + motherlen + 1, nbch - motherlen - 1)) {
6250 // No it does not
6251 continue;
6252 } // else we have match so we can proceed.
6253 } else {
6254 // no match
6255 continue;
6256 }
6257 } else {
6258 continue;
6259 }
6260 }
6261 // The start of the branch name is identical to the content
6262 // of 'aname' before the first '/'.
6263 // Let's make sure that it is not longer (we are trying
6264 // to avoid having jet2/value match the branch jet23
6265 if ((strlen(brname) > nbch) && (brname[nbch] != '.') && (brname[nbch] != '[')) {
6266 continue;
6267 }
6268 }
6269 return leaf;
6270 }
6271
6272 return nullptr;
6273}
6275TLeaf *TTree::SearchLeafInListOfFriends(const char *branchName, const char *leafName)
6276{
6277 if (!fFriends) return nullptr;
6278 // The corresponding check is in GetLeaf
6279 TFriendLock lock(this, kGetLeaf);
6280
6282 if (auto *t = frEl->GetTree())
6283 if (auto *leaf = t->GetLeaf(branchName, leafName))
6284 return leaf;
6285
6286 // Second pass in the list of friends when the leaf name is prefixed by the tree name
6289 TTree *t = frEl->GetTree();
6290 if (!t) continue;
6291 const char *subLeafName = strstr(leafName, frEl->GetName());
6292 if (subLeafName != leafName)
6293 continue;
6294 Int_t l = strlen(frEl->GetName());
6295 subLeafName += l;
6296 if (*subLeafName != '.')
6297 continue;
6298 subLeafName++;
6300 if (auto *leaf = t->GetLeaf(branchName, subLeafName))
6301 return leaf;
6302 }
6303
6304 return nullptr;
6305}
6306
6307////////////////////////////////////////////////////////////////////////////////
6308/// Searches in this tree and any of its friends for a leaf named \p leafname in branch \p branchname , returns first
6309/// match or nullptr if no match.
6310///
6311/// Search order:
6312///
6313/// 1. Look for a \p branchname match (via FindBranch(branchname)):
6314/// a. In the list of branches of this tree
6315/// b. Recursively in nested branches of each branch of this tree
6316/// c. In the friends of this tree
6317/// 2. Look for matching \p branchname and \p leafname in list of leaves of this tree
6318/// 3. Look for matching \p branchname and \p leafname in friends of this tree (eventually calling GetLeaf on each
6319/// friend)
6320///
6321/// \note \p branchname can be an empty string, in which case the function will return the first leaf with matching
6322/// \p leafname in any branch of this tree or any of its friends following the search order above.
6323///
6324/// \note \p leafname can contain the name of a friend tree with the syntax: `friend_dir_and_tree.full_leaf_name`. In
6325/// particular, `friend_dir_and_tree` can be of the form `TDirectoryName/TreeName`.
6326TLeaf* TTree::GetLeaf(const char* branchname, const char *leafname)
6327{
6328 if (leafname == nullptr) return nullptr;
6329
6330 // We already have been visited while recursively looking
6331 // through the friends tree, let return
6333 return nullptr;
6334 }
6335
6336 if (auto *br = FindBranch(branchname))
6337 if (auto leaf = br->GetLeaf(leafname))
6338 return leaf;
6339
6341 return leaf;
6342
6344 return leaf;
6345
6346 return nullptr;
6347}
6348
6349////////////////////////////////////////////////////////////////////////////////
6350/// Searches in this tree and any of its friends for a leaf named \p leafname , returns first leaf matching in any
6351/// branch.
6352///
6353/// See TTree::GetLeaf(const char* branchname, const char *leafname) for a description of the search order.
6354///
6355/// \note \p name may be in the form `branch/leaf`
6357TLeaf* TTree::GetLeaf(const char *name)
6358{
6359 // Return nullptr if name is invalid or if we have
6360 // already been visited while searching friend trees
6361 if (!name || (kGetLeaf & fFriendLockStatus))
6362 return nullptr;
6363
6364 std::string path(name);
6365 const auto sep = path.find_last_of('/');
6366 if (sep != std::string::npos)
6367 return GetLeaf(path.substr(0, sep).c_str(), name + sep + 1);
6368
6369 return GetLeaf(nullptr, name);
6370}
6371
6372namespace {
6373
6374////////////////////////////////////////////////////////////////////////////////
6375/// \brief Helper detecting *any* file transition of a tree dataset
6376///
6377/// This is a generic helper, works if the dataset is a TTree or a TChain, and
6378/// transitively detects transitions in friends.
6379///
6380/// Comparing `TChain::GetTreeNumber()` before and after a call to
6381/// `TChain::LoadTree` only detects that the chain itself switched to another of
6382/// its own sub-trees. It does *not* detect that one of the (possibly indirect)
6383/// friends of the chain switched to a new file: in that case the cached
6384/// TLeaf/TBranch pointers become dangling even though the tree number of the
6385/// chain is unchanged.
6386///
6387/// `TChain::LoadTree` (both when the chain itself moves to a new tree and, via
6388/// `TChain::RefreshFriendAddresses`, when only a friend was updated) calls
6389/// `fNotify->Notify()`. Subscribing to that notification is therefore the
6390/// reliable way to know that anything in the friend graph moved.
6391///
6392/// This derives directly from TNotifyLinkBase rather than using TNotifyLink<T>
6393/// because the latter would require a dictionary for the instantiation.
6394///
6395/// We could also use
6396/// ```
6397/// struct TLeafRefresher {
6398/// bool fDirty = true;
6399/// bool Notify() { fDirty = true; return true; }
6400/// };
6401/// ```
6402/// declared in TChain.h or InternalTreeUtils.hxx and genereate a dictionary for
6403/// TNotifyLink<TLeafRefresher>.
6404class FileTransitionDetector final : public TNotifyLinkBase {
6405 /// Set to true initially so that the very first iteration performs the lookup.
6406 bool fChanged = true;
6407 TTree &fChain;
6408
6409public:
6410 FileTransitionDetector(TTree &chain) : fChain(chain) { PrependLink(fChain); }
6411
6412 ~FileTransitionDetector() override { RemoveLink(fChain); }
6413 FileTransitionDetector(const FileTransitionDetector &) = delete;
6414 FileTransitionDetector &operator=(const FileTransitionDetector &) = delete;
6415 FileTransitionDetector(FileTransitionDetector &&) = delete;
6416 FileTransitionDetector &operator=(FileTransitionDetector &&) = delete;
6417
6418 /// Must return true: returning false would make TChain::LoadTree fail with -6.
6419 Bool_t Notify() override
6420 {
6421 fChanged = true;
6422 // Propagate to the rest of the list of subscribers, as TNotifyLink does.
6423 if (fNext)
6424 return fNext->Notify();
6425 return true;
6426 }
6427
6428 /// Returns true (once) if the chain or any of its direct or indirect friends
6429 /// switched to a new tree since the last call.
6430 bool CheckAndReset()
6431 {
6432 bool changed = fChanged;
6433 fChanged = false;
6434 return changed;
6435 }
6436};
6437} // anonymous namespace
6438
6439////////////////////////////////////////////////////////////////////////////////
6440/// Computes the extremum (minimum or maximum) for the input column name
6441///
6442/// It takes into account the following situations:
6443///
6444/// * The dataset is a TTree and contains the input column
6445/// * The dataset is a TChain and contains the input column, in which case the methods detect file switching and update
6446/// the leaf pointer correctly.
6447/// * The dataset is a TChain, contains the input column, but some files miss it, in which case the methods skip the
6448/// entries from those files.
6449/// * The dataset has a friend TTree which contains the input column
6450/// * The dataset is a TChain and has a friend TChain which contains the input column, in which case the methods detect
6451/// file switching on the friend and update the leaf pointer correctly.
6452/// * The dataset is a TChain and has a friend TChain. The input column is partially available in either the main or the
6453/// friend chain. This can happen for example if the main chain has some files missing the input column and the user
6454/// knowingly injects the input column in the files of the friend chain. In this case, the methods detect file switching
6455/// at the boundary between files of the main chain, but also detect if there are file switches in the friend chain.
6456/// Notably, the entries must still be overall aligned between the main chain and the friend one.
6457double TTree::ComputeExtremum(const char *columname, double errVal, bool (*cmp)(double, double))
6458{
6459 // Ensure the TTree cursor is brought back to the current entry after computing the value
6460 struct CurrentEntryRAII {
6461
6462 Long64_t fCurrentEntry;
6463 TTree &fTree;
6464
6465 CurrentEntryRAII(TTree &tree) : fCurrentEntry(tree.GetReadEntry()), fTree(tree) {}
6466
6467 ~CurrentEntryRAII() { fTree.LoadTree(fCurrentEntry); }
6468 } raii{*this};
6469
6470 // Initial lookup of the leaf name, this will find it whether it's in the
6471 // current tree or in any of its friends
6473 if (!leaf) {
6474 return 0;
6475 }
6476 TBranch *branch = leaf->GetBranch();
6477 assert(branch); // leaf without a branch is not allowed by construction
6478
6479 // create cache if wanted
6480 if (fCacheDoAutoInit)
6482
6483 FileTransitionDetector fileTransition{*this};
6484 double extremum{errVal};
6485 for (Long64_t i = 0; i < fEntries; ++i) {
6486 const auto entryNumber = GetEntryNumber(i);
6487 if (entryNumber < 0) break;
6489 if (localEntryNumber < 0)
6490 break;
6491
6492 // At every entry, we check if the processing has triggered a switch to
6493 // a new file. We detect both a switch of the current tree in the chain
6494 // (if this tree is a TChain) as well as a switch in any of its direct
6495 // and indirect friends (if they are also a TChain)
6496 if (fileTransition.CheckAndReset()) {
6497 branch = nullptr;
6499 if (leaf) {
6500 branch = leaf->GetBranch();
6501 assert(branch); // leaf without a branch is not allowed by construction
6502 }
6503 }
6504
6505 // We accept that the leaf may not be present in one or more files in case
6506 // it was found in a chain, we just continue processing the next entry
6507 if (!leaf)
6508 continue;
6509
6510 // If the branch belongs to a friend, the local entry number of the friend
6511 // may differ from the one of the chain (e.g. when the friend is indexed).
6512 // The owning TTree has already been positioned by TChain::LoadTree, so
6513 // its read entry is the correct one to use.
6514 auto *owningTree = branch->GetTree();
6515 branch->GetEntry(owningTree->GetReadEntry());
6516
6517 auto leafLen{leaf->GetLen()};
6518 for (decltype(leafLen) j = 0; j < leafLen; ++j) {
6519 auto val = leaf->GetValue(j);
6520 if (cmp(val, extremum)) {
6521 extremum = val;
6522 }
6523 }
6524 }
6525
6526 return extremum;
6527}
6528
6529////////////////////////////////////////////////////////////////////////////////
6530/// Return maximum of column with name columname.
6531/// if the Tree has an associated TEventList or TEntryList, the maximum
6532/// is computed for the entries in this list.
6535{
6536 return ComputeExtremum(columname, std::numeric_limits<double>::lowest(), [](double a, double b) { return a > b; });
6537}
6538
6539////////////////////////////////////////////////////////////////////////////////
6540/// Static function which returns the tree file size limit in bytes.
6545}
6546
6547////////////////////////////////////////////////////////////////////////////////
6548/// Return minimum of column with name columname.
6549/// if the Tree has an associated TEventList or TEntryList, the minimum
6550/// is computed for the entries in this list.
6553{
6554 return ComputeExtremum(columname, std::numeric_limits<double>::max(), [](double a, double b) { return a < b; });
6555}
6556
6557////////////////////////////////////////////////////////////////////////////////
6558/// Load the TTreePlayer (if not already done).
6561{
6562 if (fPlayer) {
6563 return fPlayer;
6564 }
6566 return fPlayer;
6567}
6568
6569////////////////////////////////////////////////////////////////////////////////
6570/// Find and return the TTreeCache registered with the file and which may
6571/// contain branches for us.
6574{
6575 TTreeCache *pe = dynamic_cast<TTreeCache*>(file->GetCacheRead(GetTree()));
6576 if (pe && pe->GetTree() != GetTree())
6577 pe = nullptr;
6578 return pe;
6579}
6580
6581////////////////////////////////////////////////////////////////////////////////
6582/// Find and return the TTreeCache registered with the file and which may
6583/// contain branches for us. If create is true and there is no cache
6584/// a new cache is created with default size.
6586TTreeCache *TTree::GetReadCache(TFile *file, bool create)
6587{
6588 TTreeCache *pe = GetReadCache(file);
6589 if (create && !pe) {
6590 if (fCacheDoAutoInit)
6591 SetCacheSizeAux(true, -1);
6592 pe = dynamic_cast<TTreeCache*>(file->GetCacheRead(GetTree()));
6593 if (pe && pe->GetTree() != GetTree()) pe = nullptr;
6594 }
6595 return pe;
6596}
6597
6598////////////////////////////////////////////////////////////////////////////////
6599/// Return a pointer to the list containing user objects associated to this tree.
6600///
6601/// The list is automatically created if it does not exist.
6602///
6603/// WARNING: By default the TTree destructor will delete all objects added
6604/// to this list. If you do not want these objects to be deleted,
6605/// call:
6606///
6607/// mytree->GetUserInfo()->Clear();
6608///
6609/// before deleting the tree.
6612{
6613 if (!fUserInfo) {
6614 fUserInfo = new TList();
6615 fUserInfo->SetName("UserInfo");
6616 }
6617 return fUserInfo;
6618}
6619
6620////////////////////////////////////////////////////////////////////////////////
6621/// Appends the cluster range information stored in 'fromtree' to this tree,
6622/// including the value of fAutoFlush.
6623///
6624/// This is used when doing a fast cloning (by TTreeCloner).
6625/// See also fAutoFlush and fAutoSave if needed.
6628{
6629 Long64_t autoflush = fromtree->GetAutoFlush();
6630 if (fromtree->fNClusterRange == 0 && fromtree->fAutoFlush == fAutoFlush) {
6631 // nothing to do
6632 } else if (fNClusterRange || fromtree->fNClusterRange) {
6633 Int_t newsize = fNClusterRange + 1 + fromtree->fNClusterRange;
6634 if (newsize > fMaxClusterRange) {
6635 if (fMaxClusterRange) {
6637 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
6639 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
6641 } else {
6645 }
6646 }
6647 if (fEntries) {
6651 }
6652 for (Int_t i = 0 ; i < fromtree->fNClusterRange; ++i) {
6653 fClusterRangeEnd[fNClusterRange] = fEntries + fromtree->fClusterRangeEnd[i];
6654 fClusterSize[fNClusterRange] = fromtree->fClusterSize[i];
6656 }
6658 } else {
6660 }
6662 if (autoflush > 0 && autosave > 0) {
6664 }
6665}
6666
6667////////////////////////////////////////////////////////////////////////////////
6668/// Keep a maximum of fMaxEntries in memory.
6671{
6674 for (Int_t i = 0; i < nb; ++i) {
6676 branch->KeepCircular(maxEntries);
6677 }
6678 if (fNClusterRange) {
6681 for(Int_t i = 0, j = 0; j < oldsize; ++j) {
6684 ++i;
6685 } else {
6687 }
6688 }
6689 }
6691 fReadEntry = -1;
6692}
6693
6694////////////////////////////////////////////////////////////////////////////////
6695/// Read in memory all baskets from all branches up to the limit of maxmemory bytes.
6696///
6697/// If maxmemory is non null and positive SetMaxVirtualSize is called
6698/// with this value. Default for maxmemory is 2000000000 (2 Gigabytes).
6699/// The function returns the total number of baskets read into memory
6700/// if negative an error occurred while loading the branches.
6701/// This method may be called to force branch baskets in memory
6702/// when random access to branch entries is required.
6703/// If random access to only a few branches is required, you should
6704/// call directly TBranch::LoadBaskets.
6707{
6709
6710 TIter next(GetListOfLeaves());
6711 TLeaf *leaf;
6712 Int_t nimported = 0;
6713 while ((leaf=(TLeaf*)next())) {
6714 nimported += leaf->GetBranch()->LoadBaskets();//break;
6715 }
6716 return nimported;
6717}
6718
6719////////////////////////////////////////////////////////////////////////////////
6720/// Set current entry.
6721///
6722/// Returns -2 if entry does not exist (just as TChain::LoadTree()).
6723/// Returns -6 if an error occurs in the notification callback (just as TChain::LoadTree()).
6724///
6725/// Calls fNotify->Notify() (if fNotify is not null) when starting the processing of a new tree.
6726///
6727/// \note This function is overloaded in TChain.
6729{
6730 // We have already been visited while recursively looking
6731 // through the friend trees, let's return
6733 // We need to return a negative value to avoid a circular list of friends
6734 // to think that there is always an entry somewhere in the list.
6735 return -1;
6736 }
6737
6738 // create cache if wanted
6739 if (fCacheDoAutoInit && entry >=0)
6741
6742 if (fNotify) {
6743 if (fReadEntry < 0) {
6744 fNotify->Notify();
6745 }
6746 }
6747 fReadEntry = entry;
6748
6749 bool friendHasEntry = false;
6750 if (fFriends) {
6751 // Set current entry in friends as well.
6752 //
6753 // An alternative would move this code to each of the
6754 // functions calling LoadTree (and to overload a few more).
6755 bool needUpdate = false;
6756 {
6757 // This scope is need to insure the lock is released at the right time
6759 TFriendLock lock(this, kLoadTree);
6760 TFriendElement* fe = nullptr;
6761 while ((fe = (TFriendElement*) nextf())) {
6762 if (fe->TestBit(TFriendElement::kFromChain)) {
6763 // This friend element was added by the chain that owns this
6764 // tree, the chain will deal with loading the correct entry.
6765 continue;
6766 }
6767 TTree* friendTree = fe->GetTree();
6768 if (friendTree) {
6769 if (friendTree->LoadTreeFriend(entry, this) >= 0) {
6770 friendHasEntry = true;
6771 }
6772 }
6773 if (fe->IsUpdated()) {
6774 needUpdate = true;
6775 fe->ResetUpdated();
6776 }
6777 } // for each friend
6778 }
6779 if (needUpdate) {
6780 //update list of leaves in all TTreeFormula of the TTreePlayer (if any)
6781 if (fPlayer) {
6783 }
6784 //Notify user if requested
6785 if (fNotify) {
6786 if(!fNotify->Notify()) return -6;
6787 }
6788 // We cannot know a priori if the branch(es) of the friend TChain(s) that were just
6789 // updated were supposed to be connected to possibly a TChainElement of another chain
6790 // that has befriended this TTree (i.e., one of the "external friends"). Thus, we
6791 // forward the notification that one or more friend trees were updated to the friends
6792 // of this TTree.
6793 if (fExternalFriends)
6795 external_fe->MarkUpdated();
6796 }
6797 }
6798
6799 if ((fReadEntry >= fEntries) && !friendHasEntry) {
6800 fReadEntry = -1;
6801 return -2;
6802 }
6803 return fReadEntry;
6804}
6805
6806////////////////////////////////////////////////////////////////////////////////
6807/// Load entry on behalf of our master tree, we may use an index.
6808///
6809/// Called by LoadTree() when the masterTree looks for the entry
6810/// number in a friend tree (us) corresponding to the passed entry
6811/// number in the masterTree.
6812///
6813/// If we have no index, our entry number and the masterTree entry
6814/// number are the same.
6815///
6816/// If we *do* have an index, we must find the (major, minor) value pair
6817/// in masterTree to locate our corresponding entry.
6818///
6826}
6827
6828////////////////////////////////////////////////////////////////////////////////
6829/// Generate a skeleton analysis class for this tree.
6830///
6831/// The following files are produced: classname.h and classname.C.
6832/// If classname is 0, classname will be called "nameoftree".
6833///
6834/// The generated code in classname.h includes the following:
6835///
6836/// - Identification of the original tree and the input file name.
6837/// - Definition of an analysis class (data members and member functions).
6838/// - The following member functions:
6839/// - constructor (by default opening the tree file),
6840/// - GetEntry(Long64_t entry),
6841/// - Init(TTree* tree) to initialize a new TTree,
6842/// - Show(Long64_t entry) to read and dump entry.
6843///
6844/// The generated code in classname.C includes only the main
6845/// analysis function Loop.
6846///
6847/// To use this function:
6848///
6849/// - Open your tree file (eg: TFile f("myfile.root");)
6850/// - T->MakeClass("MyClass");
6851///
6852/// where T is the name of the TTree in file myfile.root,
6853/// and MyClass.h, MyClass.C the name of the files created by this function.
6854/// In a ROOT session, you can do:
6855/// ~~~ {.cpp}
6856/// root > .L MyClass.C
6857/// root > MyClass* t = new MyClass;
6858/// root > t->GetEntry(12); // Fill data members of t with entry number 12.
6859/// root > t->Show(); // Show values of entry 12.
6860/// root > t->Show(16); // Read and show values of entry 16.
6861/// root > t->Loop(); // Loop on all entries.
6862/// ~~~
6863/// NOTE: Do not use the code generated for a single TTree which is part
6864/// of a TChain to process that entire TChain. The maximum dimensions
6865/// calculated for arrays on the basis of a single TTree from the TChain
6866/// might be (will be!) too small when processing all of the TTrees in
6867/// the TChain. You must use myChain.MakeClass() to generate the code,
6868/// not myTree.MakeClass(...).
6870Int_t TTree::MakeClass(const char* classname, Option_t* option)
6871{
6872 GetPlayer();
6873 if (!fPlayer) {
6874 return 0;
6875 }
6876 return fPlayer->MakeClass(classname, option);
6877}
6878
6879////////////////////////////////////////////////////////////////////////////////
6880/// Generate a skeleton function for this tree.
6881///
6882/// The function code is written on filename.
6883/// If filename is 0, filename will be called nameoftree.C
6884///
6885/// The generated code includes the following:
6886/// - Identification of the original Tree and Input file name,
6887/// - Opening the Tree file,
6888/// - Declaration of Tree variables,
6889/// - Setting of branches addresses,
6890/// - A skeleton for the entry loop.
6891///
6892/// To use this function:
6893///
6894/// - Open your Tree file (eg: TFile f("myfile.root");)
6895/// - T->MakeCode("MyAnalysis.C");
6896///
6897/// where T is the name of the TTree in file myfile.root
6898/// and MyAnalysis.C the name of the file created by this function.
6899///
6900/// NOTE: Since the implementation of this function, a new and better
6901/// function TTree::MakeClass() has been developed.
6903Int_t TTree::MakeCode(const char* filename)
6904{
6905 Warning("MakeCode", "MakeCode is obsolete. Use MakeClass or MakeSelector instead");
6906
6907 GetPlayer();
6908 if (!fPlayer) return 0;
6909 return fPlayer->MakeCode(filename);
6910}
6911
6912////////////////////////////////////////////////////////////////////////////////
6913/// Generate a skeleton analysis class for this Tree using TBranchProxy.
6914///
6915/// TBranchProxy is the base of a class hierarchy implementing an
6916/// indirect access to the content of the branches of a TTree.
6917///
6918/// "proxyClassname" is expected to be of the form:
6919/// ~~~ {.cpp}
6920/// [path/]fileprefix
6921/// ~~~
6922/// The skeleton will then be generated in the file:
6923/// ~~~ {.cpp}
6924/// fileprefix.h
6925/// ~~~
6926/// located in the current directory or in 'path/' if it is specified.
6927/// The class generated will be named 'fileprefix'
6928///
6929/// "macrofilename" and optionally "cutfilename" are expected to point
6930/// to source files which will be included by the generated skeleton.
6931/// Method of the same name as the file(minus the extension and path)
6932/// will be called by the generated skeleton's Process method as follow:
6933/// ~~~ {.cpp}
6934/// [if (cutfilename())] htemp->Fill(macrofilename());
6935/// ~~~
6936/// "option" can be used select some of the optional features during
6937/// the code generation. The possible options are:
6938///
6939/// - nohist : indicates that the generated ProcessFill should not fill the histogram.
6940///
6941/// 'maxUnrolling' controls how deep in the class hierarchy does the
6942/// system 'unroll' classes that are not split. Unrolling a class
6943/// allows direct access to its data members (this emulates the behavior
6944/// of TTreeFormula).
6945///
6946/// The main features of this skeleton are:
6947///
6948/// * on-demand loading of branches
6949/// * ability to use the 'branchname' as if it was a data member
6950/// * protection against array out-of-bounds errors
6951/// * ability to use the branch data as an object (when the user code is available)
6952///
6953/// For example with Event.root, if
6954/// ~~~ {.cpp}
6955/// Double_t somePx = fTracks.fPx[2];
6956/// ~~~
6957/// is executed by one of the method of the skeleton,
6958/// somePx will updated with the current value of fPx of the 3rd track.
6959///
6960/// Both macrofilename and the optional cutfilename are expected to be
6961/// the name of source files which contain at least a free standing
6962/// function with the signature:
6963/// ~~~ {.cpp}
6964/// x_t macrofilename(); // i.e function with the same name as the file
6965/// ~~~
6966/// and
6967/// ~~~ {.cpp}
6968/// y_t cutfilename(); // i.e function with the same name as the file
6969/// ~~~
6970/// x_t and y_t needs to be types that can convert respectively to a double
6971/// and a bool (because the skeleton uses:
6972///
6973/// if (cutfilename()) htemp->Fill(macrofilename());
6974///
6975/// These two functions are run in a context such that the branch names are
6976/// available as local variables of the correct (read-only) type.
6977///
6978/// Note that if you use the same 'variable' twice, it is more efficient
6979/// to 'cache' the value. For example:
6980/// ~~~ {.cpp}
6981/// Int_t n = fEventNumber; // Read fEventNumber
6982/// if (n<10 || n>10) { ... }
6983/// ~~~
6984/// is more efficient than
6985/// ~~~ {.cpp}
6986/// if (fEventNumber<10 || fEventNumber>10)
6987/// ~~~
6988/// Also, optionally, the generated selector will also call methods named
6989/// macrofilename_methodname in each of 6 main selector methods if the method
6990/// macrofilename_methodname exist (Where macrofilename is stripped of its
6991/// extension).
6992///
6993/// Concretely, with the script named h1analysisProxy.C,
6994///
6995/// - The method calls the method (if it exist)
6996/// - Begin -> void h1analysisProxy_Begin(TTree*);
6997/// - SlaveBegin -> void h1analysisProxy_SlaveBegin(TTree*);
6998/// - Notify -> bool h1analysisProxy_Notify();
6999/// - Process -> bool h1analysisProxy_Process(Long64_t);
7000/// - SlaveTerminate -> void h1analysisProxy_SlaveTerminate();
7001/// - Terminate -> void h1analysisProxy_Terminate();
7002///
7003/// If a file name macrofilename.h (or .hh, .hpp, .hxx, .hPP, .hXX) exist
7004/// it is included before the declaration of the proxy class. This can
7005/// be used in particular to insure that the include files needed by
7006/// the macro file are properly loaded.
7007///
7008/// The default histogram is accessible via the variable named 'htemp'.
7009///
7010/// If the library of the classes describing the data in the branch is
7011/// loaded, the skeleton will add the needed `include` statements and
7012/// give the ability to access the object stored in the branches.
7013///
7014/// To draw px using the file hsimple.root (generated by the
7015/// hsimple.C tutorial), we need a file named hsimple.cxx:
7016/// ~~~ {.cpp}
7017/// double hsimple() {
7018/// return px;
7019/// }
7020/// ~~~
7021/// MakeProxy can then be used indirectly via the TTree::Draw interface
7022/// as follow:
7023/// ~~~ {.cpp}
7024/// new TFile("hsimple.root")
7025/// ntuple->Draw("hsimple.cxx");
7026/// ~~~
7027/// A more complete example is available in the tutorials directory:
7028/// h1analysisProxy.cxx , h1analysProxy.h and h1analysisProxyCut.C
7029/// which reimplement the selector found in h1analysis.C
7031Int_t TTree::MakeProxy(const char* proxyClassname, const char* macrofilename, const char* cutfilename, const char* option, Int_t maxUnrolling)
7032{
7033 GetPlayer();
7034 if (!fPlayer) return 0;
7036}
7037
7038////////////////////////////////////////////////////////////////////////////////
7039/// Generate skeleton selector class for this tree.
7040///
7041/// The following files are produced: selector.h and selector.C.
7042/// If selector is 0, the selector will be called "nameoftree".
7043/// The option can be used to specify the branches that will have a data member.
7044/// - If option is "=legacy", a pre-ROOT6 selector will be generated (data
7045/// members and branch pointers instead of TTreeReaders).
7046/// - If option is empty, readers will be generated for each leaf.
7047/// - If option is "@", readers will be generated for the topmost branches.
7048/// - Individual branches can also be picked by their name:
7049/// - "X" generates readers for leaves of X.
7050/// - "@X" generates a reader for X as a whole.
7051/// - "@X;Y" generates a reader for X as a whole and also readers for the
7052/// leaves of Y.
7053/// - For further examples see the figure below.
7054///
7055/// \image html ttree_makeselector_option_examples.png
7056///
7057/// The generated code in selector.h includes the following:
7058/// - Identification of the original Tree and Input file name
7059/// - Definition of selector class (data and functions)
7060/// - The following class functions:
7061/// - constructor and destructor
7062/// - void Begin(TTree *tree)
7063/// - void SlaveBegin(TTree *tree)
7064/// - void Init(TTree *tree)
7065/// - bool Notify()
7066/// - bool Process(Long64_t entry)
7067/// - void Terminate()
7068/// - void SlaveTerminate()
7069///
7070/// The class selector derives from TSelector.
7071/// The generated code in selector.C includes empty functions defined above.
7072///
7073/// To use this function:
7074///
7075/// - connect your Tree file (eg: `TFile f("myfile.root");`)
7076/// - `T->MakeSelector("myselect");`
7077///
7078/// where T is the name of the Tree in file myfile.root
7079/// and myselect.h, myselect.C the name of the files created by this function.
7080/// In a ROOT session, you can do:
7081/// ~~~ {.cpp}
7082/// root > T->Process("myselect.C")
7083/// ~~~
7085Int_t TTree::MakeSelector(const char* selector, Option_t* option)
7086{
7087 TString opt(option);
7088 if(opt.EqualTo("=legacy", TString::ECaseCompare::kIgnoreCase)) {
7089 return MakeClass(selector, "selector");
7090 } else {
7091 GetPlayer();
7092 if (!fPlayer) return 0;
7093 return fPlayer->MakeReader(selector, option);
7094 }
7095}
7096
7097////////////////////////////////////////////////////////////////////////////////
7098/// Check if adding nbytes to memory we are still below MaxVirtualsize.
7101{
7103 return false;
7104 }
7105 return true;
7106}
7107
7108////////////////////////////////////////////////////////////////////////////////
7109/// Static function merging the trees in the TList into a new tree.
7110///
7111/// Trees in the list can be memory or disk-resident trees.
7112/// The new tree is created in the current directory (memory if gROOT).
7113/// Trees with no branches will be skipped, the branch structure
7114/// will be taken from the first non-zero-branch Tree of {li}
7117{
7118 if (!li) return nullptr;
7119 TIter next(li);
7120 TTree *newtree = nullptr;
7121 TObject *obj;
7122
7123 while ((obj=next())) {
7124 if (!obj->InheritsFrom(TTree::Class())) continue;
7125 TTree *tree = (TTree*)obj;
7126 if (tree->GetListOfBranches()->IsEmpty()) {
7127 if (gDebug > 2) {
7128 tree->Warning("MergeTrees","TTree %s has no branches, skipping.", tree->GetName());
7129 }
7130 continue; // Completely ignore the empty trees.
7131 }
7132 Long64_t nentries = tree->GetEntries();
7133 if (newtree && nentries == 0)
7134 continue; // If we already have the structure and we have no entry, save time and skip
7135 if (!newtree) {
7136 newtree = (TTree*)tree->CloneTree(-1, options);
7137 if (!newtree) continue;
7138
7139 // Once the cloning is done, separate the trees,
7140 // to avoid as many side-effects as possible
7141 // The list of clones is guaranteed to exist since we
7142 // just cloned the tree.
7143 tree->GetListOfClones()->Remove(newtree);
7144 tree->ResetBranchAddresses();
7145 newtree->ResetBranchAddresses();
7146 continue;
7147 }
7148 if (nentries == 0)
7149 continue;
7150 newtree->CopyEntries(tree, -1, options, true);
7151 }
7152 if (newtree && newtree->GetTreeIndex()) {
7153 newtree->GetTreeIndex()->Append(nullptr,false); // Force the sorting
7154 }
7155 return newtree;
7156}
7157
7158////////////////////////////////////////////////////////////////////////////////
7159/// Merge the trees in the TList into this tree.
7160///
7161/// Returns the total number of entries in the merged tree.
7162/// Trees with no branches will be skipped, the branch structure
7163/// will be taken from the first non-zero-branch Tree of {this+li}
7166{
7167 if (fBranches.IsEmpty()) {
7168 if (!li || li->IsEmpty())
7169 return 0; // Nothing to do ....
7170 // Let's find the first non-empty
7171 TIter next(li);
7172 TTree *tree;
7173 while ((tree = (TTree *)next())) {
7174 if (tree == this || tree->GetListOfBranches()->IsEmpty()) {
7175 if (gDebug > 2) {
7176 Warning("Merge","TTree %s has no branches, skipping.", tree->GetName());
7177 }
7178 continue;
7179 }
7180 // We could come from a list made up of different names, the first one still wins
7181 tree->SetName(this->GetName());
7182 auto prevEntries = tree->GetEntries();
7183 auto result = tree->Merge(li, options);
7184 if (result != prevEntries) {
7185 // If there is no additional entries, the first write was enough.
7186 tree->Write();
7187 }
7188 // Make sure things are really written out to disk before attempting any reading.
7189 if (tree->GetCurrentFile()) {
7190 tree->GetCurrentFile()->Flush();
7191 // Read back the complete info in this TTree, so that caller does not
7192 // inadvertently write the empty tree.
7193 tree->GetDirectory()->ReadTObject(this, this->GetName());
7194 }
7195 return result;
7196 }
7197 return 0; // All trees have empty branches
7198 }
7199 if (!li) return 0;
7201 // Disable the autosave as the TFileMerge keeps a list of key and deleting the underlying
7202 // key would invalidate its iteration (or require costly measure to not use the deleted keys).
7203 // Also since this is part of a merging operation, the output file is not as precious as in
7204 // the general case since the input file should still be around.
7205 fAutoSave = 0;
7206 TIter next(li);
7207 TTree *tree;
7208 while ((tree = (TTree*)next())) {
7209 if (tree==this) continue;
7210 if (!tree->InheritsFrom(TTree::Class())) {
7211 Error("Add","Attempt to add object of class: %s to a %s", tree->ClassName(), ClassName());
7213 return -1;
7214 }
7215
7216 Long64_t nentries = tree->GetEntries();
7217 if (nentries == 0) continue;
7218
7219 CopyEntries(tree, -1, options, true);
7220 }
7222 return GetEntries();
7223}
7224
7225////////////////////////////////////////////////////////////////////////////////
7226/// Merge the trees in the TList into this tree.
7227/// If info->fIsFirst is true, first we clone this TTree info the directory
7228/// info->fOutputDirectory and then overlay the new TTree information onto
7229/// this TTree object (so that this TTree object is now the appropriate to
7230/// use for further merging).
7231/// Trees with no branches will be skipped, the branch structure
7232/// will be taken from the first non-zero-branch Tree of {this+li}
7233///
7234/// Returns the total number of entries in the merged tree.
7237{
7238 if (fBranches.IsEmpty()) {
7239 if (!li || li->IsEmpty())
7240 return 0; // Nothing to do ....
7241 // Let's find the first non-empty
7242 TIter next(li);
7243 TTree *tree;
7244 while ((tree = (TTree *)next())) {
7245 if (tree == this || tree->GetListOfBranches()->IsEmpty()) {
7246 if (gDebug > 2) {
7247 Warning("Merge","TTree %s has no branches, skipping.", tree->GetName());
7248 }
7249 continue;
7250 }
7251 // We could come from a list made up of different names, the first one still wins
7252 tree->SetName(this->GetName());
7253 auto prevEntries = tree->GetEntries();
7254 auto result = tree->Merge(li, info);
7255 if (result != prevEntries) {
7256 // If there is no additional entries, the first write was enough.
7257 tree->Write();
7258 }
7259 // Make sure things are really written out to disk before attempting any reading.
7260 info->fOutputDirectory->GetFile()->Flush();
7261 // Read back the complete info in this TTree, so that TFileMerge does not
7262 // inadvertently write the empty tree.
7263 info->fOutputDirectory->ReadTObject(this, this->GetName());
7264 return result;
7265 }
7266 return 0; // All trees have empty branches
7267 }
7268 const char *options = info ? info->fOptions.Data() : "";
7269 if (info && info->fIsFirst && info->fOutputDirectory && info->fOutputDirectory->GetFile() != GetCurrentFile()) {
7270 if (GetCurrentFile() == nullptr) {
7271 // In memory TTree, all we need to do is ... write it.
7272 SetDirectory(info->fOutputDirectory);
7274 fDirectory->WriteTObject(this);
7275 } else if (info->fOptions.Contains("fast")) {
7276 InPlaceClone(info->fOutputDirectory);
7277 } else {
7278 TDirectory::TContext ctxt(info->fOutputDirectory);
7280 TTree *newtree = CloneTree(-1, options);
7281 if (info->fIOFeatures)
7282 fIOFeatures = *(info->fIOFeatures);
7283 else
7285 if (newtree) {
7286 newtree->Write();
7287 delete newtree;
7288 }
7289 // Make sure things are really written out to disk before attempting any reading.
7290 info->fOutputDirectory->GetFile()->Flush();
7291 info->fOutputDirectory->ReadTObject(this,this->GetName());
7292 }
7293 }
7294 if (!li) return 0;
7296 // Disable the autosave as the TFileMerge keeps a list of key and deleting the underlying
7297 // key would invalidate its iteration (or require costly measure to not use the deleted keys).
7298 // Also since this is part of a merging operation, the output file is not as precious as in
7299 // the general case since the input file should still be around.
7300 fAutoSave = 0;
7301 TIter next(li);
7302 TTree *tree;
7303 while ((tree = (TTree*)next())) {
7304 if (tree==this) continue;
7305 if (!tree->InheritsFrom(TTree::Class())) {
7306 Error("Add","Attempt to add object of class: %s to a %s", tree->ClassName(), ClassName());
7308 return -1;
7309 }
7310
7311 CopyEntries(tree, -1, options, true);
7312 }
7314 return GetEntries();
7315}
7316
7317////////////////////////////////////////////////////////////////////////////////
7318/// Move a cache from a file to the current file in dir.
7319/// if src is null no operation is done, if dir is null or there is no
7320/// current file the cache is deleted.
7323{
7324 if (!src) return;
7325 TFile *dst = (dir && dir != gROOT) ? dir->GetFile() : nullptr;
7326 if (src == dst) return;
7327
7329 if (dst) {
7330 src->SetCacheRead(nullptr,this);
7331 dst->SetCacheRead(pf, this);
7332 } else {
7333 if (pf) {
7334 pf->WaitFinishPrefetch();
7335 }
7336 src->SetCacheRead(nullptr,this);
7337 delete pf;
7338 }
7339}
7340
7341////////////////////////////////////////////////////////////////////////////////
7342/// Copy the content to a new new file, update this TTree with the new
7343/// location information and attach this TTree to the new directory.
7344///
7345/// options: Indicates a basket sorting method, see TTreeCloner::TTreeCloner for
7346/// details
7347///
7348/// If new and old directory are in the same file, the data is untouched,
7349/// this "just" does a call to SetDirectory.
7350/// Equivalent to an "in place" cloning of the TTree.
7351bool TTree::InPlaceClone(TDirectory *newdirectory, const char *options)
7352{
7353 if (!newdirectory) {
7355 SetDirectory(nullptr);
7356 return true;
7357 }
7358 if (newdirectory->GetFile() == GetCurrentFile()) {
7360 return true;
7361 }
7362 TTreeCloner cloner(this, newdirectory, options);
7363 if (cloner.IsValid())
7364 return cloner.Exec();
7365 else
7366 return false;
7367}
7368
7369////////////////////////////////////////////////////////////////////////////////
7370/// Function called when loading a new class library.
7372bool TTree::Notify()
7373{
7374 TIter next(GetListOfLeaves());
7375 TLeaf* leaf = nullptr;
7376 while ((leaf = (TLeaf*) next())) {
7377 leaf->Notify();
7378 leaf->GetBranch()->Notify();
7379 }
7380 return true;
7381}
7382
7383////////////////////////////////////////////////////////////////////////////////
7384/// This function may be called after having filled some entries in a Tree.
7385/// Using the information in the existing branch buffers, it will reassign
7386/// new branch buffer sizes to optimize time and memory.
7387///
7388/// The function computes the best values for branch buffer sizes such that
7389/// the total buffer sizes is less than maxMemory and nearby entries written
7390/// at the same time.
7391/// In case the branch compression factor for the data written so far is less
7392/// than compMin, the compression is disabled.
7393///
7394/// if option ="d" an analysis report is printed.
7397{
7398 //Flush existing baskets if the file is writable
7399 if (this->GetDirectory()->IsWritable()) this->FlushBasketsImpl();
7400
7401 TString opt( option );
7402 opt.ToLower();
7403 bool pDebug = opt.Contains("d");
7404 TObjArray *leaves = this->GetListOfLeaves();
7405 Int_t nleaves = leaves->GetEntries();
7407
7408 if (nleaves == 0 || treeSize == 0) {
7409 // We're being called too early, we really have nothing to do ...
7410 return;
7411 }
7413 UInt_t bmin = 512;
7414 UInt_t bmax = 256000;
7415 Double_t memFactor = 1;
7418
7419 //we make two passes
7420 //one pass to compute the relative branch buffer sizes
7421 //a second pass to compute the absolute values
7422 for (Int_t pass =0;pass<2;pass++) {
7423 oldMemsize = 0; //to count size of baskets in memory with old buffer size
7424 newMemsize = 0; //to count size of baskets in memory with new buffer size
7425 oldBaskets = 0; //to count number of baskets with old buffer size
7426 newBaskets = 0; //to count number of baskets with new buffer size
7427 for (i=0;i<nleaves;i++) {
7428 TLeaf *leaf = (TLeaf*)leaves->At(i);
7429 TBranch *branch = leaf->GetBranch();
7430 Double_t totBytes = (Double_t)branch->GetTotBytes();
7433 if (branch->GetEntries() == 0) {
7434 // There is no data, so let's make a guess ...
7436 } else {
7437 sizeOfOneEntry = 1+(UInt_t)(totBytes / (Double_t)branch->GetEntries());
7438 }
7439 Int_t oldBsize = branch->GetBasketSize();
7442 Int_t nb = branch->GetListOfBranches()->GetEntries();
7443 if (nb > 0) {
7445 continue;
7446 }
7447 Double_t bsize = oldBsize*idealFactor*memFactor; //bsize can be very large !
7448 if (bsize < 0) bsize = bmax;
7449 if (bsize > bmax) bsize = bmax;
7451 if (pass) { // only on the second pass so that it doesn't interfere with scaling
7452 // If there is an entry offset, it will be stored in the same buffer as the object data; hence,
7453 // we must bump up the size of the branch to account for this extra footprint.
7454 // If fAutoFlush is not set yet, let's assume that it is 'in the process of being set' to
7455 // the value of GetEntries().
7456 Long64_t clusterSize = (fAutoFlush > 0) ? fAutoFlush : branch->GetEntries();
7457 if (branch->GetEntryOffsetLen()) {
7458 newBsize = newBsize + (clusterSize * sizeof(Int_t) * 2);
7459 }
7460 // We used ATLAS fully-split xAOD for testing, which is a rather unbalanced TTree, 10K branches,
7461 // with 8K having baskets smaller than 512 bytes. To achieve good I/O performance ATLAS uses auto-flush 100,
7462 // resulting in the smallest baskets being ~300-400 bytes, so this change increases their memory by about 8k*150B =~ 1MB,
7463 // at the same time it significantly reduces the number of total baskets because it ensures that all 100 entries can be
7464 // stored in a single basket (the old optimization tended to make baskets too small). In a toy example with fixed sized
7465 // structures we found a factor of 2 fewer baskets needed in the new scheme.
7466 // rounds up, increases basket size to ensure all entries fit into single basket as intended
7467 newBsize = newBsize - newBsize%512 + 512;
7468 }
7470 if (newBsize < bmin) newBsize = bmin;
7471 if (newBsize > 10000000) newBsize = bmax;
7472 if (pass) {
7473 if (pDebug) Info("OptimizeBaskets", "Changing buffer size from %6d to %6d bytes for %s\n",oldBsize,newBsize,branch->GetName());
7474 branch->SetBasketSize(newBsize);
7475 }
7477 // For this number to be somewhat accurate when newBsize is 'low'
7478 // we do not include any space for meta data in the requested size (newBsize) even-though SetBasketSize will
7479 // not let it be lower than 100+TBranch::fEntryOffsetLen.
7481 if (pass == 0) continue;
7482 //Reset the compression level in case the compression factor is small
7483 Double_t comp = 1;
7484 if (branch->GetZipBytes() > 0) comp = totBytes/Double_t(branch->GetZipBytes());
7485 if (comp > 1 && comp < minComp) {
7486 if (pDebug) Info("OptimizeBaskets", "Disabling compression for branch : %s\n",branch->GetName());
7488 }
7489 }
7490 // coverity[divide_by_zero] newMemsize can not be zero as there is at least one leaf
7492 if (memFactor > 100) memFactor = 100;
7495 static const UInt_t hardmax = 1*1024*1024*1024; // Really, really never give more than 1Gb to a single buffer.
7496
7497 // Really, really never go lower than 8 bytes (we use this number
7498 // so that the calculation of the number of basket is consistent
7499 // but in fact SetBasketSize will not let the size go below
7500 // TBranch::fEntryOffsetLen + (100 + strlen(branch->GetName())
7501 // (The 2nd part being a slight over estimate of the key length.
7502 static const UInt_t hardmin = 8;
7505 }
7506 if (pDebug) {
7507 Info("OptimizeBaskets", "oldMemsize = %d, newMemsize = %d\n",oldMemsize, newMemsize);
7508 Info("OptimizeBaskets", "oldBaskets = %d, newBaskets = %d\n",oldBaskets, newBaskets);
7509 }
7510}
7511
7512////////////////////////////////////////////////////////////////////////////////
7513/// Interface to the Principal Components Analysis class.
7514///
7515/// Create an instance of TPrincipal
7516///
7517/// Fill it with the selected variables
7518///
7519/// - if option "n" is specified, the TPrincipal object is filled with
7520/// normalized variables.
7521/// - If option "p" is specified, compute the principal components
7522/// - If option "p" and "d" print results of analysis
7523/// - If option "p" and "h" generate standard histograms
7524/// - If option "p" and "c" generate code of conversion functions
7525/// - return a pointer to the TPrincipal object. It is the user responsibility
7526/// - to delete this object.
7527/// - The option default value is "np"
7528///
7529/// see TTree::Draw for explanation of the other parameters.
7530///
7531/// The created object is named "principal" and a reference to it
7532/// is added to the list of specials Root objects.
7533/// you can retrieve a pointer to the created object via:
7534/// ~~~ {.cpp}
7535/// TPrincipal *principal =
7536/// (TPrincipal*)gROOT->GetListOfSpecials()->FindObject("principal");
7537/// ~~~
7540{
7541 GetPlayer();
7542 if (fPlayer) {
7544 }
7545 return nullptr;
7546}
7547
7548////////////////////////////////////////////////////////////////////////////////
7549/// Print a summary of the tree contents.
7550///
7551/// - If option contains "all" friend trees are also printed.
7552/// - If option contains "toponly" only the top level branches are printed.
7553/// - If option contains "clusters" information about the cluster of baskets is printed.
7554///
7555/// Wildcarding can be used to print only a subset of the branches, e.g.,
7556/// `T.Print("Elec*")` will print all branches with name starting with "Elec".
7558void TTree::Print(Option_t* option) const
7559{
7560 // We already have been visited while recursively looking
7561 // through the friends tree, let's return.
7562 if (kPrint & fFriendLockStatus) {
7563 return;
7564 }
7565 Int_t s = 0;
7566 Int_t skey = 0;
7567 if (fDirectory) {
7568 TKey* key = fDirectory->GetKey(GetName());
7569 if (key) {
7570 skey = key->GetKeylen();
7571 s = key->GetNbytes();
7572 }
7573 }
7576 if (zipBytes > 0) {
7577 total += GetTotBytes();
7578 }
7580 TTree::Class()->WriteBuffer(b, (TTree*) this);
7581 total += b.Length();
7582 Long64_t file = zipBytes + s;
7583 Float_t cx = 1;
7584 if (zipBytes) {
7585 cx = (GetTotBytes() + 0.00001) / zipBytes;
7586 }
7587 Printf("******************************************************************************");
7588 Printf("*Tree :%-10s: %-54s *", GetName(), GetTitle());
7589 Printf("*Entries : %8lld : Total = %15lld bytes File Size = %10lld *", fEntries, total, file);
7590 Printf("* : : Tree compression factor = %6.2f *", cx);
7591 Printf("******************************************************************************");
7592
7593 // Avoid many check of option validity
7594 if (!option)
7595 option = "";
7596
7597 if (strncmp(option,"clusters",std::char_traits<char>::length("clusters"))==0) {
7598 Printf("%-16s %-16s %-16s %8s %20s",
7599 "Cluster Range #", "Entry Start", "Last Entry", "Size", "Number of clusters");
7600 Int_t index= 0;
7603 bool estimated = false;
7604 bool unknown = false;
7606 Long64_t nclusters = 0;
7607 if (recordedSize > 0) {
7608 nclusters = TMath::Ceil(static_cast<double>(1 + end - start) / recordedSize);
7609 Printf("%-16d %-16lld %-16lld %8lld %10lld",
7610 ind, start, end, recordedSize, nclusters);
7611 } else {
7612 // NOTE: const_cast ... DO NOT Merge for now
7613 TClusterIterator iter((TTree*)this, start);
7614 iter.Next();
7615 auto estimated_size = iter.GetNextEntry() - start;
7616 if (estimated_size > 0) {
7617 nclusters = TMath::Ceil(static_cast<double>(1 + end - start) / estimated_size);
7618 Printf("%-16d %-16lld %-16lld %8lld %10lld (estimated)",
7619 ind, start, end, recordedSize, nclusters);
7620 estimated = true;
7621 } else {
7622 Printf("%-16d %-16lld %-16lld %8lld (unknown)",
7623 ind, start, end, recordedSize);
7624 unknown = true;
7625 }
7626 }
7627 start = end + 1;
7629 };
7630 if (fNClusterRange) {
7631 for( ; index < fNClusterRange; ++index) {
7634 }
7635 }
7637 if (unknown) {
7638 Printf("Total number of clusters: (unknown)");
7639 } else {
7640 Printf("Total number of clusters: %lld %s", totalClusters, estimated ? "(estimated)" : "");
7641 }
7642 return;
7643 }
7644
7645 Int_t nl = const_cast<TTree*>(this)->GetListOfLeaves()->GetEntries();
7646 Int_t l;
7647 TBranch* br = nullptr;
7648 TLeaf* leaf = nullptr;
7649 if (strstr(option, "toponly")) {
7650 Long64_t *count = new Long64_t[nl];
7651 Int_t keep =0;
7652 for (l=0;l<nl;l++) {
7653 leaf = (TLeaf *)const_cast<TTree*>(this)->GetListOfLeaves()->At(l);
7654 br = leaf->GetBranch();
7655 // branch is its own (top level) mother only for the top level branches.
7656 if (br != br->GetMother()) {
7657 count[l] = -1;
7658 count[keep] += br->GetZipBytes();
7659 } else {
7660 keep = l;
7661 count[keep] = br->GetZipBytes();
7662 }
7663 }
7664 for (l=0;l<nl;l++) {
7665 if (count[l] < 0) continue;
7666 leaf = (TLeaf *)const_cast<TTree*>(this)->GetListOfLeaves()->At(l);
7667 br = leaf->GetBranch();
7668 Printf("branch: %-20s %9lld",br->GetName(),count[l]);
7669 }
7670 delete [] count;
7671 } else {
7672 TString reg = "*";
7673 if (strlen(option) && strchr(option,'*')) reg = option;
7674 TRegexp re(reg,true);
7675 TIter next(const_cast<TTree*>(this)->GetListOfBranches());
7677 while ((br= (TBranch*)next())) {
7678 TString st = br->GetName();
7679 st.ReplaceAll("/","_");
7680 if (st.Index(re) == kNPOS) continue;
7681 br->Print(option);
7682 }
7683 }
7684
7685 //print TRefTable (if one)
7687
7688 //print friends if option "all"
7689 if (!fFriends || !strstr(option,"all")) return;
7691 TFriendLock lock(const_cast<TTree*>(this),kPrint);
7692 TFriendElement *fr;
7693 while ((fr = (TFriendElement*)nextf())) {
7694 TTree * t = fr->GetTree();
7695 if (t) t->Print(option);
7696 }
7697}
7698
7699////////////////////////////////////////////////////////////////////////////////
7700/// Print statistics about the TreeCache for this tree.
7701/// Like:
7702/// ~~~ {.cpp}
7703/// ******TreeCache statistics for file: cms2.root ******
7704/// Reading 73921562 bytes in 716 transactions
7705/// Average transaction = 103.242405 Kbytes
7706/// Number of blocks in current cache: 202, total size : 6001193
7707/// ~~~
7708/// if option = "a" the list of blocks in the cache is printed
7711{
7712 TFile *f = GetCurrentFile();
7713 if (!f) return;
7715 if (tc) tc->Print(option);
7716}
7717
7718////////////////////////////////////////////////////////////////////////////////
7719/// Process this tree executing the TSelector code in the specified filename.
7720/// The return value is -1 in case of error and TSelector::GetStatus() in
7721/// in case of success.
7722///
7723/// The code in filename is loaded (interpreted or compiled, see below),
7724/// filename must contain a valid class implementation derived from TSelector,
7725/// where TSelector has the following member functions:
7726///
7727/// - `Begin()`: called every time a loop on the tree starts,
7728/// a convenient place to create your histograms.
7729/// - `SlaveBegin()`: called after Begin()
7730/// - `Process()`: called for each event, in this function you decide what
7731/// to read and fill your histograms.
7732/// - `SlaveTerminate()`: called at the end of the loop on the tree
7733/// - `Terminate()`: called at the end of the loop on the tree,
7734/// a convenient place to draw/fit your histograms.
7735///
7736/// If filename is of the form file.C, the file will be interpreted.
7737///
7738/// If filename is of the form file.C++, the file file.C will be compiled
7739/// and dynamically loaded.
7740///
7741/// If filename is of the form file.C+, the file file.C will be compiled
7742/// and dynamically loaded. At next call, if file.C is older than file.o
7743/// and file.so, the file.C is not compiled, only file.so is loaded.
7744///
7745/// ## NOTE1
7746///
7747/// It may be more interesting to invoke directly the other Process function
7748/// accepting a TSelector* as argument.eg
7749/// ~~~ {.cpp}
7750/// MySelector *selector = (MySelector*)TSelector::GetSelector(filename);
7751/// selector->CallSomeFunction(..);
7752/// mytree.Process(selector,..);
7753/// ~~~
7754/// ## NOTE2
7755//
7756/// One should not call this function twice with the same selector file
7757/// in the same script. If this is required, proceed as indicated in NOTE1,
7758/// by getting a pointer to the corresponding TSelector,eg
7759///
7760/// ### Workaround 1
7761///
7762/// ~~~ {.cpp}
7763/// void stubs1() {
7764/// TSelector *selector = TSelector::GetSelector("h1test.C");
7765/// TFile *f1 = new TFile("stubs_nood_le1.root");
7766/// TTree *h1 = (TTree*)f1->Get("h1");
7767/// h1->Process(selector);
7768/// TFile *f2 = new TFile("stubs_nood_le1_coarse.root");
7769/// TTree *h2 = (TTree*)f2->Get("h1");
7770/// h2->Process(selector);
7771/// }
7772/// ~~~
7773/// or use ACLIC to compile the selector
7774///
7775/// ### Workaround 2
7776///
7777/// ~~~ {.cpp}
7778/// void stubs2() {
7779/// TFile *f1 = new TFile("stubs_nood_le1.root");
7780/// TTree *h1 = (TTree*)f1->Get("h1");
7781/// h1->Process("h1test.C+");
7782/// TFile *f2 = new TFile("stubs_nood_le1_coarse.root");
7783/// TTree *h2 = (TTree*)f2->Get("h1");
7784/// h2->Process("h1test.C+");
7785/// }
7786/// ~~~
7789{
7790 GetPlayer();
7791 if (fPlayer) {
7793 }
7794 return -1;
7795}
7796
7797////////////////////////////////////////////////////////////////////////////////
7798/// Process this tree executing the code in the specified selector.
7799/// The return value is -1 in case of error and TSelector::GetStatus() in
7800/// in case of success.
7801///
7802/// The TSelector class has the following member functions:
7803///
7804/// - `Begin()`: called every time a loop on the tree starts,
7805/// a convenient place to create your histograms.
7806/// - `SlaveBegin()`: called after Begin()
7807/// - `Process()`: called for each event, in this function you decide what
7808/// to read and fill your histograms.
7809/// - `SlaveTerminate()`: called at the end of the loop on the tree
7810/// - `Terminate()`: called at the end of the loop on the tree,
7811/// a convenient place to draw/fit your histograms.
7812///
7813/// If the Tree (Chain) has an associated EventList, the loop is on the nentries
7814/// of the EventList, starting at firstentry, otherwise the loop is on the
7815/// specified Tree entries.
7818{
7819 GetPlayer();
7820 if (fPlayer) {
7821 return fPlayer->Process(selector, option, nentries, firstentry);
7822 }
7823 return -1;
7824}
7825
7826////////////////////////////////////////////////////////////////////////////////
7827/// Make a projection of a tree using selections.
7828///
7829/// Depending on the value of varexp (described in Draw) a 1-D, 2-D, etc.,
7830/// projection of the tree will be filled in histogram hname.
7831/// Note that the dimension of hname must match with the dimension of varexp.
7832///
7835{
7836 TString var;
7837 var.Form("%s>>%s", varexp, hname);
7838 TString opt("goff");
7839 if (option) {
7840 opt.Form("%sgoff", option);
7841 }
7843 return nsel;
7844}
7845
7846////////////////////////////////////////////////////////////////////////////////
7847/// Loop over entries and return a TSQLResult object containing entries following selection.
7850{
7851 GetPlayer();
7852 if (fPlayer) {
7854 }
7855 return nullptr;
7856}
7857
7858////////////////////////////////////////////////////////////////////////////////
7859/// Create or simply read branches from filename.
7860///
7861/// if branchDescriptor = "" (default), it is assumed that the Tree descriptor
7862/// is given in the first line of the file with a syntax like
7863/// ~~~ {.cpp}
7864/// A/D:Table[2]/F:Ntracks/I:astring/C
7865/// ~~~
7866/// otherwise branchDescriptor must be specified with the above syntax.
7867/// See all available datatypes [here](\ref addcolumnoffundamentaltypes).
7868///
7869/// - If the type of the first variable is not specified, it is assumed to be "/F"
7870/// - If the type of any other variable is not specified, the type of the previous
7871/// variable is assumed. eg
7872/// - `x:y:z` (all variables are assumed of type "F")
7873/// - `x/D:y:z` (all variables are of type "D")
7874/// - `x:y/D:z` (x is type "F", y and z of type "D")
7875///
7876/// delimiter allows for the use of another delimiter besides whitespace.
7877/// This provides support for direct import of common data file formats
7878/// like csv. If delimiter != ' ' and branchDescriptor == "", then the
7879/// branch description is taken from the first line in the file, but
7880/// delimiter is used for the branch names tokenization rather than ':'.
7881/// Note however that if the values in the first line do not use the
7882/// /[type] syntax, all variables are assumed to be of type "F".
7883/// If the filename ends with extensions .csv or .CSV and a delimiter is
7884/// not specified (besides ' '), the delimiter is automatically set to ','.
7885///
7886/// Lines in the input file starting with "#" are ignored. Leading whitespace
7887/// for each column data is skipped. Empty lines are skipped.
7888///
7889/// A TBranch object is created for each variable in the expression.
7890/// The total number of rows read from the file is returned.
7891///
7892/// ## FILLING a TTree WITH MULTIPLE INPUT TEXT FILES
7893///
7894/// To fill a TTree with multiple input text files, proceed as indicated above
7895/// for the first input file and omit the second argument for subsequent calls
7896/// ~~~ {.cpp}
7897/// T.ReadFile("file1.dat","branch descriptor");
7898/// T.ReadFile("file2.dat");
7899/// ~~~
7901Long64_t TTree::ReadFile(const char* filename, const char* branchDescriptor, char delimiter)
7902{
7903 if (!filename || !*filename) {
7904 Error("ReadFile","File name not specified");
7905 return 0;
7906 }
7907
7908 std::ifstream in;
7909 in.open(filename);
7910 if (!in.good()) {
7911 Error("ReadFile","Cannot open file: %s",filename);
7912 return 0;
7913 }
7914 const char* ext = strrchr(filename, '.');
7915 if(ext && ((strcmp(ext, ".csv") == 0) || (strcmp(ext, ".CSV") == 0)) && delimiter == ' ') {
7916 delimiter = ',';
7917 }
7919}
7920
7921////////////////////////////////////////////////////////////////////////////////
7922/// Determine which newline this file is using.
7923/// Return '\\r' for Windows '\\r\\n' as that already terminates.
7925char TTree::GetNewlineValue(std::istream &inputStream)
7926{
7927 Long_t inPos = inputStream.tellg();
7928 char newline = '\n';
7929 while(true) {
7930 char c = 0;
7931 inputStream.get(c);
7932 if(!inputStream.good()) {
7933 Error("ReadStream","Error reading stream: no newline found.");
7934 return 0;
7935 }
7936 if(c == newline) break;
7937 if(c == '\r') {
7938 newline = '\r';
7939 break;
7940 }
7941 }
7942 inputStream.clear();
7943 inputStream.seekg(inPos);
7944 return newline;
7945}
7946
7947////////////////////////////////////////////////////////////////////////////////
7948/// Create or simply read branches from an input stream.
7949///
7950/// \see TTree::ReadFile
7952Long64_t TTree::ReadStream(std::istream& inputStream, const char *branchDescriptor, char delimiter)
7953{
7954 char newline = 0;
7955 std::stringstream ss;
7956 std::istream *inTemp;
7957 Long_t inPos = inputStream.tellg();
7958 if (!inputStream.good()) {
7959 Error("ReadStream","Error reading stream");
7960 return 0;
7961 }
7962 if (inPos == -1) {
7963 ss << std::cin.rdbuf();
7965 inTemp = &ss;
7966 } else {
7969 }
7970 std::istream& in = *inTemp;
7971 Long64_t nlines = 0;
7972
7973 TBranch *branch = nullptr;
7975 if (nbranches == 0) {
7976 char *bdname = new char[4000];
7977 char *bd = new char[100000];
7978 Int_t nch = 0;
7980 // branch Descriptor is null, read its definition from the first line in the file
7981 if (!nch) {
7982 do {
7983 in.getline(bd, 100000, newline);
7984 if (!in.good()) {
7985 delete [] bdname;
7986 delete [] bd;
7987 Error("ReadStream","Error reading stream");
7988 return 0;
7989 }
7990 char *cursor = bd;
7991 while( isspace(*cursor) && *cursor != '\n' && *cursor != '\0') {
7992 ++cursor;
7993 }
7994 if (*cursor != '#' && *cursor != '\n' && *cursor != '\0') {
7995 break;
7996 }
7997 } while (true);
7998 ++nlines;
7999 nch = strlen(bd);
8000 } else {
8001 strlcpy(bd,branchDescriptor,100000);
8002 }
8003
8004 //parse the branch descriptor and create a branch for each element
8005 //separated by ":"
8006 void *address = &bd[90000];
8007 char *bdcur = bd;
8008 TString desc="", olddesc="F";
8009 char bdelim = ':';
8010 if(delimiter != ' ') {
8011 bdelim = delimiter;
8012 if (strchr(bdcur,bdelim)==nullptr && strchr(bdcur,':') != nullptr) {
8013 // revert to the default
8014 bdelim = ':';
8015 }
8016 }
8017 while (bdcur) {
8018 char *colon = strchr(bdcur,bdelim);
8019 if (colon) *colon = 0;
8020 strlcpy(bdname,bdcur,4000);
8021 char *slash = strchr(bdname,'/');
8022 if (slash) {
8023 *slash = 0;
8024 desc = bdcur;
8025 olddesc = slash+1;
8026 } else {
8027 desc.Form("%s/%s",bdname,olddesc.Data());
8028 }
8029 char *bracket = strchr(bdname,'[');
8030 if (bracket) {
8031 *bracket = 0;
8032 }
8033 branch = new TBranch(this,bdname,address,desc.Data(),32000);
8034 if (branch->IsZombie()) {
8035 delete branch;
8036 Warning("ReadStream","Illegal branch definition: %s",bdcur);
8037 } else {
8039 branch->SetAddress(nullptr);
8040 }
8041 if (!colon)break;
8042 bdcur = colon+1;
8043 }
8044 delete [] bdname;
8045 delete [] bd;
8046 }
8047
8049
8050 if (gDebug > 1) {
8051 Info("ReadStream", "Will use branches:");
8052 for (int i = 0 ; i < nbranches; ++i) {
8053 TBranch* br = (TBranch*) fBranches.At(i);
8054 Info("ReadStream", " %s: %s [%s]", br->GetName(),
8055 br->GetTitle(), br->GetListOfLeaves()->At(0)->IsA()->GetName());
8056 }
8057 if (gDebug > 3) {
8058 Info("ReadStream", "Dumping read tokens, format:");
8059 Info("ReadStream", "LLLLL:BBB:gfbe:GFBE:T");
8060 Info("ReadStream", " L: line number");
8061 Info("ReadStream", " B: branch number");
8062 Info("ReadStream", " gfbe: good / fail / bad / eof of token");
8063 Info("ReadStream", " GFBE: good / fail / bad / eof of file");
8064 Info("ReadStream", " T: Token being read");
8065 }
8066 }
8067
8068 //loop on all lines in the file
8069 Long64_t nGoodLines = 0;
8070 std::string line;
8071 const char sDelimBuf[2] = { delimiter, 0 };
8072 const char* sDelim = sDelimBuf;
8073 if (delimiter == ' ') {
8074 // ' ' really means whitespace
8075 sDelim = "[ \t]";
8076 }
8077 while(in.good()) {
8078 if (newline == '\r' && in.peek() == '\n') {
8079 // Windows, skip '\n':
8080 in.get();
8081 }
8082 std::getline(in, line, newline);
8083 ++nlines;
8084
8086 sLine = sLine.Strip(TString::kLeading); // skip leading whitespace
8087 if (sLine.IsNull()) {
8088 if (gDebug > 2) {
8089 Info("ReadStream", "Skipping empty line number %lld", nlines);
8090 }
8091 continue; // silently skip empty lines
8092 }
8093 if (sLine[0] == '#') {
8094 if (gDebug > 2) {
8095 Info("ReadStream", "Skipping comment line number %lld: '%s'",
8096 nlines, line.c_str());
8097 }
8098 continue;
8099 }
8100 if (gDebug > 2) {
8101 Info("ReadStream", "Parsing line number %lld: '%s'",
8102 nlines, line.c_str());
8103 }
8104
8105 // Loop on branches and read the branch values into their buffer
8106 branch = nullptr;
8107 TString tok; // one column's data
8108 TString leafData; // leaf data, possibly multiple tokens for e.g. /I[2]
8109 std::stringstream sToken; // string stream feeding leafData into leaves
8110 Ssiz_t pos = 0;
8111 Int_t iBranch = 0;
8112 bool goodLine = true; // whether the row can be filled into the tree
8113 Int_t remainingLeafLen = 0; // remaining columns for the current leaf
8114 while (goodLine && iBranch < nbranches
8115 && sLine.Tokenize(tok, pos, sDelim)) {
8116 tok = tok.Strip(TString::kLeading); // skip leading whitespace
8117 if (tok.IsNull() && delimiter == ' ') {
8118 // 1 2 should not be interpreted as 1,,,2 but 1, 2.
8119 // Thus continue until we have a non-empty token.
8120 continue;
8121 }
8122
8123 if (!remainingLeafLen) {
8124 // next branch!
8126 }
8127 TLeaf *leaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
8128 if (!remainingLeafLen) {
8129 remainingLeafLen = leaf->GetLen();
8130 if (leaf->GetMaximum() > 0) {
8131 // This is a dynamic leaf length, i.e. most likely a TLeafC's
8132 // string size. This still translates into one token:
8133 remainingLeafLen = 1;
8134 }
8135
8136 leafData = tok;
8137 } else {
8138 // append token to laf data:
8139 leafData += " ";
8140 leafData += tok;
8141 }
8143 if (remainingLeafLen) {
8144 // need more columns for this branch:
8145 continue;
8146 }
8147 ++iBranch;
8148
8149 // initialize stringstream with token
8150 sToken.clear();
8151 sToken.seekp(0, std::ios_base::beg);
8152 sToken.str(leafData.Data());
8153 sToken.seekg(0, std::ios_base::beg);
8154 leaf->ReadValue(sToken, 0 /* 0 = "all" */);
8155 if (gDebug > 3) {
8156 Info("ReadStream", "%5lld:%3d:%d%d%d%d:%d%d%d%d:%s",
8157 nlines, iBranch,
8158 (int)sToken.good(), (int)sToken.fail(),
8159 (int)sToken.bad(), (int)sToken.eof(),
8160 (int)in.good(), (int)in.fail(),
8161 (int)in.bad(), (int)in.eof(),
8162 sToken.str().c_str());
8163 }
8164
8165 // Error handling
8166 if (sToken.bad()) {
8167 // How could that happen for a stringstream?
8168 Warning("ReadStream",
8169 "Buffer error while reading data for branch %s on line %lld",
8170 branch->GetName(), nlines);
8171 } else if (!sToken.eof()) {
8172 if (sToken.fail()) {
8173 Warning("ReadStream",
8174 "Couldn't read formatted data in \"%s\" for branch %s on line %lld; ignoring line",
8175 tok.Data(), branch->GetName(), nlines);
8176 goodLine = false;
8177 } else {
8178 std::string remainder;
8179 std::getline(sToken, remainder, newline);
8180 if (!remainder.empty()) {
8181 Warning("ReadStream",
8182 "Ignoring trailing \"%s\" while reading data for branch %s on line %lld",
8183 remainder.c_str(), branch->GetName(), nlines);
8184 }
8185 }
8186 }
8187 } // tokenizer loop
8188
8189 if (iBranch < nbranches) {
8190 Warning("ReadStream",
8191 "Read too few columns (%d < %d) in line %lld; ignoring line",
8193 goodLine = false;
8194 } else if (pos != kNPOS) {
8196 if (pos < sLine.Length()) {
8197 Warning("ReadStream",
8198 "Ignoring trailing \"%s\" while reading line %lld",
8199 sLine.Data() + pos - 1 /* also print delimiter */,
8200 nlines);
8201 }
8202 }
8203
8204 //we are now ready to fill the tree
8205 if (goodLine) {
8206 Fill();
8207 ++nGoodLines;
8208 }
8209 }
8210
8211 return nGoodLines;
8212}
8213
8214////////////////////////////////////////////////////////////////////////////////
8215/// Make sure that obj (which is being deleted or will soon be) is no
8216/// longer referenced by this TTree.
8219{
8220 if (obj == fEventList) {
8221 fEventList = nullptr;
8222 }
8223 if (obj == fEntryList) {
8224 fEntryList = nullptr;
8225 }
8226 if (fUserInfo) {
8228 }
8229 if (fPlayer == obj) {
8230 fPlayer = nullptr;
8231 }
8232 if (fTreeIndex == obj) {
8233 fTreeIndex = nullptr;
8234 }
8235 if (fAliases == obj) {
8236 fAliases = nullptr;
8237 } else if (fAliases) {
8239 }
8240 if (fFriends == obj) {
8241 fFriends = nullptr;
8242 } else if (fFriends) {
8244 }
8245}
8246
8247////////////////////////////////////////////////////////////////////////////////
8248/// Refresh contents of this tree and its branches from the current status on disk.
8249///
8250/// One can call this function in case the tree file is being
8251/// updated by another process.
8253void TTree::Refresh()
8254{
8255 if (!fDirectory->GetFile()) {
8256 return;
8257 }
8259 fDirectory->Remove(this);
8260 TTree* tree; fDirectory->GetObject(GetName(),tree);
8261 if (!tree) {
8262 return;
8263 }
8264 //copy info from tree header into this Tree
8265 fEntries = 0;
8266 fNClusterRange = 0;
8267 ImportClusterRanges(tree);
8268
8269 fAutoSave = tree->fAutoSave;
8270 fEntries = tree->fEntries;
8271 fTotBytes = tree->GetTotBytes();
8272 fZipBytes = tree->GetZipBytes();
8273 fSavedBytes = tree->fSavedBytes;
8274 fTotalBuffers = tree->fTotalBuffers.load();
8275
8276 //loop on all branches and update them
8278 for (Int_t i = 0; i < nleaves; i++) {
8280 TBranch* branch = (TBranch*) leaf->GetBranch();
8281 branch->Refresh(tree->GetBranch(branch->GetName()));
8282 }
8283 fDirectory->Remove(tree);
8284 fDirectory->Append(this);
8285 delete tree;
8286 tree = nullptr;
8287}
8288
8289////////////////////////////////////////////////////////////////////////////////
8290/// Record a TFriendElement that we need to warn when the chain switches to
8291/// a new file (typically this is because this chain is a friend of another
8292/// TChain)
8299}
8300
8301
8302////////////////////////////////////////////////////////////////////////////////
8303/// Removes external friend
8308}
8309
8310
8311////////////////////////////////////////////////////////////////////////////////
8312/// Remove a friend from the list of friends.
8315{
8316 // We already have been visited while recursively looking
8317 // through the friends tree, let return
8319 return;
8320 }
8321 if (!fFriends) {
8322 return;
8323 }
8324 TFriendLock lock(this, kRemoveFriend);
8326 TFriendElement* fe = nullptr;
8327 while ((fe = (TFriendElement*) nextf())) {
8328 TTree* friend_t = fe->GetTree();
8329 if (friend_t == oldFriend) {
8330 fFriends->Remove(fe);
8331 delete fe;
8332 fe = nullptr;
8333 }
8334 }
8335}
8336
8337////////////////////////////////////////////////////////////////////////////////
8338/// Reset baskets, buffers and entries count in all branches and leaves.
8341{
8342 fNotify = nullptr;
8343 fEntries = 0;
8344 fNClusterRange = 0;
8345 fTotBytes = 0;
8346 fZipBytes = 0;
8347 fFlushedBytes = 0;
8348 fSavedBytes = 0;
8349 fTotalBuffers = 0;
8350 fChainOffset = 0;
8351 fReadEntry = -1;
8352
8353 delete fTreeIndex;
8354 fTreeIndex = nullptr;
8355
8357 for (Int_t i = 0; i < nb; ++i) {
8359 branch->Reset(option);
8360 }
8361
8362 if (fBranchRef) {
8363 fBranchRef->Reset();
8364 }
8365}
8366
8367////////////////////////////////////////////////////////////////////////////////
8368/// Resets the state of this TTree after a merge (keep the customization but
8369/// forget the data).
8372{
8373 fEntries = 0;
8374 fNClusterRange = 0;
8375 fTotBytes = 0;
8376 fZipBytes = 0;
8377 fSavedBytes = 0;
8378 fFlushedBytes = 0;
8379 fTotalBuffers = 0;
8380 fChainOffset = 0;
8381 fReadEntry = -1;
8382
8383 delete fTreeIndex;
8384 fTreeIndex = nullptr;
8385
8387 for (Int_t i = 0; i < nb; ++i) {
8389 branch->ResetAfterMerge(info);
8390 }
8391
8392 if (fBranchRef) {
8394 }
8395}
8396
8397////////////////////////////////////////////////////////////////////////////////
8398/// Tell a branch to set its address to zero.
8399///
8400/// @note If the branch owns any objects, they are deleted.
8403{
8404 if (br && br->GetTree()) {
8405 br->ResetAddress();
8406 }
8407}
8408
8409////////////////////////////////////////////////////////////////////////////////
8410/// Tell all of our branches to drop their current objects and allocate new ones.
8413{
8414 // We already have been visited while recursively looking
8415 // through the friends tree, let return
8417 return;
8418 }
8420 Int_t nbranches = branches->GetEntriesFast();
8421 for (Int_t i = 0; i < nbranches; ++i) {
8422 TBranch* branch = (TBranch*) branches->UncheckedAt(i);
8423 branch->ResetAddress();
8424 }
8425 if (fFriends) {
8428 auto *frTree = frEl->GetTree();
8429 if (frTree) {
8430 frTree->ResetBranchAddresses();
8431 }
8432 }
8433 }
8434}
8435
8436////////////////////////////////////////////////////////////////////////////////
8437/// Loop over tree entries and print entries passing selection. Interactive
8438/// pagination break is on by default.
8439///
8440/// - If varexp is 0 (or "") then print only first 8 columns.
8441/// - If varexp = "*" print all columns.
8442///
8443/// Otherwise a columns selection can be made using "var1:var2:var3".
8444///
8445/// \param firstentry first entry to scan
8446/// \param nentries total number of entries to scan (starting from firstentry). Defaults to all entries.
8447/// \note see TTree::SetScanField to control how many lines are printed between pagination breaks (Use 0 to disable pagination)
8448/// \see TTreePlayer::Scan, TTreePlayer::SetScanFileName, TTreePlayer::SetScanRedirect
8451{
8452 GetPlayer();
8453 if (fPlayer) {
8455 }
8456 return -1;
8457}
8458
8459////////////////////////////////////////////////////////////////////////////////
8460/// Set a tree variable alias.
8461///
8462/// Set an alias for an expression/formula based on the tree 'variables'.
8463///
8464/// The content of 'aliasName' can be used in TTreeFormula (i.e. TTree::Draw,
8465/// TTree::Scan, TTreeViewer) and will be evaluated as the content of
8466/// 'aliasFormula'.
8467///
8468/// If the content of 'aliasFormula' only contains symbol names, periods and
8469/// array index specification (for example event.fTracks[3]), then
8470/// the content of 'aliasName' can be used as the start of symbol.
8471///
8472/// If the alias 'aliasName' already existed, it is replaced by the new
8473/// value.
8474///
8475/// When being used, the alias can be preceded by an eventual 'Friend Alias'
8476/// (see TTree::GetFriendAlias)
8477///
8478/// Return true if it was added properly.
8479///
8480/// For example:
8481/// ~~~ {.cpp}
8482/// tree->SetAlias("x1","(tdc1[1]-tdc1[0])/49");
8483/// tree->SetAlias("y1","(tdc1[3]-tdc1[2])/47");
8484/// tree->SetAlias("x2","(tdc2[1]-tdc2[0])/49");
8485/// tree->SetAlias("y2","(tdc2[3]-tdc2[2])/47");
8486/// tree->Draw("y2-y1:x2-x1");
8487///
8488/// tree->SetAlias("theGoodTrack","event.fTracks[3]");
8489/// tree->Draw("theGoodTrack.fPx"); // same as "event.fTracks[3].fPx"
8490/// ~~~
8492bool TTree::SetAlias(const char* aliasName, const char* aliasFormula)
8493{
8494 if (!aliasName || !aliasFormula) {
8495 return false;
8496 }
8497 if (!aliasName[0] || !aliasFormula[0]) {
8498 return false;
8499 }
8500 if (!fAliases) {
8501 fAliases = new TList;
8502 } else {
8504 if (oldHolder) {
8505 oldHolder->SetTitle(aliasFormula);
8506 return true;
8507 }
8508 }
8511 return true;
8512}
8513
8514////////////////////////////////////////////////////////////////////////////////
8515/// This function may be called at the start of a program to change
8516/// the default value for fAutoFlush.
8517///
8518/// ### CASE 1 : autof > 0
8519///
8520/// autof is the number of consecutive entries after which TTree::Fill will
8521/// flush all branch buffers to disk.
8522///
8523/// ### CASE 2 : autof < 0
8524///
8525/// When filling the Tree the branch buffers will be flushed to disk when
8526/// more than autof bytes have been written to the file. At the first FlushBaskets
8527/// TTree::Fill will replace fAutoFlush by the current value of fEntries.
8528///
8529/// Calling this function with autof<0 is interesting when it is hard to estimate
8530/// the size of one entry. This value is also independent of the Tree.
8531///
8532/// The Tree is initialized with fAutoFlush=-30000000, ie that, by default,
8533/// the first AutoFlush will be done when 30 MBytes of data are written to the file.
8534///
8535/// ### CASE 3 : autof = 0
8536///
8537/// The AutoFlush mechanism is disabled.
8538///
8539/// Flushing the buffers at regular intervals optimize the location of
8540/// consecutive entries on the disk by creating clusters of baskets.
8541///
8542/// A cluster of baskets is a set of baskets that contains all
8543/// the data for a (consecutive) set of entries and that is stored
8544/// consecutively on the disk. When reading all the branches, this
8545/// is the minimum set of baskets that the TTreeCache will read.
8547void TTree::SetAutoFlush(Long64_t autof /* = -30000000 */ )
8548{
8549 // Implementation note:
8550 //
8551 // A positive value of autoflush determines the size (in number of entries) of
8552 // a cluster of baskets.
8553 //
8554 // If the value of autoflush is changed over time (this happens in
8555 // particular when the TTree results from fast merging many trees),
8556 // we record the values of fAutoFlush in the data members:
8557 // fClusterRangeEnd and fClusterSize.
8558 // In the code we refer to a range of entries where the size of the
8559 // cluster of baskets is the same (i.e the value of AutoFlush was
8560 // constant) is called a ClusterRange.
8561 //
8562 // The 2 arrays (fClusterRangeEnd and fClusterSize) have fNClusterRange
8563 // active (used) values and have fMaxClusterRange allocated entries.
8564 //
8565 // fClusterRangeEnd contains the last entries number of a cluster range.
8566 // In particular this means that the 'next' cluster starts at fClusterRangeEnd[]+1
8567 // fClusterSize contains the size in number of entries of all the cluster
8568 // within the given range.
8569 // The last range (and the only one if fNClusterRange is zero) start at
8570 // fNClusterRange[fNClusterRange-1]+1 and ends at the end of the TTree. The
8571 // size of the cluster in this range is given by the value of fAutoFlush.
8572 //
8573 // For example printing the beginning and end of each the ranges can be done by:
8574 //
8575 // Printf("%-16s %-16s %-16s %5s",
8576 // "Cluster Range #", "Entry Start", "Last Entry", "Size");
8577 // Int_t index= 0;
8578 // Long64_t clusterRangeStart = 0;
8579 // if (fNClusterRange) {
8580 // for( ; index < fNClusterRange; ++index) {
8581 // Printf("%-16d %-16lld %-16lld %5lld",
8582 // index, clusterRangeStart, fClusterRangeEnd[index], fClusterSize[index]);
8583 // clusterRangeStart = fClusterRangeEnd[index] + 1;
8584 // }
8585 // }
8586 // Printf("%-16d %-16lld %-16lld %5lld",
8587 // index, prevEntry, fEntries - 1, fAutoFlush);
8588 //
8589
8590 // Note: We store the entry number corresponding to the end of the cluster
8591 // rather than its start in order to avoid using the array if the cluster
8592 // size never varies (If there is only one value of AutoFlush for the whole TTree).
8593
8594 if( fAutoFlush != autof) {
8595 if ((fAutoFlush > 0 || autof > 0) && fFlushedBytes) {
8596 // The mechanism was already enabled, let's record the previous
8597 // cluster if needed.
8599 }
8600 fAutoFlush = autof;
8601 }
8602}
8603
8604////////////////////////////////////////////////////////////////////////////////
8605/// Mark the previous event as being at the end of the event cluster.
8606///
8607/// So, if fEntries is set to 10 (and this is the first cluster) when MarkEventCluster
8608/// is called, then the first cluster has 9 events.
8610{
8611 if (!fEntries) return;
8612
8613 if ( (fNClusterRange+1) > fMaxClusterRange ) {
8614 if (fMaxClusterRange) {
8615 // Resize arrays to hold a larger event cluster.
8618 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
8620 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
8622 } else {
8623 // Cluster ranges have never been initialized; create them now.
8624 fMaxClusterRange = 2;
8627 }
8628 }
8630 // If we are auto-flushing, then the cluster size is the same as the current auto-flush setting.
8631 if (fAutoFlush > 0) {
8632 // Even if the user triggers MarkEventRange prior to fAutoFlush being present, the TClusterIterator
8633 // will appropriately go to the next event range.
8635 // Otherwise, assume there is one cluster per event range (e.g., user is manually controlling the flush).
8636 } else if (fNClusterRange == 0) {
8638 } else {
8640 }
8642}
8643
8644/// Estimate the median cluster size for the TTree.
8645/// This value provides e.g. a reasonable cache size default if other heuristics fail.
8646/// Clusters with size 0 and the very last cluster range, that might not have been committed to fClusterSize yet,
8647/// are ignored for the purposes of the calculation.
8649{
8650 std::vector<Long64_t> clusterSizesPerRange;
8652
8653 // We ignore cluster sizes of 0 for the purposes of this function.
8654 // We also ignore the very last cluster range which might not have been committed to fClusterSize.
8655 std::copy_if(fClusterSize, fClusterSize + fNClusterRange, std::back_inserter(clusterSizesPerRange),
8656 [](Long64_t size) { return size != 0; });
8657
8658 std::vector<double> nClustersInRange; // we need to store doubles because of the signature of TMath::Median
8659 nClustersInRange.reserve(clusterSizesPerRange.size());
8660
8661 auto clusterRangeStart = 0ll;
8662 for (int i = 0; i < fNClusterRange; ++i) {
8663 const auto size = fClusterSize[i];
8664 R__ASSERT(size >= 0);
8665 if (fClusterSize[i] == 0)
8666 continue;
8667 const auto nClusters = (1 + fClusterRangeEnd[i] - clusterRangeStart) / fClusterSize[i];
8668 nClustersInRange.emplace_back(nClusters);
8670 }
8671
8673 const auto medianClusterSize =
8675 return medianClusterSize;
8676}
8677
8678////////////////////////////////////////////////////////////////////////////////
8679/// In case of a program crash, it will be possible to recover the data in the
8680/// tree up to the last AutoSave point.
8681/// This function may be called before filling a TTree to specify when the
8682/// branch buffers and TTree header are flushed to disk as part of
8683/// TTree::Fill().
8684/// The default is -300000000, ie the TTree will write data to disk once it
8685/// exceeds 300 MBytes.
8686/// CASE 1: If fAutoSave is positive the watermark is reached when a multiple of
8687/// fAutoSave entries have been filled.
8688/// CASE 2: If fAutoSave is negative the watermark is reached when -fAutoSave
8689/// bytes can be written to the file.
8690/// CASE 3: If fAutoSave is 0, AutoSave() will never be called automatically
8691/// as part of TTree::Fill().
8696}
8697
8698////////////////////////////////////////////////////////////////////////////////
8699/// Set a branch's basket size.
8700///
8701/// bname is the name of a branch.
8702///
8703/// - if bname="*", apply to all branches.
8704/// - if bname="xxx*", apply to all branches with name starting with xxx
8705///
8706/// see TRegexp for wildcarding options
8707/// bufsize = branch basket size
8709void TTree::SetBasketSize(const char* bname, Int_t bufsize)
8710{
8712 TRegexp re(bname, true);
8713 Int_t nb = 0;
8714 for (Int_t i = 0; i < nleaves; i++) {
8716 TBranch* branch = (TBranch*) leaf->GetBranch();
8717 TString s = branch->GetName();
8718 if (strcmp(bname, branch->GetName()) && (s.Index(re) == kNPOS)) {
8719 continue;
8720 }
8721 nb++;
8722 branch->SetBasketSize(bufsize);
8723 }
8724 if (!nb) {
8725 Error("SetBasketSize", "unknown branch -> '%s'", bname);
8726 }
8727}
8728
8729////////////////////////////////////////////////////////////////////////////////
8730/// Change branch address, dealing with clone trees properly.
8731/// See TTree::CheckBranchAddressType for the semantic of the return value.
8732///
8733/// Note: See the comments in TBranchElement::SetAddress() for the
8734/// meaning of the addr parameter and the object ownership policy.
8736Int_t TTree::SetBranchAddress(const char* bname, void* addr, TBranch** ptr)
8737{
8738 TBranch* branch = GetBranch(bname);
8739 if (!branch) {
8740 if (ptr) *ptr = nullptr;
8741 Error("SetBranchAddress", "unknown branch -> %s", bname);
8742 return kMissingBranch;
8743 }
8744 return SetBranchAddressImp(branch,addr,ptr);
8745}
8746
8747////////////////////////////////////////////////////////////////////////////////
8748/// Verify the validity of the type of addr before calling SetBranchAddress.
8749/// See TTree::CheckBranchAddressType for the semantic of the return value.
8750///
8751/// Note: See the comments in TBranchElement::SetAddress() for the
8752/// meaning of the addr parameter and the object ownership policy.
8754Int_t TTree::SetBranchAddress(const char* bname, void* addr, TClass* ptrClass, EDataType datatype, bool isptr)
8755{
8756 return SetBranchAddress(bname, addr, nullptr, ptrClass, datatype, isptr);
8757}
8760 bool isptr)
8761{
8762 if (auto *branchFromSelf = GetBranchFromSelf(bname)) {
8764
8765 // This will set the value of *ptr to branch.
8766 if (res >= 0) {
8767 // The check succeeded.
8768 if ((res & kNeedEnableDecomposedObj) && !branchFromSelf->GetMakeClass())
8769 branchFromSelf->SetMakeClass(true);
8771 } else {
8772 if (ptr)
8773 *ptr = nullptr;
8774 }
8775 return res;
8776 }
8777
8778 // Check friends
8779 if (fFriends) {
8780 int status{kMissingBranch};
8782 if (auto *tree = fe->GetTree()) {
8783 status = tree->SetBranchAddress(bname, addr, ptr, ptrClass, datatype, isptr, true);
8784 // We exit early from visiting all friends only if a perfect match was found
8785 if (status == kMatch)
8786 return status;
8787 }
8788 }
8789 // This allows for the valid case of friend TChain(s) which might hold
8790 // the requested branch, but might not know it yet since they haven't loaded
8791 // the tree. This is encoded in the kNoCheck == 5 value.
8792 if (status != kMissingBranch)
8793 return status;
8794 }
8795
8796 // Branch not found
8797 if (ptr)
8798 *ptr = nullptr;
8799
8800 return kMissingBranch;
8801}
8802
8803////////////////////////////////////////////////////////////////////////////////
8804/// Verify the validity of the type of addr before calling SetBranchAddress.
8805/// See TTree::CheckBranchAddressType for the semantic of the return value.
8806///
8807/// Note: See the comments in TBranchElement::SetAddress() for the
8808/// meaning of the addr parameter and the object ownership policy.
8810Int_t TTree::SetBranchAddress(const char *bname, void *addr, TBranch **ptr, TClass *ptrClass, EDataType datatype,
8811 bool isptr)
8812{
8813 auto res = SetBranchAddressImp(bname, addr, ptr, ptrClass, datatype, isptr);
8814 if (res == kMissingBranch)
8815 Error("SetBranchAddress", "unknown branch -> %s", bname);
8816 return res;
8817}
8819Int_t TTree::SetBranchAddress(const char *bname, void *addr, TBranch **ptr, TClass *ptrClass, EDataType datatype,
8820 bool isptr, bool)
8821{
8822 // This has been called while setting the branch address of friends of a TTree. We can't know a priori
8823 // which friend actually has the branch bname, so we avoid printing an error in case of missing branch
8824 return SetBranchAddressImp(bname, addr, ptr, ptrClass, datatype, isptr);
8825}
8826
8827////////////////////////////////////////////////////////////////////////////////
8828/// Change branch address, dealing with clone trees properly.
8829/// See TTree::CheckBranchAddressType for the semantic of the return value.
8830///
8831/// Note: See the comments in TBranchElement::SetAddress() for the
8832/// meaning of the addr parameter and the object ownership policy.
8835{
8836 if (ptr) {
8837 *ptr = branch;
8838 }
8839 if (fClones) {
8840 void* oldAddr = branch->GetAddress();
8841 TIter next(fClones);
8842 TTree* clone = nullptr;
8843 const char *bname = branch->GetName();
8844 while ((clone = (TTree*) next())) {
8845 TBranch* cloneBr = clone->GetBranch(bname);
8846 if (cloneBr && (cloneBr->GetAddress() == oldAddr)) {
8847 cloneBr->SetAddress(addr);
8848 }
8849 }
8850 }
8851 branch->SetAddress(addr);
8852 return kVoidPtr;
8853}
8854
8855////////////////////////////////////////////////////////////////////////////////
8856/// Set branch status to Process or DoNotProcess.
8857///
8858/// When reading a Tree, by default, all branches are read.
8859/// One can speed up considerably the analysis phase by activating
8860/// only the branches that hold variables involved in a query.
8861///
8862/// bname is the name of a branch.
8863///
8864/// - if bname="*", apply to all branches.
8865/// - if bname="xxx*", apply to all branches with name starting with xxx
8866///
8867/// see TRegexp for wildcarding options
8868///
8869/// - status = 1 branch will be processed
8870/// - = 0 branch will not be processed
8871///
8872/// Example:
8873///
8874/// Assume a tree T with sub-branches a,b,c,d,e,f,g,etc..
8875/// when doing T.GetEntry(i) all branches are read for entry i.
8876/// to read only the branches c and e, one can do
8877/// ~~~ {.cpp}
8878/// T.SetBranchStatus("*",0); //disable all branches
8879/// T.SetBranchStatus("c",1);
8880/// T.setBranchStatus("e",1);
8881/// T.GetEntry(i);
8882/// ~~~
8883/// bname is interpreted as a wild-carded TRegexp (see TRegexp::MakeWildcard).
8884/// Thus, "a*b" or "a.*b" matches branches starting with "a" and ending with
8885/// "b", but not any other branch with an "a" followed at some point by a
8886/// "b". For this second behavior, use "*a*b*". Note that TRegExp does not
8887/// support '|', and so you cannot select, e.g. track and shower branches
8888/// with "track|shower".
8889///
8890/// __WARNING! WARNING! WARNING!__
8891///
8892/// SetBranchStatus is matching the branch based on match of the branch
8893/// 'name' and not on the branch hierarchy! In order to be able to
8894/// selectively enable a top level object that is 'split' you need to make
8895/// sure the name of the top level branch is prefixed to the sub-branches'
8896/// name (by adding a dot ('.') at the end of the Branch creation and use the
8897/// corresponding bname.
8898///
8899/// I.e If your Tree has been created in split mode with a parent branch "parent."
8900/// (note the trailing dot).
8901/// ~~~ {.cpp}
8902/// T.SetBranchStatus("parent",1);
8903/// ~~~
8904/// will not activate the sub-branches of "parent". You should do:
8905/// ~~~ {.cpp}
8906/// T.SetBranchStatus("parent*",1);
8907/// ~~~
8908/// Without the trailing dot in the branch creation you have no choice but to
8909/// call SetBranchStatus explicitly for each of the sub branches.
8910///
8911/// An alternative to this function is to read directly and only
8912/// the interesting branches. Example:
8913/// ~~~ {.cpp}
8914/// TBranch *brc = T.GetBranch("c");
8915/// TBranch *bre = T.GetBranch("e");
8916/// brc->GetEntry(i);
8917/// bre->GetEntry(i);
8918/// ~~~
8919/// If found is not 0, the number of branch(es) found matching the regular
8920/// expression is returned in *found AND the error message 'unknown branch'
8921/// is suppressed.
8923void TTree::SetBranchStatus(const char* bname, bool status, UInt_t* found)
8924{
8925 // We already have been visited while recursively looking
8926 // through the friends tree, let return
8928 return;
8929 }
8930
8931 if (!bname || !*bname) {
8932 Error("SetBranchStatus", "Input regexp is an empty string: no match against branch names will be attempted.");
8933 return;
8934 }
8935
8937 TLeaf *leaf, *leafcount;
8938
8939 Int_t i,j;
8941 TRegexp re(bname,true);
8942 Int_t nb = 0;
8943
8944 // first pass, loop on all branches
8945 // for leafcount branches activate/deactivate in function of status
8946 for (i=0;i<nleaves;i++) {
8948 branch = (TBranch*)leaf->GetBranch();
8949 TString s = branch->GetName();
8950 if (strcmp(bname,"*")) { //Regexp gives wrong result for [] in name
8952 longname.Form("%s.%s",GetName(),branch->GetName());
8953 if (strcmp(bname,branch->GetName())
8954 && longname != bname
8955 && s.Index(re) == kNPOS) continue;
8956 }
8957 nb++;
8958 if (status) branch->ResetBit(kDoNotProcess);
8959 else branch->SetBit(kDoNotProcess);
8960 leafcount = leaf->GetLeafCount();
8961 if (leafcount) {
8962 bcount = leafcount->GetBranch();
8963 if (status) bcount->ResetBit(kDoNotProcess);
8964 else bcount->SetBit(kDoNotProcess);
8965 }
8966 }
8967 if (nb==0 && !strchr(bname,'*')) {
8968 branch = GetBranch(bname);
8969 if (branch) {
8970 if (status) branch->ResetBit(kDoNotProcess);
8971 else branch->SetBit(kDoNotProcess);
8972 ++nb;
8973 }
8974 }
8975
8976 //search in list of friends
8978 if (fFriends) {
8979 TFriendLock lock(this,kSetBranchStatus);
8982 TString name;
8983 while ((fe = (TFriendElement*)nextf())) {
8984 TTree *t = fe->GetTree();
8985 if (!t) continue;
8986
8987 // If the alias is present replace it with the real name.
8988 const char *subbranch = strstr(bname,fe->GetName());
8989 if (subbranch!=bname) subbranch = nullptr;
8990 if (subbranch) {
8991 subbranch += strlen(fe->GetName());
8992 if ( *subbranch != '.' ) subbranch = nullptr;
8993 else subbranch ++;
8994 }
8995 if (subbranch) {
8996 name.Form("%s.%s",t->GetName(),subbranch);
8997 } else {
8998 name = bname;
8999 }
9000 t->SetBranchStatus(name,status, &foundInFriend);
9001 }
9002 }
9003 if (!nb && !foundInFriend) {
9004 if (!found) {
9005 if (status) {
9006 if (strchr(bname,'*') != nullptr)
9007 Error("SetBranchStatus", "No branch name is matching wildcard -> %s", bname);
9008 else
9009 Error("SetBranchStatus", "unknown branch -> %s", bname);
9010 } else {
9011 if (strchr(bname,'*') != nullptr)
9012 Warning("SetBranchStatus", "No branch name is matching wildcard -> %s", bname);
9013 else
9014 Warning("SetBranchStatus", "unknown branch -> %s", bname);
9015 }
9016 }
9017 return;
9018 }
9019 if (found) *found = nb + foundInFriend;
9020
9021 // second pass, loop again on all branches
9022 // activate leafcount branches for active branches only
9023 for (i = 0; i < nleaves; i++) {
9025 branch = (TBranch*)leaf->GetBranch();
9026 if (!branch->TestBit(kDoNotProcess)) {
9027 leafcount = leaf->GetLeafCount();
9028 if (leafcount) {
9029 bcount = leafcount->GetBranch();
9030 bcount->ResetBit(kDoNotProcess);
9031 }
9032 } else {
9033 //Int_t nbranches = branch->GetListOfBranches()->GetEntriesFast();
9034 Int_t nbranches = branch->GetListOfBranches()->GetEntries();
9035 for (j=0;j<nbranches;j++) {
9036 bson = (TBranch*)branch->GetListOfBranches()->UncheckedAt(j);
9037 if (!bson) continue;
9038 if (!bson->TestBit(kDoNotProcess)) {
9039 if (bson->GetNleaves() <= 0) continue;
9040 branch->ResetBit(kDoNotProcess);
9041 break;
9042 }
9043 }
9044 }
9045 }
9046}
9047
9048////////////////////////////////////////////////////////////////////////////////
9049/// Set the current branch style. (static function)
9050///
9051/// - style = 0 old Branch
9052/// - style = 1 new Bronch
9057}
9058
9059////////////////////////////////////////////////////////////////////////////////
9060/// Set maximum size of the file cache (TTreeCache) in bytes.
9061//
9062/// - if cachesize = 0 the existing cache (if any) is disabled (deleted if any).
9063/// - if cachesize > 0, the cache is enabled or extended, if necessary
9064/// - if cachesize = -1 (default) it is set to the AutoFlush value when writing
9065/// the Tree (default is 30 MBytes).
9066///
9067/// The cacheSize might be clamped, see TFileCacheRead::SetBufferSize
9068///
9069/// TTreeCache's 'real' job is to actually prefetch (early grab from disk) the compressed data.
9070/// The cachesize controls the size of the read bytes from disk.
9071///
9072/// Returns:
9073/// - 0 size set, cache was created if possible
9074/// - -1 on error
9077{
9078 // remember that the user has requested an explicit cache setup
9079 fCacheUserSet = true;
9080
9081 return SetCacheSizeAux(false, cacheSize);
9082}
9083
9084////////////////////////////////////////////////////////////////////////////////
9085/// Set the maximum size of the file cache (TTreeCache) in bytes and create it if possible.
9086///
9087/// If autocache is true:
9088/// this may be an autocreated cache, possibly enlarging an existing
9089/// autocreated cache. The size is calculated. The value passed in cacheSize:
9090/// - cacheSize = 0 make cache if default cache creation is enabled.
9091/// - cachesize > 0 the cache is enabled or extended, if necessary
9092/// - cacheSize = -1 make a default sized cache in any case
9093///
9094/// If autocache is false:
9095/// this is a user requested cache. cacheSize is used to size the cache.
9096/// This cache should never be automatically adjusted. If cachesize is
9097/// 0, the cache is disabled (deleted if any).
9098///
9099/// The cacheSize might be clamped, see TFileCacheRead::SetBufferSize
9100///
9101/// TTreeCache's 'real' job is to actually prefetch (early grab from disk) the compressed data.
9102/// The cachesize controls the size of the read bytes from disk.
9103///
9104/// Returns:
9105/// - 0 size set, or existing autosized cache almost large enough.
9106/// (cache was created if possible)
9107/// - -1 on error
9109Int_t TTree::SetCacheSizeAux(bool autocache /* = true */, Long64_t cacheSize /* = 0 */ )
9110{
9111 if (autocache) {
9112 // used as a once only control for automatic cache setup
9113 fCacheDoAutoInit = false;
9114 }
9115
9116 if (!autocache) {
9117 // negative size means the user requests the default
9118 if (cacheSize < 0) {
9119 cacheSize = GetCacheAutoSize(true);
9120 }
9121 } else {
9122 if (cacheSize == 0) {
9123 cacheSize = GetCacheAutoSize();
9124 } else if (cacheSize < 0) {
9125 cacheSize = GetCacheAutoSize(true);
9126 }
9127 }
9128
9129 TFile* file = GetCurrentFile();
9130 if (!file || GetTree() != this) {
9131 // if there's no file or we are not a plain tree (e.g. if we're a TChain)
9132 // do not create a cache, only record the size if one was given
9133 if (!autocache) {
9134 fCacheSize = cacheSize;
9135 }
9136 if (GetTree() != this) {
9137 return 0;
9138 }
9139 if (!autocache && cacheSize>0) {
9140 Warning("SetCacheSizeAux", "A TTreeCache could not be created because the TTree has no file");
9141 }
9142 return 0;
9143 }
9144
9145 // Check for an existing cache
9146 TTreeCache* pf = GetReadCache(file);
9147 if (pf) {
9148 if (autocache) {
9149 // reset our cache status tracking in case existing cache was added
9150 // by the user without using one of the TTree methods
9151 fCacheSize = pf->GetBufferSize();
9152 fCacheUserSet = !pf->IsAutoCreated();
9153
9154 if (fCacheUserSet) {
9155 // existing cache was created by the user, don't change it
9156 return 0;
9157 }
9158 } else {
9159 // update the cache to ensure it records the user has explicitly
9160 // requested it
9161 pf->SetAutoCreated(false);
9162 }
9163
9164 // if we're using an automatically calculated size and the existing
9165 // cache is already almost large enough don't resize
9166 if (autocache && Long64_t(0.80*cacheSize) < fCacheSize) {
9167 // already large enough
9168 return 0;
9169 }
9170
9171 if (cacheSize == fCacheSize) {
9172 return 0;
9173 }
9174
9175 if (cacheSize == 0) {
9176 // delete existing cache
9177 pf->WaitFinishPrefetch();
9178 file->SetCacheRead(nullptr,this);
9179 delete pf;
9180 pf = nullptr;
9181 } else {
9182 // resize
9183 Int_t res = pf->SetBufferSize(cacheSize);
9184 if (res < 0) {
9185 return -1;
9186 }
9187 cacheSize = pf->GetBufferSize(); // update after potential clamp
9188 }
9189 } else {
9190 // no existing cache
9191 if (autocache) {
9192 if (fCacheUserSet) {
9193 // value was already set manually.
9194 if (fCacheSize == 0) return 0;
9195 // Expected a cache should exist; perhaps the user moved it
9196 // Do nothing more here.
9197 if (cacheSize) {
9198 Error("SetCacheSizeAux", "Not setting up an automatically sized TTreeCache because of missing cache previously set");
9199 }
9200 return -1;
9201 }
9202 }
9203 }
9204
9205 fCacheSize = cacheSize;
9206 if (cacheSize == 0 || pf) {
9207 return 0;
9208 }
9209
9210#ifdef R__USE_IMT
9212 pf = new TTreeCacheUnzip(this, cacheSize);
9213 else
9214#endif
9215 pf = new TTreeCache(this, cacheSize);
9216
9217 pf->SetAutoCreated(autocache);
9218
9219 return 0;
9220}
9221
9222////////////////////////////////////////////////////////////////////////////////
9223///interface to TTreeCache to set the cache entry range
9224///
9225/// Returns:
9226/// - 0 entry range set
9227/// - -1 on error
9230{
9231 if (!GetTree()) {
9232 if (LoadTree(0)<0) {
9233 Error("SetCacheEntryRange","Could not load a tree");
9234 return -1;
9235 }
9236 }
9237 if (GetTree()) {
9238 if (GetTree() != this) {
9239 return GetTree()->SetCacheEntryRange(first, last);
9240 }
9241 } else {
9242 Error("SetCacheEntryRange", "No tree is available. Could not set cache entry range");
9243 return -1;
9244 }
9245
9246 TFile *f = GetCurrentFile();
9247 if (!f) {
9248 Error("SetCacheEntryRange", "No file is available. Could not set cache entry range");
9249 return -1;
9250 }
9251 TTreeCache *tc = GetReadCache(f,true);
9252 if (!tc) {
9253 Error("SetCacheEntryRange", "No cache is available. Could not set entry range");
9254 return -1;
9255 }
9256 tc->SetEntryRange(first,last);
9257 return 0;
9258}
9259
9260////////////////////////////////////////////////////////////////////////////////
9261/// Interface to TTreeCache to set the number of entries for the learning phase
9266}
9267
9268////////////////////////////////////////////////////////////////////////////////
9269/// Enable/Disable circularity for this tree.
9270///
9271/// if maxEntries > 0 a maximum of maxEntries is kept in one buffer/basket
9272/// per branch in memory.
9273/// Note that when this function is called (maxEntries>0) the Tree
9274/// must be empty or having only one basket per branch.
9275/// if maxEntries <= 0 the tree circularity is disabled.
9276///
9277/// #### NOTE 1:
9278/// Circular Trees are interesting in online real time environments
9279/// to store the results of the last maxEntries events.
9280/// #### NOTE 2:
9281/// Calling SetCircular with maxEntries <= 0 is necessary before
9282/// merging circular Trees that have been saved on files.
9283/// #### NOTE 3:
9284/// SetCircular with maxEntries <= 0 is automatically called
9285/// by TChain::Merge
9286/// #### NOTE 4:
9287/// A circular Tree can still be saved in a file. When read back,
9288/// it is still a circular Tree and can be filled again.
9291{
9292 if (maxEntries <= 0) {
9293 // Disable circularity.
9294 fMaxEntries = 1000000000;
9295 fMaxEntries *= 1000;
9297 //in case the Tree was originally created in gROOT, the branch
9298 //compression level was set to -1. If the Tree is now associated to
9299 //a file, reset the compression level to the file compression level
9300 if (fDirectory) {
9303 if (bfile) {
9304 compress = bfile->GetCompressionSettings();
9305 }
9307 for (Int_t i = 0; i < nb; i++) {
9309 branch->SetCompressionSettings(compress);
9310 }
9311 }
9312 } else {
9313 // Enable circularity.
9316 }
9317}
9318
9319////////////////////////////////////////////////////////////////////////////////
9320/// Set the debug level and the debug range.
9321///
9322/// For entries in the debug range, the functions TBranchElement::Fill
9323/// and TBranchElement::GetEntry will print the number of bytes filled
9324/// or read for each branch.
9326void TTree::SetDebug(Int_t level, Long64_t min, Long64_t max)
9327{
9328 fDebug = level;
9329 fDebugMin = min;
9330 fDebugMax = max;
9331}
9332
9333////////////////////////////////////////////////////////////////////////////////
9334/// Update the default value for the branch's fEntryOffsetLen.
9335/// If updateExisting is true, also update all the existing branches.
9336/// If newdefault is less than 10, the new default value will be 10.
9339{
9340 if (newdefault < 10) {
9341 newdefault = 10;
9342 }
9344 if (updateExisting) {
9345 TIter next( GetListOfBranches() );
9346 TBranch *b;
9347 while ( ( b = (TBranch*)next() ) ) {
9348 b->SetEntryOffsetLen( newdefault, true );
9349 }
9350 if (fBranchRef) {
9352 }
9353 }
9354}
9355
9356////////////////////////////////////////////////////////////////////////////////
9357/// Change the tree's directory.
9358///
9359/// Remove reference to this tree from current directory and
9360/// add reference to new directory dir. The dir parameter can
9361/// be 0 in which case the tree does not belong to any directory.
9362///
9365{
9366 if (fDirectory == dir) {
9367 return;
9368 }
9369 if (fDirectory) {
9370 fDirectory->Remove(this);
9371
9372 // Delete or move the file cache if it points to this Tree
9373 TFile *file = fDirectory->GetFile();
9374 MoveReadCache(file,dir);
9375 }
9376 fDirectory = dir;
9377 if (fDirectory) {
9378 fDirectory->Append(this);
9379 }
9380 TFile* file = nullptr;
9381 if (fDirectory) {
9382 file = fDirectory->GetFile();
9383 }
9384 if (fBranchRef) {
9385 fBranchRef->SetFile(file);
9386 }
9387 TBranch* b = nullptr;
9388 TIter next(GetListOfBranches());
9389 while((b = (TBranch*) next())) {
9390 b->SetFile(file);
9391 }
9392}
9393
9394////////////////////////////////////////////////////////////////////////////////
9395/// Change number of entries in the tree.
9396///
9397/// If n >= 0, set number of entries in the tree = n.
9398///
9399/// If n < 0, set number of entries in the tree to match the
9400/// number of entries in each branch. (default for n is -1)
9401///
9402/// This function should be called only when one fills each branch
9403/// independently via TBranch::Fill without calling TTree::Fill.
9404/// Calling TTree::SetEntries() make sense only if the number of entries
9405/// in each branch is identical, a warning is issued otherwise.
9406/// The function returns the number of entries.
9407///
9410{
9411 // case 1 : force number of entries to n
9412 if (n >= 0) {
9413 fEntries = n;
9414 return n;
9415 }
9416
9417 // case 2; compute the number of entries from the number of entries in the branches
9418 TBranch* b(nullptr), *bMin(nullptr), *bMax(nullptr);
9420 Long64_t nMax = 0;
9421 TIter next(GetListOfBranches());
9422 while((b = (TBranch*) next())){
9423 Long64_t n2 = b->GetEntries();
9424 if (!bMin || n2 < nMin) {
9425 nMin = n2;
9426 bMin = b;
9427 }
9428 if (!bMax || n2 > nMax) {
9429 nMax = n2;
9430 bMax = b;
9431 }
9432 }
9433 if (bMin && nMin != nMax) {
9434 Warning("SetEntries", "Tree branches have different numbers of entries, eg %s has %lld entries while %s has %lld entries.",
9435 bMin->GetName(), nMin, bMax->GetName(), nMax);
9436 }
9437 fEntries = nMax;
9438 return fEntries;
9439}
9440
9441////////////////////////////////////////////////////////////////////////////////
9442/// Set an EntryList
9445{
9446 if (fEntryList) {
9447 //check if the previous entry list is owned by the tree
9449 delete fEntryList;
9450 }
9451 }
9452 fEventList = nullptr;
9453 if (!enlist) {
9454 fEntryList = nullptr;
9455 return;
9456 }
9458 fEntryList->SetTree(this);
9459
9460}
9461
9462////////////////////////////////////////////////////////////////////////////////
9463/// This function transfroms the given TEventList into a TEntryList
9464/// The new TEntryList is owned by the TTree and gets deleted when the tree
9465/// is deleted. This TEntryList can be returned by GetEntryList() function.
9468{
9470 if (fEntryList){
9473 fEntryList = nullptr; // Avoid problem with RecursiveRemove.
9474 delete tmp;
9475 } else {
9476 fEntryList = nullptr;
9477 }
9478 }
9479
9480 if (!evlist) {
9481 fEntryList = nullptr;
9482 fEventList = nullptr;
9483 return;
9484 }
9485
9487 char enlistname[100];
9488 snprintf(enlistname,100, "%s_%s", evlist->GetName(), "entrylist");
9489 fEntryList = new TEntryList(enlistname, evlist->GetTitle());
9490 fEntryList->SetDirectory(nullptr); // We own this.
9491 Int_t nsel = evlist->GetN();
9492 fEntryList->SetTree(this);
9494 for (Int_t i=0; i<nsel; i++){
9495 entry = evlist->GetEntry(i);
9497 }
9498 fEntryList->SetReapplyCut(evlist->GetReapplyCut());
9500}
9501
9502////////////////////////////////////////////////////////////////////////////////
9503/// Set number of entries to estimate variable limits.
9504/// If n is -1, the estimate is set to be the current maximum
9505/// for the tree (i.e. GetEntries() + 1)
9506/// If n is less than -1, the behavior is undefined.
9508void TTree::SetEstimate(Long64_t n /* = 1000000 */)
9509{
9510 if (n == 0) {
9511 n = 10000;
9512 } else if (n < 0) {
9513 n = fEntries - n;
9514 }
9515 fEstimate = n;
9516 GetPlayer();
9517 if (fPlayer) {
9519 }
9520}
9521
9522////////////////////////////////////////////////////////////////////////////////
9523/// Provide the end-user with the ability to enable/disable various experimental
9524/// IO features for this TTree.
9525///
9526/// Returns all the newly-set IO settings.
9529{
9530 // Purposely ignore all unsupported bits; TIOFeatures implementation already warned the user about the
9531 // error of their ways; this is just a safety check.
9533
9538
9540 return newSettings;
9541}
9542
9543////////////////////////////////////////////////////////////////////////////////
9544/// Set fFileNumber to number.
9545/// fFileNumber is used by TTree::Fill to set the file name
9546/// for a new file to be created when the current file exceeds fgTreeMaxSize.
9547/// (see TTree::ChangeFile)
9548/// if fFileNumber=10, the new file name will have a suffix "_11",
9549/// ie, fFileNumber is incremented before setting the file name
9551void TTree::SetFileNumber(Int_t number)
9552{
9553 if (fFileNumber < 0) {
9554 Warning("SetFileNumber", "file number must be positive. Set to 0");
9555 fFileNumber = 0;
9556 return;
9557 }
9558 fFileNumber = number;
9559}
9560
9561////////////////////////////////////////////////////////////////////////////////
9562/// Set all the branches in this TTree to be in decomposed object mode
9563/// (also known as MakeClass mode).
9564///
9565/// For MakeClass mode 0, the TTree expects the address where the data is stored
9566/// to be set by either the user or the TTree to the address of a full object
9567/// through the top level branch.
9568/// For MakeClass mode 1, this address is expected to point to a numerical type
9569/// or C-style array (variable or not) of numerical type, representing the
9570/// primitive data members.
9571/// The function's primary purpose is to allow the user to access the data
9572/// directly with numerical type variable rather than having to have the original
9573/// set of classes (or a reproduction thereof).
9574/// In other words, SetMakeClass sets the branch(es) into a
9575/// mode that allow its reading via a set of independent variables
9576/// (see the result of running TTree::MakeClass on your TTree) by changing the
9577/// interpretation of the address passed to SetAddress from being the beginning
9578/// of the object containing the data to being the exact location where the data
9579/// should be loaded. If you have the shared library corresponding to your object,
9580/// it is better if you do
9581/// `MyClass *objp = 0; tree->SetBranchAddress("toplevel",&objp);`, whereas
9582/// if you do not have the shared library but know your branch data type, e.g.
9583/// `Int_t* ptr = new Int_t[10];`, then:
9584/// `tree->SetMakeClass(1); tree->GetBranch("x")->SetAddress(ptr)` is the way to go.
9586void TTree::SetMakeClass(Int_t make)
9587{
9588 fMakeClass = make;
9589
9591 for (Int_t i = 0; i < nb; ++i) {
9593 branch->SetMakeClass(make);
9594 }
9595}
9596
9597////////////////////////////////////////////////////////////////////////////////
9598/// Set the maximum size in bytes of a Tree file (static function).
9599/// The default size is 100000000000LL, ie 100 Gigabytes.
9600///
9601/// In TTree::Fill, when the file has a size > fgMaxTreeSize,
9602/// the function closes the current file and starts writing into
9603/// a new file with a name of the style "file_1.root" if the original
9604/// requested file name was "file.root".
9609}
9610
9611////////////////////////////////////////////////////////////////////////////////
9612/// Change the name of this tree.
9614void TTree::SetName(const char* name)
9615{
9616 if (gPad) {
9617 gPad->Modified();
9618 }
9619 // Trees are named objects in a THashList.
9620 // We must update hashlists if we change the name.
9621 TFile *file = nullptr;
9622 TTreeCache *pf = nullptr;
9623 if (fDirectory) {
9624 fDirectory->Remove(this);
9625 if ((file = GetCurrentFile())) {
9626 pf = GetReadCache(file);
9627 file->SetCacheRead(nullptr,this,TFile::kDoNotDisconnect);
9628 }
9629 }
9630 // This changes our hash value.
9631 fName = name;
9632 if (fDirectory) {
9633 fDirectory->Append(this);
9634 if (pf) {
9636 }
9637 }
9638}
9640void TTree::SetNotify(TObject *obj)
9641{
9642 if (obj && fNotify && dynamic_cast<TNotifyLinkBase *>(fNotify)) {
9643 auto *oldLink = static_cast<TNotifyLinkBase *>(fNotify);
9644 auto *newLink = dynamic_cast<TNotifyLinkBase *>(obj);
9645 if (!newLink) {
9646 Warning("TTree::SetNotify",
9647 "The tree or chain already has a fNotify registered and it is a TNotifyLink, while the new object is "
9648 "not a TNotifyLink. Setting fNotify to the new value will lead to an orphan linked list of "
9649 "TNotifyLinks and it is most likely not intended. If this is the intended goal, please call "
9650 "SetNotify(nullptr) first to silence this warning.");
9651 } else if (newLink->GetNext() != oldLink && oldLink->GetNext() != newLink) {
9652 // If newLink->GetNext() == oldLink then we are prepending the new head, as in TNotifyLink::PrependLink
9653 // If oldLink->GetNext() == newLink then we are removing the head of the list, as in TNotifyLink::RemoveLink
9654 // Otherwise newLink and oldLink are unrelated:
9655 Warning("TTree::SetNotify",
9656 "The tree or chain already has a TNotifyLink registered, and the new TNotifyLink `obj` does not link "
9657 "to it. Setting fNotify to the new value will lead to an orphan linked list of TNotifyLinks and it is "
9658 "most likely not intended. If this is the intended goal, please call SetNotify(nullptr) first to "
9659 "silence this warning.");
9660 }
9661 }
9662
9663 fNotify = obj;
9664}
9665
9666////////////////////////////////////////////////////////////////////////////////
9667/// Change the name and title of this tree.
9669void TTree::SetObject(const char* name, const char* title)
9670{
9671 if (gPad) {
9672 gPad->Modified();
9673 }
9674
9675 // Trees are named objects in a THashList.
9676 // We must update hashlists if we change the name
9677 TFile *file = nullptr;
9678 TTreeCache *pf = nullptr;
9679 if (fDirectory) {
9680 fDirectory->Remove(this);
9681 if ((file = GetCurrentFile())) {
9682 pf = GetReadCache(file);
9683 file->SetCacheRead(nullptr,this,TFile::kDoNotDisconnect);
9684 }
9685 }
9686 // This changes our hash value.
9687 fName = name;
9688 fTitle = title;
9689 if (fDirectory) {
9690 fDirectory->Append(this);
9691 if (pf) {
9693 }
9694 }
9695}
9696
9697////////////////////////////////////////////////////////////////////////////////
9698/// Enable or disable parallel unzipping of Tree buffers.
9701{
9702#ifdef R__USE_IMT
9703 if (GetTree() == nullptr) {
9705 if (!GetTree())
9706 return;
9707 }
9708 if (GetTree() != this) {
9709 GetTree()->SetParallelUnzip(opt, RelSize);
9710 return;
9711 }
9712 TFile* file = GetCurrentFile();
9713 if (!file)
9714 return;
9715
9716 TTreeCache* pf = GetReadCache(file);
9717 if (pf && !( opt ^ (nullptr != dynamic_cast<TTreeCacheUnzip*>(pf)))) {
9718 // done with opt and type are in agreement.
9719 return;
9720 }
9721 delete pf;
9722 auto cacheSize = GetCacheAutoSize(true);
9723 if (opt) {
9724 auto unzip = new TTreeCacheUnzip(this, cacheSize);
9725 unzip->SetUnzipBufferSize( Long64_t(cacheSize * RelSize) );
9726 } else {
9727 pf = new TTreeCache(this, cacheSize);
9728 }
9729#else
9730 (void)opt;
9731 (void)RelSize;
9732#endif
9733}
9734
9735////////////////////////////////////////////////////////////////////////////////
9736/// Set perf stats
9741}
9742
9743////////////////////////////////////////////////////////////////////////////////
9744/// The current TreeIndex is replaced by the new index.
9745/// Note that this function does not delete the previous index.
9746/// This gives the possibility to play with more than one index, e.g.,
9747/// ~~~ {.cpp}
9748/// TVirtualIndex* oldIndex = tree.GetTreeIndex();
9749/// tree.SetTreeIndex(newIndex);
9750/// tree.Draw();
9751/// tree.SetTreeIndex(oldIndex);
9752/// tree.Draw(); etc
9753/// ~~~
9756{
9757 if (fTreeIndex) {
9758 fTreeIndex->SetTree(nullptr);
9759 }
9760 fTreeIndex = index;
9761}
9762
9763////////////////////////////////////////////////////////////////////////////////
9764/// Set tree weight.
9765///
9766/// The weight is used by TTree::Draw to automatically weight each
9767/// selected entry in the resulting histogram.
9768///
9769/// For example the equivalent of:
9770/// ~~~ {.cpp}
9771/// T.Draw("x", "w")
9772/// ~~~
9773/// is:
9774/// ~~~ {.cpp}
9775/// T.SetWeight(w);
9776/// T.Draw("x");
9777/// ~~~
9778/// This function is redefined by TChain::SetWeight. In case of a
9779/// TChain, an option "global" may be specified to set the same weight
9780/// for all trees in the TChain instead of the default behaviour
9781/// using the weights of each tree in the chain (see TChain::SetWeight).
9784{
9785 fWeight = w;
9786}
9787
9788////////////////////////////////////////////////////////////////////////////////
9789/// Print values of all active leaves for entry.
9790///
9791/// - if entry==-1, print current entry (default)
9792/// - if a leaf is an array, a maximum of lenmax elements is printed.
9795{
9796 if (entry != -1) {
9798 if (ret == -2) {
9799 Error("Show()", "Cannot read entry %lld (entry does not exist)", entry);
9800 return;
9801 } else if (ret == -1) {
9802 Error("Show()", "Cannot read entry %lld (I/O error)", entry);
9803 return;
9804 }
9805 ret = GetEntry(entry);
9806 if (ret == -1) {
9807 Error("Show()", "Cannot read entry %lld (I/O error)", entry);
9808 return;
9809 } else if (ret == 0) {
9810 Error("Show()", "Cannot read entry %lld (no data read)", entry);
9811 return;
9812 }
9813 }
9814 printf("======> EVENT:%lld\n", fReadEntry);
9816 Int_t nleaves = leaves->GetEntriesFast();
9817 Int_t ltype;
9818 for (Int_t i = 0; i < nleaves; i++) {
9819 TLeaf* leaf = (TLeaf*) leaves->UncheckedAt(i);
9820 TBranch* branch = leaf->GetBranch();
9821 if (branch->TestBit(kDoNotProcess)) {
9822 continue;
9823 }
9824 Int_t len = leaf->GetLen();
9825 if (len <= 0) {
9826 continue;
9827 }
9829 if (leaf->IsA() == TLeafElement::Class()) {
9830 leaf->PrintValue(lenmax);
9831 continue;
9832 }
9833 if (branch->GetListOfBranches()->GetEntriesFast() > 0) {
9834 continue;
9835 }
9836 ltype = 10;
9837 if (leaf->IsA() == TLeafF::Class()) {
9838 ltype = 5;
9839 }
9840 if (leaf->IsA() == TLeafD::Class()) {
9841 ltype = 5;
9842 }
9843 if (leaf->IsA() == TLeafC::Class()) {
9844 len = 1;
9845 ltype = 5;
9846 };
9847 printf(" %-15s = ", leaf->GetName());
9848 for (Int_t l = 0; l < len; l++) {
9849 leaf->PrintValue(l);
9850 if (l == (len - 1)) {
9851 printf("\n");
9852 continue;
9853 }
9854 printf(", ");
9855 if ((l % ltype) == 0) {
9856 printf("\n ");
9857 }
9858 }
9859 }
9860}
9861
9862////////////////////////////////////////////////////////////////////////////////
9863/// Start the TTreeViewer on this tree.
9864///
9865/// - ww is the width of the canvas in pixels
9866/// - wh is the height of the canvas in pixels
9868void TTree::StartViewer()
9869{
9870 GetPlayer();
9871 if (fPlayer) {
9872 fPlayer->StartViewer(600, 400);
9873 }
9874}
9875
9876////////////////////////////////////////////////////////////////////////////////
9877/// Stop the cache learning phase
9878///
9879/// Returns:
9880/// - 0 learning phase stopped or not active
9881/// - -1 on error
9884{
9885 if (!GetTree()) {
9886 if (LoadTree(0)<0) {
9887 Error("StopCacheLearningPhase","Could not load a tree");
9888 return -1;
9889 }
9890 }
9891 if (GetTree()) {
9892 if (GetTree() != this) {
9893 return GetTree()->StopCacheLearningPhase();
9894 }
9895 } else {
9896 Error("StopCacheLearningPhase", "No tree is available. Could not stop cache learning phase");
9897 return -1;
9898 }
9899
9900 TFile *f = GetCurrentFile();
9901 if (!f) {
9902 Error("StopCacheLearningPhase", "No file is available. Could not stop cache learning phase");
9903 return -1;
9904 }
9905 TTreeCache *tc = GetReadCache(f,true);
9906 if (!tc) {
9907 Error("StopCacheLearningPhase", "No cache is available. Could not stop learning phase");
9908 return -1;
9909 }
9910 tc->StopLearningPhase();
9911 return 0;
9912}
9913
9914////////////////////////////////////////////////////////////////////////////////
9915/// Set the fTree member for all branches and sub branches.
9918{
9919 Int_t nb = branches.GetEntriesFast();
9920 for (Int_t i = 0; i < nb; ++i) {
9921 TBranch* br = (TBranch*) branches.UncheckedAt(i);
9922 br->SetTree(tree);
9923
9924 Int_t writeBasket = br->GetWriteBasket();
9925 for (Int_t j = writeBasket; j >= 0; --j) {
9926 TBasket *bk = (TBasket*)br->GetListOfBaskets()->UncheckedAt(j);
9927 if (bk) {
9928 tree->IncrementTotalBuffers(bk->GetBufferSize());
9929 }
9930 }
9931
9932 tree->RegisterBranchFullName({std::string{br->GetFullName()}, br});
9933
9934 ROOT::Internal::TreeUtils::TBranch__SetTree(tree, *br->GetListOfBranches());
9935 }
9936}
9937
9938////////////////////////////////////////////////////////////////////////////////
9939/// Set the fTree member for all friend elements.
9942{
9943 if (frlist) {
9944 TObjLink *lnk = frlist->FirstLink();
9945 while (lnk) {
9946 TFriendElement *elem = (TFriendElement*)lnk->GetObject();
9947 elem->fParentTree = tree;
9948 lnk = lnk->Next();
9949 }
9950 }
9951}
9952
9953////////////////////////////////////////////////////////////////////////////////
9954/// Stream a class object.
9957{
9958 if (b.IsReading()) {
9959 UInt_t R__s, R__c;
9960 if (fDirectory) {
9961 fDirectory->Remove(this);
9962 //delete the file cache if it points to this Tree
9963 TFile *file = fDirectory->GetFile();
9964 MoveReadCache(file,nullptr);
9965 }
9966 fDirectory = nullptr;
9967 fCacheDoAutoInit = true;
9968 fCacheUserSet = false;
9969 fNamesToBranches.clear();
9970 Version_t R__v = b.ReadVersion(&R__s, &R__c);
9971 if (R__v > 4) {
9972 b.ReadClassBuffer(TTree::Class(), this, R__v, R__s, R__c);
9973
9974 fBranches.SetOwner(true); // True needed only for R__v < 19 and most R__v == 19
9975
9976 if (fBranchRef) fBranchRef->SetTree(this);
9979
9980 if (fTreeIndex) {
9981 fTreeIndex->SetTree(this);
9982 }
9983 if (fIndex.fN) {
9984 Warning("Streamer", "Old style index in this tree is deleted. Rebuild the index via TTree::BuildIndex");
9985 fIndex.Set(0);
9986 fIndexValues.Set(0);
9987 }
9988 if (fEstimate <= 10000) {
9989 fEstimate = 1000000;
9990 }
9991
9992 if (fNClusterRange) {
9993 // The I/O allocated just enough memory to hold the
9994 // current set of ranges.
9996 }
9997
9998 // Throughs calls to `GetCacheAutoSize` or `EnableCache` (for example
9999 // by TTreePlayer::Process, the cache size will be automatically
10000 // determined unless the user explicitly call `SetCacheSize`
10001 fCacheSize = 0;
10002 fCacheUserSet = false;
10003
10005 return;
10006 }
10007 //====process old versions before automatic schema evolution
10008 Stat_t djunk;
10009 Int_t ijunk;
10014 b >> fScanField;
10017 b >> djunk; fEntries = (Long64_t)djunk;
10022 if (fEstimate <= 10000) fEstimate = 1000000;
10024 if (fBranchRef) fBranchRef->SetTree(this);
10028 if (R__v > 1) fIndexValues.Streamer(b);
10029 if (R__v > 2) fIndex.Streamer(b);
10030 if (R__v > 3) {
10032 OldInfoList.Streamer(b);
10033 OldInfoList.Delete();
10034 }
10035 fNClusterRange = 0;
10038 b.CheckByteCount(R__s, R__c, TTree::IsA());
10039 //====end of old versions
10040 } else {
10041 if (fBranchRef) {
10042 fBranchRef->Clear();
10043 }
10045 if (table) TRefTable::SetRefTable(nullptr);
10046
10047 b.WriteClassBuffer(TTree::Class(), this);
10048
10049 if (table) TRefTable::SetRefTable(table);
10050 }
10051}
10052
10053////////////////////////////////////////////////////////////////////////////////
10054/// Unbinned fit of one or more variable(s) from a tree.
10055///
10056/// funcname is a TF1 function.
10057///
10058/// \note see TTree::Draw for explanations of the other parameters.
10059///
10060/// Fit the variable varexp using the function funcname using the
10061/// selection cuts given by selection.
10062///
10063/// The list of fit options is given in parameter option.
10064///
10065/// - option = "Q" Quiet mode (minimum printing)
10066/// - option = "V" Verbose mode (default is between Q and V)
10067/// - option = "E" Perform better Errors estimation using Minos technique
10068/// - option = "M" More. Improve fit results
10069///
10070/// You can specify boundary limits for some or all parameters via
10071/// ~~~ {.cpp}
10072/// func->SetParLimits(p_number, parmin, parmax);
10073/// ~~~
10074/// if parmin>=parmax, the parameter is fixed
10075///
10076/// Note that you are not forced to fix the limits for all parameters.
10077/// For example, if you fit a function with 6 parameters, you can do:
10078/// ~~~ {.cpp}
10079/// func->SetParameters(0,3.1,1.e-6,0.1,-8,100);
10080/// func->SetParLimits(4,-10,-4);
10081/// func->SetParLimits(5, 1,1);
10082/// ~~~
10083/// With this setup:
10084///
10085/// - Parameters 0->3 can vary freely
10086/// - Parameter 4 has boundaries [-10,-4] with initial value -8
10087/// - Parameter 5 is fixed to 100.
10088///
10089/// For the fit to be meaningful, the function must be self-normalized.
10090///
10091/// i.e. It must have the same integral regardless of the parameter
10092/// settings. Otherwise the fit will effectively just maximize the
10093/// area.
10094///
10095/// It is mandatory to have a normalization variable
10096/// which is fixed for the fit. e.g.
10097/// ~~~ {.cpp}
10098/// TF1* f1 = new TF1("f1", "gaus(0)/sqrt(2*3.14159)/[2]", 0, 5);
10099/// f1->SetParameters(1, 3.1, 0.01);
10100/// f1->SetParLimits(0, 1, 1); // fix the normalization parameter to 1
10101/// data->UnbinnedFit("f1", "jpsimass", "jpsipt>3.0");
10102/// ~~~
10103/// 1, 2 and 3 Dimensional fits are supported. See also TTree::Fit
10104///
10105/// Return status:
10106///
10107/// - The function return the status of the fit in the following form
10108/// fitResult = migradResult + 10*minosResult + 100*hesseResult + 1000*improveResult
10109/// - The fitResult is 0 is the fit is OK.
10110/// - The fitResult is negative in case of an error not connected with the fit.
10111/// - The number of entries used in the fit can be obtained via mytree.GetSelectedRows();
10112/// - If the number of selected entries is null the function returns -1
10115{
10116 GetPlayer();
10117 if (fPlayer) {
10119 }
10120 return -1;
10121}
10122
10123////////////////////////////////////////////////////////////////////////////////
10124/// Replace current attributes by current style.
10147}
10148
10149////////////////////////////////////////////////////////////////////////////////
10150/// Write this object to the current directory. For more see TObject::Write
10151/// If option & kFlushBasket, call FlushBasket before writing the tree.
10153Int_t TTree::Write(const char *name, Int_t option, Int_t bufsize) const
10154{
10157 return 0;
10159}
10160
10161////////////////////////////////////////////////////////////////////////////////
10162/// Write this object to the current directory. For more see TObject::Write
10163/// If option & kFlushBasket, call FlushBasket before writing the tree.
10166{
10167 return ((const TTree*)this)->Write(name, option, bufsize);
10168}
10169
10170////////////////////////////////////////////////////////////////////////////////
10171/// \class TTreeFriendLeafIter
10172///
10173/// Iterator on all the leaves in a TTree and its friend
10174
10175
10176////////////////////////////////////////////////////////////////////////////////
10177/// Create a new iterator. By default the iteration direction
10178/// is kIterForward. To go backward use kIterBackward.
10181: fTree(const_cast<TTree*>(tree))
10182, fLeafIter(nullptr)
10183, fTreeIter(nullptr)
10184, fDirection(dir)
10185{
10186}
10187
10188////////////////////////////////////////////////////////////////////////////////
10189/// Copy constructor. Does NOT copy the 'cursor' location!
10192: TIterator(iter)
10193, fTree(iter.fTree)
10194, fLeafIter(nullptr)
10195, fTreeIter(nullptr)
10196, fDirection(iter.fDirection)
10197{
10198}
10199
10200////////////////////////////////////////////////////////////////////////////////
10201/// Overridden assignment operator. Does NOT copy the 'cursor' location!
10204{
10205 if (this != &rhs && rhs.IsA() == TTreeFriendLeafIter::Class()) {
10207 fDirection = rhs1.fDirection;
10208 }
10209 return *this;
10210}
10211
10212////////////////////////////////////////////////////////////////////////////////
10213/// Overridden assignment operator. Does NOT copy the 'cursor' location!
10216{
10217 if (this != &rhs) {
10218 fDirection = rhs.fDirection;
10219 }
10220 return *this;
10221}
10222
10223////////////////////////////////////////////////////////////////////////////////
10224/// Go the next friend element
10227{
10228 if (!fTree) return nullptr;
10229
10230 TObject * next;
10231 TTree * nextTree;
10232
10233 if (!fLeafIter) {
10234 TObjArray *list = fTree->GetListOfLeaves();
10235 if (!list) return nullptr; // Can happen with an empty chain.
10236 fLeafIter = list->MakeIterator(fDirection);
10237 if (!fLeafIter) return nullptr;
10238 }
10239
10240 next = fLeafIter->Next();
10241 if (!next) {
10242 if (!fTreeIter) {
10244 if (!list) return next;
10245 fTreeIter = list->MakeIterator(fDirection);
10246 if (!fTreeIter) return nullptr;
10247 }
10249 ///nextTree = (TTree*)fTreeIter->Next();
10250 if (nextFriend) {
10251 nextTree = const_cast<TTree*>(nextFriend->GetTree());
10252 if (!nextTree) return Next();
10254 fLeafIter = nextTree->GetListOfLeaves()->MakeIterator(fDirection);
10255 if (!fLeafIter) return nullptr;
10256 next = fLeafIter->Next();
10257 }
10258 }
10259 return next;
10260}
10261
10262////////////////////////////////////////////////////////////////////////////////
10263/// Returns the object option stored in the list.
10266{
10267 if (fLeafIter) return fLeafIter->GetOption();
10268 return "";
10269}
10275}
10281}
#define R__unlikely(expr)
Definition RConfig.hxx:568
#define SafeDelete(p)
Definition RConfig.hxx:507
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
double * dst
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
bool Bool_t
Boolean (0=false, 1=true) (bool)
Definition RtypesCore.h:78
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
short Version_t
Class version identifier (short)
Definition RtypesCore.h:80
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:69
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:61
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:72
double Double_t
Double 8 bytes.
Definition RtypesCore.h:74
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
Definition RtypesCore.h:132
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:84
unsigned long long ULong64_t
Portable unsigned long integer 8 bytes.
Definition RtypesCore.h:85
const char Option_t
Option string (const char)
Definition RtypesCore.h:81
const Int_t kDoNotProcess
Definition TBranch.h:56
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
EDataType
Definition TDataType.h:28
@ kNoType_t
Definition TDataType.h:33
@ kFloat_t
Definition TDataType.h:31
@ kULong64_t
Definition TDataType.h:32
@ kInt_t
Definition TDataType.h:30
@ kchar
Definition TDataType.h:31
@ kLong_t
Definition TDataType.h:30
@ kDouble32_t
Definition TDataType.h:31
@ kShort_t
Definition TDataType.h:29
@ kBool_t
Definition TDataType.h:32
@ kBits
Definition TDataType.h:34
@ kULong_t
Definition TDataType.h:30
@ kLong64_t
Definition TDataType.h:32
@ kUShort_t
Definition TDataType.h:29
@ kDouble_t
Definition TDataType.h:31
@ kCharStar
Definition TDataType.h:34
@ kChar_t
Definition TDataType.h:29
@ kUChar_t
Definition TDataType.h:29
@ kCounter
Definition TDataType.h:34
@ kUInt_t
Definition TDataType.h:30
@ kFloat16_t
Definition TDataType.h:33
@ kOther_t
Definition TDataType.h:32
#define gDirectory
Definition TDirectory.h:385
R__EXTERN TEnv * gEnv
Definition TEnv.h:126
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:130
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:208
#define N
static unsigned int total
Option_t Option_t option
Option_t Option_t SetLineWidth
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t cursor
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t SetFillStyle
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t SetLineColor
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t SetFillColor
Option_t Option_t SetMarkerStyle
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void reg
Option_t Option_t style
char name[80]
Definition TGX11.cxx:142
int nentries
R__EXTERN TInterpreter * gCling
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:792
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:417
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2585
R__EXTERN TStyle * gStyle
Definition TStyle.h:442
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
constexpr Int_t kNEntriesResort
Definition TTree.cxx:473
static TBranch * R__FindBranchHelper(TObjArray *list, const char *branchname)
Search in the array for a branch matching the branch name, with the branch possibly expressed as a 'f...
Definition TTree.cxx:4862
static char DataTypeToChar(EDataType datatype)
Definition TTree.cxx:484
void TFriendElement__SetTree(TTree *tree, TList *frlist)
Set the fTree member for all friend elements.
Definition TTree.cxx:9940
bool CheckReshuffling(TTree &mainTree, TTree &friendTree)
Definition TTree.cxx:1266
constexpr Float_t kNEntriesResortInv
Definition TTree.cxx:474
#define R__LOCKGUARD(mutex)
#define gPad
A helper class for managing IMT work during TTree:Fill operations.
const_iterator end() const
TIOFeatures provides the end-user with the ability to change the IO behavior of data written via a TT...
UChar_t GetFeatures() const
bool Set(EIOFeatures bits)
Set a specific IO feature.
This class provides a simple interface to execute the same task multiple times in parallel threads,...
void Streamer(TBuffer &) override
Stream a TArrayD object.
Definition TArrayD.cxx:148
void Set(Int_t n) override
Set size of this array to n doubles.
Definition TArrayD.cxx:105
void Set(Int_t n) override
Set size of this array to n ints.
Definition TArrayI.cxx:104
void Streamer(TBuffer &) override
Stream a TArrayI object.
Definition TArrayI.cxx:147
Int_t fN
Definition TArray.h:38
Fill Area Attributes class.
Definition TAttFill.h:21
virtual void Streamer(TBuffer &)
virtual Color_t GetFillColor() const
Return the fill area color.
Definition TAttFill.h:32
virtual Style_t GetFillStyle() const
Return the fill area style.
Definition TAttFill.h:33
Line Attributes class.
Definition TAttLine.h:21
virtual void Streamer(TBuffer &)
virtual Color_t GetLineColor() const
Return the line color.
Definition TAttLine.h:36
virtual void SetLineStyle(Style_t lstyle)
Set the line style.
Definition TAttLine.h:46
virtual Width_t GetLineWidth() const
Return the line width.
Definition TAttLine.h:38
virtual Style_t GetLineStyle() const
Return the line style.
Definition TAttLine.h:37
Marker Attributes class.
Definition TAttMarker.h:22
virtual Style_t GetMarkerStyle() const
Return the marker style.
Definition TAttMarker.h:35
virtual Color_t GetMarkerColor() const
Return the marker color.
Definition TAttMarker.h:34
virtual Size_t GetMarkerSize() const
Return the marker size.
Definition TAttMarker.h:36
virtual void SetMarkerStyle(Style_t mstyle=1)
Set the marker style.
virtual void SetMarkerSize(Size_t msize=1)
Set the marker size.
virtual void Streamer(TBuffer &)
virtual void SetMarkerColor(Color_t mcolor=1)
Set the marker color.
Each class (see TClass) has a linked list of its base class(es).
Definition TBaseClass.h:33
ROOT::ESTLType IsSTLContainer()
Return which type (if any) of STL container the data member is.
Manages buffers for branches of a Tree.
Definition TBasket.h:34
A Branch for the case of an array of clone objects.
A Branch for the case of an object.
static TClass * Class()
A Branch for the case of an object.
A branch containing and managing a TRefTable for TRef autoloading.
Definition TBranchRef.h:34
void Reset(Option_t *option="") override
void Print(Option_t *option="") const override
Print the TRefTable branch.
void Clear(Option_t *option="") override
Clear entries in the TRefTable.
void ResetAfterMerge(TFileMergeInfo *) override
Reset a Branch after a Merge operation (drop data but keep customizations) TRefTable is cleared.
A Branch handling STL collection of pointers (vectors, lists, queues, sets and multisets) while stori...
Definition TBranchSTL.h:22
A TTree is a list of TBranches.
Definition TBranch.h:93
static TClass * Class()
TObjArray * GetListOfBranches()
Definition TBranch.h:255
virtual void SetTree(TTree *tree)
Definition TBranch.h:296
static void ResetCount()
Static function resetting fgCount.
Definition TBranch.cxx:2672
virtual void SetFile(TFile *file=nullptr)
Set file where this branch writes/reads its buffers.
Definition TBranch.cxx:2874
virtual void SetEntryOffsetLen(Int_t len, bool updateSubBranches=false)
Update the default value for the branch's fEntryOffsetLen if and only if it was already non zero (and...
Definition TBranch.cxx:2832
virtual void UpdateFile()
Refresh the value of fDirectory (i.e.
Definition TBranch.cxx:3323
Int_t Fill()
Definition TBranch.h:214
Using a TBrowser one can browse all ROOT objects.
Definition TBrowser.h:37
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket.
Definition TBufferFile.h:47
Buffer base class used for serializing objects.
Definition TBuffer.h:43
void Expand(Int_t newsize, Bool_t copy=kTRUE)
Expand (or shrink) the I/O buffer to newsize bytes.
Definition TBuffer.cxx:222
Int_t BufferSize() const
Definition TBuffer.h:98
@ kWrite
Definition TBuffer.h:73
@ kRead
Definition TBuffer.h:73
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
Bool_t CanSplit() const
Return true if the data member of this TClass can be saved separately.
Definition TClass.cxx:2331
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition TClass.cxx:2912
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition TClass.cxx:5111
Bool_t HasDataMemberInfo() const
Definition TClass.h:420
Bool_t HasCustomStreamerMember() const
The class has a Streamer method and it is implemented by the user or an older (not StreamerInfo based...
Definition TClass.h:524
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition TClass.cxx:5533
void BuildRealData(void *pointer=nullptr, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition TClass.cxx:2043
TList * GetListOfRealData() const
Definition TClass.h:468
Bool_t CanIgnoreTObjectStreamer()
Definition TClass.h:406
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition TClass.cxx:3699
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:6106
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0, Bool_t isTransient=kFALSE) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist,...
Definition TClass.cxx:4720
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4995
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2923
Version_t GetClassVersion() const
Definition TClass.h:434
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2999
An array of clone (identical) objects.
static TClass * Class()
Collection abstract base class.
Definition TCollection.h:65
static TClass * Class()
void SetName(const char *name)
const char * GetName() const override
Return name of this collection.
virtual Int_t GetEntries() const
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
void Browse(TBrowser *b) override
Browse this collection (called by TBrowser).
A specialized string object used for TTree selections.
Definition TCut.h:25
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
Bool_t IsPersistent() const
Definition TDataMember.h:91
Bool_t IsBasic() const
Return true if data member is a basic type, e.g. char, int, long...
Bool_t IsaPointer() const
Return true if data member is a pointer.
TDataType * GetDataType() const
Definition TDataMember.h:76
Longptr_t GetOffset() const
Get offset from "this".
const char * GetTypeName() const
Get the decayed type name of this data member, removing const and volatile qualifiers,...
const char * GetArrayIndex() const
If the data member is pointer and has a valid array size in its comments GetArrayIndex returns a stri...
const char * GetFullTypeName() const
Get the concrete type name of this data member, including const and volatile qualifiers.
Basic data type descriptor (datatype information is obtained from CINT).
Definition TDataType.h:44
Int_t GetType() const
Definition TDataType.h:71
TString GetTypeName()
Get basic type of typedef, e,g.: "class TDirectory*" -> "TDirectory".
Bool_t cd() override
Change current directory to "this" directory.
Bool_t IsWritable() const override
TDirectory::TContext keeps track and restore the current directory.
Definition TDirectory.h:89
Describe directory structure in memory.
Definition TDirectory.h:45
virtual TList * GetList() const
Definition TDirectory.h:223
virtual void Append(TObject *obj, Bool_t replace=kFALSE)
Append object to this directory.
virtual Int_t WriteTObject(const TObject *obj, const char *name=nullptr, Option_t *="", Int_t=0)
Write an object with proper type checking.
virtual TFile * GetFile() const
Definition TDirectory.h:221
virtual Int_t ReadKeys(Bool_t=kTRUE)
Definition TDirectory.h:249
virtual Bool_t IsWritable() const
Definition TDirectory.h:238
virtual TKey * GetKey(const char *, Short_t=9999) const
Definition TDirectory.h:222
virtual Int_t ReadTObject(TObject *, const char *)
Definition TDirectory.h:250
virtual void SaveSelf(Bool_t=kFALSE)
Definition TDirectory.h:256
virtual TList * GetListOfKeys() const
Definition TDirectory.h:224
void GetObject(const char *namecycle, T *&ptr)
Get an object with proper type checking.
Definition TDirectory.h:213
virtual TObject * Remove(TObject *)
Remove an object from the in-memory list.
Streamer around an arbitrary STL like container, which implements basic container functionality.
A List of entry numbers in a TTree or TChain.
Definition TEntryList.h:26
virtual bool Enter(Long64_t entry, TTree *tree=nullptr)
Add entry #entry to the list.
virtual void SetTree(const TTree *tree)
If a list for a tree with such name and filename exists, sets it as the current sublist If not,...
virtual TDirectory * GetDirectory() const
Definition TEntryList.h:77
virtual void SetReapplyCut(bool apply=false)
Definition TEntryList.h:108
virtual void SetDirectory(TDirectory *dir)
Add reference to directory dir. dir can be 0.
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 Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition TEnv.cxx:511
<div class="legacybox"><h2>Legacy Code</h2> TEventList is a legacy interface: there will be no bug fi...
Definition TEventList.h:31
A cache when reading files over the network.
virtual Int_t GetBufferSize() const
A class to pass information from the TFileMerger to the objects being merged.
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:130
virtual void SetCacheRead(TFileCacheRead *cache, TObject *tree=nullptr, ECacheAction action=kDisconnect)
Set a pointer to the read cache.
Definition TFile.cxx:2431
Int_t GetCompressionSettings() const
Definition TFile.h:489
Int_t GetCompressionLevel() const
Definition TFile.h:483
virtual void WriteStreamerInfo()
Write the list of TStreamerInfo as a single object in this file The class Streamer description for al...
Definition TFile.cxx:3504
@ kDoNotDisconnect
Definition TFile.h:148
virtual void Flush()
Synchronize a file's in-memory and on-disk states.
Definition TFile.cxx:1165
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition TFile.cxx:3801
virtual void WriteHeader()
Write File Header.
Definition TFile.cxx:2681
@ kCancelTTreeChangeRequest
Definition TFile.h:275
TFileCacheRead * GetCacheRead(const TObject *tree=nullptr) const
Return a pointer to the current read cache.
Definition TFile.cxx:1286
<div class="legacybox"><h2>Legacy Code</h2> TFolder is a legacy interface: there will be no bug fixes...
Definition TFolder.h:30
static TClass * Class()
A TFriendElement TF describes a TTree object TF in a file.
virtual TTree * GetTree()
Return pointer to friend TTree.
virtual Int_t DeleteGlobal(void *obj)=0
void Reset()
Iterator abstract base class.
Definition TIterator.h:30
virtual TObject * Next()=0
virtual Option_t * GetOption() const
Definition TIterator.h:40
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
void Delete(Option_t *option="") override
Delete an object from the file.
Definition TKey.cxx:584
Int_t GetKeylen() const
Definition TKey.h:86
Int_t GetNbytes() const
Definition TKey.h:88
virtual const char * GetClassName() const
Definition TKey.h:77
static TClass * Class()
static TClass * Class()
static TClass * Class()
static TClass * Class()
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition TLeaf.h:57
virtual Int_t GetLenType() const
Definition TLeaf.h:136
virtual Int_t GetLen() const
Return the number of effective elements of this leaf, for the current entry.
Definition TLeaf.cxx:405
@ kNewValue
Set if we own the value buffer and so must delete it ourselves.
Definition TLeaf.h:99
@ kIndirectAddress
Data member is a pointer to an array of basic types.
Definition TLeaf.h:98
virtual Int_t GetOffset() const
Definition TLeaf.h:140
A doubly linked list.
Definition TList.h:38
void Clear(Option_t *option="") override
Remove all objects from the list.
Definition TList.cxx:532
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
Definition TList.cxx:708
void RecursiveRemove(TObject *obj) override
Remove object from this collection and recursively remove the object from all other objects (and coll...
Definition TList.cxx:894
void Add(TObject *obj) override
Definition TList.h:81
TObject * Remove(TObject *obj) override
Remove object from the list.
Definition TList.cxx:952
virtual TObjLink * FirstLink() const
Definition TList.h:107
void Delete(Option_t *option="") override
Remove all objects from the list AND delete all heap based objects.
Definition TList.cxx:600
TObject * At(Int_t idx) const override
Returns the object at position idx. Returns 0 if idx is out of range.
Definition TList.cxx:487
A TMemFile is like a normal TFile except that it reads and writes only from memory.
Definition TMemFile.h:27
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
void Streamer(TBuffer &) override
Stream an object of class TObject.
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
TString fTitle
Definition TNamed.h:33
TNamed()
Definition TNamed.h:38
TString fName
Definition TNamed.h:32
See TNotifyLink.
Definition TNotifyLink.h:47
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
Int_t GetEntriesUnsafe() const
Return the number of objects in array (i.e.
void Clear(Option_t *option="") override
Remove all objects from the array.
void Streamer(TBuffer &) override
Stream all objects in the array to or from the I/O buffer.
Int_t GetEntries() const override
Return the number of objects in array (i.e.
void Delete(Option_t *option="") override
Remove all objects from the array AND delete all heap based objects.
TObject * At(Int_t idx) const override
Definition TObjArray.h:170
TObject * UncheckedAt(Int_t i) const
Definition TObjArray.h:90
Bool_t IsEmpty() const override
Definition TObjArray.h:65
TObject * FindObject(const char *name) const override
Find an object in this collection using its name.
void Add(TObject *obj) override
Definition TObjArray.h:68
Mother of all ROOT objects.
Definition TObject.h:42
virtual Bool_t Notify()
This method must be overridden to handle object notification (the base implementation is no-op).
Definition TObject.cxx:617
@ kBitMask
Definition TObject.h:95
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:461
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:204
@ kOnlyPrepStep
Used to request that the class specific implementation of TObject::Write just prepare the objects to ...
Definition TObject.h:115
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:226
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1082
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition TObject.h:161
virtual Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0)
Write this object to the current directory.
Definition TObject.cxx:987
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:886
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:548
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1096
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1124
virtual TClass * IsA() const
Definition TObject.h:248
void ResetBit(UInt_t f)
Definition TObject.h:203
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:71
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition TObject.h:73
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1070
Principal Components Analysis (PCA)
Definition TPrincipal.h:21
The TRealData class manages the effective list of all data members for a given class.
Definition TRealData.h:30
A TRefTable maintains the association between a referenced object and the parent object supporting th...
Definition TRefTable.h:35
static void SetRefTable(TRefTable *table)
Static function setting the current TRefTable.
static TRefTable * GetRefTable()
Static function returning the current TRefTable.
Regular expression class.
Definition TRegexp.h:31
A TSelector object is used by the TTree::Draw, TTree::Scan, TTree::Process to navigate in a TTree and...
Definition TSelector.h:31
static void * ReAlloc(void *vp, size_t size, size_t oldsize)
Reallocate (i.e.
Definition TStorage.cxx:182
Describes a persistent version of a class.
Basic string class.
Definition TString.h:137
Ssiz_t Length() const
Definition TString.h:426
void ToLower()
Change string to lower-case.
Definition TString.cxx:1190
static constexpr Ssiz_t kNPOS
Definition TString.h:285
Double_t Atof() const
Return floating-point value contained in string.
Definition TString.cxx:2135
const char * Data() const
Definition TString.h:385
Bool_t EqualTo(const char *cs, ECaseCompare cmp=kExact) const
Definition TString.h:655
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:714
@ kLeading
Definition TString.h:283
@ kTrailing
Definition TString.h:283
@ kIgnoreCase
Definition TString.h:284
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2460
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2438
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:642
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:661
void SetHistFillColor(Color_t color=1)
Definition TStyle.h:383
Color_t GetHistLineColor() const
Definition TStyle.h:235
Bool_t IsReading() const
Definition TStyle.h:300
void SetHistLineStyle(Style_t styl=0)
Definition TStyle.h:386
Style_t GetHistFillStyle() const
Definition TStyle.h:236
Color_t GetHistFillColor() const
Definition TStyle.h:234
void SetHistLineColor(Color_t color=1)
Definition TStyle.h:384
Style_t GetHistLineStyle() const
Definition TStyle.h:237
void SetHistFillStyle(Style_t styl=0)
Definition TStyle.h:385
Width_t GetHistLineWidth() const
Definition TStyle.h:238
void SetHistLineWidth(Width_t width=1)
Definition TStyle.h:387
A zero length substring is legal.
Definition TString.h:83
virtual const char * Getenv(const char *env)
Get environment variable.
Definition TSystem.cxx:1680
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
Definition TSystem.cxx:1311
A TTreeCache which exploits parallelized decompression of its own content.
static bool IsParallelUnzip()
Static function that tells wether the multithreading unzipping is activated.
A cache to speed-up the reading of ROOT datasets.
Definition TTreeCache.h:32
static void SetLearnEntries(Int_t n=10)
Static function to set the number of entries to be used in learning mode The default value for n is 1...
Class implementing or helping the various TTree cloning method.
Definition TTreeCloner.h:31
Iterator on all the leaves in a TTree and its friend.
Definition TTree.h:776
TTree * fTree
tree being iterated
Definition TTree.h:779
TIterator & operator=(const TIterator &rhs) override
Overridden assignment operator. Does NOT copy the 'cursor' location!
Definition TTree.cxx:10202
TObject * Next() override
Go the next friend element.
Definition TTree.cxx:10225
TIterator * fLeafIter
current leaf sub-iterator.
Definition TTree.h:780
Option_t * GetOption() const override
Returns the object option stored in the list.
Definition TTree.cxx:10264
TIterator * fTreeIter
current tree sub-iterator.
Definition TTree.h:781
bool fDirection
iteration direction
Definition TTree.h:782
static TClass * Class()
Helper class to iterate over cluster of baskets.
Definition TTree.h:322
Long64_t GetEstimatedClusterSize()
Estimate the cluster size.
Definition TTree.cxx:637
Long64_t Previous()
Move on to the previous cluster and return the starting entry of this previous cluster.
Definition TTree.cxx:720
Long64_t Next()
Move on to the next cluster and return the starting entry of this next cluster.
Definition TTree.cxx:676
Long64_t GetNextEntry()
Definition TTree.h:359
TClusterIterator(TTree *tree, Long64_t firstEntry)
Regular constructor.
Definition TTree.cxx:586
Helper class to prevent infinite recursion in the usage of TTree Friends.
Definition TTree.h:229
TFriendLock & operator=(const TFriendLock &)
Assignment operator.
Definition TTree.cxx:552
TFriendLock(const TFriendLock &)
Copy constructor.
Definition TTree.cxx:542
UInt_t fMethodBit
Definition TTree.h:233
TTree * fTree
Definition TTree.h:232
~TFriendLock()
Restore the state of tree the same as before we set the lock.
Definition TTree.cxx:565
A TTree represents a columnar dataset.
Definition TTree.h:89
virtual Int_t Fill()
Fill all branches.
Definition TTree.cxx:4674
virtual TFriendElement * AddFriend(const char *treename, const char *filename="")
Add a TFriendElement to the list of friends.
Definition TTree.cxx:1358
double ComputeExtremum(const char *columname, double errVal, bool(*cmp)(double, double))
Computes the extremum (minimum or maximum) for the input column name.
Definition TTree.cxx:6456
TBranchRef * fBranchRef
Branch supporting the TRefTable (if any)
Definition TTree.h:146
TStreamerInfo * BuildStreamerInfo(TClass *cl, void *pointer=nullptr, bool canOptimize=true)
Build StreamerInfo for class cl.
Definition TTree.cxx:2681
TBranch * GetBranchFromFriends(const char *branchName)
Returns a pointer to the branch with the given name, if it can be found in the list of friends of thi...
Definition TTree.cxx:5405
virtual Int_t SetBranchAddress(const char *bname, void *add, TBranch **ptr, TClass *realClass, EDataType datatype, bool isptr, bool suppressMissingBranchError)
Definition TTree.cxx:8818
virtual TBranch * FindBranch(const char *name)
Return the branch that correspond to the path 'branchname', which can include the name of the tree or...
Definition TTree.cxx:4969
virtual void SetBranchStatus(const char *bname, bool status=true, UInt_t *found=nullptr)
Set branch status to Process or DoNotProcess.
Definition TTree.cxx:8922
bool EnableCache()
Enable the TTreeCache unless explicitly disabled for this TTree by a prior call to SetCacheSize(0).
Definition TTree.cxx:2714
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition TTree.cxx:5457
static Int_t GetBranchStyle()
Static function returning the current branch style.
Definition TTree.cxx:5498
TList * fFriends
pointer to list of friend elements
Definition TTree.h:140
bool fIMTEnabled
! true if implicit multi-threading is enabled for this tree
Definition TTree.h:152
virtual bool GetBranchStatus(const char *branchname) const
Return status of branch with name branchname.
Definition TTree.cxx:5483
@ kSplitCollectionOfPointers
Definition TTree.h:318
UInt_t fFriendLockStatus
! Record which method is locking the friend recursion
Definition TTree.h:147
Long64_t fTotBytes
Total number of bytes in all branches before compression.
Definition TTree.h:96
virtual Int_t FlushBaskets(bool create_cluster=true) const
Write to disk all the basket that have not yet been individually written and create an event cluster ...
Definition TTree.cxx:5205
Int_t fMaxClusterRange
! Memory allocated for the cluster range.
Definition TTree.h:106
virtual void Show(Long64_t entry=-1, Int_t lenmax=20)
Print values of all active leaves for entry.
Definition TTree.cxx:9793
TEventList * fEventList
! Pointer to event selection list (if one)
Definition TTree.h:135
virtual Long64_t GetAutoSave() const
Definition TTree.h:503
virtual Int_t StopCacheLearningPhase()
Stop the cache learning phase.
Definition TTree.cxx:9882
virtual Int_t GetEntry(Long64_t entry, Int_t getall=0)
Read all branches of entry and return total number of bytes read.
Definition TTree.cxx:5745
std::vector< std::pair< Long64_t, TBranch * > > fSortedBranches
! Branches to be processed in parallel when IMT is on, sorted by average task time
Definition TTree.h:154
virtual void SetCircular(Long64_t maxEntries)
Enable/Disable circularity for this tree.
Definition TTree.cxx:9289
Long64_t fSavedBytes
Number of autosaved bytes.
Definition TTree.h:98
virtual Int_t AddBranchToCache(const char *bname, bool subbranches=false)
Add branch with name bname to the Tree cache.
Definition TTree.cxx:1085
Long64_t GetMedianClusterSize()
Estimate the median cluster size for the TTree.
Definition TTree.cxx:8647
virtual TClusterIterator GetClusterIterator(Long64_t firstentry)
Return an iterator over the cluster of baskets starting at firstentry.
Definition TTree.cxx:5570
virtual void ResetBranchAddress(TBranch *)
Tell a branch to set its address to zero.
Definition TTree.cxx:8401
bool fCacheUserSet
! true if the cache setting was explicitly given by user
Definition TTree.h:151
char GetNewlineValue(std::istream &inputStream)
Determine which newline this file is using.
Definition TTree.cxx:7924
TIOFeatures fIOFeatures
IO features to define for newly-written baskets and branches.
Definition TTree.h:124
virtual Long64_t GetEntryNumberWithIndex(Long64_t major, Long64_t minor=0) const
Return entry number corresponding to major and minor number.
Definition TTree.cxx:6017
Long64_t fDebugMin
! First entry number to debug
Definition TTree.h:122
virtual Long64_t SetEntries(Long64_t n=-1)
Change number of entries in the tree.
Definition TTree.cxx:9408
virtual TObjArray * GetListOfLeaves()
Definition TTree.h:584
TLeaf * SearchLeafInListOfLeaves(const char *branchName, const char *leafName)
Definition TTree.cxx:6225
virtual TBranch * BranchOld(const char *name, const char *classname, void *addobj, Int_t bufsize=32000, Int_t splitlevel=1)
Create a new TTree BranchObject.
Definition TTree.cxx:2103
virtual Int_t GetEntryWithIndex(Long64_t major, Long64_t minor=0)
Read entry corresponding to major and minor number.
Definition TTree.cxx:6035
Long64_t GetCacheAutoSize(bool withDefault=false)
Used for automatic sizing of the cache.
Definition TTree.cxx:5510
virtual TBranch * BranchRef()
Build the optional branch supporting the TRefTable.
Definition TTree.cxx:2357
TFile * GetCurrentFile() const
Return pointer to the current file.
Definition TTree.cxx:5582
TList * fAliases
List of aliases for expressions based on the tree branches.
Definition TTree.h:134
virtual TTree * CopyTree(const char *selection, Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Copy a tree with selection.
Definition TTree.cxx:3758
virtual Int_t DropBranchFromCache(const char *bname, bool subbranches=false)
Remove the branch with name 'bname' from the Tree cache.
Definition TTree.cxx:1168
virtual Int_t Fit(const char *funcname, const char *varexp, const char *selection="", Option_t *option="", Option_t *goption="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Fit a projected item(s) from a tree.
Definition TTree.cxx:5155
Long64_t * fClusterRangeEnd
[fNClusterRange] Last entry of a cluster range.
Definition TTree.h:113
void Streamer(TBuffer &) override
Stream a class object.
Definition TTree.cxx:9955
std::atomic< Long64_t > fIMTZipBytes
! Zip bytes for the IMT flush baskets.
Definition TTree.h:171
void RecursiveRemove(TObject *obj) override
Make sure that obj (which is being deleted or will soon be) is no longer referenced by this TTree.
Definition TTree.cxx:8217
TVirtualTreePlayer * GetPlayer()
Load the TTreePlayer (if not already done).
Definition TTree.cxx:6559
virtual Int_t MakeProxy(const char *classname, const char *macrofilename=nullptr, const char *cutfilename=nullptr, const char *option=nullptr, Int_t maxUnrolling=3)
Generate a skeleton analysis class for this Tree using TBranchProxy.
Definition TTree.cxx:7030
virtual Long64_t ReadStream(std::istream &inputStream, const char *branchDescriptor="", char delimiter=' ')
Create or simply read branches from an input stream.
Definition TTree.cxx:7951
virtual void SetDebug(Int_t level=1, Long64_t min=0, Long64_t max=9999999)
Set the debug level and the debug range.
Definition TTree.cxx:9325
Int_t fScanField
Number of runs before prompting in Scan.
Definition TTree.h:102
void Draw(Option_t *opt) override
Default Draw method for all objects.
Definition TTree.h:486
virtual TTree * GetFriend(const char *) const
Return a pointer to the TTree friend whose name or alias is friendname.
Definition TTree.cxx:6083
virtual void SetNotify(TObject *obj)
Sets the address of the object to be notified when the tree is loaded.
Definition TTree.cxx:9639
virtual Double_t GetMaximum(const char *columname)
Return maximum of column with name columname.
Definition TTree.cxx:6533
virtual Long64_t GetEntryNumberWithBestIndex(Long64_t major, Long64_t minor=0) const
Return entry number corresponding to major and minor number.
Definition TTree.cxx:5997
static void SetMaxTreeSize(Long64_t maxsize=100000000000LL)
Set the maximum size in bytes of a Tree file (static function).
Definition TTree.cxx:9605
void Print(Option_t *option="") const override
Print a summary of the tree contents.
Definition TTree.cxx:7557
virtual Int_t UnbinnedFit(const char *funcname, const char *varexp, const char *selection="", Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Unbinned fit of one or more variable(s) from a tree.
Definition TTree.cxx:10113
Int_t fNClusterRange
Number of Cluster range in addition to the one defined by 'AutoFlush'.
Definition TTree.h:105
virtual void PrintCacheStats(Option_t *option="") const
Print statistics about the TreeCache for this tree.
Definition TTree.cxx:7709
TVirtualTreePlayer * fPlayer
! Pointer to current Tree player
Definition TTree.h:144
virtual TIterator * GetIteratorOnAllLeaves(bool dir=kIterForward)
Creates a new iterator that will go through all the leaves on the tree itself and its friend.
Definition TTree.cxx:6220
virtual void SetMakeClass(Int_t make)
Set all the branches in this TTree to be in decomposed object mode (also known as MakeClass mode).
Definition TTree.cxx:9585
virtual bool InPlaceClone(TDirectory *newdirectory, const char *options="")
Copy the content to a new new file, update this TTree with the new location information and attach th...
Definition TTree.cxx:7350
virtual void IncrementTotalBuffers(Int_t nbytes)
Definition TTree.h:641
TObjArray fBranches
List of Branches.
Definition TTree.h:132
TDirectory * GetDirectory() const
Definition TTree.h:517
bool fCacheDoAutoInit
! true if cache auto creation or resize check is needed
Definition TTree.h:149
TTreeCache * GetReadCache(TFile *file) const
Find and return the TTreeCache registered with the file and which may contain branches for us.
Definition TTree.cxx:6572
Long64_t fEntries
Number of entries.
Definition TTree.h:94
virtual TFile * ChangeFile(TFile *file)
Called by TTree::Fill() when file has reached its maximum fgMaxTreeSize.
Definition TTree.cxx:2778
virtual TEntryList * GetEntryList()
Returns the entry list assigned to this tree.
Definition TTree.cxx:5961
virtual void SetWeight(Double_t w=1, Option_t *option="")
Set tree weight.
Definition TTree.cxx:9782
void InitializeBranchLists(bool checkLeafCount)
Divides the top-level branches into two vectors: (i) branches to be processed sequentially and (ii) b...
Definition TTree.cxx:5888
Long64_t * fClusterSize
[fNClusterRange] Number of entries in each cluster for a given range.
Definition TTree.h:114
Long64_t fFlushedBytes
Number of auto-flushed bytes.
Definition TTree.h:99
virtual void SetPerfStats(TVirtualPerfStats *perf)
Set perf stats.
Definition TTree.cxx:9737
std::atomic< Long64_t > fIMTTotBytes
! Total bytes for the IMT flush baskets
Definition TTree.h:170
virtual void SetCacheLearnEntries(Int_t n=10)
Interface to TTreeCache to set the number of entries for the learning phase.
Definition TTree.cxx:9262
TEntryList * fEntryList
! Pointer to event selection list (if one)
Definition TTree.h:136
TBranch * FindBranchFromFriends(const char *branchName)
Definition TTree.cxx:4925
virtual TVirtualIndex * GetTreeIndex() const
Definition TTree.h:613
TList * fExternalFriends
! List of TFriendsElement pointing to us and need to be notified of LoadTree. Content not owned.
Definition TTree.h:141
virtual Long64_t Merge(TCollection *list, Option_t *option="")
Merge the trees in the TList into this tree.
Definition TTree.cxx:7164
virtual void SetMaxVirtualSize(Long64_t size=0)
Definition TTree.h:725
virtual void DropBaskets()
Remove some baskets from memory.
Definition TTree.cxx:4589
virtual void SetAutoSave(Long64_t autos=-300000000)
In case of a program crash, it will be possible to recover the data in the tree up to the last AutoSa...
Definition TTree.cxx:8692
Long64_t fMaxEntryLoop
Maximum number of entries to process.
Definition TTree.h:108
virtual void SetParallelUnzip(bool opt=true, Float_t RelSize=-1)
Enable or disable parallel unzipping of Tree buffers.
Definition TTree.cxx:9699
virtual void SetDirectory(TDirectory *dir)
Change the tree's directory.
Definition TTree.cxx:9363
void SortBranchesByTime()
Sorts top-level branches by the last average task time recorded per branch.
Definition TTree.cxx:5941
void Delete(Option_t *option="") override
Delete this tree from memory or/and disk.
Definition TTree.cxx:3786
virtual TBranchRef * GetBranchRef() const
Definition TTree.h:505
TLeaf * SearchLeafInListOfFriends(const char *branchName, const char *leafName)
Definition TTree.cxx:6274
virtual Long64_t Process(const char *filename, Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Process this tree executing the TSelector code in the specified filename.
Definition TTree.cxx:7787
virtual TBranch * BranchImpRef(const char *branchname, const char *classname, TClass *ptrClass, void *addobj, Int_t bufsize, Int_t splitlevel)
Same as TTree::Branch but automatic detection of the class name.
Definition TTree.cxx:1661
virtual void SetEventList(TEventList *list)
This function transfroms the given TEventList into a TEntryList The new TEntryList is owned by the TT...
Definition TTree.cxx:9466
void MoveReadCache(TFile *src, TDirectory *dir)
Move a cache from a file to the current file in dir.
Definition TTree.cxx:7321
Long64_t fAutoFlush
Auto-flush tree when fAutoFlush entries written or -fAutoFlush (compressed) bytes produced.
Definition TTree.h:111
Int_t fUpdate
Update frequency for EntryLoop.
Definition TTree.h:103
virtual void ResetAfterMerge(TFileMergeInfo *)
Resets the state of this TTree after a merge (keep the customization but forget the data).
Definition TTree.cxx:8370
virtual Long64_t GetEntries() const
Definition TTree.h:518
virtual void SetEstimate(Long64_t nentries=1000000)
Set number of entries to estimate variable limits.
Definition TTree.cxx:9507
Int_t fTimerInterval
Timer interval in milliseconds.
Definition TTree.h:101
Int_t fDebug
! Debug level
Definition TTree.h:121
Int_t SetCacheSizeAux(bool autocache=true, Long64_t cacheSize=0)
Set the maximum size of the file cache (TTreeCache) in bytes and create it if possible.
Definition TTree.cxx:9108
virtual Long64_t AutoSave(Option_t *option="")
AutoSave tree header every fAutoSave bytes.
Definition TTree.cxx:1526
virtual Long64_t GetEntryNumber(Long64_t entry) const
Return entry number corresponding to entry.
Definition TTree.cxx:5972
virtual TTree * CloneTree(Long64_t nentries=-1, Option_t *option="")
Create a clone of this tree and copy nentries.
Definition TTree.cxx:3172
Int_t fFileNumber
! current file number (if file extensions)
Definition TTree.h:126
virtual TLeaf * GetLeaf(const char *branchname, const char *leafname)
Searches in this tree and any of its friends for a leaf named leafname in branch branchname ,...
Definition TTree.cxx:6325
virtual Long64_t GetZipBytes() const
Definition TTree.h:640
TObjArray fLeaves
Direct pointers to individual branch leaves.
Definition TTree.h:133
virtual void Reset(Option_t *option="")
Reset baskets, buffers and entries count in all branches and leaves.
Definition TTree.cxx:8339
virtual void KeepCircular()
Keep a maximum of fMaxEntries in memory.
Definition TTree.cxx:6669
virtual void SetDefaultEntryOffsetLen(Int_t newdefault, bool updateExisting=false)
Update the default value for the branch's fEntryOffsetLen.
Definition TTree.cxx:9337
virtual void DirectoryAutoAdd(TDirectory *)
Called by TKey and TObject::Clone to automatically add us to a directory when we are read from a file...
Definition TTree.cxx:3858
Long64_t fMaxVirtualSize
Maximum total size of buffers kept in memory.
Definition TTree.h:109
virtual Long64_t GetTotBytes() const
Definition TTree.h:611
virtual Int_t MakeSelector(const char *selector=nullptr, Option_t *option="")
Generate skeleton selector class for this tree.
Definition TTree.cxx:7084
virtual void SetObject(const char *name, const char *title)
Change the name and title of this tree.
Definition TTree.cxx:9668
TVirtualPerfStats * fPerfStats
! pointer to the current perf stats object
Definition TTree.h:142
Double_t fWeight
Tree weight (see TTree::SetWeight)
Definition TTree.h:100
std::vector< TBranch * > fSeqBranches
! Branches to be processed sequentially when IMT is on
Definition TTree.h:155
Long64_t fDebugMax
! Last entry number to debug
Definition TTree.h:123
Int_t fDefaultEntryOffsetLen
Initial Length of fEntryOffset table in the basket buffers.
Definition TTree.h:104
TBranch * GetBranchFromSelf(const char *branchName)
Returns a pointer to the branch with the given name, if it can be found in this tree.
Definition TTree.cxx:5369
TTree()
Default constructor and I/O constructor.
Definition TTree.cxx:763
Long64_t fAutoSave
Autosave tree when fAutoSave entries written or -fAutoSave (compressed) bytes produced.
Definition TTree.h:110
TBranch * Branch(const char *name, T *obj, Int_t bufsize=32000, Int_t splitlevel=99)
Add a new branch, and infer the data type from the type of obj being passed.
Definition TTree.h:405
std::atomic< UInt_t > fAllocationCount
indicates basket should be resized to exact memory usage, but causes significant
Definition TTree.h:162
static TTree * MergeTrees(TList *list, Option_t *option="")
Static function merging the trees in the TList into a new tree.
Definition TTree.cxx:7115
bool MemoryFull(Int_t nbytes)
Check if adding nbytes to memory we are still below MaxVirtualsize.
Definition TTree.cxx:7099
virtual Long64_t GetReadEntry() const
Definition TTree.h:604
virtual TObjArray * GetListOfBranches()
Definition TTree.h:583
Long64_t fZipBytes
Total number of bytes in all branches after compression.
Definition TTree.h:97
virtual TTree * GetTree() const
Definition TTree.h:612
TBuffer * fTransientBuffer
! Pointer to the current transient buffer.
Definition TTree.h:148
virtual void SetEntryList(TEntryList *list, Option_t *opt="")
Set an EntryList.
Definition TTree.cxx:9443
bool Notify() override
Function called when loading a new class library.
Definition TTree.cxx:7371
virtual void AddZipBytes(Int_t zip)
Definition TTree.h:384
virtual Long64_t LoadTree(Long64_t entry)
Set current entry.
Definition TTree.cxx:6727
virtual Long64_t ReadFile(const char *filename, const char *branchDescriptor="", char delimiter=' ')
Create or simply read branches from filename.
Definition TTree.cxx:7900
virtual const char * GetAlias(const char *aliasName) const
Returns the expanded value of the alias. Search in the friends if any.
Definition TTree.cxx:5302
ROOT::TIOFeatures SetIOFeatures(const ROOT::TIOFeatures &)
Provide the end-user with the ability to enable/disable various experimental IO features for this TTr...
Definition TTree.cxx:9527
virtual TBasket * CreateBasket(TBranch *)
Create a basket for this tree and given branch.
Definition TTree.cxx:3770
TList * fUserInfo
pointer to a list of user objects associated to this Tree
Definition TTree.h:143
virtual Double_t GetMinimum(const char *columname)
Return minimum of column with name columname.
Definition TTree.cxx:6551
virtual void RemoveFriend(TTree *)
Remove a friend from the list of friends.
Definition TTree.cxx:8313
virtual Long64_t GetEntriesFast() const
Return a number greater or equal to the total number of entries in the dataset.
Definition TTree.h:560
void Browse(TBrowser *) override
Browse content of the TTree.
Definition TTree.cxx:2638
virtual TList * GetUserInfo()
Return a pointer to the list containing user objects associated to this tree.
Definition TTree.cxx:6610
void RegisterBranchFullName(std::pair< std::string, TBranch * > &&kv)
Definition TTree.h:182
Long64_t fChainOffset
! Offset of 1st entry of this Tree in a TChain
Definition TTree.h:116
@ kOnlyFlushAtCluster
If set, the branch's buffers will grow until an event cluster boundary is hit, guaranteeing a basket ...
Definition TTree.h:308
@ kEntriesReshuffled
If set, signals that this TTree is the output of the processing of another TTree, and the entries are...
Definition TTree.h:313
@ kCircular
Definition TTree.h:304
virtual Long64_t GetEntriesFriend() const
Returns a number corresponding to:
Definition TTree.cxx:5617
virtual TSQLResult * Query(const char *varexp="", const char *selection="", Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Loop over entries and return a TSQLResult object containing entries following selection.
Definition TTree.cxx:7848
virtual TBranch * Bronch(const char *name, const char *classname, void *addobj, Int_t bufsize=32000, Int_t splitlevel=99)
Create a new TTree BranchElement.
Definition TTree.cxx:2433
virtual void SetBasketSize(const char *bname, Int_t buffsize=16000)
Set a branch's basket size.
Definition TTree.cxx:8708
static void SetBranchStyle(Int_t style=1)
Set the current branch style.
Definition TTree.cxx:9053
~TTree() override
Destructor.
Definition TTree.cxx:946
void ImportClusterRanges(TTree *fromtree)
Appends the cluster range information stored in 'fromtree' to this tree, including the value of fAuto...
Definition TTree.cxx:6626
TClass * IsA() const override
Definition TTree.h:765
Long64_t fEstimate
Number of entries to estimate histogram limits.
Definition TTree.h:112
Int_t FlushBasketsImpl() const
Internal implementation of the FlushBaskets algorithm.
Definition TTree.cxx:5222
virtual Long64_t LoadTreeFriend(Long64_t entry, TTree *T)
Load entry on behalf of our master tree, we may use an index.
Definition TTree.cxx:6819
Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0) override
Write this object to the current directory.
Definition TTree.cxx:10164
TVirtualIndex * fTreeIndex
Pointer to the tree Index (if any)
Definition TTree.h:139
void UseCurrentStyle() override
Replace current attributes by current style.
Definition TTree.cxx:10125
virtual Int_t GetTreeNumber() const
Definition TTree.h:614
TObject * fNotify
Object to be notified when loading a Tree.
Definition TTree.h:130
virtual TBranch * BranchImp(const char *branchname, const char *classname, TClass *ptrClass, void *addobj, Int_t bufsize, Int_t splitlevel)
Same as TTree::Branch() with added check that addobj matches className.
Definition TTree.cxx:1580
virtual TList * GetListOfClones()
Definition TTree.h:582
Long64_t fCacheSize
! Maximum size of file buffers
Definition TTree.h:115
TList * fClones
! List of cloned trees which share our addresses
Definition TTree.h:145
std::atomic< Long64_t > fTotalBuffers
! Total number of bytes in branch buffers
Definition TTree.h:118
static TClass * Class()
@ kFindBranch
Definition TTree.h:253
@ kResetBranchAddresses
Definition TTree.h:274
@ kFindLeaf
Definition TTree.h:254
@ kGetEntryWithIndex
Definition TTree.h:258
@ kPrint
Definition TTree.h:268
@ kGetFriend
Definition TTree.h:259
@ kGetBranch
Definition TTree.h:256
@ kSetBranchStatus
Definition TTree.h:273
@ kLoadTree
Definition TTree.h:262
@ kGetEntry
Definition TTree.h:257
@ kGetLeaf
Definition TTree.h:261
@ kRemoveFriend
Definition TTree.h:272
@ kGetFriendAlias
Definition TTree.h:260
@ kGetAlias
Definition TTree.h:255
virtual void SetTreeIndex(TVirtualIndex *index)
The current TreeIndex is replaced by the new index.
Definition TTree.cxx:9754
virtual void OptimizeBaskets(ULong64_t maxMemory=10000000, Float_t minComp=1.1, Option_t *option="")
This function may be called after having filled some entries in a Tree.
Definition TTree.cxx:7395
virtual Long64_t Project(const char *hname, const char *varexp, const char *selection="", Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Make a projection of a tree using selections.
Definition TTree.cxx:7833
virtual Int_t SetCacheEntryRange(Long64_t first, Long64_t last)
interface to TTreeCache to set the cache entry range
Definition TTree.cxx:9228
static Long64_t GetMaxTreeSize()
Static function which returns the tree file size limit in bytes.
Definition TTree.cxx:6541
bool fCacheDoClusterPrefetch
! true if cache is prefetching whole clusters
Definition TTree.h:150
virtual bool SetAlias(const char *aliasName, const char *aliasFormula)
Set a tree variable alias.
Definition TTree.cxx:8491
virtual void CopyAddresses(TTree *, bool undo=false)
Set branch addresses of passed tree equal to ours.
Definition TTree.cxx:3338
virtual Int_t BuildIndex(const char *majorname, const char *minorname="0", bool long64major=false, bool long64minor=false)
Build a Tree Index (default is TTreeIndex).
Definition TTree.cxx:2666
Long64_t fMaxEntries
Maximum number of entries in case of circular buffers.
Definition TTree.h:107
virtual void DropBuffers(Int_t nbytes)
Drop branch buffers to accommodate nbytes below MaxVirtualsize.
Definition TTree.cxx:4602
virtual TList * GetListOfFriends() const
Definition TTree.h:585
virtual void Refresh()
Refresh contents of this tree and its branches from the current status on disk.
Definition TTree.cxx:8252
virtual void SetAutoFlush(Long64_t autof=-30000000)
This function may be called at the start of a program to change the default value for fAutoFlush.
Definition TTree.cxx:8546
static Long64_t fgMaxTreeSize
Maximum size of a file containing a Tree.
Definition TTree.h:165
Long64_t fReadEntry
! Number of the entry being processed
Definition TTree.h:117
TArrayD fIndexValues
Sorted index values.
Definition TTree.h:137
void MarkEventCluster()
Mark the previous event as being at the end of the event cluster.
Definition TTree.cxx:8608
TBranch * FindBranchFromSelf(const char *branchName)
Definition TTree.cxx:4905
UInt_t fNEntriesSinceSorting
! Number of entries processed since the last re-sorting of branches
Definition TTree.h:153
virtual void SetFileNumber(Int_t number=0)
Set fFileNumber to number.
Definition TTree.cxx:9550
virtual TLeaf * FindLeaf(const char *name)
Find first leaf containing searchname.
Definition TTree.cxx:4992
virtual void StartViewer()
Start the TTreeViewer on this tree.
Definition TTree.cxx:9867
Int_t GetMakeClass() const
Definition TTree.h:590
virtual Int_t MakeCode(const char *filename=nullptr)
Generate a skeleton function for this tree.
Definition TTree.cxx:6902
bool fIMTFlush
! True if we are doing a multithreaded flush.
Definition TTree.h:169
TDirectory * fDirectory
! Pointer to directory holding this tree
Definition TTree.h:131
@ kNeedEnableDecomposedObj
Definition TTree.h:296
@ kClassMismatch
Definition TTree.h:289
@ kVoidPtr
Definition TTree.h:294
@ kMatchConversionCollection
Definition TTree.h:292
@ kMissingCompiledCollectionProxy
Definition TTree.h:287
@ kMismatch
Definition TTree.h:288
@ kMatchConversion
Definition TTree.h:291
@ kInternalError
Definition TTree.h:286
@ kMatch
Definition TTree.h:290
@ kMissingBranch
Definition TTree.h:285
@ kMakeClass
Definition TTree.h:293
static Int_t fgBranchStyle
Old/New branch style.
Definition TTree.h:164
virtual void ResetBranchAddresses()
Tell all of our branches to drop their current objects and allocate new ones.
Definition TTree.cxx:8411
Int_t fNfill
! Local for EntryLoop
Definition TTree.h:120
void SetName(const char *name) override
Change the name of this tree.
Definition TTree.cxx:9613
virtual void RegisterExternalFriend(TFriendElement *)
Record a TFriendElement that we need to warn when the chain switches to a new file (typically this is...
Definition TTree.cxx:8293
TArrayI fIndex
Index of sorted values.
Definition TTree.h:138
Int_t SetBranchAddressImp(const char *bname, void *add, TBranch **ptr, TClass *realClass, EDataType datatype, bool isptr)
Definition TTree.cxx:8758
virtual Int_t SetCacheSize(Long64_t cachesize=-1)
Set maximum size of the file cache (TTreeCache) in bytes.
Definition TTree.cxx:9075
void AddClone(TTree *)
Add a cloned tree to our list of trees to be notified whenever we change our branch addresses or when...
Definition TTree.cxx:1245
virtual Int_t CheckBranchAddressType(TBranch *branch, TClass *ptrClass, EDataType datatype, bool ptr)
Check whether or not the address described by the last 3 parameters matches the content of the branch...
Definition TTree.cxx:2900
TBuffer * GetTransientBuffer(Int_t size)
Returns the transient buffer currently used by this TTree for reading/writing baskets.
Definition TTree.cxx:1063
ROOT::TIOFeatures GetIOFeatures() const
Returns the current set of IO settings.
Definition TTree.cxx:6212
virtual Int_t MakeClass(const char *classname=nullptr, Option_t *option="")
Generate a skeleton analysis class for this tree.
Definition TTree.cxx:6869
virtual const char * GetFriendAlias(TTree *) const
If the 'tree' is a friend, this method returns its alias name.
Definition TTree.cxx:6140
virtual void RemoveExternalFriend(TFriendElement *)
Removes external friend.
Definition TTree.cxx:8304
Int_t fPacketSize
! Number of entries in one packet for parallel root
Definition TTree.h:119
virtual TBranch * BranchImpArr(const char *branchname, EDataType datatype, std::size_t N, void *addobj, Int_t bufsize, Int_t splitlevel)
Definition TTree.cxx:1757
virtual Long64_t Scan(const char *varexp="", const char *selection="", Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Loop over tree entries and print entries passing selection.
Definition TTree.cxx:8449
virtual TBranch * BronchExec(const char *name, const char *classname, void *addobj, bool isptrptr, Int_t bufsize, Int_t splitlevel)
Helper function implementing TTree::Bronch and TTree::Branch(const char *name, T &obj);.
Definition TTree.cxx:2441
virtual void AddTotBytes(Int_t tot)
Definition TTree.h:383
virtual Long64_t CopyEntries(TTree *tree, Long64_t nentries=-1, Option_t *option="", bool needCopyAddresses=false)
Copy nentries from given tree to this tree.
Definition TTree.cxx:3573
Int_t fMakeClass
! not zero when processing code generated by MakeClass
Definition TTree.h:125
virtual Int_t LoadBaskets(Long64_t maxmemory=2000000000)
Read in memory all baskets from all branches up to the limit of maxmemory bytes.
Definition TTree.cxx:6705
static constexpr Long64_t kMaxEntries
Used as the max value for any TTree range operation.
Definition TTree.h:281
TPrincipal * Principal(const char *varexp="", const char *selection="", Option_t *option="np", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)
Interface to the Principal Components Analysis class.
Definition TTree.cxx:7538
std::unordered_map< std::string, TBranch * > fNamesToBranches
! maps names to their branches, useful when retrieving branches by name
Definition TTree.h:174
virtual Long64_t GetAutoFlush() const
Definition TTree.h:502
Defines a common interface to inspect/change the contents of an object that represents a collection.
Abstract interface for Tree Index.
virtual Long64_t GetEntryNumberWithIndex(Long64_t major, Long64_t minor) const =0
virtual Long64_t GetEntryNumberFriend(const TTree *)=0
virtual void SetTree(TTree *T)=0
virtual Long64_t GetN() const =0
virtual Long64_t GetEntryNumberWithBestIndex(Long64_t major, Long64_t minor) const =0
Provides the interface for the an internal performance measurement and event tracing.
Abstract base class defining the interface for the plugins that implement Draw, Scan,...
virtual Long64_t Scan(const char *varexp, const char *selection, Option_t *option, Long64_t nentries, Long64_t firstentry)=0
virtual TVirtualIndex * BuildIndex(const TTree *T, const char *majorname, const char *minorname, bool long64major=false, bool long64minor=false)=0
virtual void UpdateFormulaLeaves()=0
virtual Long64_t DrawSelect(const char *varexp, const char *selection, Option_t *option, Long64_t nentries, Long64_t firstentry)=0
virtual Int_t MakeCode(const char *filename)=0
virtual Int_t UnbinnedFit(const char *formula, const char *varexp, const char *selection, Option_t *option, Long64_t nentries, Long64_t firstentry)=0
virtual Long64_t GetEntries(const char *)=0
virtual Int_t MakeProxy(const char *classname, const char *macrofilename=nullptr, const char *cutfilename=nullptr, const char *option=nullptr, Int_t maxUnrolling=3)=0
virtual TSQLResult * Query(const char *varexp, const char *selection, Option_t *option, Long64_t nentries, Long64_t firstentry)=0
virtual TPrincipal * Principal(const char *varexp="", const char *selection="", Option_t *option="np", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)=0
virtual void StartViewer(Int_t ww, Int_t wh)=0
virtual Int_t MakeReader(const char *classname, Option_t *option)=0
virtual TTree * CopyTree(const char *selection, Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)=0
virtual Long64_t Process(const char *filename, Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0)=0
virtual void SetEstimate(Long64_t n)=0
static TVirtualTreePlayer * TreePlayer(TTree *obj)
Static function returning a pointer to a Tree player.
virtual Int_t MakeClass(const char *classname, const char *option)=0
virtual Int_t Fit(const char *formula, const char *varexp, const char *selection, Option_t *option, Option_t *goption, Long64_t nentries, Long64_t firstentry)=0
TLine * line
const Int_t n
Definition legend1.C:16
Special implementation of ROOT::RRangeCast for TCollection, including a check that the cast target ty...
Definition TObject.h:395
TBranch * CallBranchImp(TTree &tree, const char *branchname, TClass *ptrClass, void *addobj, Int_t bufsize=32000, Int_t splitlevel=99)
Definition TTree.cxx:10276
TBranch * CallBranchImpRef(TTree &tree, const char *branchname, TClass *ptrClass, EDataType datatype, void *addobj, Int_t bufsize=32000, Int_t splitlevel=99)
Definition TTree.cxx:10270
void TBranch__SetTree(TTree *tree, TObjArray &branches)
Set the fTree member for all branches and sub branches.
Definition TTree.cxx:9916
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
Definition TROOT.cxx:673
ESTLType
Definition ESTLType.h:28
@ kSTLmap
Definition ESTLType.h:33
@ kSTLmultimap
Definition ESTLType.h:34
void CallRecursiveRemoveIfNeeded(TObject &obj)
call RecursiveRemove for obj if gROOT is valid and obj.TestBit(kMustCleanup) is true.
Definition TROOT.h:406
void ToHumanReadableSize(value_type bytes, Bool_t si, Double_t *coeff, const char **units)
Return the size expressed in 'human readable' format.
EFromHumanReadableSize FromHumanReadableSize(std::string_view str, T &value)
Convert strings like the following into byte counts 5MB, 5 MB, 5M, 3.7GB, 123b, 456kB,...
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:249
Double_t Median(Long64_t n, const T *a, const Double_t *w=nullptr, Long64_t *work=nullptr)
Returns the median of the array a where each entry i has weight w[i] .
Definition TMath.h:1365
Double_t Ceil(Double_t x)
Rounds x upward, returning the smallest integral value that is not less than x.
Definition TMath.h:681
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:197
Long64_t BinarySearch(Long64_t n, const T *array, T value)
Binary search in an array of n values to locate value.
Definition TMathBase.h:329
TCanvas * slash()
Definition slash.C:1
@ kUseGlobal
Use the global compression algorithm.
Definition Compression.h:93
@ kInherit
Some objects use this value to denote that the compression algorithm should be inherited from the par...
Definition Compression.h:91
@ kUseCompiledDefault
Use the compile-time default setting.
Definition Compression.h:53
th1 Draw()
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4