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#include "snprintf.h"
455
456#include "TBranchIMTHelper.h"
457#include "TNotifyLink.h"
458
459#include <chrono>
460#include <cstddef>
461#include <iostream>
462#include <fstream>
463#include <sstream>
464#include <string>
465#include <cstdio>
466#include <climits>
467#include <algorithm>
468#include <set>
469
470#ifdef R__USE_IMT
472#include <thread>
473#endif
475constexpr Int_t kNEntriesResort = 100;
477
478Int_t TTree::fgBranchStyle = 1; // Use new TBranch style with TBranchElement.
479Long64_t TTree::fgMaxTreeSize = 100000000000LL;
480
481
482////////////////////////////////////////////////////////////////////////////////
483////////////////////////////////////////////////////////////////////////////////
484////////////////////////////////////////////////////////////////////////////////
487{
488 // Return the leaflist 'char' for a given datatype.
489
490 switch(datatype) {
491 case kChar_t: return 'B';
492 case kUChar_t: return 'b';
493 case kBool_t: return 'O';
494 case kShort_t: return 'S';
495 case kUShort_t: return 's';
496 case kCounter:
497 case kInt_t: return 'I';
498 case kUInt_t: return 'i';
499 case kDouble_t: return 'D';
500 case kDouble32_t: return 'd';
501 case kFloat_t: return 'F';
502 case kFloat16_t: return 'f';
503 case kLong_t: return 'G';
504 case kULong_t: return 'g';
505 case kchar: return 0; // unsupported
506 case kLong64_t: return 'L';
507 case kULong64_t: return 'l';
508
509 case kCharStar: return 'C';
510 case kBits: return 0; //unsupported
511
512 case kOther_t:
513 case kNoType_t:
514 default:
515 return 0;
516 }
517 return 0;
518}
519
520////////////////////////////////////////////////////////////////////////////////
521/// \class TTree::TFriendLock
522/// Helper class to prevent infinite recursion in the usage of TTree Friends.
523
524////////////////////////////////////////////////////////////////////////////////
525/// Record in tree that it has been used while recursively looks through the friends.
528: fTree(tree)
529{
530 // We could also add some code to acquire an actual
531 // lock to prevent multi-thread issues
533 if (fTree) {
536 } else {
537 fPrevious = false;
538 }
539}
540
541////////////////////////////////////////////////////////////////////////////////
542/// Copy constructor.
545 fTree(tfl.fTree),
546 fMethodBit(tfl.fMethodBit),
547 fPrevious(tfl.fPrevious)
548{
549}
550
551////////////////////////////////////////////////////////////////////////////////
552/// Assignment operator.
555{
556 if(this!=&tfl) {
557 fTree=tfl.fTree;
558 fMethodBit=tfl.fMethodBit;
559 fPrevious=tfl.fPrevious;
560 }
561 return *this;
562}
563
564////////////////////////////////////////////////////////////////////////////////
565/// Restore the state of tree the same as before we set the lock.
568{
569 if (fTree) {
570 if (!fPrevious) {
571 fTree->fFriendLockStatus &= ~(fMethodBit & kBitMask);
572 }
573 }
574}
575
576////////////////////////////////////////////////////////////////////////////////
577/// \class TTree::TClusterIterator
578/// Helper class to iterate over cluster of baskets.
579/// \note In contrast to class TListIter, looping here must NOT be done using
580/// `while (iter())` or `while (iter.Next())` that would lead to an infinite loop, but rather using
581/// `while( (auto clusterStart = iter()) < tree->GetEntries() )`.
582/// \see TTree::GetClusterIterator
583
584////////////////////////////////////////////////////////////////////////////////
585/// Regular constructor.
586/// TTree is not set as const, since we might modify if it is a TChain.
588TTree::TClusterIterator::TClusterIterator(TTree *tree, Long64_t firstEntry) : fTree(tree), fClusterRange(0), fStartEntry(0), fNextEntry(0), fEstimatedSize(-1)
589{
590 if (fTree->fNClusterRange) {
591 // Find the correct cluster range.
592 //
593 // Since fClusterRangeEnd contains the inclusive upper end of the range, we need to search for the
594 // range that was containing the previous entry and add 1 (because BinarySearch consider the values
595 // to be the inclusive start of the bucket).
597
600 if (fClusterRange == 0) {
601 pedestal = 0;
603 } else {
606 }
610 } else {
612 }
613 if (autoflush <= 0) {
615 }
617 } else if ( fTree->GetAutoFlush() <= 0 ) {
618 // Case of old files before November 9 2009 *or* small tree where AutoFlush was never set.
620 } else {
622 }
623 fNextEntry = fStartEntry; // Position correctly for the first call to Next()
624}
625
626////////////////////////////////////////////////////////////////////////////////
627/// Estimate the cluster size.
628///
629/// In almost all cases, this quickly returns the size of the auto-flush
630/// in the TTree.
631///
632/// However, in the case where the cluster size was not fixed (old files and
633/// case where autoflush was explicitly set to zero), we need estimate
634/// a cluster size in relation to the size of the cache.
635///
636/// After this value is calculated once for the TClusterIterator, it is
637/// cached and reused in future calls.
640{
641 auto autoFlush = fTree->GetAutoFlush();
642 if (autoFlush > 0) return autoFlush;
643 if (fEstimatedSize > 0) return fEstimatedSize;
644
645 Long64_t zipBytes = fTree->GetZipBytes();
646 if (zipBytes == 0) {
647 fEstimatedSize = fTree->GetEntries() - 1;
648 if (fEstimatedSize <= 0)
649 fEstimatedSize = 1;
650 } else {
652 Long64_t cacheSize = fTree->GetCacheSize();
653 if (cacheSize == 0) {
654 // Humm ... let's double check on the file.
655 TFile *file = fTree->GetCurrentFile();
656 if (file) {
657 TFileCacheRead *cache = fTree->GetReadCache(file);
658 if (cache) {
659 cacheSize = cache->GetBufferSize();
660 }
661 }
662 }
663 // If neither file nor tree has a cache, use the current default.
664 if (cacheSize <= 0) {
665 cacheSize = 30000000;
666 }
667 clusterEstimate = fTree->GetEntries() * cacheSize / zipBytes;
668 // If there are no entries, then just default to 1.
669 fEstimatedSize = clusterEstimate ? clusterEstimate : 1;
670 }
671 return fEstimatedSize;
672}
673
674////////////////////////////////////////////////////////////////////////////////
675/// Move on to the next cluster and return the starting entry
676/// of this next cluster
679{
680 fStartEntry = fNextEntry;
681 if (fTree->fNClusterRange || fTree->GetAutoFlush() > 0) {
682 if (fClusterRange == fTree->fNClusterRange) {
683 // We are looking at a range which size
684 // is defined by AutoFlush itself and goes to the GetEntries.
685 fNextEntry += GetEstimatedClusterSize();
686 } else {
687 if (fStartEntry > fTree->fClusterRangeEnd[fClusterRange]) {
688 ++fClusterRange;
689 }
690 if (fClusterRange == fTree->fNClusterRange) {
691 // We are looking at the last range which size
692 // is defined by AutoFlush itself and goes to the GetEntries.
693 fNextEntry += GetEstimatedClusterSize();
694 } else {
695 Long64_t clusterSize = fTree->fClusterSize[fClusterRange];
696 if (clusterSize == 0) {
697 clusterSize = GetEstimatedClusterSize();
698 }
699 fNextEntry += clusterSize;
700 if (fNextEntry > fTree->fClusterRangeEnd[fClusterRange]) {
701 // The last cluster of the range was a partial cluster,
702 // so the next cluster starts at the beginning of the
703 // next range.
704 fNextEntry = fTree->fClusterRangeEnd[fClusterRange] + 1;
705 }
706 }
707 }
708 } else {
709 // Case of old files before November 9 2009
710 fNextEntry = fStartEntry + GetEstimatedClusterSize();
711 }
712 if (fNextEntry > fTree->GetEntries()) {
713 fNextEntry = fTree->GetEntries();
714 }
715 return fStartEntry;
716}
717
718////////////////////////////////////////////////////////////////////////////////
719/// Move on to the previous cluster and return the starting entry
720/// of this previous cluster
723{
724 fNextEntry = fStartEntry;
725 if (fTree->fNClusterRange || fTree->GetAutoFlush() > 0) {
726 if (fClusterRange == 0 || fTree->fNClusterRange == 0) {
727 // We are looking at a range which size
728 // is defined by AutoFlush itself.
729 fStartEntry -= GetEstimatedClusterSize();
730 } else {
731 if (fNextEntry <= fTree->fClusterRangeEnd[fClusterRange]) {
732 --fClusterRange;
733 }
734 if (fClusterRange == 0) {
735 // We are looking at the first range.
736 fStartEntry = 0;
737 } else {
738 Long64_t clusterSize = fTree->fClusterSize[fClusterRange];
739 if (clusterSize == 0) {
740 clusterSize = GetEstimatedClusterSize();
741 }
742 fStartEntry -= clusterSize;
743 }
744 }
745 } else {
746 // Case of old files before November 9 2009 or trees that never auto-flushed.
747 fStartEntry = fNextEntry - GetEstimatedClusterSize();
748 }
749 if (fStartEntry < 0) {
750 fStartEntry = 0;
751 }
752 return fStartEntry;
753}
754
755////////////////////////////////////////////////////////////////////////////////
756////////////////////////////////////////////////////////////////////////////////
757////////////////////////////////////////////////////////////////////////////////
758
759////////////////////////////////////////////////////////////////////////////////
760/// Default constructor and I/O constructor.
761///
762/// Note: We do *not* insert ourself into the current directory.
763///
766: TNamed()
767, TAttLine()
768, TAttFill()
769, TAttMarker()
770, fEntries(0)
771, fTotBytes(0)
772, fZipBytes(0)
773, fSavedBytes(0)
774, fFlushedBytes(0)
775, fWeight(1)
777, fScanField(25)
778, fUpdate(0)
782, fMaxEntries(0)
783, fMaxEntryLoop(0)
785, fAutoSave( -300000000)
786, fAutoFlush(-30000000)
787, fEstimate(1000000)
788, fClusterRangeEnd(nullptr)
789, fClusterSize(nullptr)
790, fCacheSize(0)
791, fChainOffset(0)
792, fReadEntry(-1)
793, fTotalBuffers(0)
794, fPacketSize(100)
795, fNfill(0)
796, fDebug(0)
797, fDebugMin(0)
798, fDebugMax(9999999)
799, fMakeClass(0)
800, fFileNumber(0)
801, fNotify(nullptr)
802, fDirectory(nullptr)
803, fBranches()
804, fLeaves()
805, fAliases(nullptr)
806, fEventList(nullptr)
807, fEntryList(nullptr)
808, fIndexValues()
809, fIndex()
810, fTreeIndex(nullptr)
811, fFriends(nullptr)
812, fExternalFriends(nullptr)
813, fPerfStats(nullptr)
814, fUserInfo(nullptr)
815, fPlayer(nullptr)
816, fClones(nullptr)
817, fBranchRef(nullptr)
819, fTransientBuffer(nullptr)
823, fIMTEnabled(ROOT::IsImplicitMTEnabled())
825{
826 fMaxEntries = 1000000000;
827 fMaxEntries *= 1000;
828
829 fMaxEntryLoop = 1000000000;
830 fMaxEntryLoop *= 1000;
831
832 fBranches.SetOwner(true);
833}
834
835////////////////////////////////////////////////////////////////////////////////
836/// Normal tree constructor.
837///
838/// The tree is created in the current directory.
839/// Use the various functions Branch below to add branches to this tree.
840///
841/// If the first character of title is a "/", the function assumes a folder name.
842/// In this case, it creates automatically branches following the folder hierarchy.
843/// splitlevel may be used in this case to control the split level.
845TTree::TTree(const char* name, const char* title, Int_t splitlevel /* = 99 */,
846 TDirectory* dir /* = gDirectory*/)
847: TNamed(name, title)
848, TAttLine()
849, TAttFill()
850, TAttMarker()
851, fEntries(0)
852, fTotBytes(0)
853, fZipBytes(0)
854, fSavedBytes(0)
855, fFlushedBytes(0)
856, fWeight(1)
857, fTimerInterval(0)
858, fScanField(25)
859, fUpdate(0)
860, fDefaultEntryOffsetLen(1000)
861, fNClusterRange(0)
862, fMaxClusterRange(0)
863, fMaxEntries(0)
864, fMaxEntryLoop(0)
865, fMaxVirtualSize(0)
866, fAutoSave( -300000000)
867, fAutoFlush(-30000000)
868, fEstimate(1000000)
869, fClusterRangeEnd(nullptr)
870, fClusterSize(nullptr)
871, fCacheSize(0)
872, fChainOffset(0)
873, fReadEntry(-1)
874, fTotalBuffers(0)
875, fPacketSize(100)
876, fNfill(0)
877, fDebug(0)
878, fDebugMin(0)
879, fDebugMax(9999999)
880, fMakeClass(0)
881, fFileNumber(0)
882, fNotify(nullptr)
883, fDirectory(dir)
884, fBranches()
885, fLeaves()
886, fAliases(nullptr)
887, fEventList(nullptr)
888, fEntryList(nullptr)
889, fIndexValues()
890, fIndex()
891, fTreeIndex(nullptr)
892, fFriends(nullptr)
893, fExternalFriends(nullptr)
894, fPerfStats(nullptr)
895, fUserInfo(nullptr)
896, fPlayer(nullptr)
897, fClones(nullptr)
898, fBranchRef(nullptr)
899, fFriendLockStatus(0)
900, fTransientBuffer(nullptr)
901, fCacheDoAutoInit(true)
902, fCacheDoClusterPrefetch(false)
903, fCacheUserSet(false)
904, fIMTEnabled(ROOT::IsImplicitMTEnabled())
905, fNEntriesSinceSorting(0)
906{
907 // TAttLine state.
911
912 // TAttFill state.
915
916 // TAttMarkerState.
920
921 fMaxEntries = 1000000000;
922 fMaxEntries *= 1000;
923
924 fMaxEntryLoop = 1000000000;
925 fMaxEntryLoop *= 1000;
926
927 // Insert ourself into the current directory.
928 // FIXME: This is very annoying behaviour, we should
929 // be able to choose to not do this like we
930 // can with a histogram.
931 if (fDirectory) fDirectory->Append(this);
932
933 fBranches.SetOwner(true);
934
935 // If title starts with "/" and is a valid folder name, a superbranch
936 // is created.
937 // FIXME: Why?
938 if (strlen(title) > 2) {
939 if (title[0] == '/') {
940 Branch(title+1,32000,splitlevel);
941 }
942 }
943}
944
945////////////////////////////////////////////////////////////////////////////////
946/// Destructor.
949{
950 if (auto link = dynamic_cast<TNotifyLinkBase*>(fNotify)) {
951 link->Clear();
952 }
953 if (fAllocationCount && (gDebug > 0)) {
954 Info("TTree::~TTree", "For tree %s, allocation count is %u.", GetName(), fAllocationCount.load());
955#ifdef R__TRACK_BASKET_ALLOC_TIME
956 Info("TTree::~TTree", "For tree %s, allocation time is %lluus.", GetName(), fAllocationTime.load());
957#endif
958 }
959
960 if (fDirectory) {
961 // We are in a directory, which may possibly be a file.
962 if (fDirectory->GetList()) {
963 // Remove us from the directory listing.
964 fDirectory->Remove(this);
965 }
966 //delete the file cache if it points to this Tree
967 TFile *file = fDirectory->GetFile();
968 MoveReadCache(file,nullptr);
969 }
970
971 // Remove the TTree from any list (linked to to the list of Cleanups) to avoid the unnecessary call to
972 // this RecursiveRemove while we delete our content.
974 ResetBit(kMustCleanup); // Don't redo it.
975
976 // We don't own the leaves in fLeaves, the branches do.
977 fLeaves.Clear();
978 // I'm ready to destroy any objects allocated by
979 // SetAddress() by my branches. If I have clones,
980 // tell them to zero their pointers to this shared
981 // memory.
982 if (fClones && fClones->GetEntries()) {
983 // I have clones.
984 // I am about to delete the objects created by
985 // SetAddress() which we are sharing, so tell
986 // the clones to release their pointers to them.
987 for (TObjLink* lnk = fClones->FirstLink(); lnk; lnk = lnk->Next()) {
988 TTree* clone = (TTree*) lnk->GetObject();
989 // clone->ResetBranchAddresses();
990
991 // Reset only the branch we have set the address of.
992 CopyAddresses(clone,true);
993 }
994 }
995 // Get rid of our branches, note that this will also release
996 // any memory allocated by TBranchElement::SetAddress().
998
999 // The TBranch destructor is using fDirectory to detect whether it
1000 // owns the TFile that contains its data (See TBranch::~TBranch)
1001 fDirectory = nullptr;
1002
1003 // FIXME: We must consider what to do with the reset of these if we are a clone.
1004 delete fPlayer;
1005 fPlayer = nullptr;
1006 if (fExternalFriends) {
1007 using namespace ROOT::Detail;
1009 fetree->Reset();
1010 fExternalFriends->Clear("nodelete");
1012 }
1013 if (fFriends) {
1014 fFriends->Delete();
1015 delete fFriends;
1016 fFriends = nullptr;
1017 }
1018 if (fAliases) {
1019 fAliases->Delete();
1020 delete fAliases;
1021 fAliases = nullptr;
1022 }
1023 if (fUserInfo) {
1024 fUserInfo->Delete();
1025 delete fUserInfo;
1026 fUserInfo = nullptr;
1027 }
1028 if (fClones) {
1029 // Clone trees should no longer be removed from fClones when they are deleted.
1030 {
1032 gROOT->GetListOfCleanups()->Remove(fClones);
1033 }
1034 // Note: fClones does not own its content.
1035 delete fClones;
1036 fClones = nullptr;
1037 }
1038 if (fEntryList) {
1039 if (fEntryList->TestBit(kCanDelete) && fEntryList->GetDirectory()==nullptr) {
1040 // Delete the entry list if it is marked to be deleted and it is not also
1041 // owned by a directory. (Otherwise we would need to make sure that a
1042 // TDirectoryFile that has a TTree in it does a 'slow' TList::Delete.
1043 delete fEntryList;
1044 fEntryList=nullptr;
1045 }
1046 }
1047 delete fTreeIndex;
1048 fTreeIndex = nullptr;
1049 delete fBranchRef;
1050 fBranchRef = nullptr;
1051 delete [] fClusterRangeEnd;
1052 fClusterRangeEnd = nullptr;
1053 delete [] fClusterSize;
1054 fClusterSize = nullptr;
1055
1056 if (fTransientBuffer) {
1057 delete fTransientBuffer;
1058 fTransientBuffer = nullptr;
1059 }
1060}
1061
1062////////////////////////////////////////////////////////////////////////////////
1063/// Returns the transient buffer currently used by this TTree for reading/writing baskets.
1075}
1076
1077////////////////////////////////////////////////////////////////////////////////
1078/// Add branch with name bname to the Tree cache.
1079/// If bname="*" all branches are added to the cache.
1080/// if subbranches is true all the branches of the subbranches are
1081/// also put to the cache.
1082///
1083/// Returns:
1084/// - 0 branch added or already included
1085/// - -1 on error
1087Int_t TTree::AddBranchToCache(const char*bname, bool subbranches)
1088{
1089 if (!GetTree()) {
1090 if (LoadTree(0)<0) {
1091 Error("AddBranchToCache","Could not load a tree");
1092 return -1;
1093 }
1094 }
1095 if (GetTree()) {
1096 if (GetTree() != this) {
1097 return GetTree()->AddBranchToCache(bname, subbranches);
1098 }
1099 } else {
1100 Error("AddBranchToCache", "No tree is available. Branch was not added to the cache");
1101 return -1;
1102 }
1103
1104 TFile *f = GetCurrentFile();
1105 if (!f) {
1106 Error("AddBranchToCache", "No file is available. Branch was not added to the cache");
1107 return -1;
1108 }
1109 TTreeCache *tc = GetReadCache(f,true);
1110 if (!tc) {
1111 Error("AddBranchToCache", "No cache is available, branch not added");
1112 return -1;
1113 }
1114 return tc->AddBranch(bname,subbranches);
1115}
1116
1117////////////////////////////////////////////////////////////////////////////////
1118/// Add branch b to the Tree cache.
1119/// if subbranches is true all the branches of the subbranches are
1120/// also put to the cache.
1121///
1122/// Returns:
1123/// - 0 branch added or already included
1124/// - -1 on error
1127{
1128 if (!GetTree()) {
1129 if (LoadTree(0)<0) {
1130 Error("AddBranchToCache","Could not load a tree");
1131 return -1;
1132 }
1133 }
1134 if (GetTree()) {
1135 if (GetTree() != this) {
1136 Int_t res = GetTree()->AddBranchToCache(b, subbranches);
1137 if (res<0) {
1138 Error("AddBranchToCache", "Error adding branch");
1139 }
1140 return res;
1141 }
1142 } else {
1143 Error("AddBranchToCache", "No tree is available. Branch was not added to the cache");
1144 return -1;
1145 }
1146
1147 TFile *f = GetCurrentFile();
1148 if (!f) {
1149 Error("AddBranchToCache", "No file is available. Branch was not added to the cache");
1150 return -1;
1151 }
1152 TTreeCache *tc = GetReadCache(f,true);
1153 if (!tc) {
1154 Error("AddBranchToCache", "No cache is available, branch not added");
1155 return -1;
1156 }
1157 return tc->AddBranch(b,subbranches);
1158}
1159
1160////////////////////////////////////////////////////////////////////////////////
1161/// Remove the branch with name 'bname' from the Tree cache.
1162/// If bname="*" all branches are removed from the cache.
1163/// if subbranches is true all the branches of the subbranches are
1164/// also removed from the cache.
1165///
1166/// Returns:
1167/// - 0 branch dropped or not in cache
1168/// - -1 on error
1170Int_t TTree::DropBranchFromCache(const char*bname, bool subbranches)
1171{
1172 if (!GetTree()) {
1173 if (LoadTree(0)<0) {
1174 Error("DropBranchFromCache","Could not load a tree");
1175 return -1;
1176 }
1177 }
1178 if (GetTree()) {
1179 if (GetTree() != this) {
1180 return GetTree()->DropBranchFromCache(bname, subbranches);
1181 }
1182 } else {
1183 Error("DropBranchFromCache", "No tree is available. Branch was not dropped from the cache");
1184 return -1;
1185 }
1186
1187 TFile *f = GetCurrentFile();
1188 if (!f) {
1189 Error("DropBranchFromCache", "No file is available. Branch was not dropped from the cache");
1190 return -1;
1191 }
1192 TTreeCache *tc = GetReadCache(f,true);
1193 if (!tc) {
1194 Error("DropBranchFromCache", "No cache is available, branch not dropped");
1195 return -1;
1196 }
1197 return tc->DropBranch(bname,subbranches);
1198}
1199
1200////////////////////////////////////////////////////////////////////////////////
1201/// Remove the branch b from the Tree cache.
1202/// if subbranches is true all the branches of the subbranches are
1203/// also removed from the cache.
1204///
1205/// Returns:
1206/// - 0 branch dropped or not in cache
1207/// - -1 on error
1210{
1211 if (!GetTree()) {
1212 if (LoadTree(0)<0) {
1213 Error("DropBranchFromCache","Could not load a tree");
1214 return -1;
1215 }
1216 }
1217 if (GetTree()) {
1218 if (GetTree() != this) {
1219 Int_t res = GetTree()->DropBranchFromCache(b, subbranches);
1220 if (res<0) {
1221 Error("DropBranchFromCache", "Error dropping branch");
1222 }
1223 return res;
1224 }
1225 } else {
1226 Error("DropBranchFromCache", "No tree is available. Branch was not dropped from the cache");
1227 return -1;
1228 }
1229
1230 TFile *f = GetCurrentFile();
1231 if (!f) {
1232 Error("DropBranchFromCache", "No file is available. Branch was not dropped from the cache");
1233 return -1;
1234 }
1235 TTreeCache *tc = GetReadCache(f,true);
1236 if (!tc) {
1237 Error("DropBranchFromCache", "No cache is available, branch not dropped");
1238 return -1;
1239 }
1240 return tc->DropBranch(b,subbranches);
1241}
1242
1243////////////////////////////////////////////////////////////////////////////////
1244/// Add a cloned tree to our list of trees to be notified whenever we change
1245/// our branch addresses or when we are deleted.
1247void TTree::AddClone(TTree* clone)
1248{
1249 if (!fClones) {
1250 fClones = new TList();
1251 fClones->SetOwner(false);
1252 // So that the clones are automatically removed from the list when
1253 // they are deleted.
1254 {
1256 gROOT->GetListOfCleanups()->Add(fClones);
1257 }
1258 }
1259 if (!fClones->FindObject(clone)) {
1260 fClones->Add(clone);
1261 }
1262}
1263
1264// Check whether mainTree and friendTree can be friends w.r.t. the kEntriesReshuffled bit.
1265// In particular, if any has the bit set, then friendTree must have a TTreeIndex and the
1266// branches used for indexing must be present in mainTree.
1267// Return true if the trees can be friends, false otherwise.
1269{
1272 const auto friendHasValidIndex = [&] {
1273 auto idx = friendTree.GetTreeIndex();
1274 return idx ? idx->IsValidFor(&mainTree) : false;
1275 }();
1276
1278 const auto reshuffledTreeName = isMainReshuffled ? mainTree.GetName() : friendTree.GetName();
1279 const auto msg =
1280 "Tree '%s' has the kEntriesReshuffled bit set and cannot have friends nor can be added as a friend unless the "
1281 "main tree has a TTreeIndex on the friend tree '%s'. You can also unset the bit manually if you know what you "
1282 "are doing; note that you risk associating wrong TTree entries of the friend with those of the main TTree!";
1283 Error("AddFriend", msg, reshuffledTreeName, friendTree.GetName());
1284 return false;
1285 }
1286 return true;
1287}
1288
1289////////////////////////////////////////////////////////////////////////////////
1290/// Add a TFriendElement to the list of friends.
1291///
1292/// This function:
1293/// - opens a file if filename is specified
1294/// - reads a Tree with name treename from the file (current directory)
1295/// - adds the Tree to the list of friends
1296/// see other AddFriend functions
1297///
1298/// A TFriendElement TF describes a TTree object TF in a file.
1299/// When a TFriendElement TF is added to the list of friends of an
1300/// existing TTree T, any variable from TF can be referenced in a query
1301/// to T.
1302///
1303/// A tree keeps a list of friends. In the context of a tree (or a chain),
1304/// friendship means unrestricted access to the friends data. In this way
1305/// it is much like adding another branch to the tree without taking the risk
1306/// of damaging it. To add a friend to the list, you can use the TTree::AddFriend
1307/// method. The tree in the diagram below has two friends (friend_tree1 and
1308/// friend_tree2) and now has access to the variables a,b,c,i,j,k,l and m.
1309///
1310/// \image html ttree_friend1.png
1311///
1312/// The AddFriend method has two parameters, the first is the tree name and the
1313/// second is the name of the ROOT file where the friend tree is saved.
1314/// AddFriend automatically opens the friend file. If no file name is given,
1315/// the tree called ft1 is assumed to be in the same file as the original tree.
1316///
1317/// tree.AddFriend("ft1","friendfile1.root");
1318/// If the friend tree has the same name as the original tree, you can give it
1319/// an alias in the context of the friendship:
1320///
1321/// tree.AddFriend("tree1 = tree","friendfile1.root");
1322/// Once the tree has friends, we can use TTree::Draw as if the friend's
1323/// variables were in the original tree. To specify which tree to use in
1324/// the Draw method, use the syntax:
1325/// ~~~ {.cpp}
1326/// <treeName>.<branchname>.<varname>
1327/// ~~~
1328/// If the variablename is enough to uniquely identify the variable, you can
1329/// leave out the tree and/or branch name.
1330/// For example, these commands generate a 3-d scatter plot of variable "var"
1331/// in the TTree tree versus variable v1 in TTree ft1 versus variable v2 in
1332/// TTree ft2.
1333/// ~~~ {.cpp}
1334/// tree.AddFriend("ft1","friendfile1.root");
1335/// tree.AddFriend("ft2","friendfile2.root");
1336/// tree.Draw("var:ft1.v1:ft2.v2");
1337/// ~~~
1338/// \image html ttree_friend2.png
1339///
1340/// The picture illustrates the access of the tree and its friends with a
1341/// Draw command.
1342/// When AddFriend is called, the ROOT file is automatically opened and the
1343/// friend tree (ft1) is read into memory. The new friend (ft1) is added to
1344/// the list of friends of tree.
1345/// The number of entries in the friend must be equal or greater to the number
1346/// of entries of the original tree. If the friend tree has fewer entries a
1347/// warning is given and the missing entries are not included in the histogram.
1348/// To retrieve the list of friends from a tree use TTree::GetListOfFriends.
1349/// When the tree is written to file (TTree::Write), the friends list is saved
1350/// with it. And when the tree is retrieved, the trees on the friends list are
1351/// also retrieved and the friendship restored.
1352/// When a tree is deleted, the elements of the friend list are also deleted.
1353/// It is possible to declare a friend tree that has the same internal
1354/// structure (same branches and leaves) as the original tree, and compare the
1355/// same values by specifying the tree.
1356/// ~~~ {.cpp}
1357/// tree.Draw("var:ft1.var:ft2.var")
1358/// ~~~
1360TFriendElement *TTree::AddFriend(const char *treename, const char *filename)
1361{
1362 if (!fFriends) {
1363 fFriends = new TList();
1364 }
1366
1367 TTree *t = fe->GetTree();
1368 bool canAddFriend = true;
1369 if (t) {
1370 canAddFriend = CheckReshuffling(*this, *t);
1371 if (!t->GetTreeIndex() && (t->GetEntries() < fEntries)) {
1372 Warning("AddFriend", "FriendElement %s in file %s has less entries %lld than its parent Tree: %lld", treename,
1374 }
1375 } else {
1376 Error("AddFriend", "Cannot find tree '%s' in file '%s', friend not added", treename, filename);
1377 canAddFriend = false;
1378 }
1379
1380 if (canAddFriend)
1381 fFriends->Add(fe);
1382 return fe;
1383}
1384
1385////////////////////////////////////////////////////////////////////////////////
1386/// Add a TFriendElement to the list of friends.
1387///
1388/// The TFile is managed by the user (e.g. the user must delete the file).
1389/// For complete description see AddFriend(const char *, const char *).
1390/// This function:
1391/// - reads a Tree with name treename from the file
1392/// - adds the Tree to the list of friends
1394TFriendElement *TTree::AddFriend(const char *treename, TFile *file)
1395{
1396 if (!fFriends) {
1397 fFriends = new TList();
1398 }
1399 TFriendElement *fe = new TFriendElement(this, treename, file);
1400 R__ASSERT(fe);
1401 TTree *t = fe->GetTree();
1402 bool canAddFriend = true;
1403 if (t) {
1404 canAddFriend = CheckReshuffling(*this, *t);
1405 if (!t->GetTreeIndex() && (t->GetEntries() < fEntries)) {
1406 Warning("AddFriend", "FriendElement %s in file %s has less entries %lld than its parent tree: %lld", treename,
1407 file->GetName(), t->GetEntries(), fEntries);
1408 }
1409 } else {
1410 Error("AddFriend", "Cannot find tree '%s' in file '%s', friend not added", treename, file->GetName());
1411 canAddFriend = false;
1412 }
1413
1414 if (canAddFriend)
1415 fFriends->Add(fe);
1416 return fe;
1417}
1418
1419////////////////////////////////////////////////////////////////////////////////
1420/// Add a TFriendElement to the list of friends.
1421///
1422/// The TTree is managed by the user (e.g., the user must delete the file).
1423/// For a complete description see AddFriend(const char *, const char *).
1425TFriendElement *TTree::AddFriend(TTree *tree, const char *alias, bool warn)
1426{
1427 if (!tree) {
1428 return nullptr;
1429 }
1430 if (!fFriends) {
1431 fFriends = new TList();
1432 }
1433 TFriendElement *fe = new TFriendElement(this, tree, alias);
1434 R__ASSERT(fe); // this assert is for historical reasons. Don't remove it unless you understand all the consequences.
1435 TTree *t = fe->GetTree();
1436 if (warn && (t->GetEntries() < fEntries)) {
1437 Warning("AddFriend", "FriendElement '%s' in file '%s' has less entries %lld than its parent tree: %lld",
1438 tree->GetName(), fe->GetFile() ? fe->GetFile()->GetName() : "(memory resident)", t->GetEntries(),
1439 fEntries);
1440 }
1441 if (CheckReshuffling(*this, *t))
1442 fFriends->Add(fe);
1443 else
1444 tree->RemoveExternalFriend(fe);
1445 return fe;
1446}
1447
1448////////////////////////////////////////////////////////////////////////////////
1449/// AutoSave tree header every fAutoSave bytes.
1450///
1451/// When large Trees are produced, it is safe to activate the AutoSave
1452/// procedure. Some branches may have buffers holding many entries.
1453/// If fAutoSave is negative, AutoSave is automatically called by
1454/// TTree::Fill when the number of bytes generated since the previous
1455/// AutoSave is greater than -fAutoSave bytes.
1456/// If fAutoSave is positive, AutoSave is automatically called by
1457/// TTree::Fill every N entries.
1458/// This function may also be invoked by the user.
1459/// Each AutoSave generates a new key on the file.
1460/// Once the key with the tree header has been written, the previous cycle
1461/// (if any) is deleted.
1462///
1463/// Note that calling TTree::AutoSave too frequently (or similarly calling
1464/// TTree::SetAutoSave with a small value) is an expensive operation.
1465/// You should make tests for your own application to find a compromise
1466/// between speed and the quantity of information you may loose in case of
1467/// a job crash.
1468///
1469/// In case your program crashes before closing the file holding this tree,
1470/// the file will be automatically recovered when you will connect the file
1471/// in UPDATE mode.
1472/// The Tree will be recovered at the status corresponding to the last AutoSave.
1473///
1474/// if option contains "SaveSelf", gDirectory->SaveSelf() is called.
1475/// This allows another process to analyze the Tree while the Tree is being filled.
1476///
1477/// if option contains "FlushBaskets", TTree::FlushBaskets is called and all
1478/// the current basket are closed-out and written to disk individually.
1479///
1480/// By default the previous header is deleted after having written the new header.
1481/// if option contains "Overwrite", the previous Tree header is deleted
1482/// before written the new header. This option is slightly faster, but
1483/// the default option is safer in case of a problem (disk quota exceeded)
1484/// when writing the new header.
1485///
1486/// The function returns the number of bytes written to the file.
1487/// if the number of bytes is null, an error has occurred while writing
1488/// the header to the file.
1489///
1490/// ## How to write a Tree in one process and view it from another process
1491///
1492/// The following two scripts illustrate how to do this.
1493/// The script treew.C is executed by process1, treer.C by process2
1494///
1495/// script treew.C:
1496/// ~~~ {.cpp}
1497/// void treew() {
1498/// TFile f("test.root","recreate");
1499/// TNtuple *ntuple = new TNtuple("ntuple","Demo","px:py:pz:random:i");
1500/// Float_t px, py, pz;
1501/// for ( Int_t i=0; i<10000000; i++) {
1502/// gRandom->Rannor(px,py);
1503/// pz = px*px + py*py;
1504/// Float_t random = gRandom->Rndm(1);
1505/// ntuple->Fill(px,py,pz,random,i);
1506/// if (i%1000 == 1) ntuple->AutoSave("SaveSelf");
1507/// }
1508/// }
1509/// ~~~
1510/// script treer.C:
1511/// ~~~ {.cpp}
1512/// void treer() {
1513/// TFile f("test.root");
1514/// TTree *ntuple = (TTree*)f.Get("ntuple");
1515/// TCanvas c1;
1516/// Int_t first = 0;
1517/// while(1) {
1518/// if (first == 0) ntuple->Draw("px>>hpx", "","",10000000,first);
1519/// else ntuple->Draw("px>>+hpx","","",10000000,first);
1520/// first = (Int_t)ntuple->GetEntries();
1521/// c1.Update();
1522/// gSystem->Sleep(1000); //sleep 1 second
1523/// ntuple->Refresh();
1524/// }
1525/// }
1526/// ~~~
1529{
1530 if (!fDirectory || fDirectory == gROOT || !fDirectory->IsWritable()) return 0;
1531 if (gDebug > 0) {
1532 Info("AutoSave", "Tree:%s after %lld bytes written\n",GetName(),GetTotBytes());
1533 }
1534 TString opt = option;
1535 opt.ToLower();
1536
1537 if (opt.Contains("flushbaskets")) {
1538 if (gDebug > 0) Info("AutoSave", "calling FlushBaskets \n");
1540 }
1541
1543
1544 TKey *key = (TKey*)fDirectory->GetListOfKeys()->FindObject(GetName());
1546 if (opt.Contains("overwrite")) {
1547 nbytes = fDirectory->WriteTObject(this,"","overwrite");
1548 } else {
1549 nbytes = fDirectory->WriteTObject(this); //nbytes will be 0 if Write failed (disk space exceeded)
1550 if (nbytes && key && strcmp(ClassName(), key->GetClassName()) == 0) {
1551 key->Delete();
1552 delete key;
1553 }
1554 }
1555 // save StreamerInfo
1556 TFile *file = fDirectory->GetFile();
1557 if (file) file->WriteStreamerInfo();
1558
1559 if (opt.Contains("saveself")) {
1561 //the following line is required in case GetUserInfo contains a user class
1562 //for which the StreamerInfo must be written. One could probably be a bit faster (Rene)
1563 if (file) file->WriteHeader();
1564 }
1565
1566 return nbytes;
1567}
1568
1569namespace {
1570 // This error message is repeated several times in the code. We write it once.
1571 const char* writeStlWithoutProxyMsg = "The class requested (%s) for the branch \"%s\""
1572 " is an instance of an stl collection and does not have a compiled CollectionProxy."
1573 " Please generate the dictionary for this collection (%s) to avoid to write corrupted data.";
1574}
1575
1576////////////////////////////////////////////////////////////////////////////////
1577/// Same as TTree::Branch() with added check that addobj matches className.
1578///
1579/// \see TTree::Branch()
1580///
1582TBranch* TTree::BranchImp(const char* branchname, const char* classname, TClass* ptrClass, void* addobj, Int_t bufsize, Int_t splitlevel)
1583{
1584 TClass* claim = TClass::GetClass(classname);
1585 if (!ptrClass) {
1586 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1588 claim->GetName(), branchname, claim->GetName());
1589 return nullptr;
1590 }
1591 return Branch(branchname, classname, (void*) addobj, bufsize, splitlevel);
1592 }
1593 TClass* actualClass = nullptr;
1594 void** addr = (void**) addobj;
1595 if (addr) {
1596 actualClass = ptrClass->GetActualClass(*addr);
1597 }
1598 if (ptrClass && claim) {
1599 if (!(claim->InheritsFrom(ptrClass) || ptrClass->InheritsFrom(claim))) {
1600 // Note we currently do not warn in case of splicing or over-expectation).
1601 if (claim->IsLoaded() && ptrClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), ptrClass->GetTypeInfo()->name() ) == 0) {
1602 // The type is the same according to the C++ type_info, we must be in the case of
1603 // a template of Double32_t. This is actually a correct case.
1604 } else {
1605 Error("Branch", "The class requested (%s) for \"%s\" is different from the type of the pointer passed (%s)",
1606 claim->GetName(), branchname, ptrClass->GetName());
1607 }
1608 } else if (actualClass && (claim != actualClass) && !actualClass->InheritsFrom(claim)) {
1609 if (claim->IsLoaded() && actualClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), actualClass->GetTypeInfo()->name() ) == 0) {
1610 // The type is the same according to the C++ type_info, we must be in the case of
1611 // a template of Double32_t. This is actually a correct case.
1612 } else {
1613 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s",
1614 actualClass->GetName(), branchname, claim->GetName());
1615 }
1616 }
1617 }
1618 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1620 claim->GetName(), branchname, claim->GetName());
1621 return nullptr;
1622 }
1623 return Branch(branchname, classname, (void*) addobj, bufsize, splitlevel);
1624}
1625
1626////////////////////////////////////////////////////////////////////////////////
1627/// Same as TTree::Branch but automatic detection of the class name.
1628/// \see TTree::Branch
1631{
1632 if (!ptrClass) {
1633 Error("Branch", "The pointer specified for %s is not of a class known to ROOT", branchname);
1634 return nullptr;
1635 }
1636 TClass* actualClass = nullptr;
1637 void** addr = (void**) addobj;
1638 if (addr && *addr) {
1639 actualClass = ptrClass->GetActualClass(*addr);
1640 if (!actualClass) {
1641 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",
1642 branchname, ptrClass->GetName());
1644 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1645 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());
1646 return nullptr;
1647 }
1648 } else {
1650 }
1651 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1653 actualClass->GetName(), branchname, actualClass->GetName());
1654 return nullptr;
1655 }
1656 return Branch(branchname, actualClass->GetName(), (void*) addobj, bufsize, splitlevel);
1657}
1658
1659////////////////////////////////////////////////////////////////////////////////
1660/// Same as TTree::Branch but automatic detection of the class name.
1661/// \see TTree::Branch
1663TBranch* TTree::BranchImpRef(const char* branchname, const char *classname, TClass* ptrClass, void *addobj, Int_t bufsize, Int_t splitlevel)
1664{
1665 TClass* claim = TClass::GetClass(classname);
1666 if (!ptrClass) {
1667 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1669 claim->GetName(), branchname, claim->GetName());
1670 return nullptr;
1671 } else if (claim == nullptr) {
1672 Error("Branch", "The pointer specified for %s is not of a class known to ROOT and %s is not a known class", branchname, classname);
1673 return nullptr;
1674 }
1675 ptrClass = claim;
1676 }
1677 TClass* actualClass = nullptr;
1678 if (!addobj) {
1679 Error("Branch", "Reference interface requires a valid object (for branch: %s)!", branchname);
1680 return nullptr;
1681 }
1682 actualClass = ptrClass->GetActualClass(addobj);
1683 if (ptrClass && claim) {
1684 if (!(claim->InheritsFrom(ptrClass) || ptrClass->InheritsFrom(claim))) {
1685 // Note we currently do not warn in case of splicing or over-expectation).
1686 if (claim->IsLoaded() && ptrClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), ptrClass->GetTypeInfo()->name() ) == 0) {
1687 // The type is the same according to the C++ type_info, we must be in the case of
1688 // a template of Double32_t. This is actually a correct case.
1689 } else {
1690 Error("Branch", "The class requested (%s) for \"%s\" is different from the type of the object passed (%s)",
1691 claim->GetName(), branchname, ptrClass->GetName());
1692 }
1693 } else if (actualClass && (claim != actualClass) && !actualClass->InheritsFrom(claim)) {
1694 if (claim->IsLoaded() && actualClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), actualClass->GetTypeInfo()->name() ) == 0) {
1695 // The type is the same according to the C++ type_info, we must be in the case of
1696 // a template of Double32_t. This is actually a correct case.
1697 } else {
1698 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s",
1699 actualClass->GetName(), branchname, claim->GetName());
1700 }
1701 }
1702 }
1703 if (!actualClass) {
1704 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",
1705 branchname, ptrClass->GetName());
1707 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1708 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());
1709 return nullptr;
1710 }
1711 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1713 actualClass->GetName(), branchname, actualClass->GetName());
1714 return nullptr;
1715 }
1716 return BronchExec(branchname, actualClass->GetName(), (void*) addobj, false, bufsize, splitlevel);
1717}
1718
1719////////////////////////////////////////////////////////////////////////////////
1720/// Same as TTree::Branch but automatic detection of the class name.
1721/// \see TTree::Branch
1724{
1725 if (!ptrClass) {
1726 if (datatype == kOther_t || datatype == kNoType_t) {
1727 Error("Branch", "The pointer specified for %s is not of a class or type known to ROOT", branchname);
1728 } else {
1730 return Branch(branchname,addobj,varname.Data(),bufsize);
1731 }
1732 return nullptr;
1733 }
1734 TClass* actualClass = nullptr;
1735 if (!addobj) {
1736 Error("Branch", "Reference interface requires a valid object (for branch: %s)!", branchname);
1737 return nullptr;
1738 }
1739 actualClass = ptrClass->GetActualClass(addobj);
1740 if (!actualClass) {
1741 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",
1742 branchname, ptrClass->GetName());
1744 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1745 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());
1746 return nullptr;
1747 }
1748 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1750 actualClass->GetName(), branchname, actualClass->GetName());
1751 return nullptr;
1752 }
1753 return BronchExec(branchname, actualClass->GetName(), (void*) addobj, false, bufsize, splitlevel);
1754}
1755
1756////////////////////////////////////////////////////////////////////////////////
1757// Wrapper to turn Branch call with an std::array into the relevant leaf list
1758// call
1759TBranch *TTree::BranchImpArr(const char *branchname, EDataType datatype, std::size_t N, void *addobj, Int_t bufsize,
1760 Int_t /* splitlevel */)
1761{
1762 if (datatype == kOther_t || datatype == kNoType_t) {
1763 Error("Branch",
1764 "The inner type of the std::array passed specified for %s is not of a class or type known to ROOT",
1765 branchname);
1766 } else {
1768 varname.Form("%s[%d]/%c", branchname, (int)N, DataTypeToChar(datatype));
1769 return Branch(branchname, addobj, varname.Data(), bufsize);
1770 }
1771 return nullptr;
1772}
1773
1774////////////////////////////////////////////////////////////////////////////////
1775/// Deprecated function. Use next function instead.
1777Int_t TTree::Branch(TList* li, Int_t bufsize /* = 32000 */ , Int_t splitlevel /* = 99 */)
1778{
1779 return Branch((TCollection*) li, bufsize, splitlevel);
1780}
1781
1782////////////////////////////////////////////////////////////////////////////////
1783/// Create one branch for each element in the collection.
1784///
1785/// Each entry in the collection becomes a top level branch if the
1786/// corresponding class is not a collection. If it is a collection, the entry
1787/// in the collection becomes in turn top level branches, etc.
1788/// The splitlevel is decreased by 1 every time a new collection is found.
1789/// For example if list is a TObjArray*
1790/// - if splitlevel = 1, one top level branch is created for each element
1791/// of the TObjArray.
1792/// - if splitlevel = 2, one top level branch is created for each array element.
1793/// if, in turn, one of the array elements is a TCollection, one top level
1794/// branch will be created for each element of this collection.
1795///
1796/// In case a collection element is a TClonesArray, the special Tree constructor
1797/// for TClonesArray is called.
1798/// The collection itself cannot be a TClonesArray.
1799///
1800/// The function returns the total number of branches created.
1801///
1802/// If name is given, all branch names will be prefixed with name_.
1803///
1804/// IMPORTANT NOTE1: This function should not be called with splitlevel < 1.
1805///
1806/// IMPORTANT NOTE2: The branches created by this function will have names
1807/// corresponding to the collection or object names. It is important
1808/// to give names to collections to avoid misleading branch names or
1809/// identical branch names. By default collections have a name equal to
1810/// the corresponding class name, e.g. the default name for a TList is "TList".
1811///
1812/// And in general, in case two or more master branches contain subbranches
1813/// with identical names, one must add a "." (dot) character at the end
1814/// of the master branch name. This will force the name of the subbranches
1815/// to be of the form `master.subbranch` instead of simply `subbranch`.
1816/// This situation happens when the top level object
1817/// has two or more members referencing the same class.
1818/// Without the dot, the prefix will not be there and that might cause ambiguities.
1819/// For example, if a Tree has two branches B1 and B2 corresponding
1820/// to objects of the same class MyClass, one can do:
1821/// ~~~ {.cpp}
1822/// tree.Branch("B1.","MyClass",&b1,8000,1);
1823/// tree.Branch("B2.","MyClass",&b2,8000,1);
1824/// ~~~
1825/// if MyClass has 3 members a,b,c, the two instructions above will generate
1826/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
1827/// In other words, the trailing dot of the branch name is semantically relevant
1828/// and recommended.
1829///
1830/// Example:
1831/// ~~~ {.cpp}
1832/// {
1833/// TTree T("T","test list");
1834/// TList *list = new TList();
1835///
1836/// TObjArray *a1 = new TObjArray();
1837/// a1->SetName("a1");
1838/// list->Add(a1);
1839/// TH1F *ha1a = new TH1F("ha1a","ha1",100,0,1);
1840/// TH1F *ha1b = new TH1F("ha1b","ha1",100,0,1);
1841/// a1->Add(ha1a);
1842/// a1->Add(ha1b);
1843/// TObjArray *b1 = new TObjArray();
1844/// b1->SetName("b1");
1845/// list->Add(b1);
1846/// TH1F *hb1a = new TH1F("hb1a","hb1",100,0,1);
1847/// TH1F *hb1b = new TH1F("hb1b","hb1",100,0,1);
1848/// b1->Add(hb1a);
1849/// b1->Add(hb1b);
1850///
1851/// TObjArray *a2 = new TObjArray();
1852/// a2->SetName("a2");
1853/// list->Add(a2);
1854/// TH1S *ha2a = new TH1S("ha2a","ha2",100,0,1);
1855/// TH1S *ha2b = new TH1S("ha2b","ha2",100,0,1);
1856/// a2->Add(ha2a);
1857/// a2->Add(ha2b);
1858///
1859/// T.Branch(list,16000,2);
1860/// T.Print();
1861/// }
1862/// ~~~
1864Int_t TTree::Branch(TCollection* li, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */, const char* name /* = "" */)
1865{
1866
1867 if (!li) {
1868 return 0;
1869 }
1870 TObject* obj = nullptr;
1871 Int_t nbranches = GetListOfBranches()->GetEntries();
1872 if (li->InheritsFrom(TClonesArray::Class())) {
1873 Error("Branch", "Cannot call this constructor for a TClonesArray");
1874 return 0;
1875 }
1876 Int_t nch = strlen(name);
1878 TIter next(li);
1879 while ((obj = next())) {
1881 TCollection* col = (TCollection*) obj;
1882 if (nch) {
1883 branchname.Form("%s_%s_", name, col->GetName());
1884 } else {
1885 branchname.Form("%s_", col->GetName());
1886 }
1888 } else {
1889 if (nch && (name[nch-1] == '_')) {
1890 branchname.Form("%s%s", name, obj->GetName());
1891 } else {
1892 if (nch) {
1893 branchname.Form("%s_%s", name, obj->GetName());
1894 } else {
1895 branchname.Form("%s", obj->GetName());
1896 }
1897 }
1898 if (splitlevel > 99) {
1899 branchname += ".";
1900 }
1901 Bronch(branchname, obj->ClassName(), li->GetObjectRef(obj), bufsize, splitlevel - 1);
1902 }
1903 }
1904 return GetListOfBranches()->GetEntries() - nbranches;
1905}
1906
1907////////////////////////////////////////////////////////////////////////////////
1908/// Create one branch for each element in the folder.
1909/// Returns the total number of branches created.
1911Int_t TTree::Branch(const char* foldername, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
1912{
1913 TObject* ob = gROOT->FindObjectAny(foldername);
1914 if (!ob) {
1915 return 0;
1916 }
1917 if (ob->IsA() != TFolder::Class()) {
1918 return 0;
1919 }
1920 Int_t nbranches = GetListOfBranches()->GetEntries();
1921 TFolder* folder = (TFolder*) ob;
1922 TIter next(folder->GetListOfFolders());
1923 TObject* obj = nullptr;
1924 char* curname = new char[1000];
1925 char occur[20];
1926 while ((obj = next())) {
1927 snprintf(curname,1000, "%s/%s", foldername, obj->GetName());
1928 if (obj->IsA() == TFolder::Class()) {
1930 } else {
1931 void* add = (void*) folder->GetListOfFolders()->GetObjectRef(obj);
1932 for (Int_t i = 0; i < 1000; ++i) {
1933 if (curname[i] == 0) {
1934 break;
1935 }
1936 if (curname[i] == '/') {
1937 curname[i] = '.';
1938 }
1939 }
1940 Int_t noccur = folder->Occurence(obj);
1941 if (noccur > 0) {
1942 snprintf(occur,20, "_%d", noccur);
1943 strlcat(curname, occur,1000);
1944 }
1946 if (br) br->SetBranchFolder();
1947 }
1948 }
1949 delete[] curname;
1950 return GetListOfBranches()->GetEntries() - nbranches;
1951}
1952
1953////////////////////////////////////////////////////////////////////////////////
1954/// Create a new TTree Branch.
1955///
1956/// This Branch constructor is provided to support non-objects in
1957/// a Tree. The variables described in leaflist may be simple
1958/// variables or structures. // See the two following
1959/// constructors for writing objects in a Tree.
1960///
1961/// By default the branch buffers are stored in the same file as the Tree.
1962/// use TBranch::SetFile to specify a different file
1963///
1964/// * address is the address of the first item of a structure.
1965/// * leaflist is the concatenation of all the variable names and types
1966/// separated by a colon character :
1967/// The variable name and the variable type are separated by a slash (/).
1968/// The variable type may be 0,1 or 2 characters. If no type is given,
1969/// the type of the variable is assumed to be the same as the previous
1970/// variable. If the first variable does not have a type, it is assumed
1971/// of type `F` by default. The list of currently supported types is given below:
1972/// - `C` : a character string terminated by the 0 character
1973/// - `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.
1974/// - `b` : an 8 bit unsigned integer (`UChar_t`)
1975/// - `S` : a 16 bit signed integer (`Short_t`)
1976/// - `s` : a 16 bit unsigned integer (`UShort_t`)
1977/// - `I` : a 32 bit signed integer (`Int_t`)
1978/// - `i` : a 32 bit unsigned integer (`UInt_t`)
1979/// - `F` : a 32 bit floating point (`Float_t`)
1980/// - `f` : a 24 bit floating point with truncated mantissa (`Float16_t`)
1981/// - `D` : a 64 bit floating point (`Double_t`)
1982/// - `d` : a 24 bit truncated floating point (`Double32_t`)
1983/// - `L` : a 64 bit signed integer (`Long64_t`)
1984/// - `l` : a 64 bit unsigned integer (`ULong64_t`)
1985/// - `G` : a long signed integer, stored as 64 bit (`Long_t`)
1986/// - `g` : a long unsigned integer, stored as 64 bit (`ULong_t`)
1987/// - `O` : [the letter `o`, not a zero] a boolean (`bool`)
1988///
1989/// Arrays of values are supported with the following syntax:
1990/// - If leaf name has the form var[nelem], where nelem is alphanumeric, then
1991/// if nelem is a leaf name, it is used as the variable size of the array,
1992/// otherwise return 0.
1993/// The leaf referred to by nelem **MUST** be an int (/I),
1994/// - If leaf name has the form var[nelem], where nelem is a non-negative integer, then
1995/// it is used as the fixed size of the array.
1996/// - If leaf name has the form of a multi-dimensional array (e.g. var[nelem][nelem2])
1997/// where nelem and nelem2 are non-negative integer) then
1998/// it is used as a 2 dimensional array of fixed size.
1999/// - In case of the truncated floating point types (Float16_t and Double32_t) you can
2000/// furthermore specify the range in the style [xmin,xmax] or [xmin,xmax,nbits] after
2001/// the type character. See `TStreamerElement::GetRange()` for further information.
2002///
2003/// Any of other form is not supported.
2004///
2005/// Note that the TTree will assume that all the item are contiguous in memory.
2006/// On some platform, this is not always true of the member of a struct or a class,
2007/// due to padding and alignment. Sorting your data member in order of decreasing
2008/// sizeof usually leads to their being contiguous in memory.
2009///
2010/// * bufsize is the buffer size in bytes for this branch
2011/// The default value is 32000 bytes and should be ok for most cases.
2012/// You can specify a larger value (e.g. 256000) if your Tree is not split
2013/// and each entry is large (Megabytes)
2014/// A small value for bufsize is optimum if you intend to access
2015/// the entries in the Tree randomly and your Tree is in split mode.
2017TBranch* TTree::Branch(const char* name, void* address, const char* leaflist, Int_t bufsize /* = 32000 */)
2018{
2019 TBranch* branch = new TBranch(this, name, address, leaflist, bufsize);
2020 if (branch->IsZombie()) {
2021 delete branch;
2022 branch = nullptr;
2023 return nullptr;
2024 }
2026 return branch;
2027}
2028
2029////////////////////////////////////////////////////////////////////////////////
2030/// Create a new branch with the object of class classname at address addobj.
2031///
2032/// WARNING:
2033///
2034/// Starting with Root version 3.01, the Branch function uses the new style
2035/// branches (TBranchElement). To get the old behaviour, you can:
2036/// - call BranchOld or
2037/// - call TTree::SetBranchStyle(0)
2038///
2039/// Note that with the new style, classname does not need to derive from TObject.
2040/// It must derived from TObject if the branch style has been set to 0 (old)
2041///
2042/// Note: See the comments in TBranchElement::SetAddress() for a more
2043/// detailed discussion of the meaning of the addobj parameter in
2044/// the case of new-style branches.
2045///
2046/// Use splitlevel < 0 instead of splitlevel=0 when the class
2047/// has a custom Streamer
2048///
2049/// Note: if the split level is set to the default (99), TTree::Branch will
2050/// not issue a warning if the class can not be split.
2052TBranch* TTree::Branch(const char* name, const char* classname, void* addobj, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2053{
2054 if (fgBranchStyle == 1) {
2055 return Bronch(name, classname, addobj, bufsize, splitlevel);
2056 } else {
2057 if (splitlevel < 0) {
2058 splitlevel = 0;
2059 }
2060 return BranchOld(name, classname, addobj, bufsize, splitlevel);
2061 }
2062}
2063
2064////////////////////////////////////////////////////////////////////////////////
2065/// Create a new TTree BranchObject.
2066///
2067/// Build a TBranchObject for an object of class classname.
2068/// addobj is the address of a pointer to an object of class classname.
2069/// IMPORTANT: classname must derive from TObject.
2070/// The class dictionary must be available (ClassDef in class header).
2071///
2072/// This option requires access to the library where the corresponding class
2073/// is defined. Accessing one single data member in the object implies
2074/// reading the full object.
2075/// See the next Branch constructor for a more efficient storage
2076/// in case the entry consists of arrays of identical objects.
2077///
2078/// By default the branch buffers are stored in the same file as the Tree.
2079/// use TBranch::SetFile to specify a different file
2080///
2081/// IMPORTANT NOTE about branch names:
2082///
2083/// And in general, in case two or more master branches contain subbranches
2084/// with identical names, one must add a "." (dot) character at the end
2085/// of the master branch name. This will force the name of the subbranches
2086/// to be of the form `master.subbranch` instead of simply `subbranch`.
2087/// This situation happens when the top level object
2088/// has two or more members referencing the same class.
2089/// For example, if a Tree has two branches B1 and B2 corresponding
2090/// to objects of the same class MyClass, one can do:
2091/// ~~~ {.cpp}
2092/// tree.Branch("B1.","MyClass",&b1,8000,1);
2093/// tree.Branch("B2.","MyClass",&b2,8000,1);
2094/// ~~~
2095/// if MyClass has 3 members a,b,c, the two instructions above will generate
2096/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
2097///
2098/// bufsize is the buffer size in bytes for this branch
2099/// The default value is 32000 bytes and should be ok for most cases.
2100/// You can specify a larger value (e.g. 256000) if your Tree is not split
2101/// and each entry is large (Megabytes)
2102/// A small value for bufsize is optimum if you intend to access
2103/// the entries in the Tree randomly and your Tree is in split mode.
2105TBranch* TTree::BranchOld(const char* name, const char* classname, void* addobj, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 1 */)
2106{
2107 TClass* cl = TClass::GetClass(classname);
2108 if (!cl) {
2109 Error("BranchOld", "Cannot find class: '%s'", classname);
2110 return nullptr;
2111 }
2112 if (!cl->IsTObject()) {
2113 if (fgBranchStyle == 0) {
2114 Fatal("BranchOld", "The requested class ('%s') does not inherit from TObject.\n"
2115 "\tfgBranchStyle is set to zero requesting by default to use BranchOld.\n"
2116 "\tIf this is intentional use Bronch instead of Branch or BranchOld.", classname);
2117 } else {
2118 Fatal("BranchOld", "The requested class ('%s') does not inherit from TObject.\n"
2119 "\tYou can not use BranchOld to store objects of this type.",classname);
2120 }
2121 return nullptr;
2122 }
2123 TBranch* branch = new TBranchObject(this, name, classname, addobj, bufsize, splitlevel);
2125 if (!splitlevel) {
2126 return branch;
2127 }
2128 // We are going to fully split the class now.
2129 TObjArray* blist = branch->GetListOfBranches();
2130 const char* rdname = nullptr;
2131 const char* dname = nullptr;
2133 char** apointer = (char**) addobj;
2134 TObject* obj = (TObject*) *apointer;
2135 bool delobj = false;
2136 if (!obj) {
2137 obj = (TObject*) cl->New();
2138 delobj = true;
2139 }
2140 // Build the StreamerInfo if first time for the class.
2141 BuildStreamerInfo(cl, obj);
2142 // Loop on all public data members of the class and its base classes.
2144 Int_t isDot = 0;
2145 if (name[lenName-1] == '.') {
2146 isDot = 1;
2147 }
2148 TBranch* branch1 = nullptr;
2149 TRealData* rd = nullptr;
2150 TRealData* rdi = nullptr;
2152 TIter next(cl->GetListOfRealData());
2153 // Note: This loop results in a full split because the
2154 // real data list includes all data members of
2155 // data members.
2156 while ((rd = (TRealData*) next())) {
2157 if (rd->TestBit(TRealData::kTransient)) continue;
2158
2159 // Loop over all data members creating branches for each one.
2160 TDataMember* dm = rd->GetDataMember();
2161 if (!dm->IsPersistent()) {
2162 // Do not process members with an "!" as the first character in the comment field.
2163 continue;
2164 }
2165 if (rd->IsObject()) {
2166 // We skip data members of class type.
2167 // But we do build their real data, their
2168 // streamer info, and write their streamer
2169 // info to the current directory's file.
2170 // Oh yes, and we also do this for all of
2171 // their base classes.
2173 if (clm) {
2174 BuildStreamerInfo(clm, (char*) obj + rd->GetThisOffset());
2175 }
2176 continue;
2177 }
2178 rdname = rd->GetName();
2179 dname = dm->GetName();
2180 if (cl->CanIgnoreTObjectStreamer()) {
2181 // Skip the TObject base class data members.
2182 // FIXME: This prevents a user from ever
2183 // using these names themself!
2184 if (!strcmp(dname, "fBits")) {
2185 continue;
2186 }
2187 if (!strcmp(dname, "fUniqueID")) {
2188 continue;
2189 }
2190 }
2191 TDataType* dtype = dm->GetDataType();
2192 Int_t code = 0;
2193 if (dtype) {
2194 code = dm->GetDataType()->GetType();
2195 }
2196 // Encode branch name. Use real data member name
2198 if (isDot) {
2199 if (dm->IsaPointer()) {
2200 // FIXME: This is wrong! The asterisk is not usually in the front!
2201 branchname.Form("%s%s", name, &rdname[1]);
2202 } else {
2203 branchname.Form("%s%s", name, &rdname[0]);
2204 }
2205 }
2206 // FIXME: Change this to a string stream.
2208 Int_t offset = rd->GetThisOffset();
2209 char* pointer = ((char*) obj) + offset;
2210 if (dm->IsaPointer()) {
2211 // We have a pointer to an object or a pointer to an array of basic types.
2212 TClass* clobj = nullptr;
2213 if (!dm->IsBasic()) {
2215 }
2216 if (clobj && clobj->InheritsFrom(TClonesArray::Class())) {
2217 // We have a pointer to a clones array.
2218 char* cpointer = (char*) pointer;
2219 char** ppointer = (char**) cpointer;
2221 if (splitlevel != 2) {
2222 if (isDot) {
2224 } else {
2225 // FIXME: This is wrong! The asterisk is not usually in the front!
2226 branch1 = new TBranchClones(branch,&branchname.Data()[1], pointer, bufsize);
2227 }
2228 blist->Add(branch1);
2229 } else {
2230 if (isDot) {
2231 branch1 = new TBranchObject(branch, branchname, li->ClassName(), pointer, bufsize);
2232 } else {
2233 // FIXME: This is wrong! The asterisk is not usually in the front!
2234 branch1 = new TBranchObject(branch, &branchname.Data()[1], li->ClassName(), pointer, bufsize);
2235 }
2236 blist->Add(branch1);
2237 }
2238 } else if (clobj) {
2239 // We have a pointer to an object.
2240 //
2241 // It must be a TObject object.
2242 if (!clobj->IsTObject()) {
2243 continue;
2244 }
2245 branch1 = new TBranchObject(branch, dname, clobj->GetName(), pointer, bufsize, 0);
2246 if (isDot) {
2247 branch1->SetName(branchname);
2248 } else {
2249 // FIXME: This is wrong! The asterisk is not usually in the front!
2250 // Do not use the first character (*).
2251 branch1->SetName(&branchname.Data()[1]);
2252 }
2253 blist->Add(branch1);
2254 } else {
2255 // We have a pointer to an array of basic types.
2256 //
2257 // Check the comments in the text of the code for an index specification.
2258 const char* index = dm->GetArrayIndex();
2259 if (index[0]) {
2260 // We are a pointer to a varying length array of basic types.
2261 //check that index is a valid data member name
2262 //if member is part of an object (e.g. fA and index=fN)
2263 //index must be changed from fN to fA.fN
2264 TString aindex (rd->GetName());
2265 Ssiz_t rdot = aindex.Last('.');
2266 if (rdot>=0) {
2267 aindex.Remove(rdot+1);
2268 aindex.Append(index);
2269 }
2270 nexti.Reset();
2271 while ((rdi = (TRealData*) nexti())) {
2272 if (rdi->TestBit(TRealData::kTransient)) continue;
2273
2274 if (!strcmp(rdi->GetName(), index)) {
2275 break;
2276 }
2277 if (!strcmp(rdi->GetName(), aindex)) {
2278 index = rdi->GetName();
2279 break;
2280 }
2281 }
2282
2283 char vcode = DataTypeToChar((EDataType)code);
2284 // Note that we differentiate between strings and
2285 // char array by the fact that there is NO specified
2286 // size for a string (see next if (code == 1)
2287
2288 if (vcode) {
2289 leaflist.Form("%s[%s]/%c", &rdname[0], index, vcode);
2290 } else {
2291 Error("BranchOld", "Cannot create branch for rdname: %s code: %d", branchname.Data(), code);
2292 leaflist = "";
2293 }
2294 } else {
2295 // We are possibly a character string.
2296 if (code == 1) {
2297 // We are a character string.
2298 leaflist.Form("%s/%s", dname, "C");
2299 } else {
2300 // Invalid array specification.
2301 // FIXME: We need an error message here.
2302 continue;
2303 }
2304 }
2305 // There are '*' in both the branchname and leaflist, remove them.
2306 TString bname( branchname );
2307 bname.ReplaceAll("*","");
2308 leaflist.ReplaceAll("*","");
2309 // Add the branch to the tree and indicate that the address
2310 // is that of a pointer to be dereferenced before using.
2311 branch1 = new TBranch(branch, bname, *((void**) pointer), leaflist, bufsize);
2312 TLeaf* leaf = (TLeaf*) branch1->GetListOfLeaves()->At(0);
2314 leaf->SetAddress((void**) pointer);
2315 blist->Add(branch1);
2316 }
2317 } else if (dm->IsBasic()) {
2318 // We have a basic type.
2319
2320 char vcode = DataTypeToChar((EDataType)code);
2321 if (vcode) {
2322 leaflist.Form("%s/%c", rdname, vcode);
2323 } else {
2324 Error("BranchOld", "Cannot create branch for rdname: %s code: %d", branchname.Data(), code);
2325 leaflist = "";
2326 }
2327 branch1 = new TBranch(branch, branchname, pointer, leaflist, bufsize);
2328 branch1->SetTitle(rdname);
2329 blist->Add(branch1);
2330 } else {
2331 // We have a class type.
2332 // Note: This cannot happen due to the rd->IsObject() test above.
2333 // FIXME: Put an error message here just in case.
2334 }
2335 if (branch1) {
2336 branch1->SetOffset(offset);
2337 } else {
2338 Warning("BranchOld", "Cannot process member: '%s'", rdname);
2339 }
2340 }
2341 if (delobj) {
2342 delete obj;
2343 obj = nullptr;
2344 }
2345 return branch;
2346}
2347
2348////////////////////////////////////////////////////////////////////////////////
2349/// Build the optional branch supporting the TRefTable.
2350/// This branch will keep all the information to find the branches
2351/// containing referenced objects.
2352///
2353/// At each Tree::Fill, the branch numbers containing the
2354/// referenced objects are saved to the TBranchRef basket.
2355/// When the Tree header is saved (via TTree::Write), the branch
2356/// is saved keeping the information with the pointers to the branches
2357/// having referenced objects.
2360{
2361 if (!fBranchRef) {
2362 fBranchRef = new TBranchRef(this);
2363 }
2364 return fBranchRef;
2365}
2366
2367////////////////////////////////////////////////////////////////////////////////
2368/// Create a new TTree BranchElement.
2369///
2370/// ## WARNING about this new function
2371///
2372/// This function is designed to replace the internal
2373/// implementation of the old TTree::Branch (whose implementation
2374/// has been moved to BranchOld).
2375///
2376/// NOTE: The 'Bronch' method supports only one possible calls
2377/// signature (where the object type has to be specified
2378/// explicitly and the address must be the address of a pointer).
2379/// For more flexibility use 'Branch'. Use Bronch only in (rare)
2380/// cases (likely to be legacy cases) where both the new and old
2381/// implementation of Branch needs to be used at the same time.
2382///
2383/// This function is far more powerful than the old Branch
2384/// function. It supports the full C++, including STL and has
2385/// the same behaviour in split or non-split mode. classname does
2386/// not have to derive from TObject. The function is based on
2387/// the new TStreamerInfo.
2388///
2389/// Build a TBranchElement for an object of class classname.
2390///
2391/// addr is the address of a pointer to an object of class
2392/// classname. The class dictionary must be available (ClassDef
2393/// in class header).
2394///
2395/// Note: See the comments in TBranchElement::SetAddress() for a more
2396/// detailed discussion of the meaning of the addr parameter.
2397///
2398/// This option requires access to the library where the
2399/// corresponding class is defined. Accessing one single data
2400/// member in the object implies reading the full object.
2401///
2402/// By default the branch buffers are stored in the same file as the Tree.
2403/// use TBranch::SetFile to specify a different file
2404///
2405/// IMPORTANT NOTE about branch names:
2406///
2407/// And in general, in case two or more master branches contain subbranches
2408/// with identical names, one must add a "." (dot) character at the end
2409/// of the master branch name. This will force the name of the subbranches
2410/// to be of the form `master.subbranch` instead of simply `subbranch`.
2411/// This situation happens when the top level object
2412/// has two or more members referencing the same class.
2413/// For example, if a Tree has two branches B1 and B2 corresponding
2414/// to objects of the same class MyClass, one can do:
2415/// ~~~ {.cpp}
2416/// tree.Branch("B1.","MyClass",&b1,8000,1);
2417/// tree.Branch("B2.","MyClass",&b2,8000,1);
2418/// ~~~
2419/// if MyClass has 3 members a,b,c, the two instructions above will generate
2420/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
2421///
2422/// bufsize is the buffer size in bytes for this branch
2423/// The default value is 32000 bytes and should be ok for most cases.
2424/// You can specify a larger value (e.g. 256000) if your Tree is not split
2425/// and each entry is large (Megabytes)
2426/// A small value for bufsize is optimum if you intend to access
2427/// the entries in the Tree randomly and your Tree is in split mode.
2428///
2429/// Use splitlevel < 0 instead of splitlevel=0 when the class
2430/// has a custom Streamer
2431///
2432/// Note: if the split level is set to the default (99), TTree::Branch will
2433/// not issue a warning if the class can not be split.
2435TBranch* TTree::Bronch(const char* name, const char* classname, void* addr, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2436{
2437 return BronchExec(name, classname, addr, true, bufsize, splitlevel);
2438}
2439
2440////////////////////////////////////////////////////////////////////////////////
2441/// Helper function implementing TTree::Bronch and TTree::Branch(const char *name, T &obj);
2443TBranch* TTree::BronchExec(const char* name, const char* classname, void* addr, bool isptrptr, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2444{
2445 TClass* cl = TClass::GetClass(classname);
2446 if (!cl) {
2447 Error("Bronch", "Cannot find class:%s", classname);
2448 return nullptr;
2449 }
2450
2451 //if splitlevel <= 0 and class has a custom Streamer, we must create
2452 //a TBranchObject. We cannot assume that TClass::ReadBuffer is consistent
2453 //with the custom Streamer. The penalty is that one cannot process
2454 //this Tree without the class library containing the class.
2455
2456 char* objptr = nullptr;
2457 if (!isptrptr) {
2458 objptr = (char*)addr;
2459 } else if (addr) {
2460 objptr = *((char**) addr);
2461 }
2462
2463 if (cl == TClonesArray::Class()) {
2465 if (!clones) {
2466 Error("Bronch", "Pointer to TClonesArray is null");
2467 return nullptr;
2468 }
2469 if (!clones->GetClass()) {
2470 Error("Bronch", "TClonesArray with no class defined in branch: %s", name);
2471 return nullptr;
2472 }
2473 if (!clones->GetClass()->HasDataMemberInfo()) {
2474 Error("Bronch", "TClonesArray with no dictionary defined in branch: %s", name);
2475 return nullptr;
2476 }
2477 bool hasCustomStreamer = clones->GetClass()->HasCustomStreamerMember();
2478 if (splitlevel > 0) {
2480 Warning("Bronch", "Using split mode on a class: %s with a custom Streamer", clones->GetClass()->GetName());
2481 } else {
2482 if (hasCustomStreamer) clones->BypassStreamer(false);
2483 TBranchObject *branch = new TBranchObject(this,name,classname,addr,bufsize,0,/*compress=*/ -1,isptrptr);
2485 return branch;
2486 }
2487 }
2488
2489 if (cl->GetCollectionProxy()) {
2491 //if (!collProxy) {
2492 // Error("Bronch", "%s is missing its CollectionProxy (for branch %s)", classname, name);
2493 //}
2494 TClass* inklass = collProxy->GetValueClass();
2495 if (!inklass && (collProxy->GetType() == 0)) {
2496 Error("Bronch", "%s with no class defined in branch: %s", classname, name);
2497 return nullptr;
2498 }
2499 if ((splitlevel > 0) && inklass && (inklass->GetCollectionProxy() == nullptr)) {
2501 if ((stl != ROOT::kSTLmap) && (stl != ROOT::kSTLmultimap)) {
2502 if (!inklass->HasDataMemberInfo()) {
2503 Error("Bronch", "Container with no dictionary defined in branch: %s", name);
2504 return nullptr;
2505 }
2506 if (inklass->HasCustomStreamerMember()) {
2507 Warning("Bronch", "Using split mode on a class: %s with a custom Streamer", inklass->GetName());
2508 }
2509 }
2510 }
2511 //-------------------------------------------------------------------------
2512 // If the splitting switch is enabled, the split level is big enough and
2513 // the collection contains pointers we can split it
2514 //////////////////////////////////////////////////////////////////////////
2515
2516 TBranch *branch;
2517 if( splitlevel > kSplitCollectionOfPointers && collProxy->HasPointers() )
2519 else
2522 if (isptrptr) {
2523 branch->SetAddress(addr);
2524 } else {
2525 branch->SetObject(addr);
2526 }
2527 return branch;
2528 }
2529
2530 bool hasCustomStreamer = false;
2531 if (!cl->HasDataMemberInfo() && !cl->GetCollectionProxy()) {
2532 Error("Bronch", "Cannot find dictionary for class: %s", classname);
2533 return nullptr;
2534 }
2535
2536 if (!cl->GetCollectionProxy() && cl->HasCustomStreamerMember()) {
2537 // Not an STL container and the linkdef file had a "-" after the class name.
2538 hasCustomStreamer = true;
2539 }
2540
2541 if (splitlevel < 0 || ((splitlevel == 0) && hasCustomStreamer && cl->IsTObject())) {
2544 return branch;
2545 }
2546
2547 if (cl == TClonesArray::Class()) {
2548 // Special case of TClonesArray.
2549 // No dummy object is created.
2550 // The streamer info is not rebuilt unoptimized.
2551 // No dummy top-level branch is created.
2552 // No splitting is attempted.
2555 if (isptrptr) {
2556 branch->SetAddress(addr);
2557 } else {
2558 branch->SetObject(addr);
2559 }
2560 return branch;
2561 }
2562
2563 //
2564 // If we are not given an object to use as an i/o buffer
2565 // then create a temporary one which we will delete just
2566 // before returning.
2567 //
2568
2569 bool delobj = false;
2570
2571 if (!objptr) {
2572 objptr = (char*) cl->New();
2573 delobj = true;
2574 }
2575
2576 //
2577 // Avoid splitting unsplittable classes.
2578 //
2579
2580 if ((splitlevel > 0) && !cl->CanSplit()) {
2581 if (splitlevel != 99) {
2582 Warning("Bronch", "%s cannot be split, resetting splitlevel to 0", cl->GetName());
2583 }
2584 splitlevel = 0;
2585 }
2586
2587 //
2588 // Make sure the streamer info is built and fetch it.
2589 //
2590 // If we are splitting, then make sure the streamer info
2591 // is built unoptimized (data members are not combined).
2592 //
2593
2595 if (!sinfo) {
2596 Error("Bronch", "Cannot build the StreamerInfo for class: %s", cl->GetName());
2597 return nullptr;
2598 }
2599
2600 //
2601 // Create a dummy top level branch object.
2602 //
2603
2604 Int_t id = -1;
2605 if (splitlevel > 0) {
2606 id = -2;
2607 }
2610
2611 //
2612 // Do splitting, if requested.
2613 //
2614
2616 branch->Unroll(name, cl, sinfo, objptr, bufsize, splitlevel);
2617 }
2618
2619 //
2620 // Setup our offsets into the user's i/o buffer.
2621 //
2622
2623 if (isptrptr) {
2624 branch->SetAddress(addr);
2625 } else {
2626 branch->SetObject(addr);
2627 }
2628
2629 if (delobj) {
2630 cl->Destructor(objptr);
2631 objptr = nullptr;
2632 }
2633
2634 return branch;
2635}
2636
2637////////////////////////////////////////////////////////////////////////////////
2638/// Browse content of the TTree.
2641{
2643 if (fUserInfo) {
2644 if (strcmp("TList",fUserInfo->GetName())==0) {
2645 fUserInfo->SetName("UserInfo");
2646 b->Add(fUserInfo);
2647 fUserInfo->SetName("TList");
2648 } else {
2649 b->Add(fUserInfo);
2650 }
2651 }
2652}
2653
2654////////////////////////////////////////////////////////////////////////////////
2655/// Build a Tree Index (default is TTreeIndex).
2656/// See a description of the parameters and functionality in
2657/// TTreeIndex::TTreeIndex().
2658///
2659/// The return value is the number of entries in the Index (< 0 indicates failure).
2660///
2661/// A TTreeIndex object pointed by fTreeIndex is created.
2662/// This object will be automatically deleted by the TTree destructor.
2663/// If an index is already existing, this is replaced by the new one without being
2664/// deleted. This behaviour prevents the deletion of a previously external index
2665/// assigned to the TTree via the TTree::SetTreeIndex() method.
2666/// \see TTree::SetTreeIndex()
2668Int_t TTree::BuildIndex(const char* majorname, const char* minorname /* = "0" */, bool long64major, bool long64minor)
2669{
2671 if (fTreeIndex->IsZombie()) {
2672 delete fTreeIndex;
2673 fTreeIndex = nullptr;
2674 return 0;
2675 }
2676 return fTreeIndex->GetN();
2677}
2678
2679////////////////////////////////////////////////////////////////////////////////
2680/// Build StreamerInfo for class cl.
2681/// pointer is an optional argument that may contain a pointer to an object of cl.
2683TStreamerInfo* TTree::BuildStreamerInfo(TClass* cl, void* pointer /* = 0 */, bool canOptimize /* = true */ )
2684{
2685 if (!cl) {
2686 return nullptr;
2687 }
2688 cl->BuildRealData(pointer);
2690
2691 // Create StreamerInfo for all base classes.
2692 TBaseClass* base = nullptr;
2693 TIter nextb(cl->GetListOfBases());
2694 while((base = (TBaseClass*) nextb())) {
2695 if (base->IsSTLContainer()) {
2696 continue;
2697 }
2698 TClass* clm = TClass::GetClass(base->GetName());
2700 }
2701 if (sinfo && fDirectory) {
2702 sinfo->ForceWriteInfo(fDirectory->GetFile());
2703 }
2704 return sinfo;
2705}
2706
2707////////////////////////////////////////////////////////////////////////////////
2708/// Enable the TTreeCache unless explicitly disabled for this TTree by
2709/// a prior call to `SetCacheSize(0)`.
2710/// If the environment variable `ROOT_TTREECACHE_SIZE` or the rootrc config
2711/// `TTreeCache.Size` has been set to zero, this call will over-ride them with
2712/// a value of 1.0 (i.e. use a cache size to hold 1 cluster)
2713///
2714/// Return true if there is a cache attached to the `TTree` (either pre-exisiting
2715/// or created as part of this call)
2716bool TTree::EnableCache()
2717{
2718 TFile* file = GetCurrentFile();
2719 if (!file)
2720 return false;
2721 // Check for an existing cache
2722 TTreeCache* pf = GetReadCache(file);
2723 if (pf)
2724 return true;
2725 if (fCacheUserSet && fCacheSize == 0)
2726 return false;
2727 return (0 == SetCacheSizeAux(true, -1));
2728}
2729
2730////////////////////////////////////////////////////////////////////////////////
2731/// Called by TTree::Fill() when file has reached its maximum fgMaxTreeSize.
2732/// Create a new file. If the original file is named "myfile.root",
2733/// subsequent files are named "myfile_1.root", "myfile_2.root", etc.
2734///
2735/// Returns a pointer to the new file.
2736///
2737/// Currently, the automatic change of file is restricted
2738/// to the case where the tree is in the top level directory.
2739/// The file should not contain sub-directories.
2740///
2741/// Before switching to a new file, the tree header is written
2742/// to the current file, then the current file is closed.
2743///
2744/// To process the multiple files created by ChangeFile, one must use
2745/// a TChain.
2746///
2747/// The new file name has a suffix "_N" where N is equal to fFileNumber+1.
2748/// By default a Root session starts with fFileNumber=0. One can set
2749/// fFileNumber to a different value via TTree::SetFileNumber.
2750/// In case a file named "_N" already exists, the function will try
2751/// a file named "__N", then "___N", etc.
2752///
2753/// fgMaxTreeSize can be set via the static function TTree::SetMaxTreeSize.
2754/// The default value of fgMaxTreeSize is 100 Gigabytes.
2755///
2756/// If the current file contains other objects like TH1 and TTree,
2757/// these objects are automatically moved to the new file.
2758///
2759/// \warning Be careful when writing the final Tree header to the file!
2760/// Don't do:
2761/// ~~~ {.cpp}
2762/// TFile *file = new TFile("myfile.root","recreate");
2763/// TTree *T = new TTree("T","title");
2764/// T->Fill(); // Loop
2765/// file->Write();
2766/// file->Close();
2767/// ~~~
2768/// \warning but do the following:
2769/// ~~~ {.cpp}
2770/// TFile *file = new TFile("myfile.root","recreate");
2771/// TTree *T = new TTree("T","title");
2772/// T->Fill(); // Loop
2773/// file = T->GetCurrentFile(); // To get the pointer to the current file
2774/// file->Write();
2775/// file->Close();
2776/// ~~~
2777///
2778/// \note This method is never called if the input file is a `TMemFile` or derivate.
2781{
2782 // Changing file clashes with the design of TMemFile and derivates, see #6523,
2783 // as well as with TFileMerger operations, see #6640.
2784 if ((dynamic_cast<TMemFile *>(file)) || file->TestBit(TFile::kCancelTTreeChangeRequest))
2785 return file;
2786 file->cd();
2787 Write();
2788 Reset();
2789 constexpr auto kBufSize = 2000;
2790 char* fname = new char[kBufSize];
2791 ++fFileNumber;
2792 char uscore[10];
2793 for (Int_t i = 0; i < 10; ++i) {
2794 uscore[i] = 0;
2795 }
2796 Int_t nus = 0;
2797 // Try to find a suitable file name that does not already exist.
2798 while (nus < 10) {
2799 uscore[nus] = '_';
2800 fname[0] = 0;
2801 strlcpy(fname, file->GetName(), kBufSize);
2802
2803 if (fFileNumber > 1) {
2804 char* cunder = strrchr(fname, '_');
2805 if (cunder) {
2807 const char* cdot = strrchr(file->GetName(), '.');
2808 if (cdot) {
2810 }
2811 } else {
2812 char fcount[21];
2813 snprintf(fcount,21, "%s%d", uscore, fFileNumber);
2815 }
2816 } else {
2817 char* cdot = strrchr(fname, '.');
2818 if (cdot) {
2820 strlcat(fname, strrchr(file->GetName(), '.'), kBufSize);
2821 } else {
2822 char fcount[21];
2823 snprintf(fcount,21, "%s%d", uscore, fFileNumber);
2825 }
2826 }
2828 break;
2829 }
2830 ++nus;
2831 Warning("ChangeFile", "file %s already exists, trying with %d underscores", fname, nus + 1);
2832 }
2834 TFile* newfile = TFile::Open(fname, "recreate", "chain files", compress);
2835 if (newfile == nullptr) {
2836 Error("Fill","Failed to open new file %s, continuing as a memory tree.",fname);
2837 } else {
2838 Printf("Fill: Switching to new file: %s", fname);
2839 }
2840 // The current directory may contain histograms and trees.
2841 // These objects must be moved to the new file.
2842 TBranch* branch = nullptr;
2843 TObject* obj = nullptr;
2844 while ((obj = file->GetList()->First())) {
2845 file->Remove(obj);
2846 // Histogram: just change the directory.
2847 if (obj->InheritsFrom("TH1")) {
2848 gROOT->ProcessLine(TString::Format("((%s*)0x%zx)->SetDirectory((TDirectory*)0x%zx);", obj->ClassName(), (size_t) obj, (size_t) newfile));
2849 continue;
2850 }
2851 // Tree: must save all trees in the old file, reset them.
2852 if (obj->InheritsFrom(TTree::Class())) {
2853 TTree* t = (TTree*) obj;
2854 if (t != this) {
2855 t->AutoSave();
2856 t->Reset();
2858 }
2861 while ((branch = (TBranch*)nextb())) {
2862 branch->SetFile(newfile);
2863 }
2864 if (t->GetBranchRef()) {
2865 t->GetBranchRef()->SetFile(newfile);
2866 }
2867 continue;
2868 }
2869 // Not a TH1 or a TTree, move object to new file.
2870 if (newfile) newfile->Append(obj);
2871 file->Remove(obj);
2872 }
2873 file->TObject::Delete();
2874 file = nullptr;
2875 delete[] fname;
2876 fname = nullptr;
2877 return newfile;
2878}
2879
2880////////////////////////////////////////////////////////////////////////////////
2881/// Check whether or not the address described by the last 3 parameters
2882/// matches the content of the branch. If a Data Model Evolution conversion
2883/// is involved, reset the fInfo of the branch.
2884/// The return values are:
2885//
2886/// - kMissingBranch (-5) : Missing branch
2887/// - kInternalError (-4) : Internal error (could not find the type corresponding to a data type number)
2888/// - kMissingCompiledCollectionProxy (-3) : Missing compiled collection proxy for a compiled collection
2889/// - kMismatch (-2) : Non-Class Pointer type given does not match the type expected by the branch
2890/// - kClassMismatch (-1) : Class Pointer type given does not match the type expected by the branch
2891/// - kMatch (0) : perfect match
2892/// - kMatchConversion (1) : match with (I/O) conversion
2893/// - kMatchConversionCollection (2) : match with (I/O) conversion of the content of a collection
2894/// - kMakeClass (3) : MakeClass mode so we can not check.
2895/// - kVoidPtr (4) : void* passed so no check was made.
2896/// - kNoCheck (5) : Underlying TBranch not yet available so no check was made.
2897/// In addition this can be multiplexed with the two bits:
2898/// - kNeedEnableDecomposedObj : in order for the address (type) to be 'usable' the branch needs to be in Decomposed Object (aka MakeClass) mode.
2899/// - kNeedDisableDecomposedObj : in order for the address (type) to be 'usable' the branch needs to not be in Decomposed Object (aka MakeClass) mode.
2900/// This bits can be masked out by using kDecomposedObjMask
2903{
2904 if (GetMakeClass()) {
2905 // If we are in MakeClass mode so we do not really use classes.
2906 return kMakeClass;
2907 }
2908
2909 // Let's determine what we need!
2910 TClass* expectedClass = nullptr;
2912 if (0 != branch->GetExpectedType(expectedClass,expectedType) ) {
2913 // Something went wrong, the warning message has already been issued.
2914 return kInternalError;
2915 }
2916 bool isBranchElement = branch->InheritsFrom( TBranchElement::Class() );
2917 if (expectedClass && datatype == kOther_t && ptrClass == nullptr) {
2918 if (isBranchElement) {
2920 bEl->SetTargetClass( expectedClass->GetName() );
2921 }
2922 if (expectedClass && expectedClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(expectedClass->GetCollectionProxy())) {
2923 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2924 "The class expected (%s) refers to an stl collection and do not have a compiled CollectionProxy. "
2925 "Please generate the dictionary for this class (%s)",
2926 branch->GetName(), expectedClass->GetName(), expectedClass->GetName());
2928 }
2929 if (!expectedClass->IsLoaded()) {
2930 // The originally expected class does not have a dictionary, it is then plausible that the pointer being passed is the right type
2931 // (we really don't know). So let's express that.
2932 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2933 "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."
2934 "Please generate the dictionary for this class (%s)",
2935 branch->GetName(), expectedClass->GetName(), expectedClass->GetName());
2936 } else {
2937 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2938 "This is probably due to a missing dictionary, the original data class for this branch is %s.", branch->GetName(), expectedClass->GetName());
2939 }
2940 return kClassMismatch;
2941 }
2942 if (expectedClass && ptrClass && (branch->GetMother() == branch)) {
2943 // Top Level branch
2944 if (!isptr) {
2945 Error("SetBranchAddress", "The address for \"%s\" should be the address of a pointer!", branch->GetName());
2946 }
2947 }
2948 if (expectedType == kFloat16_t) {
2950 }
2951 if (expectedType == kDouble32_t) {
2953 }
2954 if (datatype == kFloat16_t) {
2956 }
2957 if (datatype == kDouble32_t) {
2959 }
2960
2961 /////////////////////////////////////////////////////////////////////////////
2962 // Deal with the class renaming
2963 /////////////////////////////////////////////////////////////////////////////
2964
2965 if( expectedClass && ptrClass &&
2968 ptrClass->GetSchemaRules() &&
2969 ptrClass->GetSchemaRules()->HasRuleWithSourceClass( expectedClass->GetName() ) ) {
2971
2972 if ( ptrClass->GetCollectionProxy() && expectedClass->GetCollectionProxy() ) {
2973 if (gDebug > 7)
2974 Info("SetBranchAddress", "Matching STL collection (at least according to the SchemaRuleSet when "
2975 "reading a %s into a %s",expectedClass->GetName(),ptrClass->GetName());
2976
2977 bEl->SetTargetClass( ptrClass->GetName() );
2978 return kMatchConversion;
2979
2980 } else if ( !ptrClass->GetConversionStreamerInfo( expectedClass, bEl->GetClassVersion() ) &&
2981 !ptrClass->FindConversionStreamerInfo( expectedClass, bEl->GetCheckSum() ) ) {
2982 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());
2983
2984 bEl->SetTargetClass( expectedClass->GetName() );
2985 return kClassMismatch;
2986 }
2987 else {
2988
2989 bEl->SetTargetClass( ptrClass->GetName() );
2990 return kMatchConversion;
2991 }
2992
2993 } else if (expectedClass && ptrClass && !expectedClass->InheritsFrom(ptrClass)) {
2994
2995 if (expectedClass->GetCollectionProxy() && ptrClass->GetCollectionProxy() &&
2997 expectedClass->GetCollectionProxy()->GetValueClass() &&
2998 ptrClass->GetCollectionProxy()->GetValueClass() )
2999 {
3000 // In case of collection, we know how to convert them, if we know how to convert their content.
3001 // NOTE: we need to extend this to std::pair ...
3002
3003 TClass *onfileValueClass = expectedClass->GetCollectionProxy()->GetValueClass();
3004 TClass *inmemValueClass = ptrClass->GetCollectionProxy()->GetValueClass();
3005
3006 if (inmemValueClass->GetSchemaRules() &&
3007 inmemValueClass->GetSchemaRules()->HasRuleWithSourceClass(onfileValueClass->GetName() ) )
3008 {
3010 bEl->SetTargetClass( ptrClass->GetName() );
3012 }
3013 }
3014
3015 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());
3016 if (isBranchElement) {
3018 bEl->SetTargetClass( expectedClass->GetName() );
3019 }
3020 return kClassMismatch;
3021
3022 } else if ((expectedType != kOther_t) && (datatype != kOther_t) && (expectedType != kNoType_t) && (datatype != kNoType_t) && (expectedType != datatype)) {
3023 if (datatype != kChar_t) {
3024 // For backward compatibility we assume that (char*) was just a cast and/or a generic address
3025 Error("SetBranchAddress", "The pointer type given \"%s\" (%d) does not correspond to the type needed \"%s\" (%d) by the branch: %s",
3027 return kMismatch;
3028 }
3029 } else if ((expectedClass && (datatype != kOther_t && datatype != kNoType_t && datatype != kInt_t)) ||
3031 // Sometime a null pointer can look an int, avoid complaining in that case.
3032 if (expectedClass) {
3033 Error("SetBranchAddress", "The pointer type given \"%s\" (%d) does not correspond to the type needed \"%s\" by the branch: %s",
3034 TDataType::GetTypeName(datatype), datatype, expectedClass->GetName(), branch->GetName());
3035 if (isBranchElement) {
3037 bEl->SetTargetClass( expectedClass->GetName() );
3038 }
3039 } else {
3040 // 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
3041 // a struct).
3042 bool found = false;
3043 if (ptrClass->IsLoaded()) {
3044 TIter next(ptrClass->GetListOfRealData());
3045 TRealData *rdm;
3046 while ((rdm = (TRealData*)next())) {
3047 if (rdm->GetThisOffset() == 0) {
3048 TDataType *dmtype = rdm->GetDataMember()->GetDataType();
3049 if (dmtype) {
3050 EDataType etype = (EDataType)dmtype->GetType();
3051 if (etype == expectedType) {
3052 found = true;
3053 }
3054 }
3055 break;
3056 }
3057 }
3058 } else {
3059 TIter next(ptrClass->GetListOfDataMembers());
3060 TDataMember *dm;
3061 while ((dm = (TDataMember*)next())) {
3062 if (dm->GetOffset() == 0) {
3063 TDataType *dmtype = dm->GetDataType();
3064 if (dmtype) {
3065 EDataType etype = (EDataType)dmtype->GetType();
3066 if (etype == expectedType) {
3067 found = true;
3068 }
3069 }
3070 break;
3071 }
3072 }
3073 }
3074 if (found) {
3075 // let's check the size.
3076 TLeaf *last = (TLeaf*)branch->GetListOfLeaves()->Last();
3077 long len = last->GetOffset() + last->GetLenType() * last->GetLen();
3078 if (len <= ptrClass->Size()) {
3079 return kMatch;
3080 }
3081 }
3082 Error("SetBranchAddress", "The pointer type given \"%s\" does not correspond to the type needed \"%s\" (%d) by the branch: %s",
3084 }
3085 return kMismatch;
3086 }
3087 if (expectedClass && expectedClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(expectedClass->GetCollectionProxy())) {
3088 Error("SetBranchAddress", writeStlWithoutProxyMsg,
3089 expectedClass->GetName(), branch->GetName(), expectedClass->GetName());
3090 if (isBranchElement) {
3092 bEl->SetTargetClass( expectedClass->GetName() );
3093 }
3095 }
3096 if (isBranchElement) {
3097 if (expectedClass) {
3099 bEl->SetTargetClass( expectedClass->GetName() );
3100 } else if (expectedType != kNoType_t && expectedType != kOther_t) {
3102 }
3103 }
3104 return kMatch;
3105}
3106
3107////////////////////////////////////////////////////////////////////////////////
3108/// Create a clone of this tree and copy nentries.
3109///
3110/// By default copy all entries.
3111/// The compression level of the cloned tree is set to the destination
3112/// file's compression level.
3113///
3114/// NOTE: Only active branches are copied. See TTree::SetBranchStatus for more
3115/// information and usage regarding the (de)activation of branches. More
3116/// examples are provided in the tutorials listed below.
3117///
3118/// NOTE: If the TTree is a TChain, the structure of the first TTree
3119/// is used for the copy.
3120///
3121/// IMPORTANT: The cloned tree stays connected with this tree until
3122/// this tree is deleted. In particular, any changes in
3123/// branch addresses in this tree are forwarded to the
3124/// clone trees, unless a branch in a clone tree has had
3125/// its address changed, in which case that change stays in
3126/// effect. When this tree is deleted, all the addresses of
3127/// the cloned tree are reset to their default values.
3128///
3129/// If 'option' contains the word 'fast' and nentries is -1, the
3130/// cloning will be done without unzipping or unstreaming the baskets
3131/// (i.e., a direct copy of the raw bytes on disk).
3132///
3133/// When 'fast' is specified, 'option' can also contain a sorting
3134/// order for the baskets in the output file.
3135///
3136/// There are currently 3 supported sorting order:
3137///
3138/// - SortBasketsByOffset (the default)
3139/// - SortBasketsByBranch
3140/// - SortBasketsByEntry
3141///
3142/// When using SortBasketsByOffset the baskets are written in the
3143/// output file in the same order as in the original file (i.e. the
3144/// baskets are sorted by their offset in the original file; Usually
3145/// this also means that the baskets are sorted by the index/number of
3146/// the _last_ entry they contain)
3147///
3148/// When using SortBasketsByBranch all the baskets of each individual
3149/// branches are stored contiguously. This tends to optimize reading
3150/// speed when reading a small number (1->5) of branches, since all
3151/// their baskets will be clustered together instead of being spread
3152/// across the file. However it might decrease the performance when
3153/// reading more branches (or the full entry).
3154///
3155/// When using SortBasketsByEntry the baskets with the lowest starting
3156/// entry are written first. (i.e. the baskets are sorted by the
3157/// index/number of the first entry they contain). This means that on
3158/// the file the baskets will be in the order in which they will be
3159/// needed when reading the whole tree sequentially.
3160///
3161/// For examples of CloneTree, see tutorials:
3162///
3163/// - copytree.C:
3164/// A macro to copy a subset of a TTree to a new TTree.
3165/// The input file has been generated by the program in
3166/// $ROOTSYS/test/Event with: Event 1000 1 1 1
3167///
3168/// - copytree2.C:
3169/// A macro to copy a subset of a TTree to a new TTree.
3170/// One branch of the new Tree is written to a separate file.
3171/// The input file has been generated by the program in
3172/// $ROOTSYS/test/Event with: Event 1000 1 1 1
3174TTree* TTree::CloneTree(Long64_t nentries /* = -1 */, Option_t* option /* = "" */)
3175{
3176 // Options
3177 bool fastClone = false;
3178
3179 TString opt = option;
3180 opt.ToLower();
3181 if (opt.Contains("fast")) {
3182 fastClone = true;
3183 }
3184
3185 // If we are a chain, switch to the first tree.
3186 if (fEntries > 0) {
3187 const auto res = LoadTree(0);
3188 if (res < -2 || res == -1) {
3189 // -1 is not accepted, it happens when no trees were defined
3190 // -2 is the only acceptable error, when the chain has zero entries, but tree(s) were defined
3191 // Other errors (-3, ...) are not accepted
3192 Error("CloneTree", "returning nullptr since LoadTree failed with code %lld.", res);
3193 return nullptr;
3194 }
3195 }
3196
3197 // Note: For a tree we get the this pointer, for
3198 // a chain we get the chain's current tree.
3199 TTree* thistree = GetTree();
3200
3201 // We will use this to override the IO features on the cloned branches.
3203 ;
3204
3205 // Note: For a chain, the returned clone will be
3206 // a clone of the chain's first tree.
3207 TTree* newtree = (TTree*) thistree->Clone();
3208 if (!newtree) {
3209 return nullptr;
3210 }
3211
3212 // The clone should not delete any objects allocated by SetAddress().
3213 TObjArray* branches = newtree->GetListOfBranches();
3214 Int_t nb = branches->GetEntriesFast();
3215 for (Int_t i = 0; i < nb; ++i) {
3216 TBranch* br = (TBranch*) branches->UncheckedAt(i);
3217 if (br->InheritsFrom(TBranchElement::Class())) {
3218 ((TBranchElement*) br)->ResetDeleteObject();
3219 }
3220 }
3221
3222 // Add the new tree to the list of clones so that
3223 // we can later inform it of changes to branch addresses.
3224 thistree->AddClone(newtree);
3225 if (thistree != this) {
3226 // In case this object is a TChain, add the clone
3227 // also to the TChain's list of clones.
3229 }
3230
3231 newtree->Reset();
3232
3233 TDirectory* ndir = newtree->GetDirectory();
3234 TFile* nfile = nullptr;
3235 if (ndir) {
3236 nfile = ndir->GetFile();
3237 }
3238 Int_t newcomp = -1;
3239 if (nfile) {
3240 newcomp = nfile->GetCompressionSettings();
3241 }
3242
3243 //
3244 // Delete non-active branches from the clone.
3245 //
3246 // Note: If we are a chain, this does nothing
3247 // since chains have no leaves.
3248 TObjArray* leaves = newtree->GetListOfLeaves();
3249 Int_t nleaves = leaves->GetEntriesFast();
3250 for (Int_t lndx = 0; lndx < nleaves; ++lndx) {
3251 TLeaf* leaf = (TLeaf*) leaves->UncheckedAt(lndx);
3252 if (!leaf) {
3253 continue;
3254 }
3255 TBranch* branch = leaf->GetBranch();
3256 if (branch && (newcomp > -1)) {
3257 branch->SetCompressionSettings(newcomp);
3258 }
3259 if (branch) branch->SetIOFeatures(features);
3260 if (!branch || !branch->TestBit(kDoNotProcess)) {
3261 continue;
3262 }
3263 // size might change at each iteration of the loop over the leaves.
3264 nb = branches->GetEntriesFast();
3265 for (Long64_t i = 0; i < nb; ++i) {
3266 TBranch* br = (TBranch*) branches->UncheckedAt(i);
3267 if (br == branch) {
3268 branches->RemoveAt(i);
3269 delete br;
3270 br = nullptr;
3271 branches->Compress();
3272 break;
3273 }
3274 TObjArray* lb = br->GetListOfBranches();
3275 Int_t nb1 = lb->GetEntriesFast();
3276 for (Int_t j = 0; j < nb1; ++j) {
3277 TBranch* b1 = (TBranch*) lb->UncheckedAt(j);
3278 if (!b1) {
3279 continue;
3280 }
3281 if (b1 == branch) {
3282 lb->RemoveAt(j);
3283 delete b1;
3284 b1 = nullptr;
3285 lb->Compress();
3286 break;
3287 }
3289 Int_t nb2 = lb1->GetEntriesFast();
3290 for (Int_t k = 0; k < nb2; ++k) {
3291 TBranch* b2 = (TBranch*) lb1->UncheckedAt(k);
3292 if (!b2) {
3293 continue;
3294 }
3295 if (b2 == branch) {
3296 lb1->RemoveAt(k);
3297 delete b2;
3298 b2 = nullptr;
3299 lb1->Compress();
3300 break;
3301 }
3302 }
3303 }
3304 }
3305 }
3306 leaves->Compress();
3307
3308 // Copy MakeClass status.
3309 newtree->SetMakeClass(fMakeClass);
3310
3311 // Copy branch addresses.
3313
3314 //
3315 // Copy entries if requested.
3316 //
3317
3318 if (nentries != 0) {
3319 if (fastClone && (nentries < 0)) {
3320 if ( newtree->CopyEntries( this, -1, option, false ) < 0 ) {
3321 // There was a problem!
3322 Error("CloneTTree", "TTree has not been cloned\n");
3323 delete newtree;
3324 newtree = nullptr;
3325 return nullptr;
3326 }
3327 } else {
3328 newtree->CopyEntries( this, nentries, option, false );
3329 }
3330 }
3331
3332 return newtree;
3333}
3334
3335////////////////////////////////////////////////////////////////////////////////
3336/// Set branch addresses of passed tree equal to ours.
3337/// If undo is true, reset the branch addresses instead of copying them.
3338/// This ensures 'separation' of a cloned tree from its original.
3340void TTree::CopyAddresses(TTree* tree, bool undo)
3341{
3342 // Copy branch addresses starting from branches.
3344 Int_t nbranches = branches->GetEntriesFast();
3345 for (Int_t i = 0; i < nbranches; ++i) {
3346 TBranch* branch = (TBranch*) branches->UncheckedAt(i);
3347 if (branch->TestBit(kDoNotProcess)) {
3348 continue;
3349 }
3350 if (undo) {
3351 TBranch* br = tree->GetBranch(branch->GetName());
3352 tree->ResetBranchAddress(br);
3353 } else {
3354 char* addr = branch->GetAddress();
3355 if (!addr) {
3356 if (branch->IsA() == TBranch::Class()) {
3357 // If the branch was created using a leaflist, the branch itself may not have
3358 // an address but the leaf might already.
3359 TLeaf *firstleaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
3360 if (!firstleaf || firstleaf->GetValuePointer()) {
3361 // Either there is no leaf (and thus no point in copying the address)
3362 // or the leaf has an address but we can not copy it via the branche
3363 // this will be copied via the next loop (over the leaf).
3364 continue;
3365 }
3366 }
3367 // Note: This may cause an object to be allocated.
3368 branch->SetAddress(nullptr);
3369 addr = branch->GetAddress();
3370 }
3371 TBranch* br = tree->GetBranch(branch->GetFullName());
3372 if (br) {
3373 if (br->GetMakeClass() != branch->GetMakeClass())
3374 br->SetMakeClass(branch->GetMakeClass());
3375 br->SetAddress(addr);
3376 // The copy does not own any object allocated by SetAddress().
3377 if (br->InheritsFrom(TBranchElement::Class())) {
3378 ((TBranchElement*) br)->ResetDeleteObject();
3379 }
3380 } else {
3381 Warning("CopyAddresses", "Could not find branch named '%s' in tree named '%s'", branch->GetName(), tree->GetName());
3382 }
3383 }
3384 }
3385
3386 // Copy branch addresses starting from leaves.
3388 Int_t ntleaves = tleaves->GetEntriesFast();
3389 std::set<TLeaf*> updatedLeafCount;
3390 for (Int_t i = 0; i < ntleaves; ++i) {
3391 TLeaf* tleaf = (TLeaf*) tleaves->UncheckedAt(i);
3392 TBranch* tbranch = tleaf->GetBranch();
3393 TBranch* branch = GetBranch(tbranch->GetName());
3394 if (!branch) {
3395 continue;
3396 }
3397 TLeaf* leaf = branch->GetLeaf(tleaf->GetName());
3398 if (!leaf) {
3399 continue;
3400 }
3401 if (branch->TestBit(kDoNotProcess)) {
3402 continue;
3403 }
3404 if (undo) {
3405 // Now we know whether the address has been transferred
3407 } else {
3408 TBranchElement *mother = dynamic_cast<TBranchElement*>(leaf->GetBranch()->GetMother());
3409 bool needAddressReset = false;
3410 if (leaf->GetLeafCount() && (leaf->TestBit(TLeaf::kNewValue) || !leaf->GetValuePointer() || (mother && mother->IsObjectOwner())) && tleaf->GetLeafCount())
3411 {
3412 // If it is an array and it was allocated by the leaf itself,
3413 // let's make sure it is large enough for the incoming data.
3414 if (leaf->GetLeafCount()->GetMaximum() < tleaf->GetLeafCount()->GetMaximum()) {
3415 leaf->GetLeafCount()->IncludeRange( tleaf->GetLeafCount() );
3416 updatedLeafCount.insert(leaf->GetLeafCount());
3417 needAddressReset = true;
3418 } else {
3419 needAddressReset = (updatedLeafCount.find(leaf->GetLeafCount()) != updatedLeafCount.end());
3420 }
3421 }
3422 if (needAddressReset && leaf->GetValuePointer()) {
3423 if (leaf->IsA() == TLeafElement::Class() && mother)
3424 mother->ResetAddress();
3425 else
3426 leaf->SetAddress(nullptr);
3427 }
3428 if (!branch->GetAddress() && !leaf->GetValuePointer()) {
3429 // We should attempts to set the address of the branch.
3430 // something like:
3431 //(TBranchElement*)branch->GetMother()->SetAddress(0)
3432 //plus a few more subtleties (see TBranchElement::GetEntry).
3433 //but for now we go the simplest route:
3434 //
3435 // Note: This may result in the allocation of an object.
3436 branch->SetupAddresses();
3437 }
3438 if (branch->GetAddress()) {
3439 tree->SetBranchAddress(branch->GetName(), (void*) branch->GetAddress());
3440 TBranch* br = tree->GetBranch(branch->GetName());
3441 if (br) {
3442 if (br->IsA() != branch->IsA()) {
3443 Error(
3444 "CopyAddresses",
3445 "Branch kind mismatch between input tree '%s' and output tree '%s' for branch '%s': '%s' vs '%s'",
3446 tree->GetName(), br->GetTree()->GetName(), br->GetName(), branch->IsA()->GetName(),
3447 br->IsA()->GetName());
3448 }
3449 // The copy does not own any object allocated by SetAddress().
3450 // FIXME: We do too much here, br may not be a top-level branch.
3451 if (br->InheritsFrom(TBranchElement::Class())) {
3452 ((TBranchElement*) br)->ResetDeleteObject();
3453 }
3454 } else {
3455 Warning("CopyAddresses", "Could not find branch named '%s' in tree named '%s'", branch->GetName(), tree->GetName());
3456 }
3457 } else {
3458 tleaf->SetAddress(leaf->GetValuePointer());
3459 }
3460 }
3461 }
3462
3463 if (undo &&
3464 ( tree->IsA()->InheritsFrom("TNtuple") || tree->IsA()->InheritsFrom("TNtupleD") )
3465 ) {
3466 tree->ResetBranchAddresses();
3467 }
3468}
3469
3470namespace {
3471
3472 enum EOnIndexError { kDrop, kKeep, kBuild };
3473
3474 bool R__HandleIndex(EOnIndexError onIndexError, TTree *newtree, TTree *oldtree)
3475 {
3476 // Return true if we should continue to handle indices, false otherwise.
3477
3478 bool withIndex = true;
3479
3480 if ( newtree->GetTreeIndex() ) {
3481 if ( oldtree->GetTree()->GetTreeIndex() == nullptr ) {
3482 switch (onIndexError) {
3483 case kDrop:
3484 delete newtree->GetTreeIndex();
3485 newtree->SetTreeIndex(nullptr);
3486 withIndex = false;
3487 break;
3488 case kKeep:
3489 // Nothing to do really.
3490 break;
3491 case kBuild:
3492 // Build the index then copy it
3493 if (oldtree->GetTree()->BuildIndex(newtree->GetTreeIndex()->GetMajorName(), newtree->GetTreeIndex()->GetMinorName())) {
3494 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3495 // Clean up
3496 delete oldtree->GetTree()->GetTreeIndex();
3497 oldtree->GetTree()->SetTreeIndex(nullptr);
3498 }
3499 break;
3500 }
3501 } else {
3502 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3503 }
3504 } else if ( oldtree->GetTree()->GetTreeIndex() != nullptr ) {
3505 // We discover the first index in the middle of the chain.
3506 switch (onIndexError) {
3507 case kDrop:
3508 // Nothing to do really.
3509 break;
3510 case kKeep: {
3511 TVirtualIndex *index = (TVirtualIndex*) oldtree->GetTree()->GetTreeIndex()->Clone();
3512 index->SetTree(newtree);
3513 newtree->SetTreeIndex(index);
3514 break;
3515 }
3516 case kBuild:
3517 if (newtree->GetEntries() == 0) {
3518 // Start an index.
3519 TVirtualIndex *index = (TVirtualIndex*) oldtree->GetTree()->GetTreeIndex()->Clone();
3520 index->SetTree(newtree);
3521 newtree->SetTreeIndex(index);
3522 } else {
3523 // Build the index so far.
3524 if (newtree->BuildIndex(oldtree->GetTree()->GetTreeIndex()->GetMajorName(), oldtree->GetTree()->GetTreeIndex()->GetMinorName())) {
3525 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3526 }
3527 }
3528 break;
3529 }
3530 } else if ( onIndexError == kDrop ) {
3531 // There is no index on this or on tree->GetTree(), we know we have to ignore any further
3532 // index
3533 withIndex = false;
3534 }
3535 return withIndex;
3536 }
3537}
3538
3539////////////////////////////////////////////////////////////////////////////////
3540/// Copy nentries from given tree to this tree.
3541/// This routines assumes that the branches that intended to be copied are
3542/// already connected. The typical case is that this tree was created using
3543/// tree->CloneTree(0).
3544///
3545/// By default copy all entries.
3546///
3547/// Returns number of bytes copied to this tree.
3548///
3549/// If 'option' contains the word 'fast' and nentries is -1, the cloning will be
3550/// done without unzipping or unstreaming the baskets (i.e., a direct copy of the
3551/// raw bytes on disk).
3552///
3553/// When 'fast' is specified, 'option' can also contains a sorting order for the
3554/// baskets in the output file.
3555///
3556/// There are currently 3 supported sorting order:
3557///
3558/// - SortBasketsByOffset (the default)
3559/// - SortBasketsByBranch
3560/// - SortBasketsByEntry
3561///
3562/// See TTree::CloneTree for a detailed explanation of the semantics of these 3 options.
3563///
3564/// If the tree or any of the underlying tree of the chain has an index, that index and any
3565/// index in the subsequent underlying TTree objects will be merged.
3566///
3567/// There are currently three 'options' to control this merging:
3568/// - NoIndex : all the TTreeIndex object are dropped.
3569/// - DropIndexOnError : if any of the underlying TTree object do no have a TTreeIndex,
3570/// they are all dropped.
3571/// - AsIsIndexOnError [default]: In case of missing TTreeIndex, the resulting TTree index has gaps.
3572/// - BuildIndexOnError : If any of the underlying TTree objects do not have a TTreeIndex,
3573/// all TTreeIndex are 'ignored' and the missing piece are rebuilt.
3575Long64_t TTree::CopyEntries(TTree* tree, Long64_t nentries /* = -1 */, Option_t* option /* = "" */, bool needCopyAddresses /* = false */)
3576{
3577 if (!tree) {
3578 return 0;
3579 }
3580 // Options
3581 TString opt = option;
3582 opt.ToLower();
3583 bool fastClone = opt.Contains("fast");
3584 bool withIndex = !opt.Contains("noindex");
3585 EOnIndexError onIndexError;
3586 if (opt.Contains("asisindex")) {
3588 } else if (opt.Contains("buildindex")) {
3590 } else if (opt.Contains("dropindex")) {
3592 } else {
3594 }
3595 Ssiz_t cacheSizeLoc = opt.Index("cachesize=");
3596 Long64_t cacheSize = -1;
3598 // If the parse faile, cacheSize stays at -1.
3599 Ssiz_t cacheSizeEnd = opt.Index(" ",cacheSizeLoc+10) - (cacheSizeLoc+10);
3603 Warning("CopyEntries","The cachesize option can not be parsed: %s. The default size will be used.",cacheSizeStr.String().Data());
3605 double m;
3606 const char *munit = nullptr;
3607 ROOT::ToHumanReadableSize(std::numeric_limits<decltype(cacheSize)>::max(),false,&m,&munit);
3608
3609 Warning("CopyEntries","The cachesize option is too large: %s (%g%s max). The default size will be used.",cacheSizeStr.String().Data(),m,munit);
3610 }
3611 }
3612 if (gDebug > 0 && cacheSize != -1) Info("CopyEntries","Using Cache size: %lld\n",cacheSize);
3613
3614 Long64_t nbytes = 0;
3616 if (nentries < 0) {
3618 } else if (nentries > treeEntries) {
3620 }
3621
3623 // Quickly copy the basket without decompression and streaming.
3625 for (Long64_t i = 0; i < nentries; i += tree->GetTree()->GetEntries()) {
3626 if (tree->LoadTree(i) < 0) {
3627 break;
3628 }
3629 if ( withIndex ) {
3630 withIndex = R__HandleIndex( onIndexError, this, tree );
3631 }
3632 if (this->GetDirectory()) {
3633 TFile* file2 = this->GetDirectory()->GetFile();
3634 if (file2 && (file2->GetEND() > TTree::GetMaxTreeSize())) {
3635 if (this->GetDirectory() == (TDirectory*) file2) {
3636 this->ChangeFile(file2);
3637 }
3638 }
3639 }
3641 if (cloner.IsValid()) {
3642 this->SetEntries(this->GetEntries() + tree->GetTree()->GetEntries());
3643 if (cacheSize != -1) cloner.SetCacheSize(cacheSize);
3644 cloner.Exec();
3645 } else {
3646 if (i == 0) {
3647 Warning("CopyEntries","%s",cloner.GetWarning());
3648 // If the first cloning does not work, something is really wrong
3649 // (since apriori the source and target are exactly the same structure!)
3650 return -1;
3651 } else {
3652 if (cloner.NeedConversion()) {
3653 TTree *localtree = tree->GetTree();
3654 Long64_t tentries = localtree->GetEntries();
3655 if (needCopyAddresses) {
3656 // Copy MakeClass status.
3657 tree->SetMakeClass(fMakeClass);
3658 // Copy branch addresses.
3659 CopyAddresses(tree);
3660 }
3661 for (Long64_t ii = 0; ii < tentries; ii++) {
3662 if (localtree->GetEntry(ii) <= 0) {
3663 break;
3664 }
3665 this->Fill();
3666 }
3667 if (needCopyAddresses)
3668 tree->ResetBranchAddresses();
3669 if (this->GetTreeIndex()) {
3670 this->GetTreeIndex()->Append(tree->GetTree()->GetTreeIndex(), true);
3671 }
3672 } else {
3673 Warning("CopyEntries","%s",cloner.GetWarning());
3674 if (tree->GetDirectory() && tree->GetDirectory()->GetFile()) {
3675 Warning("CopyEntries", "Skipped file %s\n", tree->GetDirectory()->GetFile()->GetName());
3676 } else {
3677 Warning("CopyEntries", "Skipped file number %d\n", tree->GetTreeNumber());
3678 }
3679 }
3680 }
3681 }
3682
3683 }
3684 if (this->GetTreeIndex()) {
3685 this->GetTreeIndex()->Append(nullptr,false); // Force the sorting
3686 }
3687 nbytes = GetTotBytes() - totbytes;
3688 } else {
3689 if (nentries < 0) {
3691 } else if (nentries > treeEntries) {
3693 }
3694 if (needCopyAddresses) {
3695 // Copy MakeClass status.
3696 tree->SetMakeClass(fMakeClass);
3697 // Copy branch addresses.
3698 CopyAddresses(tree);
3699 }
3700 Int_t treenumber = -1;
3701 for (Long64_t i = 0; i < nentries; i++) {
3702 if (tree->LoadTree(i) < 0) {
3703 break;
3704 }
3705 if (treenumber != tree->GetTreeNumber()) {
3706 if ( withIndex ) {
3707 withIndex = R__HandleIndex( onIndexError, this, tree );
3708 }
3709 treenumber = tree->GetTreeNumber();
3710 }
3711 if (tree->GetEntry(i) <= 0) {
3712 break;
3713 }
3714 nbytes += this->Fill();
3715 }
3716 if (needCopyAddresses)
3717 tree->ResetBranchAddresses();
3718 if (this->GetTreeIndex()) {
3719 this->GetTreeIndex()->Append(nullptr,false); // Force the sorting
3720 }
3721 }
3722 return nbytes;
3723}
3724
3725////////////////////////////////////////////////////////////////////////////////
3726/// Copy a tree with selection.
3727///
3728/// ### Important:
3729///
3730/// The returned copied tree stays connected with the original tree
3731/// until the original tree is deleted. In particular, any changes
3732/// to the branch addresses in the original tree are also made to
3733/// the copied tree. Any changes made to the branch addresses of the
3734/// copied tree are overridden anytime the original tree changes its
3735/// branch addresses. When the original tree is deleted, all the
3736/// branch addresses of the copied tree are set to zero.
3737///
3738/// For examples of CopyTree, see the tutorials:
3739///
3740/// - copytree.C:
3741/// Example macro to copy a subset of a tree to a new tree.
3742/// The input file was generated by running the program in
3743/// $ROOTSYS/test/Event in this way:
3744/// ~~~ {.cpp}
3745/// ./Event 1000 1 1 1
3746/// ~~~
3747/// - copytree2.C
3748/// Example macro to copy a subset of a tree to a new tree.
3749/// One branch of the new tree is written to a separate file.
3750/// The input file was generated by running the program in
3751/// $ROOTSYS/test/Event in this way:
3752/// ~~~ {.cpp}
3753/// ./Event 1000 1 1 1
3754/// ~~~
3755/// - copytree3.C
3756/// Example macro to copy a subset of a tree to a new tree.
3757/// Only selected entries are copied to the new tree.
3758/// NOTE that only the active branches are copied.
3760TTree* TTree::CopyTree(const char* selection, Option_t* option /* = 0 */, Long64_t nentries /* = TTree::kMaxEntries */, Long64_t firstentry /* = 0 */)
3761{
3762 GetPlayer();
3763 if (fPlayer) {
3765 }
3766 return nullptr;
3767}
3768
3769////////////////////////////////////////////////////////////////////////////////
3770/// Create a basket for this tree and given branch.
3773{
3774 if (!branch) {
3775 return nullptr;
3776 }
3777 return new TBasket(branch->GetName(), GetName(), branch);
3778}
3779
3780////////////////////////////////////////////////////////////////////////////////
3781/// Delete this tree from memory or/and disk.
3782///
3783/// - if option == "all" delete Tree object from memory AND from disk
3784/// all baskets on disk are deleted. All keys with same name
3785/// are deleted.
3786/// - if option =="" only Tree object in memory is deleted.
3788void TTree::Delete(Option_t* option /* = "" */)
3789{
3790 TFile *file = GetCurrentFile();
3791
3792 // delete all baskets and header from file
3793 if (file && option && !strcmp(option,"all")) {
3794 if (!file->IsWritable()) {
3795 Error("Delete","File : %s is not writable, cannot delete Tree:%s", file->GetName(),GetName());
3796 return;
3797 }
3798
3799 //find key and import Tree header in memory
3800 TKey *key = fDirectory->GetKey(GetName());
3801 if (!key) return;
3802
3804 file->cd();
3805
3806 //get list of leaves and loop on all the branches baskets
3807 TIter next(GetListOfLeaves());
3808 TLeaf *leaf;
3809 char header[16];
3810 Int_t ntot = 0;
3811 Int_t nbask = 0;
3813 while ((leaf = (TLeaf*)next())) {
3814 TBranch *branch = leaf->GetBranch();
3815 Int_t nbaskets = branch->GetMaxBaskets();
3816 for (Int_t i=0;i<nbaskets;i++) {
3817 Long64_t pos = branch->GetBasketSeek(i);
3818 if (!pos) continue;
3819 TFile *branchFile = branch->GetFile();
3820 if (!branchFile) continue;
3821 branchFile->GetRecordHeader(header,pos,16,nbytes,objlen,keylen);
3822 if (nbytes <= 0) continue;
3823 branchFile->MakeFree(pos,pos+nbytes-1);
3824 ntot += nbytes;
3825 nbask++;
3826 }
3827 }
3828
3829 // delete Tree header key and all keys with the same name
3830 // A Tree may have been saved many times. Previous cycles are invalid.
3831 while (key) {
3832 ntot += key->GetNbytes();
3833 key->Delete();
3834 delete key;
3835 key = fDirectory->GetKey(GetName());
3836 }
3837 if (dirsav) dirsav->cd();
3838 if (gDebug) Info("TTree::Delete", "Deleting Tree: %s: %d baskets deleted. Total space freed = %d bytes\n",GetName(),nbask,ntot);
3839 }
3840
3841 if (fDirectory) {
3842 fDirectory->Remove(this);
3843 //delete the file cache if it points to this Tree
3844 MoveReadCache(file,nullptr);
3845 fDirectory = nullptr;
3847 }
3848
3849 // Delete object from Cling symbol table so it can not be used anymore.
3850 gCling->DeleteGlobal(this);
3851
3852 // Warning: We have intentional invalidated this object while inside a member function!
3853 delete this;
3854}
3855
3856 ///////////////////////////////////////////////////////////////////////////////
3857 /// Called by TKey and TObject::Clone to automatically add us to a directory
3858 /// when we are read from a file.
3861{
3862 if (fDirectory == dir) return;
3863 if (fDirectory) {
3864 fDirectory->Remove(this);
3865 // Delete or move the file cache if it points to this Tree
3866 TFile *file = fDirectory->GetFile();
3867 MoveReadCache(file,dir);
3868 }
3869 fDirectory = dir;
3870 TBranch* b = nullptr;
3871 TIter next(GetListOfBranches());
3872 while((b = (TBranch*) next())) {
3873 b->UpdateFile();
3874 }
3875 if (fBranchRef) {
3877 }
3878 if (fDirectory) fDirectory->Append(this);
3879}
3880
3881////////////////////////////////////////////////////////////////////////////////
3882/// Draw expression varexp for specified entries.
3883///
3884/// \return -1 in case of error or number of selected events in case of success.
3885/// If `selection` involves an array variable `x[n]`, for example `x[] > 0` or
3886/// `x > 0`, then we return the number of selected instances rather than number of events.
3887/// In the output of `tree.Scan()`, instances are shown in individual printed rows, thus
3888/// each event (tree entry) is split across the various instances (lines) of the array.
3889/// In contrast, the function `GetEntries(selection)` always returns the number of entries selected.
3890///
3891/// This function accepts TCut objects as arguments.
3892/// Useful to use the string operator +
3893///
3894/// Example:
3895///
3896/// ~~~ {.cpp}
3897/// ntuple.Draw("x",cut1+cut2+cut3);
3898/// ~~~
3899
3904}
3905
3906/////////////////////////////////////////////////////////////////////////////////////////
3907/// \brief Draw expression varexp for entries and objects that pass a (optional) selection.
3908///
3909/// \return -1 in case of error or number of selected events in case of success.
3910/// If `selection` involves an array variable `x[n]`, for example `x[] > 0` or
3911/// `x > 0`, then we return the number of selected instances rather than number of events.
3912/// In the output of `tree.Scan()`, instances are shown in individual printed rows, thus
3913/// each event (tree entry) is split across the various instances (lines) of the array.
3914/// In contrast, the function `GetEntries(selection)` always returns the number of entries selected.
3915///
3916/// \param [in] varexp
3917/// \parblock
3918/// A string that takes one of these general forms:
3919/// - "e1" produces a 1-d histogram (TH1F) of expression "e1"
3920/// - "e1:e2" produces an unbinned 2-d scatter-plot (TGraph) of "e1"
3921/// on the y-axis versus "e2" on the x-axis
3922/// - "e1:e2:e3" produces an unbinned 3-d scatter-plot (TPolyMarker3D) of "e1"
3923/// vs "e2" vs "e3" on the z-, y-, x-axis, respectively
3924/// - "e1:e2:e3:e4" produces an unbinned 3-d scatter-plot (TPolyMarker3D) of "e1"
3925/// vs "e2" vs "e3" and "e4" mapped on the current color palette.
3926/// (to create histograms in the 2, 3, and 4 dimensional case,
3927/// see section "Saving the result of Draw to an histogram")
3928/// - "e1:e2:e3:e4:e5" with option "GL5D" produces a 5D plot using OpenGL. `gStyle->SetCanvasPreferGL(true)` is
3929/// needed.
3930/// - Any number of variables no fewer than two can be used with the options "CANDLE" and "PARA"
3931/// - An arbitrary number of variables can be used with the option "GOFF"
3932///
3933/// Examples:
3934/// - "x": the simplest case, it draws a 1-Dim histogram of column x
3935/// - "sqrt(x)", "x*y/z": draw histogram with the values of the specified numerical expression across TTree events
3936/// - "y:sqrt(x)": 2-Dim histogram of y versus sqrt(x)
3937/// - "px:py:pz:2.5*E": produces a 3-d scatter-plot of px vs py ps pz
3938/// and the color number of each marker will be 2.5*E.
3939/// If the color number is negative it is set to 0.
3940/// If the color number is greater than the current number of colors
3941/// it is set to the highest color number. The default number of
3942/// colors is 50. See TStyle::SetPalette for setting a new color palette.
3943///
3944/// The expressions can use all the operations and built-in functions
3945/// supported by TFormula (see TFormula::Analyze()), including free
3946/// functions taking numerical arguments (e.g. TMath::Bessel()).
3947/// In addition, you can call member functions taking numerical
3948/// arguments. For example, these are two valid expressions:
3949/// ~~~ {.cpp}
3950/// TMath::BreitWigner(fPx,3,2)
3951/// event.GetHistogram()->GetXaxis()->GetXmax()
3952/// ~~~
3953/// \endparblock
3954/// \param [in] selection
3955/// \parblock
3956/// A string containing a selection expression.
3957/// In a selection all usual C++ mathematical and logical operators are allowed.
3958/// The value corresponding to the selection expression is used as a weight
3959/// to fill the histogram (a weight of 0 is equivalent to not filling the histogram).\n
3960/// \n
3961/// Examples:
3962/// - "x<y && sqrt(z)>3.2": returns a weight = 0 or 1
3963/// - "(x+y)*(sqrt(z)>3.2)": returns a weight = x+y if sqrt(z)>3.2, 0 otherwise\n
3964/// \n
3965/// If the selection expression returns an array, it is iterated over in sync with the
3966/// array returned by the varexp argument (as described below in "Drawing expressions using arrays and array
3967/// elements"). For example, if, for a given event, varexp evaluates to
3968/// `{1., 2., 3.}` and selection evaluates to `{0, 1, 0}`, the resulting histogram is filled with the value 2. For
3969/// example, for each event here we perform a simple object selection:
3970/// ~~~{.cpp}
3971/// // Muon_pt is an array: fill a histogram with the array elements > 100 in each event
3972/// tree->Draw('Muon_pt', 'Muon_pt > 100')
3973/// ~~~
3974/// \endparblock
3975/// \param [in] option
3976/// \parblock
3977/// The drawing option.
3978/// - When an histogram is produced it can be any histogram drawing option
3979/// listed in THistPainter.
3980/// - when no option is specified:
3981/// - the default histogram drawing option is used
3982/// if the expression is of the form "e1".
3983/// - if the expression is of the form "e1:e2"or "e1:e2:e3" a cloud of
3984/// unbinned 2D or 3D points is drawn respectively.
3985/// - if the expression has four fields "e1:e2:e3:e4" a cloud of unbinned 3D
3986/// points is produced with e1 vs e2 vs e3, and e4 is mapped on the current color
3987/// palette.
3988/// - If option COL is specified when varexp has three fields:
3989/// ~~~ {.cpp}
3990/// tree.Draw("e1:e2:e3","","col");
3991/// ~~~
3992/// a 2D scatter is produced with e1 vs e2, and e3 is mapped on the current
3993/// color palette. The colors for e3 are evaluated once in linear scale before
3994/// painting. Therefore changing the pad to log scale along Z as no effect
3995/// on the colors.
3996/// - if expression has more than four fields the option "PARA"or "CANDLE"
3997/// can be used.
3998/// - If option contains the string "goff", no graphics is generated.
3999/// \endparblock
4000/// \param [in] nentries The number of entries to process (default is all)
4001/// \param [in] firstentry The first entry to process (default is 0)
4002///
4003/// ### Drawing expressions using arrays and array elements
4004///
4005/// Let assumes, a leaf fMatrix, on the branch fEvent, which is a 3 by 3 array,
4006/// or a TClonesArray.
4007/// In a TTree::Draw expression you can now access fMatrix using the following
4008/// syntaxes:
4009///
4010/// | String passed | What is used for each entry of the tree
4011/// |-----------------|--------------------------------------------------------|
4012/// | `fMatrix` | the 9 elements of fMatrix |
4013/// | `fMatrix[][]` | the 9 elements of fMatrix |
4014/// | `fMatrix[2][2]` | only the elements fMatrix[2][2] |
4015/// | `fMatrix[1]` | the 3 elements fMatrix[1][0], fMatrix[1][1] and fMatrix[1][2] |
4016/// | `fMatrix[1][]` | the 3 elements fMatrix[1][0], fMatrix[1][1] and fMatrix[1][2] |
4017/// | `fMatrix[][0]` | the 3 elements fMatrix[0][0], fMatrix[1][0] and fMatrix[2][0] |
4018///
4019/// "fEvent.fMatrix...." same as "fMatrix..." (unless there is more than one leaf named fMatrix!).
4020///
4021/// In summary, if a specific index is not specified for a dimension, TTree::Draw
4022/// will loop through all the indices along this dimension. Leaving off the
4023/// last (right most) dimension of specifying then with the two characters '[]'
4024/// is equivalent. For variable size arrays (and TClonesArray) the range
4025/// of the first dimension is recalculated for each entry of the tree.
4026/// You can also specify the index as an expression of any other variables from the
4027/// tree.
4028///
4029/// TTree::Draw also now properly handling operations involving 2 or more arrays.
4030///
4031/// Let assume a second matrix fResults[5][2], here are a sample of some
4032/// of the possible combinations, the number of elements they produce and
4033/// the loop used:
4034///
4035/// | expression | element(s) | Loop |
4036/// |----------------------------------|------------|--------------------------|
4037/// | `fMatrix[2][1] - fResults[5][2]` | one | no loop |
4038/// | `fMatrix[2][] - fResults[5][2]` | three | on 2nd dim fMatrix |
4039/// | `fMatrix[2][] - fResults[5][]` | two | on both 2nd dimensions |
4040/// | `fMatrix[][2] - fResults[][1]` | three | on both 1st dimensions |
4041/// | `fMatrix[][2] - fResults[][]` | six | on both 1st and 2nd dimensions of fResults |
4042/// | `fMatrix[][2] - fResults[3][]` | two | on 1st dim of fMatrix and 2nd of fResults (at the same time) |
4043/// | `fMatrix[][] - fResults[][]` | six | on 1st dim then on 2nd dim |
4044/// | `fMatrix[][fResult[][]]` | 30 | on 1st dim of fMatrix then on both dimensions of fResults. The
4045/// value if fResults[j][k] is used as the second index of fMatrix.|
4046///
4047///
4048/// In summary, TTree::Draw loops through all unspecified dimensions. To
4049/// figure out the range of each loop, we match each unspecified dimension
4050/// from left to right (ignoring ALL dimensions for which an index has been
4051/// specified), in the equivalent loop matched dimensions use the same index
4052/// and are restricted to the smallest range (of only the matched dimensions).
4053/// When involving variable arrays, the range can of course be different
4054/// for each entry of the tree.
4055///
4056/// So the loop equivalent to "fMatrix[][2] - fResults[3][]" is:
4057/// ~~~ {.cpp}
4058/// for (Int_t i0; i < min(3,2); i++) {
4059/// use the value of (fMatrix[i0][2] - fMatrix[3][i0])
4060/// }
4061/// ~~~
4062/// So the loop equivalent to "fMatrix[][2] - fResults[][]" is:
4063/// ~~~ {.cpp}
4064/// for (Int_t i0; i < min(3,5); i++) {
4065/// for (Int_t i1; i1 < 2; i1++) {
4066/// use the value of (fMatrix[i0][2] - fMatrix[i0][i1])
4067/// }
4068/// }
4069/// ~~~
4070/// So the loop equivalent to "fMatrix[][] - fResults[][]" is:
4071/// ~~~ {.cpp}
4072/// for (Int_t i0; i < min(3,5); i++) {
4073/// for (Int_t i1; i1 < min(3,2); i1++) {
4074/// use the value of (fMatrix[i0][i1] - fMatrix[i0][i1])
4075/// }
4076/// }
4077/// ~~~
4078/// So the loop equivalent to "fMatrix[][fResults[][]]" is:
4079/// ~~~ {.cpp}
4080/// for (Int_t i0; i0 < 3; i0++) {
4081/// for (Int_t j2; j2 < 5; j2++) {
4082/// for (Int_t j3; j3 < 2; j3++) {
4083/// i1 = fResults[j2][j3];
4084/// use the value of fMatrix[i0][i1]
4085/// }
4086/// }
4087/// ~~~
4088/// ### Retrieving the result of Draw
4089///
4090/// By default a temporary histogram called `htemp` is created. It will be:
4091///
4092/// - A TH1F* in case of a mono-dimensional distribution: `Draw("e1")`,
4093/// - A TH2F* in case of a bi-dimensional distribution: `Draw("e1:e2")`,
4094/// - A TH3F* in case of a three-dimensional distribution: `Draw("e1:e2:e3")`.
4095///
4096/// In the one dimensional case the `htemp` is filled and drawn whatever the drawing
4097/// option is.
4098///
4099/// In the two and three dimensional cases, with the default drawing option (`""`),
4100/// a cloud of points is drawn and the histogram `htemp` is not filled. For all the other
4101/// drawing options `htemp` will be filled.
4102///
4103/// In all cases `htemp` can be retrieved by calling:
4104///
4105/// ~~~ {.cpp}
4106/// auto htemp = (TH1F*)gPad->GetPrimitive("htemp"); // 1D
4107/// auto htemp = (TH2F*)gPad->GetPrimitive("htemp"); // 2D
4108/// auto htemp = (TH3F*)gPad->GetPrimitive("htemp"); // 3D
4109/// ~~~
4110///
4111/// In the two dimensional case (`Draw("e1;e2")`), with the default drawing option, the
4112/// data is filled into a TGraph named `Graph`. This TGraph can be retrieved by
4113/// calling
4114///
4115/// ~~~ {.cpp}
4116/// auto graph = (TGraph*)gPad->GetPrimitive("Graph");
4117/// ~~~
4118///
4119/// For the three and four dimensional cases, with the default drawing option, an unnamed
4120/// TPolyMarker3D is produced, and therefore cannot be retrieved.
4121///
4122/// In all cases `htemp` can be used to access the axes. For instance in the 2D case:
4123///
4124/// ~~~ {.cpp}
4125/// auto htemp = (TH2F*)gPad->GetPrimitive("htemp");
4126/// auto xaxis = htemp->GetXaxis();
4127/// ~~~
4128///
4129/// When the option `"A"` is used (with TGraph painting option) to draw a 2D
4130/// distribution:
4131/// ~~~ {.cpp}
4132/// tree.Draw("e1:e2","","A*");
4133/// ~~~
4134/// a scatter plot is produced (with stars in that case) but the axis creation is
4135/// delegated to TGraph and `htemp` is not created.
4136///
4137/// ### Saving the result of Draw to a histogram
4138///
4139/// If `varexp` contains `>>hnew` (following the variable(s) name(s)),
4140/// the new histogram called `hnew` is created and it is kept in the current
4141/// directory (and also the current pad). This works for all dimensions.
4142///
4143/// Example:
4144/// ~~~ {.cpp}
4145/// tree.Draw("sqrt(x)>>hsqrt","y>0")
4146/// ~~~
4147/// will draw `sqrt(x)` and save the histogram as "hsqrt" in the current
4148/// directory. To retrieve it do:
4149/// ~~~ {.cpp}
4150/// TH1F *hsqrt = (TH1F*)gDirectory->Get("hsqrt");
4151/// ~~~
4152/// The binning information is taken from the environment variables
4153/// ~~~ {.cpp}
4154/// Hist.Binning.?D.?
4155/// ~~~
4156/// In addition, the name of the histogram can be followed by up to 9
4157/// numbers between '(' and ')', where the numbers describe the
4158/// following:
4159///
4160/// - 1 - bins in x-direction
4161/// - 2 - lower limit in x-direction
4162/// - 3 - upper limit in x-direction
4163/// - 4-6 same for y-direction
4164/// - 7-9 same for z-direction
4165///
4166/// When a new binning is used the new value will become the default.
4167/// Values can be skipped.
4168///
4169/// Example:
4170/// ~~~ {.cpp}
4171/// tree.Draw("sqrt(x)>>hsqrt(500,10,20)")
4172/// // plot sqrt(x) between 10 and 20 using 500 bins
4173/// tree.Draw("sqrt(x):sin(y)>>hsqrt(100,10,60,50,.1,.5)")
4174/// // plot sqrt(x) against sin(y)
4175/// // 100 bins in x-direction; lower limit on x-axis is 10; upper limit is 60
4176/// // 50 bins in y-direction; lower limit on y-axis is .1; upper limit is .5
4177/// ~~~
4178/// By default, if a histogram with the same name is already registered to the current
4179/// ROOT directory, the specified histogram is reset. To continue to append data to an
4180/// existing histogram, use "+" in front of the histogram name.
4181///
4182/// A '+' in front of the histogram name is ignored, when the name is followed by
4183/// binning information as described in the previous paragraph.
4184/// ~~~ {.cpp}
4185/// tree.Draw("sqrt(x)>>+hsqrt","y>0")
4186/// ~~~
4187/// will not reset `hsqrt`, but will continue filling. This works for 1-D, 2-D
4188/// and 3-D histograms.
4189///
4190/// Note that when the automatic registration of histograms is off (see \ref DisableObjectAutoRegistration() ),
4191/// external histogram are not visible to TTree::Draw unless they are registered to the current directory explicitly.
4192/// ~~~ {.cpp}
4193/// auto histo = new TH1D("histo", ...);
4194/// histo->SetDirectory(gDirectory);
4195/// tree.Draw("sqrt(x)>>histo","y>0")
4196/// ~~~
4197/// When auto-registration is off, histograms created by TTree::Draw will still be registered to the current directory.
4198///
4199/// ### Accessing collection objects
4200///
4201/// TTree::Draw default's handling of collections is to assume that any
4202/// request on a collection pertain to it content. For example, if fTracks
4203/// is a collection of Track objects, the following:
4204/// ~~~ {.cpp}
4205/// tree->Draw("event.fTracks.fPx");
4206/// ~~~
4207/// will plot the value of fPx for each Track objects inside the collection.
4208/// Also
4209/// ~~~ {.cpp}
4210/// tree->Draw("event.fTracks.size()");
4211/// ~~~
4212/// would plot the result of the member function Track::size() for each
4213/// Track object inside the collection.
4214/// To access information about the collection itself, TTree::Draw support
4215/// the '@' notation. If a variable which points to a collection is prefixed
4216/// or postfixed with '@', the next part of the expression will pertain to
4217/// the collection object. For example:
4218/// ~~~ {.cpp}
4219/// tree->Draw("event.@fTracks.size()");
4220/// ~~~
4221/// will plot the size of the collection referred to by `fTracks` (i.e the number
4222/// of Track objects).
4223///
4224/// ### Drawing 'objects'
4225///
4226/// When a class has a member function named AsDouble or AsString, requesting
4227/// to directly draw the object will imply a call to one of the 2 functions.
4228/// If both AsDouble and AsString are present, AsDouble will be used.
4229/// AsString can return either a char*, a std::string or a TString.s
4230/// For example, the following
4231/// ~~~ {.cpp}
4232/// tree->Draw("event.myTTimeStamp");
4233/// ~~~
4234/// will draw the same histogram as
4235/// ~~~ {.cpp}
4236/// tree->Draw("event.myTTimeStamp.AsDouble()");
4237/// ~~~
4238/// In addition, when the object is a type TString or std::string, TTree::Draw
4239/// will call respectively `TString::Data` and `std::string::c_str()`
4240///
4241/// If the object is a TBits, the histogram will contain the index of the bit
4242/// that are turned on.
4243///
4244/// ### Retrieving information about the tree itself.
4245///
4246/// You can refer to the tree (or chain) containing the data by using the
4247/// string 'This'.
4248/// You can then could any TTree methods. For example:
4249/// ~~~ {.cpp}
4250/// tree->Draw("This->GetReadEntry()");
4251/// ~~~
4252/// will display the local entry numbers be read.
4253/// ~~~ {.cpp}
4254/// tree->Draw("This->GetUserInfo()->At(0)->GetName()");
4255/// ~~~
4256/// will display the name of the first 'user info' object.
4257///
4258/// ### Special functions and variables
4259///
4260/// `Entry$`: A TTree::Draw formula can use the special variable `Entry$`
4261/// to access the entry number being read. For example to draw every
4262/// other entry use:
4263/// ~~~ {.cpp}
4264/// tree.Draw("myvar","Entry$%2==0");
4265/// ~~~
4266/// - `Entry$` : return the current entry number (`== TTree::GetReadEntry()`)
4267/// - `LocalEntry$` : return the current entry number in the current tree of a
4268/// chain (`== GetTree()->GetReadEntry()`)
4269/// - `Entries$` : return the total number of entries (== TTree::GetEntries())
4270/// - `LocalEntries$` : return the total number of entries in the current tree
4271/// of a chain (== GetTree()->TTree::GetEntries())
4272/// - `Length$` : return the total number of element of this formula for this
4273/// entry (`==TTreeFormula::GetNdata()`)
4274/// - `Iteration$` : return the current iteration over this formula for this
4275/// entry (i.e. varies from 0 to `Length$ - 1`).
4276/// - `Length$(formula )` : return the total number of element of the formula
4277/// given as a parameter.
4278/// - `Sum$(formula )` : return the sum of the value of the elements of the
4279/// formula given as a parameter. For example the mean for all the elements in
4280/// one entry can be calculated with: `Sum$(formula )/Length$(formula )`
4281/// - `Min$(formula )` : return the minimum (within one TTree entry) of the value of the
4282/// elements of the formula given as a parameter.
4283/// - `Max$(formula )` : return the maximum (within one TTree entry) of the value of the
4284/// elements of the formula given as a parameter.
4285/// - `MinIf$(formula,condition)`
4286/// - `MaxIf$(formula,condition)` : return the minimum (maximum) (within one TTree entry)
4287/// of the value of the elements of the formula given as a parameter
4288/// if they match the condition. If no element matches the condition,
4289/// the result is zero. To avoid the resulting peak at zero, use the
4290/// pattern:
4291/// ~~~ {.cpp}
4292/// tree->Draw("MinIf$(formula,condition)","condition");
4293/// ~~~
4294/// which will avoid calculation `MinIf$` for the entries that have no match
4295/// for the condition.
4296/// - `Alt$(primary,alternate)` : return the value of "primary" if it is available
4297/// for the current iteration otherwise return the value of "alternate".
4298/// For example, with arr1[3] and arr2[2]
4299/// ~~~ {.cpp}
4300/// tree->Draw("arr1+Alt$(arr2,0)");
4301/// ~~~
4302/// will draw arr1[0]+arr2[0] ; arr1[1]+arr2[1] and arr1[2]+0
4303/// Or with a variable size array arr3
4304/// ~~~ {.cpp}
4305/// tree->Draw("Alt$(arr3[0],0)+Alt$(arr3[1],0)+Alt$(arr3[2],0)");
4306/// ~~~
4307/// will draw the sum arr3 for the index 0 to min(2,actual_size_of_arr3-1)
4308/// As a comparison
4309/// ~~~ {.cpp}
4310/// tree->Draw("arr3[0]+arr3[1]+arr3[2]");
4311/// ~~~
4312/// will draw the sum arr3 for the index 0 to 2 only if the
4313/// actual_size_of_arr3 is greater or equal to 3.
4314/// Note that the array in 'primary' is flattened/linearized thus using
4315/// `Alt$` with multi-dimensional arrays of different dimensions is unlikely
4316/// to yield the expected results. To visualize a bit more what elements
4317/// would be matched by TTree::Draw, TTree::Scan can be used:
4318/// ~~~ {.cpp}
4319/// tree->Scan("arr1:Alt$(arr2,0)");
4320/// ~~~
4321/// will print on one line the value of arr1 and (arr2,0) that will be
4322/// matched by
4323/// ~~~ {.cpp}
4324/// tree->Draw("arr1-Alt$(arr2,0)");
4325/// ~~~
4326/// The ternary operator is not directly supported in TTree::Draw however, to plot the
4327/// equivalent of `var2<20 ? -99 : var1`, you can use:
4328/// ~~~ {.cpp}
4329/// tree->Draw("(var2<20)*99+(var2>=20)*var1","");
4330/// ~~~
4331///
4332/// ### Drawing a user function accessing the TTree data directly
4333///
4334/// If the formula contains a file name, TTree::MakeProxy will be used
4335/// to load and execute this file. In particular it will draw the
4336/// result of a function with the same name as the file. The function
4337/// will be executed in a context where the name of the branches can
4338/// be used as a C++ variable.
4339///
4340/// For example draw px using the file hsimple.root (generated by the
4341/// hsimple.C tutorial), we need a file named hsimple.cxx:
4342/// ~~~ {.cpp}
4343/// double hsimple() {
4344/// return px;
4345/// }
4346/// ~~~
4347/// MakeProxy can then be used indirectly via the TTree::Draw interface
4348/// as follow:
4349/// ~~~ {.cpp}
4350/// new TFile("hsimple.root")
4351/// ntuple->Draw("hsimple.cxx");
4352/// ~~~
4353/// A more complete example is available in the tutorials directory:
4354/// `h1analysisProxy.cxx`, `h1analysProxy.h` and `h1analysisProxyCut.C`
4355/// which reimplement the selector found in `h1analysis.C`
4356///
4357/// The main features of this facility are:
4358///
4359/// * on-demand loading of branches
4360/// * ability to use the 'branchname' as if it was a data member
4361/// * protection against array out-of-bound
4362/// * ability to use the branch data as object (when the user code is available)
4363///
4364/// See TTree::MakeProxy for more details.
4365///
4366/// ### Making a Profile histogram
4367///
4368/// In case of a 2-Dim expression, one can generate a TProfile histogram
4369/// instead of a TH2F histogram by specifying option=prof or option=profs
4370/// or option=profi or option=profg ; the trailing letter select the way
4371/// the bin error are computed, See TProfile2D::SetErrorOption for
4372/// details on the differences.
4373/// The option=prof is automatically selected in case of y:x>>pf
4374/// where pf is an existing TProfile histogram.
4375///
4376/// ### Making a 2D Profile histogram
4377///
4378/// In case of a 3-Dim expression, one can generate a TProfile2D histogram
4379/// instead of a TH3F histogram by specifying option=prof or option=profs.
4380/// or option=profi or option=profg ; the trailing letter select the way
4381/// the bin error are computed, See TProfile2D::SetErrorOption for
4382/// details on the differences.
4383/// The option=prof is automatically selected in case of z:y:x>>pf
4384/// where pf is an existing TProfile2D histogram.
4385///
4386/// ### Making a 5D plot using GL
4387///
4388/// If option GL5D is specified together with 5 variables, a 5D plot is drawn
4389/// using OpenGL. See tree502_staff.C as example.
4390///
4391/// ### Making a parallel coordinates plot
4392///
4393/// In case of a 2-Dim or more expression with the option=para, one can generate
4394/// a parallel coordinates plot. With that option, the number of dimensions is
4395/// arbitrary. Giving more than 4 variables without the option=para or
4396/// option=candle or option=goff will produce an error.
4397///
4398/// ### Making a candle sticks chart
4399///
4400/// In case of a 2-Dim or more expression with the option=candle, one can generate
4401/// a candle sticks chart. With that option, the number of dimensions is
4402/// arbitrary. Giving more than 4 variables without the option=para or
4403/// option=candle or option=goff will produce an error.
4404///
4405/// ### Normalizing the output histogram to 1
4406///
4407/// When option contains "norm" the output histogram is normalized to 1.
4408///
4409/// ### Saving the result of Draw to a TEventList, a TEntryList or a TEntryListArray
4410///
4411/// TTree::Draw can be used to fill a TEventList object (list of entry numbers)
4412/// instead of histogramming one variable.
4413/// If varexp0 has the form >>elist , a TEventList object named "elist"
4414/// is created in the current directory. elist will contain the list
4415/// of entry numbers satisfying the current selection.
4416/// If option "entrylist" is used, a TEntryList object is created
4417/// If the selection contains arrays, vectors or any container class and option
4418/// "entrylistarray" is used, a TEntryListArray object is created
4419/// containing also the subentries satisfying the selection, i.e. the indices of
4420/// the branches which hold containers classes.
4421/// Example:
4422/// ~~~ {.cpp}
4423/// tree.Draw(">>yplus","y>0")
4424/// ~~~
4425/// will create a TEventList object named "yplus" in the current directory.
4426/// In an interactive session, one can type (after TTree::Draw)
4427/// ~~~ {.cpp}
4428/// yplus.Print("all")
4429/// ~~~
4430/// to print the list of entry numbers in the list.
4431/// ~~~ {.cpp}
4432/// tree.Draw(">>yplus", "y>0", "entrylist")
4433/// ~~~
4434/// will create a TEntryList object names "yplus" in the current directory
4435/// ~~~ {.cpp}
4436/// tree.Draw(">>yplus", "y>0", "entrylistarray")
4437/// ~~~
4438/// will create a TEntryListArray object names "yplus" in the current directory
4439///
4440/// By default, the specified entry list is reset.
4441/// To continue to append data to an existing list, use "+" in front
4442/// of the list name;
4443/// ~~~ {.cpp}
4444/// tree.Draw(">>+yplus","y>0")
4445/// ~~~
4446/// will not reset yplus, but will enter the selected entries at the end
4447/// of the existing list.
4448///
4449/// Note that when the automatic registration of event lists is off (see \ref DisableObjectAutoRegistration() ),
4450/// they are not visible to TTree::Draw unless they are registered to the current directory explicitly.
4451/// ~~~ {.cpp}
4452/// auto elist = new TEventList("elist", ...);
4453/// elist->SetDirectory(gDirectory);
4454/// tree.Draw(">>+elist","y>0")
4455/// ~~~
4456///
4457/// ### Using a TEventList, TEntryList or TEntryListArray as Input
4458///
4459/// Once a TEventList or a TEntryList object has been generated, it can be used as input
4460/// for TTree::Draw. Use TTree::SetEventList or TTree::SetEntryList to set the
4461/// current event list
4462///
4463/// Example 1:
4464/// ~~~ {.cpp}
4465/// TEventList *elist = (TEventList*)gDirectory->Get("yplus");
4466/// tree->SetEventList(elist);
4467/// tree->Draw("py");
4468/// ~~~
4469/// Example 2:
4470/// ~~~ {.cpp}
4471/// TEntryList *elist = (TEntryList*)gDirectory->Get("yplus");
4472/// tree->SetEntryList(elist);
4473/// tree->Draw("py");
4474/// ~~~
4475/// If a TEventList object is used as input, a new TEntryList object is created
4476/// inside the SetEventList function. In case of a TChain, all tree headers are loaded
4477/// for this transformation. This new object is owned by the chain and is deleted
4478/// with it, unless the user extracts it by calling GetEntryList() function.
4479/// See also comments to SetEventList() function of TTree and TChain.
4480///
4481/// If arrays are used in the selection criteria and TEntryListArray is not used,
4482/// all the entries that have at least one element of the array that satisfy the selection
4483/// are entered in the list.
4484///
4485/// Example:
4486/// ~~~ {.cpp}
4487/// tree.Draw(">>pyplus","fTracks.fPy>0");
4488/// tree->SetEventList(pyplus);
4489/// tree->Draw("fTracks.fPy");
4490/// ~~~
4491/// will draw the fPy of ALL tracks in event with at least one track with
4492/// a positive fPy.
4493///
4494/// To select only the elements that did match the original selection
4495/// use TEventList::SetReapplyCut or TEntryList::SetReapplyCut.
4496///
4497/// Example:
4498/// ~~~ {.cpp}
4499/// tree.Draw(">>pyplus","fTracks.fPy>0");
4500/// pyplus->SetReapplyCut(true);
4501/// tree->SetEventList(pyplus);
4502/// tree->Draw("fTracks.fPy");
4503/// ~~~
4504/// will draw the fPy of only the tracks that have a positive fPy.
4505///
4506/// To draw only the elements that match a selection in case of arrays,
4507/// you can also use TEntryListArray (faster in case of a more general selection).
4508///
4509/// Example:
4510/// ~~~ {.cpp}
4511/// tree.Draw(">>pyplus","fTracks.fPy>0", "entrylistarray");
4512/// tree->SetEntryList(pyplus);
4513/// tree->Draw("fTracks.fPy");
4514/// ~~~
4515/// will draw the fPy of only the tracks that have a positive fPy,
4516/// but without redoing the selection.
4517///
4518/// Note: Use tree->SetEventList(0) if you do not want use the list as input.
4519///
4520/// ### How to obtain more info from TTree::Draw
4521///
4522/// Once TTree::Draw has been called, it is possible to access useful
4523/// information still stored in the TTree object via the following functions:
4524///
4525/// - GetSelectedRows() // return the number of values accepted by the selection expression. In case where no selection
4526/// was specified, returns the number of values processed.
4527/// - GetV1() // returns a pointer to the double array of V1
4528/// - GetV2() // returns a pointer to the double array of V2
4529/// - GetV3() // returns a pointer to the double array of V3
4530/// - GetV4() // returns a pointer to the double array of V4
4531/// - GetW() // returns a pointer to the double array of Weights where weight equal the result of the
4532/// selection expression.
4533///
4534/// where V1,V2,V3 correspond to the expressions in
4535/// ~~~ {.cpp}
4536/// TTree::Draw("V1:V2:V3:V4",selection);
4537/// ~~~
4538/// If the expression has more than 4 component use GetVal(index)
4539///
4540/// Example:
4541/// ~~~ {.cpp}
4542/// Root > ntuple->Draw("py:px","pz>4");
4543/// Root > TGraph *gr = new TGraph(ntuple->GetSelectedRows(),
4544/// ntuple->GetV2(), ntuple->GetV1());
4545/// Root > gr->Draw("ap"); //draw graph in current pad
4546/// ~~~
4547///
4548/// A more complete complete tutorial (treegetval.C) shows how to use the
4549/// GetVal() method.
4550///
4551/// creates a TGraph object with a number of points corresponding to the
4552/// number of entries selected by the expression "pz>4", the x points of the graph
4553/// being the px values of the Tree and the y points the py values.
4554///
4555/// Important note: By default TTree::Draw creates the arrays obtained
4556/// with GetW, GetV1, GetV2, GetV3, GetV4, GetVal with a length corresponding
4557/// to the parameter fEstimate. The content will be the last `GetSelectedRows() % GetEstimate()`
4558/// values calculated.
4559/// By default fEstimate=1000000 and can be modified
4560/// via TTree::SetEstimate. To keep in memory all the results (in case
4561/// where there is only one result per entry), use
4562/// ~~~ {.cpp}
4563/// tree->SetEstimate(tree->GetEntries()+1); // same as tree->SetEstimate(-1);
4564/// ~~~
4565/// You must call SetEstimate if the expected number of selected rows
4566/// you need to look at is greater than 1000000.
4567///
4568/// You can use the option "goff" to turn off the graphics output
4569/// of TTree::Draw in the above example.
4570///
4571/// ### Automatic interface to TTree::Draw via the TTreeViewer
4572///
4573/// A complete graphical interface to this function is implemented
4574/// in the class TTreeViewer.
4575/// To start the TTreeViewer, three possibilities:
4576/// - select TTree context menu item "StartViewer"
4577/// - type the command "TTreeViewer TV(treeName)"
4578/// - execute statement "tree->StartViewer();"
4581{
4582 GetPlayer();
4583 if (fPlayer)
4585 return -1;
4586}
4587
4588////////////////////////////////////////////////////////////////////////////////
4589/// Remove some baskets from memory.
4591void TTree::DropBaskets()
4592{
4593 TBranch* branch = nullptr;
4595 for (Int_t i = 0; i < nb; ++i) {
4597 branch->DropBaskets("all");
4598 }
4599}
4600
4601////////////////////////////////////////////////////////////////////////////////
4602/// Drop branch buffers to accommodate nbytes below MaxVirtualsize.
4605{
4606 // Be careful not to remove current read/write buffers.
4608 for (Int_t i = 0; i < nleaves; ++i) {
4610 TBranch* branch = (TBranch*) leaf->GetBranch();
4611 Int_t nbaskets = branch->GetListOfBaskets()->GetEntries();
4612 for (Int_t j = 0; j < nbaskets - 1; ++j) {
4613 if ((j == branch->GetReadBasket()) || (j == branch->GetWriteBasket())) {
4614 continue;
4615 }
4616 TBasket* basket = (TBasket*)branch->GetListOfBaskets()->UncheckedAt(j);
4617 if (basket) {
4618 basket->DropBuffers();
4620 return;
4621 }
4622 }
4623 }
4624 }
4625}
4626
4627////////////////////////////////////////////////////////////////////////////////
4628/// Fill all branches.
4629///
4630/// This function loops on all the branches of this tree. For
4631/// each branch, it copies to the branch buffer (basket) the current
4632/// values of the leaves data types. If a leaf is a simple data type,
4633/// a simple conversion to a machine independent format has to be done.
4634///
4635/// This machine independent version of the data is copied into a
4636/// basket (each branch has its own basket). When a basket is full
4637/// (32k worth of data by default), it is then optionally compressed
4638/// and written to disk (this operation is also called committing or
4639/// 'flushing' the basket). The committed baskets are then
4640/// immediately removed from memory.
4641///
4642/// The function returns the number of bytes committed to the
4643/// individual branches.
4644///
4645/// If a write error occurs, the number of bytes returned is -1.
4646///
4647/// If no data are written, because, e.g., the branch is disabled,
4648/// the number of bytes returned is 0.
4649///
4650/// __The baskets are flushed and the Tree header saved at regular intervals__
4651///
4652/// At regular intervals, when the amount of data written so far is
4653/// greater than fAutoFlush (see SetAutoFlush) all the baskets are flushed to disk.
4654/// This makes future reading faster as it guarantees that baskets belonging to nearby
4655/// entries will be on the same disk region.
4656/// When the first call to flush the baskets happen, we also take this opportunity
4657/// to optimize the baskets buffers.
4658/// We also check if the amount of data written is greater than fAutoSave (see SetAutoSave).
4659/// In this case we also write the Tree header. This makes the Tree recoverable up to this point
4660/// in case the program writing the Tree crashes.
4661/// The decisions to FlushBaskets and Auto Save can be made based either on the number
4662/// of bytes written (fAutoFlush and fAutoSave negative) or on the number of entries
4663/// written (fAutoFlush and fAutoSave positive).
4664/// Note that the user can decide to call FlushBaskets and AutoSave in her event loop
4665/// base on the number of events written instead of the number of bytes written.
4666///
4667/// \note Calling `TTree::FlushBaskets` too often increases the IO time.
4668///
4669/// \note Calling `TTree::AutoSave` too often increases the IO time and also the
4670/// file size.
4671///
4672/// \note This method calls `TTree::ChangeFile` when the tree reaches a size
4673/// greater than `TTree::fgMaxTreeSize`. This doesn't happen if the tree is
4674/// attached to a `TMemFile` or derivate.
4677{
4678 Int_t nbytes = 0;
4679 Int_t nwrite = 0;
4680 Int_t nerror = 0;
4682
4683 // Case of one single super branch. Automatically update
4684 // all the branch addresses if a new object was created.
4685 if (nbranches == 1)
4686 ((TBranch *)fBranches.UncheckedAt(0))->UpdateAddress();
4687
4688 if (fBranchRef)
4689 fBranchRef->Clear();
4690
4691#ifdef R__USE_IMT
4694 if (useIMT) {
4695 fIMTFlush = true;
4696 fIMTZipBytes.store(0);
4697 fIMTTotBytes.store(0);
4698 }
4699#endif
4700
4701 for (Int_t i = 0; i < nbranches; ++i) {
4702 // Loop over all branches, filling and accumulating bytes written and error counts.
4704
4705 if (branch->TestBit(kDoNotProcess))
4706 continue;
4707
4708#ifndef R__USE_IMT
4709 nwrite = branch->FillImpl(nullptr);
4710#else
4711 nwrite = branch->FillImpl(useIMT ? &imtHelper : nullptr);
4712#endif
4713 if (nwrite < 0) {
4714 if (nerror < 2) {
4715 Error("Fill", "Failed filling branch:%s.%s, nbytes=%d, entry=%lld\n"
4716 " This error is symptomatic of a Tree created as a memory-resident Tree\n"
4717 " Instead of doing:\n"
4718 " TTree *T = new TTree(...)\n"
4719 " TFile *f = new TFile(...)\n"
4720 " you should do:\n"
4721 " TFile *f = new TFile(...)\n"
4722 " TTree *T = new TTree(...)\n\n",
4723 GetName(), branch->GetName(), nwrite, fEntries + 1);
4724 } else {
4725 Error("Fill", "Failed filling branch:%s.%s, nbytes=%d, entry=%lld", GetName(), branch->GetName(), nwrite,
4726 fEntries + 1);
4727 }
4728 ++nerror;
4729 } else {
4730 nbytes += nwrite;
4731 }
4732 }
4733
4734#ifdef R__USE_IMT
4735 if (fIMTFlush) {
4736 imtHelper.Wait();
4737 fIMTFlush = false;
4738 const_cast<TTree *>(this)->AddTotBytes(fIMTTotBytes);
4739 const_cast<TTree *>(this)->AddZipBytes(fIMTZipBytes);
4740 nbytes += imtHelper.GetNbytes();
4741 nerror += imtHelper.GetNerrors();
4742 }
4743#endif
4744
4745 if (fBranchRef)
4746 fBranchRef->Fill();
4747
4748 ++fEntries;
4749
4750 if (fEntries > fMaxEntries)
4751 KeepCircular();
4752
4753 if (gDebug > 0)
4754 Info("TTree::Fill", " - A: %d %lld %lld %lld %lld %lld %lld \n", nbytes, fEntries, fAutoFlush, fAutoSave,
4756
4757 bool autoFlush = false;
4758 bool autoSave = false;
4759
4760 if (fAutoFlush != 0 || fAutoSave != 0) {
4761 // Is it time to flush or autosave baskets?
4762 if (fFlushedBytes == 0) {
4763 // If fFlushedBytes == 0, it means we never flushed or saved, so
4764 // we need to check if it's time to do it and recompute the values
4765 // of fAutoFlush and fAutoSave in terms of the number of entries.
4766 // Decision can be based initially either on the number of bytes
4767 // or the number of entries written.
4769
4770 if (fAutoFlush)
4772
4773 if (fAutoSave)
4774 autoSave = fAutoSave < 0 ? (zipBytes > -fAutoSave) : fEntries % fAutoSave == 0;
4775
4776 if (autoFlush || autoSave) {
4777 // First call FlushBasket to make sure that fTotBytes is up to date.
4779 autoFlush = false; // avoid auto flushing again later
4780
4781 // When we are in one-basket-per-cluster mode, there is no need to optimize basket:
4782 // they will automatically grow to the size needed for an event cluster (with the basket
4783 // shrinking preventing them from growing too much larger than the actually-used space).
4785 OptimizeBaskets(GetTotBytes(), 1, "");
4786 if (gDebug > 0)
4787 Info("TTree::Fill", "OptimizeBaskets called at entry %lld, fZipBytes=%lld, fFlushedBytes=%lld\n",
4789 }
4791 fAutoFlush = fEntries; // Use test on entries rather than bytes
4792
4793 // subsequently in run
4794 if (fAutoSave < 0) {
4795 // Set fAutoSave to the largest integer multiple of
4796 // fAutoFlush events such that fAutoSave*fFlushedBytes
4797 // < (minus the input value of fAutoSave)
4799 if (zipBytes != 0) {
4801 } else if (totBytes != 0) {
4803 } else {
4805 TTree::Class()->WriteBuffer(b, (TTree *)this);
4806 Long64_t total = b.Length();
4808 }
4809 } else if (fAutoSave > 0) {
4811 }
4812
4813 if (fAutoSave != 0 && fEntries >= fAutoSave)
4814 autoSave = true;
4815
4816 if (gDebug > 0)
4817 Info("TTree::Fill", "First AutoFlush. fAutoFlush = %lld, fAutoSave = %lld\n", fAutoFlush, fAutoSave);
4818 }
4819 } else {
4820 // Check if we need to auto flush
4821 if (fAutoFlush) {
4822 if (fNClusterRange == 0)
4823 autoFlush = fEntries > 1 && fEntries % fAutoFlush == 0;
4824 else
4826 }
4827 // Check if we need to auto save
4828 if (fAutoSave)
4829 autoSave = fEntries % fAutoSave == 0;
4830 }
4831 }
4832
4833 if (autoFlush) {
4835 if (gDebug > 0)
4836 Info("TTree::Fill", "FlushBaskets() called at entry %lld, fZipBytes=%lld, fFlushedBytes=%lld\n", fEntries,
4839 }
4840
4841 if (autoSave) {
4842 AutoSave(); // does not call FlushBasketsImpl() again
4843 if (gDebug > 0)
4844 Info("TTree::Fill", "AutoSave called at entry %lld, fZipBytes=%lld, fSavedBytes=%lld\n", fEntries,
4846 }
4847
4848 // Check that output file is still below the maximum size.
4849 // If above, close the current file and continue on a new file.
4850 // Currently, the automatic change of file is restricted
4851 // to the case where the tree is in the top level directory.
4852 if (fDirectory)
4853 if (TFile *file = fDirectory->GetFile())
4854 if (static_cast<TDirectory *>(file) == fDirectory && (file->GetEND() > fgMaxTreeSize))
4855 ChangeFile(file);
4856
4857 return nerror == 0 ? nbytes : -1;
4858}
4859
4860////////////////////////////////////////////////////////////////////////////////
4861/// Search in the array for a branch matching the branch name,
4862/// with the branch possibly expressed as a 'full' path name (with dots).
4864static TBranch *R__FindBranchHelper(TObjArray *list, const char *branchname) {
4865 if (list==nullptr || branchname == nullptr || branchname[0] == '\0') return nullptr;
4866
4867 Int_t nbranches = list->GetEntries();
4868
4870
4871 for(Int_t index = 0; index < nbranches; ++index) {
4872 TBranch *where = (TBranch*)list->UncheckedAt(index);
4873
4874 const char *name = where->GetName();
4875 UInt_t len = strlen(name);
4876 if (len && name[len - 1] == ']' && (brlen == 0 || branchname[brlen - 1] != ']')) {
4877 const char *dim = strchr(name,'[');
4878 if (dim) {
4879 len = dim - name;
4880 }
4881 }
4882 if (brlen == len && strncmp(branchname,name,len)==0) {
4883 return where;
4884 }
4885 TBranch *next = nullptr;
4886 if ((brlen >= len) && (branchname[len] == '.')
4887 && strncmp(name, branchname, len) == 0) {
4888 // The prefix subbranch name match the branch name.
4889
4890 next = where->FindBranch(branchname);
4891 if (!next) {
4892 next = where->FindBranch(branchname+len+1);
4893 }
4894 if (next) return next;
4895 }
4896 const char *dot = strchr((char*)branchname,'.');
4897 if (dot) {
4898 if (len==(size_t)(dot-branchname) &&
4899 strncmp(branchname,name,dot-branchname)==0 ) {
4900 return R__FindBranchHelper(where->GetListOfBranches(),dot+1);
4901 }
4902 }
4903 }
4904 return nullptr;
4905}
4907TBranch *TTree::FindBranchFromSelf(const char *branchName)
4908{
4909 // If the first part of the name match the TTree name, look for the right part in the
4910 // list of branches. This will allow the branchName to be preceded by the name of this tree.
4911 if (strncmp(fName.Data(), branchName, fName.Length()) == 0 && branchName[fName.Length()] == '.')
4912 if (auto *br = R__FindBranchHelper(GetListOfBranches(), branchName + fName.Length() + 1))
4913 return br;
4914
4915 // If we did not find it, let's try to find the full name in the list of branches.
4916 if (auto *br = R__FindBranchHelper(GetListOfBranches(), branchName))
4917 return br;
4918
4919 // If we still did not find, let's try to find it within each branch assuming it does not contain the branch name.
4921 if (auto *nestedbranch = branch->FindBranch(branchName))
4922 return nestedbranch;
4923
4924 return nullptr;
4925}
4927TBranch *TTree::FindBranchFromFriends(const char *branchName)
4928{
4929 if (!fFriends) {
4930 return nullptr;
4931 }
4932
4933 TFriendLock lock(this, kFindBranch);
4935 TTree *t = frEl->GetTree();
4936 if (!t) {
4937 continue;
4938 }
4939 // If the alias is present replace it with the real name.
4940 const char *subbranch = strstr(branchName, frEl->GetName());
4941 if (subbranch != branchName) {
4942 subbranch = nullptr;
4943 }
4944 if (subbranch) {
4945 subbranch += strlen(frEl->GetName());
4946 if (*subbranch != '.') {
4947 subbranch = nullptr;
4948 } else {
4949 ++subbranch;
4950 }
4951 }
4952 std::ostringstream name;
4953 if (subbranch) {
4954 name << t->GetName() << "." << subbranch;
4955 } else {
4956 name << branchName;
4957 }
4958 if (auto *br = t->FindBranch(name.str().c_str()))
4959 return br;
4960 }
4961
4962 return nullptr;
4963}
4964
4965////////////////////////////////////////////////////////////////////////////////
4966/// Return the branch that correspond to the path 'branchname', which can
4967/// include the name of the tree or the omitted name of the parent branches.
4968/// In case of ambiguity, returns the first match.
4969/// \sa TTree::GetBranch
4972{
4973 // We already have been visited while recursively looking
4974 // through the friends tree, let return
4976 return nullptr;
4977 }
4978
4979 if (!branchname)
4980 return nullptr;
4981
4982 if (auto *br = FindBranchFromSelf(branchname))
4983 return br;
4984
4985 if (auto *br = FindBranchFromFriends(branchname))
4986 return br;
4987
4988 return nullptr;
4989}
4990
4991////////////////////////////////////////////////////////////////////////////////
4992/// Find first leaf containing searchname.
4994TLeaf* TTree::FindLeaf(const char* searchname)
4995{
4996 if (!searchname)
4997 return nullptr;
4998
4999 // We already have been visited while recursively looking
5000 // through the friends tree, let's return.
5002 return nullptr;
5003 }
5004
5005 // This will allow the branchname to be preceded by
5006 // the name of this tree.
5007 const char* subsearchname = strstr(searchname, GetName());
5008 if (subsearchname != searchname) {
5009 subsearchname = nullptr;
5010 }
5011 if (subsearchname) {
5013 if (*subsearchname != '.') {
5014 subsearchname = nullptr;
5015 } else {
5016 ++subsearchname;
5017 if (subsearchname[0] == 0) {
5018 subsearchname = nullptr;
5019 }
5020 }
5021 }
5022
5027
5028 const bool searchnameHasDot = strchr(searchname, '.') != nullptr;
5029
5030 // For leaves we allow for one level up to be prefixed to the name.
5031 TIter next(GetListOfLeaves());
5032 TLeaf* leaf = nullptr;
5033 while ((leaf = (TLeaf*) next())) {
5034 leafname = leaf->GetName();
5035 Ssiz_t dim = leafname.First('[');
5036 if (dim >= 0) leafname.Remove(dim);
5037
5038 if (leafname == searchname) {
5039 return leaf;
5040 }
5042 return leaf;
5043 }
5044 // The TLeafElement contains the branch name
5045 // in its name, let's use the title.
5046 leaftitle = leaf->GetTitle();
5047 dim = leaftitle.First('[');
5048 if (dim >= 0) leaftitle.Remove(dim);
5049
5050 if (leaftitle == searchname) {
5051 return leaf;
5052 }
5054 return leaf;
5055 }
5056 if (!searchnameHasDot)
5057 continue;
5058 TBranch* branch = leaf->GetBranch();
5059 if (branch) {
5060 longname.Form("%s.%s",branch->GetName(),leafname.Data());
5061 dim = longname.First('[');
5062 if (dim>=0) longname.Remove(dim);
5063 if (longname == searchname) {
5064 return leaf;
5065 }
5067 return leaf;
5068 }
5069 longtitle.Form("%s.%s",branch->GetName(),leaftitle.Data());
5070 dim = longtitle.First('[');
5071 if (dim>=0) longtitle.Remove(dim);
5072 if (longtitle == searchname) {
5073 return leaf;
5074 }
5076 return leaf;
5077 }
5078 // The following is for the case where the branch is only
5079 // a sub-branch. Since we do not see it through
5080 // TTree::GetListOfBranches, we need to see it indirectly.
5081 // This is the less sturdy part of this search ... it may
5082 // need refining ...
5083 if (strstr(searchname, ".") && !strcmp(searchname, branch->GetName())) {
5084 return leaf;
5085 }
5086 if (subsearchname && strstr(subsearchname, ".") && !strcmp(subsearchname, branch->GetName())) {
5087 return leaf;
5088 }
5089 }
5090 }
5091 // Search in list of friends.
5092 if (!fFriends) {
5093 return nullptr;
5094 }
5095 TFriendLock lock(this, kFindLeaf);
5097 TFriendElement* fe = nullptr;
5098 while ((fe = (TFriendElement*) nextf())) {
5099 TTree* t = fe->GetTree();
5100 if (!t) {
5101 continue;
5102 }
5103 // If the alias is present replace it with the real name.
5104 subsearchname = strstr(searchname, fe->GetName());
5105 if (subsearchname != searchname) {
5106 subsearchname = nullptr;
5107 }
5108 if (subsearchname) {
5109 subsearchname += strlen(fe->GetName());
5110 if (*subsearchname != '.') {
5111 subsearchname = nullptr;
5112 } else {
5113 ++subsearchname;
5114 }
5115 }
5116 if (subsearchname) {
5117 leafname.Form("%s.%s",t->GetName(),subsearchname);
5118 } else {
5120 }
5121 leaf = t->FindLeaf(leafname);
5122 if (leaf) {
5123 return leaf;
5124 }
5125 }
5126 return nullptr;
5127}
5128
5129////////////////////////////////////////////////////////////////////////////////
5130/// Fit a projected item(s) from a tree.
5131///
5132/// funcname is a TF1 function.
5133///
5134/// See TTree::Draw() for explanations of the other parameters.
5135///
5136/// By default the temporary histogram created is called htemp.
5137/// If varexp contains >>hnew , the new histogram created is called hnew
5138/// and it is kept in the current directory.
5139///
5140/// The function returns the number of selected entries.
5141///
5142/// Example:
5143/// ~~~ {.cpp}
5144/// tree.Fit(pol4,"sqrt(x)>>hsqrt","y>0")
5145/// ~~~
5146/// will fit sqrt(x) and save the histogram as "hsqrt" in the current
5147/// directory.
5148///
5149/// See also TTree::UnbinnedFit
5150///
5151/// ## Return status
5152///
5153/// The function returns the status of the histogram fit (see TH1::Fit)
5154/// If no entries were selected, the function returns -1;
5155/// (i.e. fitResult is null if the fit is OK)
5158{
5159 GetPlayer();
5160 if (fPlayer) {
5162 }
5163 return -1;
5164}
5165
5166namespace {
5167struct BoolRAIIToggle {
5168 bool &m_val;
5169
5170 BoolRAIIToggle(bool &val) : m_val(val) { m_val = true; }
5171 ~BoolRAIIToggle() { m_val = false; }
5172};
5173}
5174
5175////////////////////////////////////////////////////////////////////////////////
5176/// Write to disk all the basket that have not yet been individually written and
5177/// create an event cluster boundary (by default).
5178///
5179/// If the caller wishes to flush the baskets but not create an event cluster,
5180/// then set create_cluster to false.
5181///
5182/// If ROOT has IMT-mode enabled, this will launch multiple TBB tasks in parallel
5183/// via TThreadExecutor to do this operation; one per basket compression. If the
5184/// caller utilizes TBB also, care must be taken to prevent deadlocks.
5185///
5186/// For example, let's say the caller holds mutex A and calls FlushBaskets; while
5187/// TBB is waiting for the ROOT compression tasks to complete, it may decide to
5188/// run another one of the user's tasks in this thread. If the second user task
5189/// tries to acquire A, then a deadlock will occur. The example call sequence
5190/// looks like this:
5191///
5192/// - User acquires mutex A
5193/// - User calls FlushBaskets.
5194/// - ROOT launches N tasks and calls wait.
5195/// - TBB schedules another user task, T2.
5196/// - T2 tries to acquire mutex A.
5197///
5198/// At this point, the thread will deadlock: the code may function with IMT-mode
5199/// disabled if the user assumed the legacy code never would run their own TBB
5200/// tasks.
5201///
5202/// SO: users of TBB who want to enable IMT-mode should carefully review their
5203/// locking patterns and make sure they hold no coarse-grained application
5204/// locks when they invoke ROOT.
5205///
5206/// Return the number of bytes written or -1 in case of write error.
5208{
5210 if (retval == -1) return retval;
5211
5212 if (create_cluster) const_cast<TTree *>(this)->MarkEventCluster();
5213 return retval;
5214}
5215
5216////////////////////////////////////////////////////////////////////////////////
5217/// Internal implementation of the FlushBaskets algorithm.
5218/// Unlike the public interface, this does NOT create an explicit event cluster
5219/// boundary; it is up to the (internal) caller to determine whether that should
5220/// done.
5221///
5222/// Otherwise, the comments for FlushBaskets applies.
5225{
5226 if (!fDirectory) return 0;
5227 Int_t nbytes = 0;
5228 Int_t nerror = 0;
5229 TObjArray *lb = const_cast<TTree*>(this)->GetListOfBranches();
5230 Int_t nb = lb->GetEntriesFast();
5231
5232#ifdef R__USE_IMT
5234 if (useIMT) {
5235 // ROOT-9668: here we need to check if the size of fSortedBranches is different from the
5236 // size of the list of branches before triggering the initialisation of the fSortedBranches
5237 // container to cover two cases:
5238 // 1. This is the first time we flush. fSortedBranches is empty and we need to fill it.
5239 // 2. We flushed at least once already but a branch has been be added to the tree since then
5240 if (fSortedBranches.size() != unsigned(nb)) { const_cast<TTree*>(this)->InitializeBranchLists(false); }
5241
5242 BoolRAIIToggle sentry(fIMTFlush);
5243 fIMTZipBytes.store(0);
5244 fIMTTotBytes.store(0);
5245 std::atomic<Int_t> nerrpar(0);
5246 std::atomic<Int_t> nbpar(0);
5247 std::atomic<Int_t> pos(0);
5248
5249 auto mapFunction = [&]() {
5250 // The branch to process is obtained when the task starts to run.
5251 // This way, since branches are sorted, we make sure that branches
5252 // leading to big tasks are processed first. If we assigned the
5253 // branch at task creation time, the scheduler would not necessarily
5254 // respect our sorting.
5255 Int_t j = pos.fetch_add(1);
5256
5257 auto branch = fSortedBranches[j].second;
5258 if (R__unlikely(!branch)) { return; }
5259
5260 if (R__unlikely(gDebug > 0)) {
5261 std::stringstream ss;
5262 ss << std::this_thread::get_id();
5263 Info("FlushBaskets", "[IMT] Thread %s", ss.str().c_str());
5264 Info("FlushBaskets", "[IMT] Running task for branch #%d: %s", j, branch->GetName());
5265 }
5266
5267 Int_t nbtask = branch->FlushBaskets();
5268
5269 if (nbtask < 0) { nerrpar++; }
5270 else { nbpar += nbtask; }
5271 };
5272
5274 pool.Foreach(mapFunction, nb);
5275
5276 fIMTFlush = false;
5277 const_cast<TTree*>(this)->AddTotBytes(fIMTTotBytes);
5278 const_cast<TTree*>(this)->AddZipBytes(fIMTZipBytes);
5279
5280 return nerrpar ? -1 : nbpar.load();
5281 }
5282#endif
5283 for (Int_t j = 0; j < nb; j++) {
5284 TBranch* branch = (TBranch*) lb->UncheckedAt(j);
5285 if (branch) {
5286 Int_t nwrite = branch->FlushBaskets();
5287 if (nwrite<0) {
5288 ++nerror;
5289 } else {
5290 nbytes += nwrite;
5291 }
5292 }
5293 }
5294 if (nerror) {
5295 return -1;
5296 } else {
5297 return nbytes;
5298 }
5299}
5300
5301////////////////////////////////////////////////////////////////////////////////
5302/// Returns the expanded value of the alias. Search in the friends if any.
5304const char* TTree::GetAlias(const char* aliasName) const
5305{
5306 // We already have been visited while recursively looking
5307 // through the friends tree, let's return.
5309 return nullptr;
5310 }
5311 if (fAliases) {
5313 if (alias) {
5314 return alias->GetTitle();
5315 }
5316 }
5317 if (!fFriends) {
5318 return nullptr;
5319 }
5320 TFriendLock lock(const_cast<TTree*>(this), kGetAlias);
5322 TFriendElement* fe = nullptr;
5323 while ((fe = (TFriendElement*) nextf())) {
5324 TTree* t = fe->GetTree();
5325 if (t) {
5326 const char* alias = t->GetAlias(aliasName);
5327 if (alias) {
5328 return alias;
5329 }
5330 const char* subAliasName = strstr(aliasName, fe->GetName());
5331 if (subAliasName && (subAliasName[strlen(fe->GetName())] == '.')) {
5332 alias = t->GetAlias(aliasName + strlen(fe->GetName()) + 1);
5333 if (alias) {
5334 return alias;
5335 }
5336 }
5337 }
5338 }
5339 return nullptr;
5340}
5341
5342namespace {
5343/// Do a breadth first search through the implied hierarchy
5344/// of branches.
5345/// To avoid scanning through the list multiple time
5346/// we also remember the 'depth-first' match.
5347TBranch *R__GetBranch(const TObjArray &branches, const char *name)
5348{
5349 TBranch *result = nullptr;
5350 Int_t nb = branches.GetEntriesFast();
5351 for (Int_t i = 0; i < nb; i++) {
5352 TBranch* b = (TBranch*)branches.UncheckedAt(i);
5353 if (!b)
5354 continue;
5355 if (!strcmp(b->GetName(), name)) {
5356 return b;
5357 }
5358 if (!strcmp(b->GetFullName(), name)) {
5359 return b;
5360 }
5361 if (!result)
5362 result = R__GetBranch(*(b->GetListOfBranches()), name);
5363 }
5364 return result;
5365}
5366}
5367
5368////////////////////////////////////////////////////////////////////////////////
5369/// Returns a pointer to the branch with the given name, if it can be found in
5370/// this tree. Otherwise, returns nullptr.
5371TBranch *TTree::GetBranchFromSelf(const char *branchName)
5372{
5373 // Look for an exact match in the list of top level
5374 // branches.
5375 if (auto *br = static_cast<TBranch *>(fBranches.FindObject(branchName)))
5376 return br;
5377
5378 // Look for an exact match in the mapping from branch name to TBranch *
5379 // gathered when first reading the TTree from disk.
5380 if (auto it = fNamesToBranches.find(branchName); it != fNamesToBranches.end())
5381 return it->second;
5382
5383 // Search using branches, breadth first.
5384 if (auto *br = R__GetBranch(fBranches, branchName))
5385 return br;
5386
5387 // Search using leaves.
5389 Int_t nleaves = leaves->GetEntriesFast();
5390 for (Int_t i = 0; i < nleaves; i++) {
5391 TLeaf *leaf = (TLeaf *)leaves->UncheckedAt(i);
5392 TBranch *branch = leaf->GetBranch();
5393 if (!strcmp(branch->GetName(), branchName)) {
5394 return branch;
5395 }
5396 if (!strcmp(branch->GetFullName(), branchName)) {
5397 return branch;
5398 }
5399 }
5400
5401 return nullptr;
5402}
5403
5404////////////////////////////////////////////////////////////////////////////////
5405/// Returns a pointer to the branch with the given name, if it can be found in
5406/// the list of friends of this tree. Otherwise, returns nullptr.
5407TBranch *TTree::GetBranchFromFriends(const char *branchName)
5408{
5409 if (!fFriends) {
5410 return nullptr;
5411 }
5412
5413 // Search in list of friends.
5414 TFriendLock lock(this, kGetBranch);
5415 TIter next(fFriends);
5416 TFriendElement *fe = nullptr;
5417 while ((fe = (TFriendElement *)next())) {
5418 TTree *t = fe->GetTree();
5419 if (t) {
5420 TBranch *branch = t->GetBranch(branchName);
5421 if (branch) {
5422 return branch;
5423 }
5424 }
5425 }
5426
5427 // Second pass in the list of friends when
5428 // the branch name is prefixed by the tree name.
5429 next.Reset();
5430 while ((fe = (TFriendElement *)next())) {
5431 TTree *t = fe->GetTree();
5432 if (!t) {
5433 continue;
5434 }
5435 const char *subname = strstr(branchName, fe->GetName());
5436 if (subname != branchName) {
5437 continue;
5438 }
5439 Int_t l = strlen(fe->GetName());
5440 subname += l;
5441 if (*subname != '.') {
5442 continue;
5443 }
5444 subname++;
5446 if (branch) {
5447 return branch;
5448 }
5449 }
5450
5451 return nullptr;
5452}
5453
5454////////////////////////////////////////////////////////////////////////////////
5455/// Return pointer to the branch with the given name in this tree or its friends.
5456/// The search is done breadth first.
5457/// \sa TTree::FindBranch
5459TBranch *TTree::GetBranch(const char *name)
5460{
5461 // We already have been visited while recursively
5462 // looking through the friends tree, let's return.
5464 return nullptr;
5465 }
5466
5467 if (!name)
5468 return nullptr;
5469
5470 if (auto *br = GetBranchFromSelf(name))
5471 return br;
5472
5473 if (auto *br = GetBranchFromFriends(name))
5474 return br;
5475
5476 return nullptr;
5477}
5478
5479////////////////////////////////////////////////////////////////////////////////
5480/// Return status of branch with name branchname.
5481///
5482/// - 0 if branch is not activated
5483/// - 1 if branch is activated
5485bool TTree::GetBranchStatus(const char* branchname) const
5486{
5487 TBranch* br = const_cast<TTree*>(this)->GetBranch(branchname);
5488 if (br) {
5489 return br->TestBit(kDoNotProcess) == 0;
5490 }
5491 return false;
5492}
5493
5494////////////////////////////////////////////////////////////////////////////////
5495/// Static function returning the current branch style.
5496///
5497/// - style = 0 old Branch
5498/// - style = 1 new Bronch
5503}
5504
5505////////////////////////////////////////////////////////////////////////////////
5506/// Used for automatic sizing of the cache.
5507///
5508/// Estimates a suitable size in bytes for the tree cache based on AutoFlush.
5509/// A cache sizing factor is taken from the configuration. If this yields zero
5510/// and withDefault is true the historical algorithm for default size is used.
5512Long64_t TTree::GetCacheAutoSize(bool withDefault /* = false */ )
5513{
5515 {
5516 Long64_t cacheSize = 0;
5517 if (fAutoFlush < 0) {
5518 cacheSize = Long64_t(-cacheFactor * fAutoFlush);
5519 } else if (fAutoFlush == 0) {
5521 if (medianClusterSize > 0)
5522 cacheSize = Long64_t(cacheFactor * 1.5 * medianClusterSize * GetZipBytes() / (fEntries + 1));
5523 else
5524 cacheSize = Long64_t(cacheFactor * 1.5 * 30000000); // use the default value of fAutoFlush
5525 } else {
5526 cacheSize = Long64_t(cacheFactor * 1.5 * fAutoFlush * GetZipBytes() / (fEntries + 1));
5527 }
5528 if (cacheSize >= (INT_MAX / 4)) {
5529 cacheSize = INT_MAX / 4;
5530 }
5531 return cacheSize;
5532 };
5533
5534 const char *stcs;
5535 Double_t cacheFactor = 0.0;
5536 if (!(stcs = gSystem->Getenv("ROOT_TTREECACHE_SIZE")) || !*stcs) {
5537 cacheFactor = gEnv->GetValue("TTreeCache.Size", 1.0);
5538 } else {
5540 }
5541
5542 if (cacheFactor < 0.0) {
5543 // ignore negative factors
5544 cacheFactor = 0.0;
5545 }
5546
5548
5549 if (cacheSize < 0) {
5550 cacheSize = 0;
5551 }
5552
5553 if (cacheSize == 0 && withDefault) {
5554 cacheSize = calculateCacheSize(1.0);
5555 }
5556
5557 return cacheSize;
5558}
5559
5560////////////////////////////////////////////////////////////////////////////////
5561/// Return an iterator over the cluster of baskets starting at firstentry.
5562///
5563/// This iterator is not yet supported for TChain object.
5564/// ~~~ {.cpp}
5565/// TTree::TClusterIterator clusterIter = tree->GetClusterIterator(entry);
5566/// Long64_t clusterStart;
5567/// while( (clusterStart = clusterIter()) < tree->GetEntries() ) {
5568/// printf("The cluster starts at %lld and ends at %lld (inclusive)\n",clusterStart,clusterIter.GetNextEntry()-1);
5569/// }
5570/// ~~~
5573{
5574 // create cache if wanted
5575 if (fCacheDoAutoInit)
5577
5578 return TClusterIterator(this,firstentry);
5579}
5580
5581////////////////////////////////////////////////////////////////////////////////
5582/// Return pointer to the current file.
5585{
5586 if (!fDirectory || fDirectory==gROOT) {
5587 return nullptr;
5588 }
5589 return fDirectory->GetFile();
5590}
5591
5592////////////////////////////////////////////////////////////////////////////////
5593/// Return the number of entries matching the selection.
5594/// Return -1 in case of errors.
5595///
5596/// If the selection uses any arrays or containers, we return the number
5597/// of entries where at least one element match the selection.
5598/// GetEntries is implemented using the selector class TSelectorEntries,
5599/// which can be used directly (see code in TTreePlayer::GetEntries) for
5600/// additional option.
5601/// If SetEventList was used on the TTree or TChain, only that subset
5602/// of entries will be considered.
5605{
5606 GetPlayer();
5607 if (fPlayer) {
5608 return fPlayer->GetEntries(selection);
5609 }
5610 return -1;
5611}
5612
5613////////////////////////////////////////////////////////////////////////////////
5614/// Returns a number corresponding to:
5615/// - The number of entries in this tree, if greater than zero
5616/// - The number of entries in the first friend tree, if there are any friends
5617/// - 0 otherwise
5620{
5621 if (fEntries) return fEntries;
5622 if (!fFriends) return 0;
5624 if (!fr) return 0;
5625 TTree *t = fr->GetTree();
5626 if (t==nullptr) return 0;
5627 return t->GetEntriesFriend();
5628}
5629
5630////////////////////////////////////////////////////////////////////////////////
5631/// Read all branches of entry and return total number of bytes read.
5632///
5633/// - `getall = 0` : get only active branches
5634/// - `getall = 1` : get all branches
5635///
5636/// The function returns the number of bytes read from the input buffer.
5637/// If entry does not exist the function returns 0.
5638/// If an I/O error occurs, the function returns -1.
5639/// If all branches are disabled and getall == 0, it also returns 0
5640/// even if the specified entry exists in the tree, since zero bytes were read.
5641///
5642/// If the Tree has friends, also read the friends entry.
5643///
5644/// To activate/deactivate one or more branches, use TBranch::SetBranchStatus
5645/// For example, if you have a Tree with several hundred branches, and you
5646/// are interested only by branches named "a" and "b", do
5647/// ~~~ {.cpp}
5648/// mytree.SetBranchStatus("*",0); //disable all branches
5649/// mytree.SetBranchStatus("a",1);
5650/// mytree.SetBranchStatus("b",1);
5651/// ~~~
5652/// when calling mytree.GetEntry(i); only branches "a" and "b" will be read.
5653///
5654/// __WARNING!!__
5655/// If your Tree has been created in split mode with a parent branch "parent.",
5656/// ~~~ {.cpp}
5657/// mytree.SetBranchStatus("parent",1);
5658/// ~~~
5659/// will not activate the sub-branches of "parent". You should do:
5660/// ~~~ {.cpp}
5661/// mytree.SetBranchStatus("parent*",1);
5662/// ~~~
5663/// Without the trailing dot in the branch creation you have no choice but to
5664/// call SetBranchStatus explicitly for each of the sub branches.
5665///
5666/// An alternative is to call directly
5667/// ~~~ {.cpp}
5668/// brancha.GetEntry(i)
5669/// branchb.GetEntry(i);
5670/// ~~~
5671/// ## IMPORTANT NOTE
5672///
5673/// By default, GetEntry reuses the space allocated by the previous object
5674/// for each branch. You can force the previous object to be automatically
5675/// deleted if you call mybranch.SetAutoDelete(true) (default is false).
5676///
5677/// Example:
5678///
5679/// Consider the example in $ROOTSYS/test/Event.h
5680/// The top level branch in the tree T is declared with:
5681/// ~~~ {.cpp}
5682/// Event *event = 0; //event must be null or point to a valid object
5683/// //it must be initialized
5684/// T.SetBranchAddress("event",&event);
5685/// ~~~
5686/// When reading the Tree, one can choose one of these 3 options:
5687///
5688/// ## OPTION 1
5689///
5690/// ~~~ {.cpp}
5691/// for (Long64_t i=0;i<nentries;i++) {
5692/// T.GetEntry(i);
5693/// // the object event has been filled at this point
5694/// }
5695/// ~~~
5696/// The default (recommended). At the first entry an object of the class
5697/// Event will be created and pointed by event. At the following entries,
5698/// event will be overwritten by the new data. All internal members that are
5699/// TObject* are automatically deleted. It is important that these members
5700/// be in a valid state when GetEntry is called. Pointers must be correctly
5701/// initialized. However these internal members will not be deleted if the
5702/// characters "->" are specified as the first characters in the comment
5703/// field of the data member declaration.
5704///
5705/// If "->" is specified, the pointer member is read via pointer->Streamer(buf).
5706/// In this case, it is assumed that the pointer is never null (case of
5707/// pointer TClonesArray *fTracks in the Event example). If "->" is not
5708/// specified, the pointer member is read via buf >> pointer. In this case
5709/// the pointer may be null. Note that the option with "->" is faster to
5710/// read or write and it also consumes less space in the file.
5711///
5712/// ## OPTION 2
5713///
5714/// The option AutoDelete is set
5715/// ~~~ {.cpp}
5716/// TBranch *branch = T.GetBranch("event");
5717/// branch->SetAddress(&event);
5718/// branch->SetAutoDelete(true);
5719/// for (Long64_t i=0;i<nentries;i++) {
5720/// T.GetEntry(i);
5721/// // the object event has been filled at this point
5722/// }
5723/// ~~~
5724/// In this case, at each iteration, the object event is deleted by GetEntry
5725/// and a new instance of Event is created and filled.
5726///
5727/// ## OPTION 3
5728///
5729/// ~~~ {.cpp}
5730/// Same as option 1, but you delete yourself the event.
5731///
5732/// for (Long64_t i=0;i<nentries;i++) {
5733/// delete event;
5734/// event = 0; // EXTREMELY IMPORTANT
5735/// T.GetEntry(i);
5736/// // the object event has been filled at this point
5737/// }
5738/// ~~~
5739/// It is strongly recommended to use the default option 1. It has the
5740/// additional advantage that functions like TTree::Draw (internally calling
5741/// TTree::GetEntry) will be functional even when the classes in the file are
5742/// not available.
5743///
5744/// Note: See the comments in TBranchElement::SetAddress() for the
5745/// object ownership policy of the underlying (user) data.
5748{
5749 // We already have been visited while recursively looking
5750 // through the friends tree, let return
5751 if (kGetEntry & fFriendLockStatus) return 0;
5752
5753 if (entry < 0 || entry >= fEntries) return 0;
5754 Int_t i;
5755 Int_t nbytes = 0;
5756 fReadEntry = entry;
5757
5758 // create cache if wanted
5759 if (fCacheDoAutoInit)
5761
5763 Int_t nb=0;
5764
5765 auto seqprocessing = [&]() {
5766 TBranch *branch;
5767 for (i=0;i<nbranches;i++) {
5769 nb = branch->GetEntry(entry, getall);
5770 if (nb < 0) break;
5771 nbytes += nb;
5772 }
5773 };
5774
5775#ifdef R__USE_IMT
5777 if (fSortedBranches.empty())
5779
5780 // Count branches are processed first and sequentially
5781 for (auto branch : fSeqBranches) {
5782 nb = branch->GetEntry(entry, getall);
5783 if (nb < 0) break;
5784 nbytes += nb;
5785 }
5786 if (nb < 0) return nb;
5787
5788 // Enable this IMT use case (activate its locks)
5790
5791 Int_t errnb = 0;
5792 std::atomic<Int_t> pos(0);
5793 std::atomic<Int_t> nbpar(0);
5794
5795 auto mapFunction = [&]() {
5796 // The branch to process is obtained when the task starts to run.
5797 // This way, since branches are sorted, we make sure that branches
5798 // leading to big tasks are processed first. If we assigned the
5799 // branch at task creation time, the scheduler would not necessarily
5800 // respect our sorting.
5801 Int_t j = pos.fetch_add(1);
5802
5803 Int_t nbtask = 0;
5804 auto branch = fSortedBranches[j].second;
5805
5806 if (gDebug > 0) {
5807 std::stringstream ss;
5808 ss << std::this_thread::get_id();
5809 Info("GetEntry", "[IMT] Thread %s", ss.str().c_str());
5810 Info("GetEntry", "[IMT] Running task for branch #%d: %s", j, branch->GetName());
5811 }
5812
5813 std::chrono::time_point<std::chrono::system_clock> start, end;
5814
5815 start = std::chrono::system_clock::now();
5816 nbtask = branch->GetEntry(entry, getall);
5817 end = std::chrono::system_clock::now();
5818
5819 Long64_t tasktime = (Long64_t)std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
5820 fSortedBranches[j].first += tasktime;
5821
5822 if (nbtask < 0) errnb = nbtask;
5823 else nbpar += nbtask;
5824 };
5825
5827 pool.Foreach(mapFunction, fSortedBranches.size());
5828
5829 if (errnb < 0) {
5830 nb = errnb;
5831 }
5832 else {
5833 // Save the number of bytes read by the tasks
5834 nbytes += nbpar;
5835
5836 // Re-sort branches if necessary
5840 }
5841 }
5842 }
5843 else {
5844 seqprocessing();
5845 }
5846#else
5847 seqprocessing();
5848#endif
5849 if (nb < 0) return nb;
5850
5851 // GetEntry in list of friends
5852 if (!fFriends) return nbytes;
5853 TFriendLock lock(this,kGetEntry);
5856 while ((fe = (TFriendElement*)nextf())) {
5857 TTree *t = fe->GetTree();
5858 if (t) {
5859 if (fe->TestBit(TFriendElement::kFromChain)) {
5860 nb = t->GetEntry(t->GetReadEntry(),getall);
5861 } else {
5862 if ( t->LoadTreeFriend(entry,this) >= 0 ) {
5863 nb = t->GetEntry(t->GetReadEntry(),getall);
5864 } else nb = 0;
5865 }
5866 if (nb < 0) return nb;
5867 nbytes += nb;
5868 }
5869 }
5870 return nbytes;
5871}
5872
5873
5874////////////////////////////////////////////////////////////////////////////////
5875/// Divides the top-level branches into two vectors: (i) branches to be
5876/// processed sequentially and (ii) branches to be processed in parallel.
5877/// Even if IMT is on, some branches might need to be processed first and in a
5878/// sequential fashion: in the parallelization of GetEntry, those are the
5879/// branches that store the size of another branch for every entry
5880/// (e.g. the size of an array branch). If such branches were processed
5881/// in parallel with the rest, there could be two threads invoking
5882/// TBranch::GetEntry on one of them at the same time, since a branch that
5883/// depends on a size (or count) branch will also invoke GetEntry on the latter.
5884/// This method can be invoked several times during the event loop if the TTree
5885/// is being written, for example when adding new branches. In these cases, the
5886/// `checkLeafCount` parameter is false.
5887/// \param[in] checkLeafCount True if we need to check whether some branches are
5888/// count leaves.
5891{
5893
5894 // The special branch fBranchRef needs to be processed sequentially:
5895 // we add it once only.
5896 if (fBranchRef && fBranchRef != fSeqBranches[0]) {
5897 fSeqBranches.push_back(fBranchRef);
5898 }
5899
5900 // The branches to be processed sequentially are those that are the leaf count of another branch
5901 if (checkLeafCount) {
5902 for (Int_t i = 0; i < nbranches; i++) {
5904 auto leafCount = ((TLeaf*)branch->GetListOfLeaves()->At(0))->GetLeafCount();
5905 if (leafCount) {
5906 auto countBranch = leafCount->GetBranch();
5907 if (std::find(fSeqBranches.begin(), fSeqBranches.end(), countBranch) == fSeqBranches.end()) {
5908 fSeqBranches.push_back(countBranch);
5909 }
5910 }
5911 }
5912 }
5913
5914 // Any branch that is not a leaf count can be safely processed in parallel when reading
5915 // We need to reset the vector to make sure we do not re-add several times the same branch.
5916 if (!checkLeafCount) {
5917 fSortedBranches.clear();
5918 }
5919 for (Int_t i = 0; i < nbranches; i++) {
5920 Long64_t bbytes = 0;
5922 if (std::find(fSeqBranches.begin(), fSeqBranches.end(), branch) == fSeqBranches.end()) {
5923 bbytes = branch->GetTotBytes("*");
5924 fSortedBranches.emplace_back(bbytes, branch);
5925 }
5926 }
5927
5928 // Initially sort parallel branches by size
5929 std::sort(fSortedBranches.begin(),
5930 fSortedBranches.end(),
5931 [](std::pair<Long64_t,TBranch*> a, std::pair<Long64_t,TBranch*> b) {
5932 return a.first > b.first;
5933 });
5934
5935 for (size_t i = 0; i < fSortedBranches.size(); i++) {
5936 fSortedBranches[i].first = 0LL;
5937 }
5938}
5939
5940////////////////////////////////////////////////////////////////////////////////
5941/// Sorts top-level branches by the last average task time recorded per branch.
5944{
5945 for (size_t i = 0; i < fSortedBranches.size(); i++) {
5947 }
5948
5949 std::sort(fSortedBranches.begin(),
5950 fSortedBranches.end(),
5951 [](std::pair<Long64_t,TBranch*> a, std::pair<Long64_t,TBranch*> b) {
5952 return a.first > b.first;
5953 });
5954
5955 for (size_t i = 0; i < fSortedBranches.size(); i++) {
5956 fSortedBranches[i].first = 0LL;
5957 }
5958}
5959
5960////////////////////////////////////////////////////////////////////////////////
5961///Returns the entry list assigned to this tree
5964{
5965 return fEntryList;
5966}
5967
5968////////////////////////////////////////////////////////////////////////////////
5969/// Return entry number corresponding to entry.
5970///
5971/// if no TEntryList set returns entry
5972/// else returns the entry number corresponding to the list index=entry
5975{
5976 if (!fEntryList) {
5977 return entry;
5978 }
5979
5980 return fEntryList->GetEntry(entry);
5981}
5982
5983////////////////////////////////////////////////////////////////////////////////
5984/// Return entry number corresponding to major and minor number.
5985/// Note that this function returns only the entry number, not the data
5986/// To read the data corresponding to an entry number, use TTree::GetEntryWithIndex
5987/// the BuildIndex function has created a table of Long64_t* of sorted values
5988/// corresponding to val = major<<31 + minor;
5989/// The function performs binary search in this sorted table.
5990/// If it finds a pair that matches val, it returns directly the
5991/// index in the table.
5992/// If an entry corresponding to major and minor is not found, the function
5993/// returns the index of the major,minor pair immediately lower than the
5994/// requested value, ie it will return -1 if the pair is lower than
5995/// the first entry in the index.
5996///
5997/// See also GetEntryNumberWithIndex
6005}
6006
6007////////////////////////////////////////////////////////////////////////////////
6008/// Return entry number corresponding to major and minor number.
6009/// Note that this function returns only the entry number, not the data
6010/// To read the data corresponding to an entry number, use TTree::GetEntryWithIndex
6011/// the BuildIndex function has created a table of Long64_t* of sorted values
6012/// corresponding to val = major<<31 + minor;
6013/// The function performs binary search in this sorted table.
6014/// If it finds a pair that matches val, it returns directly the
6015/// index in the table, otherwise it returns -1.
6016///
6017/// See also GetEntryNumberWithBestIndex
6020{
6021 if (!fTreeIndex) {
6022 return -1;
6023 }
6025}
6026
6027////////////////////////////////////////////////////////////////////////////////
6028/// Read entry corresponding to major and minor number.
6029///
6030/// The function returns the total number of bytes read; -1 if entry not found.
6031/// If the Tree has friend trees, the corresponding entry with
6032/// the index values (major,minor) is read. Note that the master Tree
6033/// and its friend may have different entry serial numbers corresponding
6034/// to (major,minor).
6035/// \note See TTreeIndex::GetEntryNumberWithIndex for information about the maximum values accepted for major and minor
6038{
6039 // We already have been visited while recursively looking
6040 // through the friends tree, let's return.
6042 return 0;
6043 }
6045 if (serial < 0) {
6046 return -1;
6047 }
6048 // create cache if wanted
6049 if (fCacheDoAutoInit)
6051
6052 Int_t i;
6053 Int_t nbytes = 0;
6054 fReadEntry = serial;
6055 TBranch *branch;
6057 Int_t nb;
6058 for (i = 0; i < nbranches; ++i) {
6060 nb = branch->GetEntry(serial);
6061 if (nb < 0) return nb;
6062 nbytes += nb;
6063 }
6064 // GetEntry in list of friends
6065 if (!fFriends) return nbytes;
6068 TFriendElement* fe = nullptr;
6069 while ((fe = (TFriendElement*) nextf())) {
6070 TTree *t = fe->GetTree();
6071 if (t) {
6072 serial = t->GetEntryNumberWithIndex(major,minor);
6073 if (serial <0) return -nbytes;
6074 nb = t->GetEntry(serial);
6075 if (nb < 0) return nb;
6076 nbytes += nb;
6077 }
6078 }
6079 return nbytes;
6080}
6081
6082////////////////////////////////////////////////////////////////////////////////
6083/// Return a pointer to the TTree friend whose name or alias is `friendname`.
6085TTree* TTree::GetFriend(const char *friendname) const
6086{
6087
6088 // We already have been visited while recursively
6089 // looking through the friends tree, let's return.
6091 return nullptr;
6092 }
6093 if (!fFriends) {
6094 return nullptr;
6095 }
6096 TFriendLock lock(const_cast<TTree*>(this), kGetFriend);
6098 TFriendElement* fe = nullptr;
6099 while ((fe = (TFriendElement*) nextf())) {
6100 if (strcmp(friendname,fe->GetName())==0
6101 || strcmp(friendname,fe->GetTreeName())==0) {
6102 return fe->GetTree();
6103 }
6104 }
6105 // After looking at the first level,
6106 // let's see if it is a friend of friends.
6107 nextf.Reset();
6108 fe = nullptr;
6109 while ((fe = (TFriendElement*) nextf())) {
6110 TTree *res = fe->GetTree()->GetFriend(friendname);
6111 if (res) {
6112 return res;
6113 }
6114 }
6115 return nullptr;
6116}
6117
6118////////////////////////////////////////////////////////////////////////////////
6119/// If the 'tree' is a friend, this method returns its alias name.
6120///
6121/// This alias is an alternate name for the tree.
6122///
6123/// It can be used in conjunction with a branch or leaf name in a TTreeFormula,
6124/// to specify in which particular tree the branch or leaf can be found if
6125/// the friend trees have branches or leaves with the same name as the master
6126/// tree.
6127///
6128/// It can also be used in conjunction with an alias created using
6129/// TTree::SetAlias in a TTreeFormula, e.g.:
6130/// ~~~ {.cpp}
6131/// maintree->Draw("treealias.fPx - treealias.myAlias");
6132/// ~~~
6133/// where fPx is a branch of the friend tree aliased as 'treealias' and 'myAlias'
6134/// was created using TTree::SetAlias on the friend tree.
6135///
6136/// However, note that 'treealias.myAlias' will be expanded literally,
6137/// without remembering that it comes from the aliased friend and thus
6138/// the branch name might not be disambiguated properly, which means
6139/// that you may not be able to take advantage of this feature.
6140///
6142const char *TTree::GetFriendAlias(TTree *tree) const
6143{
6144 if ((tree == this) || (tree == GetTree())) {
6145 return nullptr;
6146 }
6147
6148 // We already have been visited while recursively
6149 // looking through the friends tree, let's return.
6151 return nullptr;
6152 }
6153
6154 // This is a TTree and it does not have any friends, we can return early
6155 if (GetTree() == this && !fFriends)
6156 return nullptr;
6157
6158 TFriendLock lock(const_cast<TTree *>(this), kGetFriendAlias);
6159
6160 auto lookForFriendNameInListOfFriends = [tree](const TList &friends) -> const char * {
6162 auto *frElTree = frEl->GetTree();
6163 // Simplest case: we found a friend which tree is the same as the input tree
6164 if (frElTree == tree)
6165 return frEl->GetName();
6166 // Try again: the friend tree might be actually a TChain
6167 if (frElTree && frElTree->GetTree() == tree)
6168 return frEl->GetName();
6169 }
6170 return nullptr;
6171 };
6172
6173 // First, look for the immediate friends of this tree
6174 if (fFriends) {
6176 if (friendAlias)
6177 return friendAlias;
6178 }
6179
6180 // Then, check if this is a TChain and the current tree has friends
6181 // The non-redundant scenario here is that the currently-available
6182 // inner TTree of this TChain has a list of friends which the TChain
6183 // itself doesn't know anything about.
6184 if (const auto *innerListOfFriends = GetTree()->GetListOfFriends();
6187 if (friendAlias)
6188 return friendAlias;
6189 }
6190
6191 // Recursively look into the list of friends of this tree
6192 if (fFriends) {
6194 const char *friendAlias = frEl->GetTree()->GetFriendAlias(tree);
6195 if (friendAlias)
6196 return friendAlias;
6197 }
6198 }
6199
6200 // Recursively look into the list of friends of the inner tree
6201 if (const auto *innerListOfFriends = GetTree()->GetListOfFriends();
6204 const char *friendAlias = frEl->GetTree()->GetFriendAlias(tree);
6205 if (friendAlias)
6206 return friendAlias;
6207 }
6208 }
6209 return nullptr;
6210}
6211
6212////////////////////////////////////////////////////////////////////////////////
6213/// Returns the current set of IO settings
6215{
6216 return fIOFeatures;
6217}
6218
6219////////////////////////////////////////////////////////////////////////////////
6220/// Creates a new iterator that will go through all the leaves on the tree itself and its friend.
6223{
6224 return new TTreeFriendLeafIter(this, dir);
6225}
6227TLeaf *TTree::SearchLeafInListOfLeaves(const char *branchName, const char *leafName)
6228{
6230 if (strcmp(leaf->GetFullName(), leafName) != 0 && strcmp(leaf->GetName(), leafName) != 0)
6231 continue; // leafName does not match GetName() nor GetFullName(), this is not the right leaf
6232 if (branchName) {
6233 // check the branchName is also a match
6234 TBranch *br = leaf->GetBranch();
6235 // if a quick comparison with the branch full name is a match, we are done
6236 if (!strcmp(br->GetFullName(), branchName))
6237 return leaf;
6238 UInt_t nbch = strlen(branchName);
6239 const char* brname = br->GetName();
6240 TBranch *mother = br->GetMother();
6241 if (strncmp(brname, branchName, nbch)) {
6242 if (mother != br) {
6243 const char *mothername = mother->GetName();
6245 if (!strcmp(mothername, branchName)) {
6246 return leaf;
6247 } else if (nbch > motherlen && strncmp(mothername, branchName, motherlen) == 0 &&
6248 (mothername[motherlen - 1] == '.' || branchName[motherlen] == '.')) {
6249 // 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.
6250 if (strncmp(brname, branchName + motherlen + 1, nbch - motherlen - 1)) {
6251 // No it does not
6252 continue;
6253 } // else we have match so we can proceed.
6254 } else {
6255 // no match
6256 continue;
6257 }
6258 } else {
6259 continue;
6260 }
6261 }
6262 // The start of the branch name is identical to the content
6263 // of 'aname' before the first '/'.
6264 // Let's make sure that it is not longer (we are trying
6265 // to avoid having jet2/value match the branch jet23
6266 if ((strlen(brname) > nbch) && (brname[nbch] != '.') && (brname[nbch] != '[')) {
6267 continue;
6268 }
6269 }
6270 return leaf;
6271 }
6272
6273 return nullptr;
6274}
6276TLeaf *TTree::SearchLeafInListOfFriends(const char *branchName, const char *leafName)
6277{
6278 if (!fFriends) return nullptr;
6279 // The corresponding check is in GetLeaf
6280 TFriendLock lock(this, kGetLeaf);
6281
6283 if (auto *t = frEl->GetTree())
6284 if (auto *leaf = t->GetLeaf(branchName, leafName))
6285 return leaf;
6286
6287 // Second pass in the list of friends when the leaf name is prefixed by the tree name
6290 TTree *t = frEl->GetTree();
6291 if (!t) continue;
6292 const char *subLeafName = strstr(leafName, frEl->GetName());
6293 if (subLeafName != leafName)
6294 continue;
6295 Int_t l = strlen(frEl->GetName());
6296 subLeafName += l;
6297 if (*subLeafName != '.')
6298 continue;
6299 subLeafName++;
6301 if (auto *leaf = t->GetLeaf(branchName, subLeafName))
6302 return leaf;
6303 }
6304
6305 return nullptr;
6306}
6307
6308////////////////////////////////////////////////////////////////////////////////
6309/// Searches in this tree and any of its friends for a leaf named \p leafname in branch \p branchname , returns first
6310/// match or nullptr if no match.
6311///
6312/// Search order:
6313///
6314/// 1. Look for a \p branchname match (via FindBranch(branchname)):
6315/// a. In the list of branches of this tree
6316/// b. Recursively in nested branches of each branch of this tree
6317/// c. In the friends of this tree
6318/// 2. Look for matching \p branchname and \p leafname in list of leaves of this tree
6319/// 3. Look for matching \p branchname and \p leafname in friends of this tree (eventually calling GetLeaf on each
6320/// friend)
6321///
6322/// \note \p branchname can be an empty string, in which case the function will return the first leaf with matching
6323/// \p leafname in any branch of this tree or any of its friends following the search order above.
6324///
6325/// \note \p leafname can contain the name of a friend tree with the syntax: `friend_dir_and_tree.full_leaf_name`. In
6326/// particular, `friend_dir_and_tree` can be of the form `TDirectoryName/TreeName`.
6327TLeaf* TTree::GetLeaf(const char* branchname, const char *leafname)
6328{
6329 if (leafname == nullptr) return nullptr;
6330
6331 // We already have been visited while recursively looking
6332 // through the friends tree, let return
6334 return nullptr;
6335 }
6336
6337 if (auto *br = FindBranch(branchname))
6338 if (auto leaf = br->GetLeaf(leafname))
6339 return leaf;
6340
6342 return leaf;
6343
6345 return leaf;
6346
6347 return nullptr;
6348}
6349
6350////////////////////////////////////////////////////////////////////////////////
6351/// Searches in this tree and any of its friends for a leaf named \p leafname , returns first leaf matching in any
6352/// branch.
6353///
6354/// See TTree::GetLeaf(const char* branchname, const char *leafname) for a description of the search order.
6355///
6356/// \note \p name may be in the form `branch/leaf`
6358TLeaf* TTree::GetLeaf(const char *name)
6359{
6360 // Return nullptr if name is invalid or if we have
6361 // already been visited while searching friend trees
6362 if (!name || (kGetLeaf & fFriendLockStatus))
6363 return nullptr;
6364
6365 std::string path(name);
6366 const auto sep = path.find_last_of('/');
6367 if (sep != std::string::npos)
6368 return GetLeaf(path.substr(0, sep).c_str(), name + sep + 1);
6369
6370 return GetLeaf(nullptr, name);
6371}
6372
6373namespace {
6374
6375////////////////////////////////////////////////////////////////////////////////
6376/// \brief Helper detecting *any* file transition of a tree dataset
6377///
6378/// This is a generic helper, works if the dataset is a TTree or a TChain, and
6379/// transitively detects transitions in friends.
6380///
6381/// Comparing `TChain::GetTreeNumber()` before and after a call to
6382/// `TChain::LoadTree` only detects that the chain itself switched to another of
6383/// its own sub-trees. It does *not* detect that one of the (possibly indirect)
6384/// friends of the chain switched to a new file: in that case the cached
6385/// TLeaf/TBranch pointers become dangling even though the tree number of the
6386/// chain is unchanged.
6387///
6388/// `TChain::LoadTree` (both when the chain itself moves to a new tree and, via
6389/// `TChain::RefreshFriendAddresses`, when only a friend was updated) calls
6390/// `fNotify->Notify()`. Subscribing to that notification is therefore the
6391/// reliable way to know that anything in the friend graph moved.
6392///
6393/// This derives directly from TNotifyLinkBase rather than using TNotifyLink<T>
6394/// because the latter would require a dictionary for the instantiation.
6395///
6396/// We could also use
6397/// ```
6398/// struct TLeafRefresher {
6399/// bool fDirty = true;
6400/// bool Notify() { fDirty = true; return true; }
6401/// };
6402/// ```
6403/// declared in TChain.h or InternalTreeUtils.hxx and genereate a dictionary for
6404/// TNotifyLink<TLeafRefresher>.
6405class FileTransitionDetector final : public TNotifyLinkBase {
6406 /// Set to true initially so that the very first iteration performs the lookup.
6407 bool fChanged = true;
6408 TTree &fChain;
6409
6410public:
6411 FileTransitionDetector(TTree &chain) : fChain(chain) { PrependLink(fChain); }
6412
6413 ~FileTransitionDetector() override { RemoveLink(fChain); }
6414 FileTransitionDetector(const FileTransitionDetector &) = delete;
6415 FileTransitionDetector &operator=(const FileTransitionDetector &) = delete;
6416 FileTransitionDetector(FileTransitionDetector &&) = delete;
6417 FileTransitionDetector &operator=(FileTransitionDetector &&) = delete;
6418
6419 /// Must return true: returning false would make TChain::LoadTree fail with -6.
6420 Bool_t Notify() override
6421 {
6422 fChanged = true;
6423 // Propagate to the rest of the list of subscribers, as TNotifyLink does.
6424 if (fNext)
6425 return fNext->Notify();
6426 return true;
6427 }
6428
6429 /// Returns true (once) if the chain or any of its direct or indirect friends
6430 /// switched to a new tree since the last call.
6431 bool CheckAndReset()
6432 {
6433 bool changed = fChanged;
6434 fChanged = false;
6435 return changed;
6436 }
6437};
6438} // anonymous namespace
6439
6440////////////////////////////////////////////////////////////////////////////////
6441/// Computes the extremum (minimum or maximum) for the input column name
6442///
6443/// It takes into account the following situations:
6444///
6445/// * The dataset is a TTree and contains the input column
6446/// * The dataset is a TChain and contains the input column, in which case the methods detect file switching and update
6447/// the leaf pointer correctly.
6448/// * The dataset is a TChain, contains the input column, but some files miss it, in which case the methods skip the
6449/// entries from those files.
6450/// * The dataset has a friend TTree which contains the input column
6451/// * The dataset is a TChain and has a friend TChain which contains the input column, in which case the methods detect
6452/// file switching on the friend and update the leaf pointer correctly.
6453/// * The dataset is a TChain and has a friend TChain. The input column is partially available in either the main or the
6454/// friend chain. This can happen for example if the main chain has some files missing the input column and the user
6455/// knowingly injects the input column in the files of the friend chain. In this case, the methods detect file switching
6456/// at the boundary between files of the main chain, but also detect if there are file switches in the friend chain.
6457/// Notably, the entries must still be overall aligned between the main chain and the friend one.
6458double TTree::ComputeExtremum(const char *columname, double errVal, bool (*cmp)(double, double))
6459{
6460 // Ensure the TTree cursor is brought back to the current entry after computing the value
6461 struct CurrentEntryRAII {
6462
6463 Long64_t fCurrentEntry;
6464 TTree &fTree;
6465
6466 CurrentEntryRAII(TTree &tree) : fCurrentEntry(tree.GetReadEntry()), fTree(tree) {}
6467
6468 ~CurrentEntryRAII() { fTree.LoadTree(fCurrentEntry); }
6469 } raii{*this};
6470
6471 // Initial lookup of the leaf name, this will find it whether it's in the
6472 // current tree or in any of its friends
6474 if (!leaf) {
6475 return 0;
6476 }
6477 TBranch *branch = leaf->GetBranch();
6478 assert(branch); // leaf without a branch is not allowed by construction
6479
6480 // create cache if wanted
6481 if (fCacheDoAutoInit)
6483
6484 FileTransitionDetector fileTransition{*this};
6485 double extremum{errVal};
6486 for (Long64_t i = 0; i < fEntries; ++i) {
6487 const auto entryNumber = GetEntryNumber(i);
6488 if (entryNumber < 0) break;
6490 if (localEntryNumber < 0)
6491 break;
6492
6493 // At every entry, we check if the processing has triggered a switch to
6494 // a new file. We detect both a switch of the current tree in the chain
6495 // (if this tree is a TChain) as well as a switch in any of its direct
6496 // and indirect friends (if they are also a TChain)
6497 if (fileTransition.CheckAndReset()) {
6498 branch = nullptr;
6500 if (leaf) {
6501 branch = leaf->GetBranch();
6502 assert(branch); // leaf without a branch is not allowed by construction
6503 }
6504 }
6505
6506 // We accept that the leaf may not be present in one or more files in case
6507 // it was found in a chain, we just continue processing the next entry
6508 if (!leaf)
6509 continue;
6510
6511 // If the branch belongs to a friend, the local entry number of the friend
6512 // may differ from the one of the chain (e.g. when the friend is indexed).
6513 // The owning TTree has already been positioned by TChain::LoadTree, so
6514 // its read entry is the correct one to use.
6515 auto *owningTree = branch->GetTree();
6516 branch->GetEntry(owningTree->GetReadEntry());
6517
6518 auto leafLen{leaf->GetLen()};
6519 for (decltype(leafLen) j = 0; j < leafLen; ++j) {
6520 auto val = leaf->GetValue(j);
6521 if (cmp(val, extremum)) {
6522 extremum = val;
6523 }
6524 }
6525 }
6526
6527 return extremum;
6528}
6529
6530////////////////////////////////////////////////////////////////////////////////
6531/// Return maximum of column with name columname.
6532/// if the Tree has an associated TEventList or TEntryList, the maximum
6533/// is computed for the entries in this list.
6536{
6537 return ComputeExtremum(columname, std::numeric_limits<double>::lowest(), [](double a, double b) { return a > b; });
6538}
6539
6540////////////////////////////////////////////////////////////////////////////////
6541/// Static function which returns the tree file size limit in bytes.
6546}
6547
6548////////////////////////////////////////////////////////////////////////////////
6549/// Return minimum of column with name columname.
6550/// if the Tree has an associated TEventList or TEntryList, the minimum
6551/// is computed for the entries in this list.
6554{
6555 return ComputeExtremum(columname, std::numeric_limits<double>::max(), [](double a, double b) { return a < b; });
6556}
6557
6558////////////////////////////////////////////////////////////////////////////////
6559/// Load the TTreePlayer (if not already done).
6562{
6563 if (fPlayer) {
6564 return fPlayer;
6565 }
6567 return fPlayer;
6568}
6569
6570////////////////////////////////////////////////////////////////////////////////
6571/// Find and return the TTreeCache registered with the file and which may
6572/// contain branches for us.
6575{
6576 TTreeCache *pe = dynamic_cast<TTreeCache*>(file->GetCacheRead(GetTree()));
6577 if (pe && pe->GetTree() != GetTree())
6578 pe = nullptr;
6579 return pe;
6580}
6581
6582////////////////////////////////////////////////////////////////////////////////
6583/// Find and return the TTreeCache registered with the file and which may
6584/// contain branches for us. If create is true and there is no cache
6585/// a new cache is created with default size.
6587TTreeCache *TTree::GetReadCache(TFile *file, bool create)
6588{
6589 TTreeCache *pe = GetReadCache(file);
6590 if (create && !pe) {
6591 if (fCacheDoAutoInit)
6592 SetCacheSizeAux(true, -1);
6593 pe = dynamic_cast<TTreeCache*>(file->GetCacheRead(GetTree()));
6594 if (pe && pe->GetTree() != GetTree()) pe = nullptr;
6595 }
6596 return pe;
6597}
6598
6599////////////////////////////////////////////////////////////////////////////////
6600/// Return a pointer to the list containing user objects associated to this tree.
6601///
6602/// The list is automatically created if it does not exist.
6603///
6604/// WARNING: By default the TTree destructor will delete all objects added
6605/// to this list. If you do not want these objects to be deleted,
6606/// call:
6607///
6608/// mytree->GetUserInfo()->Clear();
6609///
6610/// before deleting the tree.
6613{
6614 if (!fUserInfo) {
6615 fUserInfo = new TList();
6616 fUserInfo->SetName("UserInfo");
6617 }
6618 return fUserInfo;
6619}
6620
6621////////////////////////////////////////////////////////////////////////////////
6622/// Appends the cluster range information stored in 'fromtree' to this tree,
6623/// including the value of fAutoFlush.
6624///
6625/// This is used when doing a fast cloning (by TTreeCloner).
6626/// See also fAutoFlush and fAutoSave if needed.
6629{
6630 Long64_t autoflush = fromtree->GetAutoFlush();
6631 if (fromtree->fNClusterRange == 0 && fromtree->fAutoFlush == fAutoFlush) {
6632 // nothing to do
6633 } else if (fNClusterRange || fromtree->fNClusterRange) {
6634 Int_t newsize = fNClusterRange + 1 + fromtree->fNClusterRange;
6635 if (newsize > fMaxClusterRange) {
6636 if (fMaxClusterRange) {
6638 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
6640 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
6642 } else {
6646 }
6647 }
6648 if (fEntries) {
6652 }
6653 for (Int_t i = 0 ; i < fromtree->fNClusterRange; ++i) {
6654 fClusterRangeEnd[fNClusterRange] = fEntries + fromtree->fClusterRangeEnd[i];
6655 fClusterSize[fNClusterRange] = fromtree->fClusterSize[i];
6657 }
6659 } else {
6661 }
6663 if (autoflush > 0 && autosave > 0) {
6665 }
6666}
6667
6668////////////////////////////////////////////////////////////////////////////////
6669/// Keep a maximum of fMaxEntries in memory.
6672{
6675 for (Int_t i = 0; i < nb; ++i) {
6677 branch->KeepCircular(maxEntries);
6678 }
6679 if (fNClusterRange) {
6682 for(Int_t i = 0, j = 0; j < oldsize; ++j) {
6685 ++i;
6686 } else {
6688 }
6689 }
6690 }
6692 fReadEntry = -1;
6693}
6694
6695////////////////////////////////////////////////////////////////////////////////
6696/// Read in memory all baskets from all branches up to the limit of maxmemory bytes.
6697///
6698/// If maxmemory is non null and positive SetMaxVirtualSize is called
6699/// with this value. Default for maxmemory is 2000000000 (2 Gigabytes).
6700/// The function returns the total number of baskets read into memory
6701/// if negative an error occurred while loading the branches.
6702/// This method may be called to force branch baskets in memory
6703/// when random access to branch entries is required.
6704/// If random access to only a few branches is required, you should
6705/// call directly TBranch::LoadBaskets.
6708{
6710
6711 TIter next(GetListOfLeaves());
6712 TLeaf *leaf;
6713 Int_t nimported = 0;
6714 while ((leaf=(TLeaf*)next())) {
6715 nimported += leaf->GetBranch()->LoadBaskets();//break;
6716 }
6717 return nimported;
6718}
6719
6720////////////////////////////////////////////////////////////////////////////////
6721/// Set current entry.
6722///
6723/// Returns -2 if entry does not exist (just as TChain::LoadTree()).
6724/// Returns -6 if an error occurs in the notification callback (just as TChain::LoadTree()).
6725///
6726/// Calls fNotify->Notify() (if fNotify is not null) when starting the processing of a new tree.
6727///
6728/// \note This function is overloaded in TChain.
6730{
6731 // We have already been visited while recursively looking
6732 // through the friend trees, let's return
6734 // We need to return a negative value to avoid a circular list of friends
6735 // to think that there is always an entry somewhere in the list.
6736 return -1;
6737 }
6738
6739 // create cache if wanted
6740 if (fCacheDoAutoInit && entry >=0)
6742
6743 if (fNotify) {
6744 if (fReadEntry < 0) {
6745 fNotify->Notify();
6746 }
6747 }
6748 fReadEntry = entry;
6749
6750 bool friendHasEntry = false;
6751 if (fFriends) {
6752 // Set current entry in friends as well.
6753 //
6754 // An alternative would move this code to each of the
6755 // functions calling LoadTree (and to overload a few more).
6756 bool needUpdate = false;
6757 {
6758 // This scope is need to insure the lock is released at the right time
6760 TFriendLock lock(this, kLoadTree);
6761 TFriendElement* fe = nullptr;
6762 while ((fe = (TFriendElement*) nextf())) {
6763 if (fe->TestBit(TFriendElement::kFromChain)) {
6764 // This friend element was added by the chain that owns this
6765 // tree, the chain will deal with loading the correct entry.
6766 continue;
6767 }
6768 TTree* friendTree = fe->GetTree();
6769 if (friendTree) {
6770 if (friendTree->LoadTreeFriend(entry, this) >= 0) {
6771 friendHasEntry = true;
6772 }
6773 }
6774 if (fe->IsUpdated()) {
6775 needUpdate = true;
6776 fe->ResetUpdated();
6777 }
6778 } // for each friend
6779 }
6780 if (needUpdate) {
6781 //update list of leaves in all TTreeFormula of the TTreePlayer (if any)
6782 if (fPlayer) {
6784 }
6785 //Notify user if requested
6786 if (fNotify) {
6787 if(!fNotify->Notify()) return -6;
6788 }
6789 // We cannot know a priori if the branch(es) of the friend TChain(s) that were just
6790 // updated were supposed to be connected to possibly a TChainElement of another chain
6791 // that has befriended this TTree (i.e., one of the "external friends"). Thus, we
6792 // forward the notification that one or more friend trees were updated to the friends
6793 // of this TTree.
6794 if (fExternalFriends)
6796 external_fe->MarkUpdated();
6797 }
6798 }
6799
6800 if ((fReadEntry >= fEntries) && !friendHasEntry) {
6801 fReadEntry = -1;
6802 return -2;
6803 }
6804 return fReadEntry;
6805}
6806
6807////////////////////////////////////////////////////////////////////////////////
6808/// Load entry on behalf of our master tree, we may use an index.
6809///
6810/// Called by LoadTree() when the masterTree looks for the entry
6811/// number in a friend tree (us) corresponding to the passed entry
6812/// number in the masterTree.
6813///
6814/// If we have no index, our entry number and the masterTree entry
6815/// number are the same.
6816///
6817/// If we *do* have an index, we must find the (major, minor) value pair
6818/// in masterTree to locate our corresponding entry.
6819///
6827}
6828
6829////////////////////////////////////////////////////////////////////////////////
6830/// Generate a skeleton analysis class for this tree.
6831///
6832/// The following files are produced: classname.h and classname.C.
6833/// If classname is 0, classname will be called "nameoftree".
6834///
6835/// The generated code in classname.h includes the following:
6836///
6837/// - Identification of the original tree and the input file name.
6838/// - Definition of an analysis class (data members and member functions).
6839/// - The following member functions:
6840/// - constructor (by default opening the tree file),
6841/// - GetEntry(Long64_t entry),
6842/// - Init(TTree* tree) to initialize a new TTree,
6843/// - Show(Long64_t entry) to read and dump entry.
6844///
6845/// The generated code in classname.C includes only the main
6846/// analysis function Loop.
6847///
6848/// To use this function:
6849///
6850/// - Open your tree file (eg: TFile f("myfile.root");)
6851/// - T->MakeClass("MyClass");
6852///
6853/// where T is the name of the TTree in file myfile.root,
6854/// and MyClass.h, MyClass.C the name of the files created by this function.
6855/// In a ROOT session, you can do:
6856/// ~~~ {.cpp}
6857/// root > .L MyClass.C
6858/// root > MyClass* t = new MyClass;
6859/// root > t->GetEntry(12); // Fill data members of t with entry number 12.
6860/// root > t->Show(); // Show values of entry 12.
6861/// root > t->Show(16); // Read and show values of entry 16.
6862/// root > t->Loop(); // Loop on all entries.
6863/// ~~~
6864/// NOTE: Do not use the code generated for a single TTree which is part
6865/// of a TChain to process that entire TChain. The maximum dimensions
6866/// calculated for arrays on the basis of a single TTree from the TChain
6867/// might be (will be!) too small when processing all of the TTrees in
6868/// the TChain. You must use myChain.MakeClass() to generate the code,
6869/// not myTree.MakeClass(...).
6871Int_t TTree::MakeClass(const char* classname, Option_t* option)
6872{
6873 GetPlayer();
6874 if (!fPlayer) {
6875 return 0;
6876 }
6877 return fPlayer->MakeClass(classname, option);
6878}
6879
6880////////////////////////////////////////////////////////////////////////////////
6881/// Generate a skeleton function for this tree.
6882///
6883/// The function code is written on filename.
6884/// If filename is 0, filename will be called nameoftree.C
6885///
6886/// The generated code includes the following:
6887/// - Identification of the original Tree and Input file name,
6888/// - Opening the Tree file,
6889/// - Declaration of Tree variables,
6890/// - Setting of branches addresses,
6891/// - A skeleton for the entry loop.
6892///
6893/// To use this function:
6894///
6895/// - Open your Tree file (eg: TFile f("myfile.root");)
6896/// - T->MakeCode("MyAnalysis.C");
6897///
6898/// where T is the name of the TTree in file myfile.root
6899/// and MyAnalysis.C the name of the file created by this function.
6900///
6901/// NOTE: Since the implementation of this function, a new and better
6902/// function TTree::MakeClass() has been developed.
6904Int_t TTree::MakeCode(const char* filename)
6905{
6906 Warning("MakeCode", "MakeCode is obsolete. Use MakeClass or MakeSelector instead");
6907
6908 GetPlayer();
6909 if (!fPlayer) return 0;
6910 return fPlayer->MakeCode(filename);
6911}
6912
6913////////////////////////////////////////////////////////////////////////////////
6914/// Generate a skeleton analysis class for this Tree using TBranchProxy.
6915///
6916/// TBranchProxy is the base of a class hierarchy implementing an
6917/// indirect access to the content of the branches of a TTree.
6918///
6919/// "proxyClassname" is expected to be of the form:
6920/// ~~~ {.cpp}
6921/// [path/]fileprefix
6922/// ~~~
6923/// The skeleton will then be generated in the file:
6924/// ~~~ {.cpp}
6925/// fileprefix.h
6926/// ~~~
6927/// located in the current directory or in 'path/' if it is specified.
6928/// The class generated will be named 'fileprefix'
6929///
6930/// "macrofilename" and optionally "cutfilename" are expected to point
6931/// to source files which will be included by the generated skeleton.
6932/// Method of the same name as the file(minus the extension and path)
6933/// will be called by the generated skeleton's Process method as follow:
6934/// ~~~ {.cpp}
6935/// [if (cutfilename())] htemp->Fill(macrofilename());
6936/// ~~~
6937/// "option" can be used select some of the optional features during
6938/// the code generation. The possible options are:
6939///
6940/// - nohist : indicates that the generated ProcessFill should not fill the histogram.
6941///
6942/// 'maxUnrolling' controls how deep in the class hierarchy does the
6943/// system 'unroll' classes that are not split. Unrolling a class
6944/// allows direct access to its data members (this emulates the behavior
6945/// of TTreeFormula).
6946///
6947/// The main features of this skeleton are:
6948///
6949/// * on-demand loading of branches
6950/// * ability to use the 'branchname' as if it was a data member
6951/// * protection against array out-of-bounds errors
6952/// * ability to use the branch data as an object (when the user code is available)
6953///
6954/// For example with Event.root, if
6955/// ~~~ {.cpp}
6956/// Double_t somePx = fTracks.fPx[2];
6957/// ~~~
6958/// is executed by one of the method of the skeleton,
6959/// somePx will updated with the current value of fPx of the 3rd track.
6960///
6961/// Both macrofilename and the optional cutfilename are expected to be
6962/// the name of source files which contain at least a free standing
6963/// function with the signature:
6964/// ~~~ {.cpp}
6965/// x_t macrofilename(); // i.e function with the same name as the file
6966/// ~~~
6967/// and
6968/// ~~~ {.cpp}
6969/// y_t cutfilename(); // i.e function with the same name as the file
6970/// ~~~
6971/// x_t and y_t needs to be types that can convert respectively to a double
6972/// and a bool (because the skeleton uses:
6973///
6974/// if (cutfilename()) htemp->Fill(macrofilename());
6975///
6976/// These two functions are run in a context such that the branch names are
6977/// available as local variables of the correct (read-only) type.
6978///
6979/// Note that if you use the same 'variable' twice, it is more efficient
6980/// to 'cache' the value. For example:
6981/// ~~~ {.cpp}
6982/// Int_t n = fEventNumber; // Read fEventNumber
6983/// if (n<10 || n>10) { ... }
6984/// ~~~
6985/// is more efficient than
6986/// ~~~ {.cpp}
6987/// if (fEventNumber<10 || fEventNumber>10)
6988/// ~~~
6989/// Also, optionally, the generated selector will also call methods named
6990/// macrofilename_methodname in each of 6 main selector methods if the method
6991/// macrofilename_methodname exist (Where macrofilename is stripped of its
6992/// extension).
6993///
6994/// Concretely, with the script named h1analysisProxy.C,
6995///
6996/// - The method calls the method (if it exist)
6997/// - Begin -> void h1analysisProxy_Begin(TTree*);
6998/// - SlaveBegin -> void h1analysisProxy_SlaveBegin(TTree*);
6999/// - Notify -> bool h1analysisProxy_Notify();
7000/// - Process -> bool h1analysisProxy_Process(Long64_t);
7001/// - SlaveTerminate -> void h1analysisProxy_SlaveTerminate();
7002/// - Terminate -> void h1analysisProxy_Terminate();
7003///
7004/// If a file name macrofilename.h (or .hh, .hpp, .hxx, .hPP, .hXX) exist
7005/// it is included before the declaration of the proxy class. This can
7006/// be used in particular to insure that the include files needed by
7007/// the macro file are properly loaded.
7008///
7009/// The default histogram is accessible via the variable named 'htemp'.
7010///
7011/// If the library of the classes describing the data in the branch is
7012/// loaded, the skeleton will add the needed `include` statements and
7013/// give the ability to access the object stored in the branches.
7014///
7015/// To draw px using the file hsimple.root (generated by the
7016/// hsimple.C tutorial), we need a file named hsimple.cxx:
7017/// ~~~ {.cpp}
7018/// double hsimple() {
7019/// return px;
7020/// }
7021/// ~~~
7022/// MakeProxy can then be used indirectly via the TTree::Draw interface
7023/// as follow:
7024/// ~~~ {.cpp}
7025/// new TFile("hsimple.root")
7026/// ntuple->Draw("hsimple.cxx");
7027/// ~~~
7028/// A more complete example is available in the tutorials directory:
7029/// h1analysisProxy.cxx , h1analysProxy.h and h1analysisProxyCut.C
7030/// which reimplement the selector found in h1analysis.C
7032Int_t TTree::MakeProxy(const char* proxyClassname, const char* macrofilename, const char* cutfilename, const char* option, Int_t maxUnrolling)
7033{
7034 GetPlayer();
7035 if (!fPlayer) return 0;
7037}
7038
7039////////////////////////////////////////////////////////////////////////////////
7040/// Generate skeleton selector class for this tree.
7041///
7042/// The following files are produced: selector.h and selector.C.
7043/// If selector is 0, the selector will be called "nameoftree".
7044/// The option can be used to specify the branches that will have a data member.
7045/// - If option is "=legacy", a pre-ROOT6 selector will be generated (data
7046/// members and branch pointers instead of TTreeReaders).
7047/// - If option is empty, readers will be generated for each leaf.
7048/// - If option is "@", readers will be generated for the topmost branches.
7049/// - Individual branches can also be picked by their name:
7050/// - "X" generates readers for leaves of X.
7051/// - "@X" generates a reader for X as a whole.
7052/// - "@X;Y" generates a reader for X as a whole and also readers for the
7053/// leaves of Y.
7054/// - For further examples see the figure below.
7055///
7056/// \image html ttree_makeselector_option_examples.png
7057///
7058/// The generated code in selector.h includes the following:
7059/// - Identification of the original Tree and Input file name
7060/// - Definition of selector class (data and functions)
7061/// - The following class functions:
7062/// - constructor and destructor
7063/// - void Begin(TTree *tree)
7064/// - void SlaveBegin(TTree *tree)
7065/// - void Init(TTree *tree)
7066/// - bool Notify()
7067/// - bool Process(Long64_t entry)
7068/// - void Terminate()
7069/// - void SlaveTerminate()
7070///
7071/// The class selector derives from TSelector.
7072/// The generated code in selector.C includes empty functions defined above.
7073///
7074/// To use this function:
7075///
7076/// - connect your Tree file (eg: `TFile f("myfile.root");`)
7077/// - `T->MakeSelector("myselect");`
7078///
7079/// where T is the name of the Tree in file myfile.root
7080/// and myselect.h, myselect.C the name of the files created by this function.
7081/// In a ROOT session, you can do:
7082/// ~~~ {.cpp}
7083/// root > T->Process("myselect.C")
7084/// ~~~
7086Int_t TTree::MakeSelector(const char* selector, Option_t* option)
7087{
7088 TString opt(option);
7089 if(opt.EqualTo("=legacy", TString::ECaseCompare::kIgnoreCase)) {
7090 return MakeClass(selector, "selector");
7091 } else {
7092 GetPlayer();
7093 if (!fPlayer) return 0;
7094 return fPlayer->MakeReader(selector, option);
7095 }
7096}
7097
7098////////////////////////////////////////////////////////////////////////////////
7099/// Check if adding nbytes to memory we are still below MaxVirtualsize.
7102{
7104 return false;
7105 }
7106 return true;
7107}
7108
7109////////////////////////////////////////////////////////////////////////////////
7110/// Static function merging the trees in the TList into a new tree.
7111///
7112/// Trees in the list can be memory or disk-resident trees.
7113/// The new tree is created in the current directory (memory if gROOT).
7114/// Trees with no branches will be skipped, the branch structure
7115/// will be taken from the first non-zero-branch Tree of {li}
7118{
7119 if (!li) return nullptr;
7120 TIter next(li);
7121 TTree *newtree = nullptr;
7122 TObject *obj;
7123
7124 while ((obj=next())) {
7125 if (!obj->InheritsFrom(TTree::Class())) continue;
7126 TTree *tree = (TTree*)obj;
7127 if (tree->GetListOfBranches()->IsEmpty()) {
7128 if (gDebug > 2) {
7129 tree->Warning("MergeTrees","TTree %s has no branches, skipping.", tree->GetName());
7130 }
7131 continue; // Completely ignore the empty trees.
7132 }
7133 Long64_t nentries = tree->GetEntries();
7134 if (newtree && nentries == 0)
7135 continue; // If we already have the structure and we have no entry, save time and skip
7136 if (!newtree) {
7137 newtree = (TTree*)tree->CloneTree(-1, options);
7138 if (!newtree) continue;
7139
7140 // Once the cloning is done, separate the trees,
7141 // to avoid as many side-effects as possible
7142 // The list of clones is guaranteed to exist since we
7143 // just cloned the tree.
7144 tree->GetListOfClones()->Remove(newtree);
7145 tree->ResetBranchAddresses();
7146 newtree->ResetBranchAddresses();
7147 continue;
7148 }
7149 if (nentries == 0)
7150 continue;
7151 newtree->CopyEntries(tree, -1, options, true);
7152 }
7153 if (newtree && newtree->GetTreeIndex()) {
7154 newtree->GetTreeIndex()->Append(nullptr,false); // Force the sorting
7155 }
7156 return newtree;
7157}
7158
7159////////////////////////////////////////////////////////////////////////////////
7160/// Merge the trees in the TList into this tree.
7161///
7162/// Returns the total number of entries in the merged tree.
7163/// Trees with no branches will be skipped, the branch structure
7164/// will be taken from the first non-zero-branch Tree of {this+li}
7167{
7168 if (fBranches.IsEmpty()) {
7169 if (!li || li->IsEmpty())
7170 return 0; // Nothing to do ....
7171 // Let's find the first non-empty
7172 TIter next(li);
7173 TTree *tree;
7174 while ((tree = (TTree *)next())) {
7175 if (tree == this || tree->GetListOfBranches()->IsEmpty()) {
7176 if (gDebug > 2) {
7177 Warning("Merge","TTree %s has no branches, skipping.", tree->GetName());
7178 }
7179 continue;
7180 }
7181 // We could come from a list made up of different names, the first one still wins
7182 tree->SetName(this->GetName());
7183 auto prevEntries = tree->GetEntries();
7184 auto result = tree->Merge(li, options);
7185 if (result != prevEntries) {
7186 // If there is no additional entries, the first write was enough.
7187 tree->Write();
7188 }
7189 // Make sure things are really written out to disk before attempting any reading.
7190 if (tree->GetCurrentFile()) {
7191 tree->GetCurrentFile()->Flush();
7192 // Read back the complete info in this TTree, so that caller does not
7193 // inadvertently write the empty tree.
7194 tree->GetDirectory()->ReadTObject(this, this->GetName());
7195 }
7196 return result;
7197 }
7198 return 0; // All trees have empty branches
7199 }
7200 if (!li) return 0;
7202 // Disable the autosave as the TFileMerge keeps a list of key and deleting the underlying
7203 // key would invalidate its iteration (or require costly measure to not use the deleted keys).
7204 // Also since this is part of a merging operation, the output file is not as precious as in
7205 // the general case since the input file should still be around.
7206 fAutoSave = 0;
7207 TIter next(li);
7208 TTree *tree;
7209 while ((tree = (TTree*)next())) {
7210 if (tree==this) continue;
7211 if (!tree->InheritsFrom(TTree::Class())) {
7212 Error("Add","Attempt to add object of class: %s to a %s", tree->ClassName(), ClassName());
7214 return -1;
7215 }
7216
7217 Long64_t nentries = tree->GetEntries();
7218 if (nentries == 0) continue;
7219
7220 CopyEntries(tree, -1, options, true);
7221 }
7223 return GetEntries();
7224}
7225
7226////////////////////////////////////////////////////////////////////////////////
7227/// Merge the trees in the TList into this tree.
7228/// If info->fIsFirst is true, first we clone this TTree info the directory
7229/// info->fOutputDirectory and then overlay the new TTree information onto
7230/// this TTree object (so that this TTree object is now the appropriate to
7231/// use for further merging).
7232/// Trees with no branches will be skipped, the branch structure
7233/// will be taken from the first non-zero-branch Tree of {this+li}
7234///
7235/// Returns the total number of entries in the merged tree.
7238{
7239 if (fBranches.IsEmpty()) {
7240 if (!li || li->IsEmpty())
7241 return 0; // Nothing to do ....
7242 // Let's find the first non-empty
7243 TIter next(li);
7244 TTree *tree;
7245 while ((tree = (TTree *)next())) {
7246 if (tree == this || tree->GetListOfBranches()->IsEmpty()) {
7247 if (gDebug > 2) {
7248 Warning("Merge","TTree %s has no branches, skipping.", tree->GetName());
7249 }
7250 continue;
7251 }
7252 // We could come from a list made up of different names, the first one still wins
7253 tree->SetName(this->GetName());
7254 auto prevEntries = tree->GetEntries();
7255 auto result = tree->Merge(li, info);
7256 if (result != prevEntries) {
7257 // If there is no additional entries, the first write was enough.
7258 tree->Write();
7259 }
7260 // Make sure things are really written out to disk before attempting any reading.
7261 info->fOutputDirectory->GetFile()->Flush();
7262 // Read back the complete info in this TTree, so that TFileMerge does not
7263 // inadvertently write the empty tree.
7264 info->fOutputDirectory->ReadTObject(this, this->GetName());
7265 return result;
7266 }
7267 return 0; // All trees have empty branches
7268 }
7269 const char *options = info ? info->fOptions.Data() : "";
7270 if (info && info->fIsFirst && info->fOutputDirectory && info->fOutputDirectory->GetFile() != GetCurrentFile()) {
7271 if (GetCurrentFile() == nullptr) {
7272 // In memory TTree, all we need to do is ... write it.
7273 SetDirectory(info->fOutputDirectory);
7275 fDirectory->WriteTObject(this);
7276 } else if (info->fOptions.Contains("fast")) {
7277 InPlaceClone(info->fOutputDirectory);
7278 } else {
7279 TDirectory::TContext ctxt(info->fOutputDirectory);
7281 TTree *newtree = CloneTree(-1, options);
7282 if (info->fIOFeatures)
7283 fIOFeatures = *(info->fIOFeatures);
7284 else
7286 if (newtree) {
7287 newtree->Write();
7288 delete newtree;
7289 }
7290 // Make sure things are really written out to disk before attempting any reading.
7291 info->fOutputDirectory->GetFile()->Flush();
7292 info->fOutputDirectory->ReadTObject(this,this->GetName());
7293 }
7294 }
7295 if (!li) return 0;
7297 // Disable the autosave as the TFileMerge keeps a list of key and deleting the underlying
7298 // key would invalidate its iteration (or require costly measure to not use the deleted keys).
7299 // Also since this is part of a merging operation, the output file is not as precious as in
7300 // the general case since the input file should still be around.
7301 fAutoSave = 0;
7302 TIter next(li);
7303 TTree *tree;
7304 while ((tree = (TTree*)next())) {
7305 if (tree==this) continue;
7306 if (!tree->InheritsFrom(TTree::Class())) {
7307 Error("Add","Attempt to add object of class: %s to a %s", tree->ClassName(), ClassName());
7309 return -1;
7310 }
7311
7312 CopyEntries(tree, -1, options, true);
7313 }
7315 return GetEntries();
7316}
7317
7318////////////////////////////////////////////////////////////////////////////////
7319/// Move a cache from a file to the current file in dir.
7320/// if src is null no operation is done, if dir is null or there is no
7321/// current file the cache is deleted.
7324{
7325 if (!src) return;
7326 TFile *dst = (dir && dir != gROOT) ? dir->GetFile() : nullptr;
7327 if (src == dst) return;
7328
7330 if (dst) {
7331 src->SetCacheRead(nullptr,this);
7332 dst->SetCacheRead(pf, this);
7333 } else {
7334 if (pf) {
7335 pf->WaitFinishPrefetch();
7336 }
7337 src->SetCacheRead(nullptr,this);
7338 delete pf;
7339 }
7340}
7341
7342////////////////////////////////////////////////////////////////////////////////
7343/// Copy the content to a new new file, update this TTree with the new
7344/// location information and attach this TTree to the new directory.
7345///
7346/// options: Indicates a basket sorting method, see TTreeCloner::TTreeCloner for
7347/// details
7348///
7349/// If new and old directory are in the same file, the data is untouched,
7350/// this "just" does a call to SetDirectory.
7351/// Equivalent to an "in place" cloning of the TTree.
7352bool TTree::InPlaceClone(TDirectory *newdirectory, const char *options)
7353{
7354 if (!newdirectory) {
7356 SetDirectory(nullptr);
7357 return true;
7358 }
7359 if (newdirectory->GetFile() == GetCurrentFile()) {
7361 return true;
7362 }
7363 TTreeCloner cloner(this, newdirectory, options);
7364 if (cloner.IsValid())
7365 return cloner.Exec();
7366 else
7367 return false;
7368}
7369
7370////////////////////////////////////////////////////////////////////////////////
7371/// Function called when loading a new class library.
7373bool TTree::Notify()
7374{
7375 TIter next(GetListOfLeaves());
7376 TLeaf* leaf = nullptr;
7377 while ((leaf = (TLeaf*) next())) {
7378 leaf->Notify();
7379 leaf->GetBranch()->Notify();
7380 }
7381 return true;
7382}
7383
7384////////////////////////////////////////////////////////////////////////////////
7385/// This function may be called after having filled some entries in a Tree.
7386/// Using the information in the existing branch buffers, it will reassign
7387/// new branch buffer sizes to optimize time and memory.
7388///
7389/// The function computes the best values for branch buffer sizes such that
7390/// the total buffer sizes is less than maxMemory and nearby entries written
7391/// at the same time.
7392/// In case the branch compression factor for the data written so far is less
7393/// than compMin, the compression is disabled.
7394///
7395/// if option ="d" an analysis report is printed.
7398{
7399 //Flush existing baskets if the file is writable
7400 if (this->GetDirectory()->IsWritable()) this->FlushBasketsImpl();
7401
7402 TString opt( option );
7403 opt.ToLower();
7404 bool pDebug = opt.Contains("d");
7405 TObjArray *leaves = this->GetListOfLeaves();
7406 Int_t nleaves = leaves->GetEntries();
7408
7409 if (nleaves == 0 || treeSize == 0) {
7410 // We're being called too early, we really have nothing to do ...
7411 return;
7412 }
7414 UInt_t bmin = 512;
7415 UInt_t bmax = 256000;
7416 Double_t memFactor = 1;
7419
7420 //we make two passes
7421 //one pass to compute the relative branch buffer sizes
7422 //a second pass to compute the absolute values
7423 for (Int_t pass =0;pass<2;pass++) {
7424 oldMemsize = 0; //to count size of baskets in memory with old buffer size
7425 newMemsize = 0; //to count size of baskets in memory with new buffer size
7426 oldBaskets = 0; //to count number of baskets with old buffer size
7427 newBaskets = 0; //to count number of baskets with new buffer size
7428 for (i=0;i<nleaves;i++) {
7429 TLeaf *leaf = (TLeaf*)leaves->At(i);
7430 TBranch *branch = leaf->GetBranch();
7431 Double_t totBytes = (Double_t)branch->GetTotBytes();
7434 if (branch->GetEntries() == 0) {
7435 // There is no data, so let's make a guess ...
7437 } else {
7438 sizeOfOneEntry = 1+(UInt_t)(totBytes / (Double_t)branch->GetEntries());
7439 }
7440 Int_t oldBsize = branch->GetBasketSize();
7443 Int_t nb = branch->GetListOfBranches()->GetEntries();
7444 if (nb > 0) {
7446 continue;
7447 }
7448 Double_t bsize = oldBsize*idealFactor*memFactor; //bsize can be very large !
7449 if (bsize < 0) bsize = bmax;
7450 if (bsize > bmax) bsize = bmax;
7452 if (pass) { // only on the second pass so that it doesn't interfere with scaling
7453 // If there is an entry offset, it will be stored in the same buffer as the object data; hence,
7454 // we must bump up the size of the branch to account for this extra footprint.
7455 // If fAutoFlush is not set yet, let's assume that it is 'in the process of being set' to
7456 // the value of GetEntries().
7457 Long64_t clusterSize = (fAutoFlush > 0) ? fAutoFlush : branch->GetEntries();
7458 if (branch->GetEntryOffsetLen()) {
7459 newBsize = newBsize + (clusterSize * sizeof(Int_t) * 2);
7460 }
7461 // We used ATLAS fully-split xAOD for testing, which is a rather unbalanced TTree, 10K branches,
7462 // with 8K having baskets smaller than 512 bytes. To achieve good I/O performance ATLAS uses auto-flush 100,
7463 // resulting in the smallest baskets being ~300-400 bytes, so this change increases their memory by about 8k*150B =~ 1MB,
7464 // at the same time it significantly reduces the number of total baskets because it ensures that all 100 entries can be
7465 // stored in a single basket (the old optimization tended to make baskets too small). In a toy example with fixed sized
7466 // structures we found a factor of 2 fewer baskets needed in the new scheme.
7467 // rounds up, increases basket size to ensure all entries fit into single basket as intended
7468 newBsize = newBsize - newBsize%512 + 512;
7469 }
7471 if (newBsize < bmin) newBsize = bmin;
7472 if (newBsize > 10000000) newBsize = bmax;
7473 if (pass) {
7474 if (pDebug) Info("OptimizeBaskets", "Changing buffer size from %6d to %6d bytes for %s\n",oldBsize,newBsize,branch->GetName());
7475 branch->SetBasketSize(newBsize);
7476 }
7478 // For this number to be somewhat accurate when newBsize is 'low'
7479 // we do not include any space for meta data in the requested size (newBsize) even-though SetBasketSize will
7480 // not let it be lower than 100+TBranch::fEntryOffsetLen.
7482 if (pass == 0) continue;
7483 //Reset the compression level in case the compression factor is small
7484 Double_t comp = 1;
7485 if (branch->GetZipBytes() > 0) comp = totBytes/Double_t(branch->GetZipBytes());
7486 if (comp > 1 && comp < minComp) {
7487 if (pDebug) Info("OptimizeBaskets", "Disabling compression for branch : %s\n",branch->GetName());
7489 }
7490 }
7491 // coverity[divide_by_zero] newMemsize can not be zero as there is at least one leaf
7493 if (memFactor > 100) memFactor = 100;
7496 static const UInt_t hardmax = 1*1024*1024*1024; // Really, really never give more than 1Gb to a single buffer.
7497
7498 // Really, really never go lower than 8 bytes (we use this number
7499 // so that the calculation of the number of basket is consistent
7500 // but in fact SetBasketSize will not let the size go below
7501 // TBranch::fEntryOffsetLen + (100 + strlen(branch->GetName())
7502 // (The 2nd part being a slight over estimate of the key length.
7503 static const UInt_t hardmin = 8;
7506 }
7507 if (pDebug) {
7508 Info("OptimizeBaskets", "oldMemsize = %d, newMemsize = %d\n",oldMemsize, newMemsize);
7509 Info("OptimizeBaskets", "oldBaskets = %d, newBaskets = %d\n",oldBaskets, newBaskets);
7510 }
7511}
7512
7513////////////////////////////////////////////////////////////////////////////////
7514/// Interface to the Principal Components Analysis class.
7515///
7516/// Create an instance of TPrincipal
7517///
7518/// Fill it with the selected variables
7519///
7520/// - if option "n" is specified, the TPrincipal object is filled with
7521/// normalized variables.
7522/// - If option "p" is specified, compute the principal components
7523/// - If option "p" and "d" print results of analysis
7524/// - If option "p" and "h" generate standard histograms
7525/// - If option "p" and "c" generate code of conversion functions
7526/// - return a pointer to the TPrincipal object. It is the user responsibility
7527/// - to delete this object.
7528/// - The option default value is "np"
7529///
7530/// see TTree::Draw for explanation of the other parameters.
7531///
7532/// The created object is named "principal" and a reference to it
7533/// is added to the list of specials Root objects.
7534/// you can retrieve a pointer to the created object via:
7535/// ~~~ {.cpp}
7536/// TPrincipal *principal =
7537/// (TPrincipal*)gROOT->GetListOfSpecials()->FindObject("principal");
7538/// ~~~
7541{
7542 GetPlayer();
7543 if (fPlayer) {
7545 }
7546 return nullptr;
7547}
7548
7549////////////////////////////////////////////////////////////////////////////////
7550/// Print a summary of the tree contents.
7551///
7552/// - If option contains "all" friend trees are also printed.
7553/// - If option contains "toponly" only the top level branches are printed.
7554/// - If option contains "clusters" information about the cluster of baskets is printed.
7555///
7556/// Wildcarding can be used to print only a subset of the branches, e.g.,
7557/// `T.Print("Elec*")` will print all branches with name starting with "Elec".
7559void TTree::Print(Option_t* option) const
7560{
7561 // We already have been visited while recursively looking
7562 // through the friends tree, let's return.
7563 if (kPrint & fFriendLockStatus) {
7564 return;
7565 }
7566 Int_t s = 0;
7567 Int_t skey = 0;
7568 if (fDirectory) {
7569 TKey* key = fDirectory->GetKey(GetName());
7570 if (key) {
7571 skey = key->GetKeylen();
7572 s = key->GetNbytes();
7573 }
7574 }
7577 if (zipBytes > 0) {
7578 total += GetTotBytes();
7579 }
7581 TTree::Class()->WriteBuffer(b, (TTree*) this);
7582 total += b.Length();
7583 Long64_t file = zipBytes + s;
7584 Float_t cx = 1;
7585 if (zipBytes) {
7586 cx = (GetTotBytes() + 0.00001) / zipBytes;
7587 }
7588 Printf("******************************************************************************");
7589 Printf("*Tree :%-10s: %-54s *", GetName(), GetTitle());
7590 Printf("*Entries : %8lld : Total = %15lld bytes File Size = %10lld *", fEntries, total, file);
7591 Printf("* : : Tree compression factor = %6.2f *", cx);
7592 Printf("******************************************************************************");
7593
7594 // Avoid many check of option validity
7595 if (!option)
7596 option = "";
7597
7598 if (strncmp(option,"clusters",std::char_traits<char>::length("clusters"))==0) {
7599 Printf("%-16s %-16s %-16s %8s %20s",
7600 "Cluster Range #", "Entry Start", "Last Entry", "Size", "Number of clusters");
7601 Int_t index= 0;
7604 bool estimated = false;
7605 bool unknown = false;
7607 Long64_t nclusters = 0;
7608 if (recordedSize > 0) {
7609 nclusters = TMath::Ceil(static_cast<double>(1 + end - start) / recordedSize);
7610 Printf("%-16d %-16lld %-16lld %8lld %10lld",
7611 ind, start, end, recordedSize, nclusters);
7612 } else {
7613 // NOTE: const_cast ... DO NOT Merge for now
7614 TClusterIterator iter((TTree*)this, start);
7615 iter.Next();
7616 auto estimated_size = iter.GetNextEntry() - start;
7617 if (estimated_size > 0) {
7618 nclusters = TMath::Ceil(static_cast<double>(1 + end - start) / estimated_size);
7619 Printf("%-16d %-16lld %-16lld %8lld %10lld (estimated)",
7620 ind, start, end, recordedSize, nclusters);
7621 estimated = true;
7622 } else {
7623 Printf("%-16d %-16lld %-16lld %8lld (unknown)",
7624 ind, start, end, recordedSize);
7625 unknown = true;
7626 }
7627 }
7628 start = end + 1;
7630 };
7631 if (fNClusterRange) {
7632 for( ; index < fNClusterRange; ++index) {
7635 }
7636 }
7638 if (unknown) {
7639 Printf("Total number of clusters: (unknown)");
7640 } else {
7641 Printf("Total number of clusters: %lld %s", totalClusters, estimated ? "(estimated)" : "");
7642 }
7643 return;
7644 }
7645
7646 Int_t nl = const_cast<TTree*>(this)->GetListOfLeaves()->GetEntries();
7647 Int_t l;
7648 TBranch* br = nullptr;
7649 TLeaf* leaf = nullptr;
7650 if (strstr(option, "toponly")) {
7651 Long64_t *count = new Long64_t[nl];
7652 Int_t keep =0;
7653 for (l=0;l<nl;l++) {
7654 leaf = (TLeaf *)const_cast<TTree*>(this)->GetListOfLeaves()->At(l);
7655 br = leaf->GetBranch();
7656 // branch is its own (top level) mother only for the top level branches.
7657 if (br != br->GetMother()) {
7658 count[l] = -1;
7659 count[keep] += br->GetZipBytes();
7660 } else {
7661 keep = l;
7662 count[keep] = br->GetZipBytes();
7663 }
7664 }
7665 for (l=0;l<nl;l++) {
7666 if (count[l] < 0) continue;
7667 leaf = (TLeaf *)const_cast<TTree*>(this)->GetListOfLeaves()->At(l);
7668 br = leaf->GetBranch();
7669 Printf("branch: %-20s %9lld",br->GetName(),count[l]);
7670 }
7671 delete [] count;
7672 } else {
7673 TString reg = "*";
7674 if (strlen(option) && strchr(option,'*')) reg = option;
7675 TRegexp re(reg,true);
7676 TIter next(const_cast<TTree*>(this)->GetListOfBranches());
7678 while ((br= (TBranch*)next())) {
7679 TString st = br->GetName();
7680 st.ReplaceAll("/","_");
7681 if (st.Index(re) == kNPOS) continue;
7682 br->Print(option);
7683 }
7684 }
7685
7686 //print TRefTable (if one)
7688
7689 //print friends if option "all"
7690 if (!fFriends || !strstr(option,"all")) return;
7692 TFriendLock lock(const_cast<TTree*>(this),kPrint);
7693 TFriendElement *fr;
7694 while ((fr = (TFriendElement*)nextf())) {
7695 TTree * t = fr->GetTree();
7696 if (t) t->Print(option);
7697 }
7698}
7699
7700////////////////////////////////////////////////////////////////////////////////
7701/// Print statistics about the TreeCache for this tree.
7702/// Like:
7703/// ~~~ {.cpp}
7704/// ******TreeCache statistics for file: cms2.root ******
7705/// Reading 73921562 bytes in 716 transactions
7706/// Average transaction = 103.242405 Kbytes
7707/// Number of blocks in current cache: 202, total size : 6001193
7708/// ~~~
7709/// if option = "a" the list of blocks in the cache is printed
7712{
7713 TFile *f = GetCurrentFile();
7714 if (!f) return;
7716 if (tc) tc->Print(option);
7717}
7718
7719////////////////////////////////////////////////////////////////////////////////
7720/// Process this tree executing the TSelector code in the specified filename.
7721/// The return value is -1 in case of error and TSelector::GetStatus() in
7722/// in case of success.
7723///
7724/// The code in filename is loaded (interpreted or compiled, see below),
7725/// filename must contain a valid class implementation derived from TSelector,
7726/// where TSelector has the following member functions:
7727///
7728/// - `Begin()`: called every time a loop on the tree starts,
7729/// a convenient place to create your histograms.
7730/// - `SlaveBegin()`: called after Begin()
7731/// - `Process()`: called for each event, in this function you decide what
7732/// to read and fill your histograms.
7733/// - `SlaveTerminate()`: called at the end of the loop on the tree
7734/// - `Terminate()`: called at the end of the loop on the tree,
7735/// a convenient place to draw/fit your histograms.
7736///
7737/// If filename is of the form file.C, the file will be interpreted.
7738///
7739/// If filename is of the form file.C++, the file file.C will be compiled
7740/// and dynamically loaded.
7741///
7742/// If filename is of the form file.C+, the file file.C will be compiled
7743/// and dynamically loaded. At next call, if file.C is older than file.o
7744/// and file.so, the file.C is not compiled, only file.so is loaded.
7745///
7746/// ## NOTE1
7747///
7748/// It may be more interesting to invoke directly the other Process function
7749/// accepting a TSelector* as argument.eg
7750/// ~~~ {.cpp}
7751/// MySelector *selector = (MySelector*)TSelector::GetSelector(filename);
7752/// selector->CallSomeFunction(..);
7753/// mytree.Process(selector,..);
7754/// ~~~
7755/// ## NOTE2
7756//
7757/// One should not call this function twice with the same selector file
7758/// in the same script. If this is required, proceed as indicated in NOTE1,
7759/// by getting a pointer to the corresponding TSelector,eg
7760///
7761/// ### Workaround 1
7762///
7763/// ~~~ {.cpp}
7764/// void stubs1() {
7765/// TSelector *selector = TSelector::GetSelector("h1test.C");
7766/// TFile *f1 = new TFile("stubs_nood_le1.root");
7767/// TTree *h1 = (TTree*)f1->Get("h1");
7768/// h1->Process(selector);
7769/// TFile *f2 = new TFile("stubs_nood_le1_coarse.root");
7770/// TTree *h2 = (TTree*)f2->Get("h1");
7771/// h2->Process(selector);
7772/// }
7773/// ~~~
7774/// or use ACLIC to compile the selector
7775///
7776/// ### Workaround 2
7777///
7778/// ~~~ {.cpp}
7779/// void stubs2() {
7780/// TFile *f1 = new TFile("stubs_nood_le1.root");
7781/// TTree *h1 = (TTree*)f1->Get("h1");
7782/// h1->Process("h1test.C+");
7783/// TFile *f2 = new TFile("stubs_nood_le1_coarse.root");
7784/// TTree *h2 = (TTree*)f2->Get("h1");
7785/// h2->Process("h1test.C+");
7786/// }
7787/// ~~~
7790{
7791 GetPlayer();
7792 if (fPlayer) {
7794 }
7795 return -1;
7796}
7797
7798////////////////////////////////////////////////////////////////////////////////
7799/// Process this tree executing the code in the specified selector.
7800/// The return value is -1 in case of error and TSelector::GetStatus() in
7801/// in case of success.
7802///
7803/// The TSelector class has the following member functions:
7804///
7805/// - `Begin()`: called every time a loop on the tree starts,
7806/// a convenient place to create your histograms.
7807/// - `SlaveBegin()`: called after Begin()
7808/// - `Process()`: called for each event, in this function you decide what
7809/// to read and fill your histograms.
7810/// - `SlaveTerminate()`: called at the end of the loop on the tree
7811/// - `Terminate()`: called at the end of the loop on the tree,
7812/// a convenient place to draw/fit your histograms.
7813///
7814/// If the Tree (Chain) has an associated EventList, the loop is on the nentries
7815/// of the EventList, starting at firstentry, otherwise the loop is on the
7816/// specified Tree entries.
7819{
7820 GetPlayer();
7821 if (fPlayer) {
7822 return fPlayer->Process(selector, option, nentries, firstentry);
7823 }
7824 return -1;
7825}
7826
7827////////////////////////////////////////////////////////////////////////////////
7828/// Make a projection of a tree using selections.
7829///
7830/// Depending on the value of varexp (described in Draw) a 1-D, 2-D, etc.,
7831/// projection of the tree will be filled in histogram hname.
7832/// Note that the dimension of hname must match with the dimension of varexp.
7833///
7836{
7837 TString var;
7838 var.Form("%s>>%s", varexp, hname);
7839 TString opt("goff");
7840 if (option) {
7841 opt.Form("%sgoff", option);
7842 }
7844 return nsel;
7845}
7846
7847////////////////////////////////////////////////////////////////////////////////
7848/// Loop over entries and return a TSQLResult object containing entries following selection.
7851{
7852 GetPlayer();
7853 if (fPlayer) {
7855 }
7856 return nullptr;
7857}
7858
7859////////////////////////////////////////////////////////////////////////////////
7860/// Create or simply read branches from filename.
7861///
7862/// if branchDescriptor = "" (default), it is assumed that the Tree descriptor
7863/// is given in the first line of the file with a syntax like
7864/// ~~~ {.cpp}
7865/// A/D:Table[2]/F:Ntracks/I:astring/C
7866/// ~~~
7867/// otherwise branchDescriptor must be specified with the above syntax.
7868/// See all available datatypes [here](\ref addcolumnoffundamentaltypes).
7869///
7870/// - If the type of the first variable is not specified, it is assumed to be "/F"
7871/// - If the type of any other variable is not specified, the type of the previous
7872/// variable is assumed. eg
7873/// - `x:y:z` (all variables are assumed of type "F")
7874/// - `x/D:y:z` (all variables are of type "D")
7875/// - `x:y/D:z` (x is type "F", y and z of type "D")
7876///
7877/// delimiter allows for the use of another delimiter besides whitespace.
7878/// This provides support for direct import of common data file formats
7879/// like csv. If delimiter != ' ' and branchDescriptor == "", then the
7880/// branch description is taken from the first line in the file, but
7881/// delimiter is used for the branch names tokenization rather than ':'.
7882/// Note however that if the values in the first line do not use the
7883/// /[type] syntax, all variables are assumed to be of type "F".
7884/// If the filename ends with extensions .csv or .CSV and a delimiter is
7885/// not specified (besides ' '), the delimiter is automatically set to ','.
7886///
7887/// Lines in the input file starting with "#" are ignored. Leading whitespace
7888/// for each column data is skipped. Empty lines are skipped.
7889///
7890/// A TBranch object is created for each variable in the expression.
7891/// The total number of rows read from the file is returned.
7892///
7893/// ## FILLING a TTree WITH MULTIPLE INPUT TEXT FILES
7894///
7895/// To fill a TTree with multiple input text files, proceed as indicated above
7896/// for the first input file and omit the second argument for subsequent calls
7897/// ~~~ {.cpp}
7898/// T.ReadFile("file1.dat","branch descriptor");
7899/// T.ReadFile("file2.dat");
7900/// ~~~
7902Long64_t TTree::ReadFile(const char* filename, const char* branchDescriptor, char delimiter)
7903{
7904 if (!filename || !*filename) {
7905 Error("ReadFile","File name not specified");
7906 return 0;
7907 }
7908
7909 std::ifstream in;
7910 in.open(filename);
7911 if (!in.good()) {
7912 Error("ReadFile","Cannot open file: %s",filename);
7913 return 0;
7914 }
7915 const char* ext = strrchr(filename, '.');
7916 if(ext && ((strcmp(ext, ".csv") == 0) || (strcmp(ext, ".CSV") == 0)) && delimiter == ' ') {
7917 delimiter = ',';
7918 }
7920}
7921
7922////////////////////////////////////////////////////////////////////////////////
7923/// Determine which newline this file is using.
7924/// Return '\\r' for Windows '\\r\\n' as that already terminates.
7926char TTree::GetNewlineValue(std::istream &inputStream)
7927{
7928 Long_t inPos = inputStream.tellg();
7929 char newline = '\n';
7930 while(true) {
7931 char c = 0;
7932 inputStream.get(c);
7933 if(!inputStream.good()) {
7934 Error("ReadStream","Error reading stream: no newline found.");
7935 return 0;
7936 }
7937 if(c == newline) break;
7938 if(c == '\r') {
7939 newline = '\r';
7940 break;
7941 }
7942 }
7943 inputStream.clear();
7944 inputStream.seekg(inPos);
7945 return newline;
7946}
7947
7948////////////////////////////////////////////////////////////////////////////////
7949/// Create or simply read branches from an input stream.
7950///
7951/// \see TTree::ReadFile
7953Long64_t TTree::ReadStream(std::istream& inputStream, const char *branchDescriptor, char delimiter)
7954{
7955 char newline = 0;
7956 std::stringstream ss;
7957 std::istream *inTemp;
7958 Long_t inPos = inputStream.tellg();
7959 if (!inputStream.good()) {
7960 Error("ReadStream","Error reading stream");
7961 return 0;
7962 }
7963 if (inPos == -1) {
7964 ss << std::cin.rdbuf();
7966 inTemp = &ss;
7967 } else {
7970 }
7971 std::istream& in = *inTemp;
7972 Long64_t nlines = 0;
7973
7974 TBranch *branch = nullptr;
7976 if (nbranches == 0) {
7977 char *bdname = new char[4000];
7978 char *bd = new char[100000];
7979 Int_t nch = 0;
7981 // branch Descriptor is null, read its definition from the first line in the file
7982 if (!nch) {
7983 do {
7984 in.getline(bd, 100000, newline);
7985 if (!in.good()) {
7986 delete [] bdname;
7987 delete [] bd;
7988 Error("ReadStream","Error reading stream");
7989 return 0;
7990 }
7991 char *cursor = bd;
7992 while( isspace(*cursor) && *cursor != '\n' && *cursor != '\0') {
7993 ++cursor;
7994 }
7995 if (*cursor != '#' && *cursor != '\n' && *cursor != '\0') {
7996 break;
7997 }
7998 } while (true);
7999 ++nlines;
8000 nch = strlen(bd);
8001 } else {
8002 strlcpy(bd,branchDescriptor,100000);
8003 }
8004
8005 //parse the branch descriptor and create a branch for each element
8006 //separated by ":"
8007 void *address = &bd[90000];
8008 char *bdcur = bd;
8009 TString desc="", olddesc="F";
8010 char bdelim = ':';
8011 if(delimiter != ' ') {
8012 bdelim = delimiter;
8013 if (strchr(bdcur,bdelim)==nullptr && strchr(bdcur,':') != nullptr) {
8014 // revert to the default
8015 bdelim = ':';
8016 }
8017 }
8018 while (bdcur) {
8019 char *colon = strchr(bdcur,bdelim);
8020 if (colon) *colon = 0;
8021 strlcpy(bdname,bdcur,4000);
8022 char *slash = strchr(bdname,'/');
8023 if (slash) {
8024 *slash = 0;
8025 desc = bdcur;
8026 olddesc = slash+1;
8027 } else {
8028 desc.Form("%s/%s",bdname,olddesc.Data());
8029 }
8030 char *bracket = strchr(bdname,'[');
8031 if (bracket) {
8032 *bracket = 0;
8033 }
8034 branch = new TBranch(this,bdname,address,desc.Data(),32000);
8035 if (branch->IsZombie()) {
8036 delete branch;
8037 Warning("ReadStream","Illegal branch definition: %s",bdcur);
8038 } else {
8040 branch->SetAddress(nullptr);
8041 }
8042 if (!colon)break;
8043 bdcur = colon+1;
8044 }
8045 delete [] bdname;
8046 delete [] bd;
8047 }
8048
8050
8051 if (gDebug > 1) {
8052 Info("ReadStream", "Will use branches:");
8053 for (int i = 0 ; i < nbranches; ++i) {
8054 TBranch* br = (TBranch*) fBranches.At(i);
8055 Info("ReadStream", " %s: %s [%s]", br->GetName(),
8056 br->GetTitle(), br->GetListOfLeaves()->At(0)->IsA()->GetName());
8057 }
8058 if (gDebug > 3) {
8059 Info("ReadStream", "Dumping read tokens, format:");
8060 Info("ReadStream", "LLLLL:BBB:gfbe:GFBE:T");
8061 Info("ReadStream", " L: line number");
8062 Info("ReadStream", " B: branch number");
8063 Info("ReadStream", " gfbe: good / fail / bad / eof of token");
8064 Info("ReadStream", " GFBE: good / fail / bad / eof of file");
8065 Info("ReadStream", " T: Token being read");
8066 }
8067 }
8068
8069 //loop on all lines in the file
8070 Long64_t nGoodLines = 0;
8071 std::string line;
8072 const char sDelimBuf[2] = { delimiter, 0 };
8073 const char* sDelim = sDelimBuf;
8074 if (delimiter == ' ') {
8075 // ' ' really means whitespace
8076 sDelim = "[ \t]";
8077 }
8078 while(in.good()) {
8079 if (newline == '\r' && in.peek() == '\n') {
8080 // Windows, skip '\n':
8081 in.get();
8082 }
8083 std::getline(in, line, newline);
8084 ++nlines;
8085
8087 sLine = sLine.Strip(TString::kLeading); // skip leading whitespace
8088 if (sLine.IsNull()) {
8089 if (gDebug > 2) {
8090 Info("ReadStream", "Skipping empty line number %lld", nlines);
8091 }
8092 continue; // silently skip empty lines
8093 }
8094 if (sLine[0] == '#') {
8095 if (gDebug > 2) {
8096 Info("ReadStream", "Skipping comment line number %lld: '%s'",
8097 nlines, line.c_str());
8098 }
8099 continue;
8100 }
8101 if (gDebug > 2) {
8102 Info("ReadStream", "Parsing line number %lld: '%s'",
8103 nlines, line.c_str());
8104 }
8105
8106 // Loop on branches and read the branch values into their buffer
8107 branch = nullptr;
8108 TString tok; // one column's data
8109 TString leafData; // leaf data, possibly multiple tokens for e.g. /I[2]
8110 std::stringstream sToken; // string stream feeding leafData into leaves
8111 Ssiz_t pos = 0;
8112 Int_t iBranch = 0;
8113 bool goodLine = true; // whether the row can be filled into the tree
8114 Int_t remainingLeafLen = 0; // remaining columns for the current leaf
8115 while (goodLine && iBranch < nbranches
8116 && sLine.Tokenize(tok, pos, sDelim)) {
8117 tok = tok.Strip(TString::kLeading); // skip leading whitespace
8118 if (tok.IsNull() && delimiter == ' ') {
8119 // 1 2 should not be interpreted as 1,,,2 but 1, 2.
8120 // Thus continue until we have a non-empty token.
8121 continue;
8122 }
8123
8124 if (!remainingLeafLen) {
8125 // next branch!
8127 }
8128 TLeaf *leaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
8129 if (!remainingLeafLen) {
8130 remainingLeafLen = leaf->GetLen();
8131 if (leaf->GetMaximum() > 0) {
8132 // This is a dynamic leaf length, i.e. most likely a TLeafC's
8133 // string size. This still translates into one token:
8134 remainingLeafLen = 1;
8135 }
8136
8137 leafData = tok;
8138 } else {
8139 // append token to laf data:
8140 leafData += " ";
8141 leafData += tok;
8142 }
8144 if (remainingLeafLen) {
8145 // need more columns for this branch:
8146 continue;
8147 }
8148 ++iBranch;
8149
8150 // initialize stringstream with token
8151 sToken.clear();
8152 sToken.seekp(0, std::ios_base::beg);
8153 sToken.str(leafData.Data());
8154 sToken.seekg(0, std::ios_base::beg);
8155 leaf->ReadValue(sToken, 0 /* 0 = "all" */);
8156 if (gDebug > 3) {
8157 Info("ReadStream", "%5lld:%3d:%d%d%d%d:%d%d%d%d:%s",
8158 nlines, iBranch,
8159 (int)sToken.good(), (int)sToken.fail(),
8160 (int)sToken.bad(), (int)sToken.eof(),
8161 (int)in.good(), (int)in.fail(),
8162 (int)in.bad(), (int)in.eof(),
8163 sToken.str().c_str());
8164 }
8165
8166 // Error handling
8167 if (sToken.bad()) {
8168 // How could that happen for a stringstream?
8169 Warning("ReadStream",
8170 "Buffer error while reading data for branch %s on line %lld",
8171 branch->GetName(), nlines);
8172 } else if (!sToken.eof()) {
8173 if (sToken.fail()) {
8174 Warning("ReadStream",
8175 "Couldn't read formatted data in \"%s\" for branch %s on line %lld; ignoring line",
8176 tok.Data(), branch->GetName(), nlines);
8177 goodLine = false;
8178 } else {
8179 std::string remainder;
8180 std::getline(sToken, remainder, newline);
8181 if (!remainder.empty()) {
8182 Warning("ReadStream",
8183 "Ignoring trailing \"%s\" while reading data for branch %s on line %lld",
8184 remainder.c_str(), branch->GetName(), nlines);
8185 }
8186 }
8187 }
8188 } // tokenizer loop
8189
8190 if (iBranch < nbranches) {
8191 Warning("ReadStream",
8192 "Read too few columns (%d < %d) in line %lld; ignoring line",
8194 goodLine = false;
8195 } else if (pos != kNPOS) {
8197 if (pos < sLine.Length()) {
8198 Warning("ReadStream",
8199 "Ignoring trailing \"%s\" while reading line %lld",
8200 sLine.Data() + pos - 1 /* also print delimiter */,
8201 nlines);
8202 }
8203 }
8204
8205 //we are now ready to fill the tree
8206 if (goodLine) {
8207 Fill();
8208 ++nGoodLines;
8209 }
8210 }
8211
8212 return nGoodLines;
8213}
8214
8215////////////////////////////////////////////////////////////////////////////////
8216/// Make sure that obj (which is being deleted or will soon be) is no
8217/// longer referenced by this TTree.
8220{
8221 if (obj == fEventList) {
8222 fEventList = nullptr;
8223 }
8224 if (obj == fEntryList) {
8225 fEntryList = nullptr;
8226 }
8227 if (fUserInfo) {
8229 }
8230 if (fPlayer == obj) {
8231 fPlayer = nullptr;
8232 }
8233 if (fTreeIndex == obj) {
8234 fTreeIndex = nullptr;
8235 }
8236 if (fAliases == obj) {
8237 fAliases = nullptr;
8238 } else if (fAliases) {
8240 }
8241 if (fFriends == obj) {
8242 fFriends = nullptr;
8243 } else if (fFriends) {
8245 }
8246}
8247
8248////////////////////////////////////////////////////////////////////////////////
8249/// Refresh contents of this tree and its branches from the current status on disk.
8250///
8251/// One can call this function in case the tree file is being
8252/// updated by another process.
8254void TTree::Refresh()
8255{
8256 if (!fDirectory->GetFile()) {
8257 return;
8258 }
8260 fDirectory->Remove(this);
8261 TTree* tree; fDirectory->GetObject(GetName(),tree);
8262 if (!tree) {
8263 return;
8264 }
8265 //copy info from tree header into this Tree
8266 fEntries = 0;
8267 fNClusterRange = 0;
8268 ImportClusterRanges(tree);
8269
8270 fAutoSave = tree->fAutoSave;
8271 fEntries = tree->fEntries;
8272 fTotBytes = tree->GetTotBytes();
8273 fZipBytes = tree->GetZipBytes();
8274 fSavedBytes = tree->fSavedBytes;
8275 fTotalBuffers = tree->fTotalBuffers.load();
8276
8277 //loop on all branches and update them
8279 for (Int_t i = 0; i < nleaves; i++) {
8281 TBranch* branch = (TBranch*) leaf->GetBranch();
8282 branch->Refresh(tree->GetBranch(branch->GetName()));
8283 }
8284 fDirectory->Remove(tree);
8285 fDirectory->Append(this);
8286 delete tree;
8287 tree = nullptr;
8288}
8289
8290////////////////////////////////////////////////////////////////////////////////
8291/// Record a TFriendElement that we need to warn when the chain switches to
8292/// a new file (typically this is because this chain is a friend of another
8293/// TChain)
8300}
8301
8302
8303////////////////////////////////////////////////////////////////////////////////
8304/// Removes external friend
8309}
8310
8311
8312////////////////////////////////////////////////////////////////////////////////
8313/// Remove a friend from the list of friends.
8316{
8317 // We already have been visited while recursively looking
8318 // through the friends tree, let return
8320 return;
8321 }
8322 if (!fFriends) {
8323 return;
8324 }
8325 TFriendLock lock(this, kRemoveFriend);
8327 TFriendElement* fe = nullptr;
8328 while ((fe = (TFriendElement*) nextf())) {
8329 TTree* friend_t = fe->GetTree();
8330 if (friend_t == oldFriend) {
8331 fFriends->Remove(fe);
8332 delete fe;
8333 fe = nullptr;
8334 }
8335 }
8336}
8337
8338////////////////////////////////////////////////////////////////////////////////
8339/// Reset baskets, buffers and entries count in all branches and leaves.
8342{
8343 fNotify = nullptr;
8344 fEntries = 0;
8345 fNClusterRange = 0;
8346 fTotBytes = 0;
8347 fZipBytes = 0;
8348 fFlushedBytes = 0;
8349 fSavedBytes = 0;
8350 fTotalBuffers = 0;
8351 fChainOffset = 0;
8352 fReadEntry = -1;
8353
8354 delete fTreeIndex;
8355 fTreeIndex = nullptr;
8356
8358 for (Int_t i = 0; i < nb; ++i) {
8360 branch->Reset(option);
8361 }
8362
8363 if (fBranchRef) {
8364 fBranchRef->Reset();
8365 }
8366}
8367
8368////////////////////////////////////////////////////////////////////////////////
8369/// Resets the state of this TTree after a merge (keep the customization but
8370/// forget the data).
8373{
8374 fEntries = 0;
8375 fNClusterRange = 0;
8376 fTotBytes = 0;
8377 fZipBytes = 0;
8378 fSavedBytes = 0;
8379 fFlushedBytes = 0;
8380 fTotalBuffers = 0;
8381 fChainOffset = 0;
8382 fReadEntry = -1;
8383
8384 delete fTreeIndex;
8385 fTreeIndex = nullptr;
8386
8388 for (Int_t i = 0; i < nb; ++i) {
8390 branch->ResetAfterMerge(info);
8391 }
8392
8393 if (fBranchRef) {
8395 }
8396}
8397
8398////////////////////////////////////////////////////////////////////////////////
8399/// Tell a branch to set its address to zero.
8400///
8401/// @note If the branch owns any objects, they are deleted.
8404{
8405 if (br && br->GetTree()) {
8406 br->ResetAddress();
8407 }
8408}
8409
8410////////////////////////////////////////////////////////////////////////////////
8411/// Tell all of our branches to drop their current objects and allocate new ones.
8414{
8415 // We already have been visited while recursively looking
8416 // through the friends tree, let return
8418 return;
8419 }
8421 Int_t nbranches = branches->GetEntriesFast();
8422 for (Int_t i = 0; i < nbranches; ++i) {
8423 TBranch* branch = (TBranch*) branches->UncheckedAt(i);
8424 branch->ResetAddress();
8425 }
8426 if (fFriends) {
8429 auto *frTree = frEl->GetTree();
8430 if (frTree) {
8431 frTree->ResetBranchAddresses();
8432 }
8433 }
8434 }
8435}
8436
8437////////////////////////////////////////////////////////////////////////////////
8438/// Loop over tree entries and print entries passing selection. Interactive
8439/// pagination break is on by default.
8440///
8441/// - If varexp is 0 (or "") then print only first 8 columns.
8442/// - If varexp = "*" print all columns.
8443///
8444/// Otherwise a columns selection can be made using "var1:var2:var3".
8445///
8446/// \param firstentry first entry to scan
8447/// \param nentries total number of entries to scan (starting from firstentry). Defaults to all entries.
8448/// \note see TTree::SetScanField to control how many lines are printed between pagination breaks (Use 0 to disable pagination)
8449/// \see TTreePlayer::Scan, TTreePlayer::SetScanFileName, TTreePlayer::SetScanRedirect
8452{
8453 GetPlayer();
8454 if (fPlayer) {
8456 }
8457 return -1;
8458}
8459
8460////////////////////////////////////////////////////////////////////////////////
8461/// Set a tree variable alias.
8462///
8463/// Set an alias for an expression/formula based on the tree 'variables'.
8464///
8465/// The content of 'aliasName' can be used in TTreeFormula (i.e. TTree::Draw,
8466/// TTree::Scan, TTreeViewer) and will be evaluated as the content of
8467/// 'aliasFormula'.
8468///
8469/// If the content of 'aliasFormula' only contains symbol names, periods and
8470/// array index specification (for example event.fTracks[3]), then
8471/// the content of 'aliasName' can be used as the start of symbol.
8472///
8473/// If the alias 'aliasName' already existed, it is replaced by the new
8474/// value.
8475///
8476/// When being used, the alias can be preceded by an eventual 'Friend Alias'
8477/// (see TTree::GetFriendAlias)
8478///
8479/// Return true if it was added properly.
8480///
8481/// For example:
8482/// ~~~ {.cpp}
8483/// tree->SetAlias("x1","(tdc1[1]-tdc1[0])/49");
8484/// tree->SetAlias("y1","(tdc1[3]-tdc1[2])/47");
8485/// tree->SetAlias("x2","(tdc2[1]-tdc2[0])/49");
8486/// tree->SetAlias("y2","(tdc2[3]-tdc2[2])/47");
8487/// tree->Draw("y2-y1:x2-x1");
8488///
8489/// tree->SetAlias("theGoodTrack","event.fTracks[3]");
8490/// tree->Draw("theGoodTrack.fPx"); // same as "event.fTracks[3].fPx"
8491/// ~~~
8493bool TTree::SetAlias(const char* aliasName, const char* aliasFormula)
8494{
8495 if (!aliasName || !aliasFormula) {
8496 return false;
8497 }
8498 if (!aliasName[0] || !aliasFormula[0]) {
8499 return false;
8500 }
8501 if (!fAliases) {
8502 fAliases = new TList;
8503 } else {
8505 if (oldHolder) {
8506 oldHolder->SetTitle(aliasFormula);
8507 return true;
8508 }
8509 }
8512 return true;
8513}
8514
8515////////////////////////////////////////////////////////////////////////////////
8516/// This function may be called at the start of a program to change
8517/// the default value for fAutoFlush.
8518///
8519/// ### CASE 1 : autof > 0
8520///
8521/// autof is the number of consecutive entries after which TTree::Fill will
8522/// flush all branch buffers to disk.
8523///
8524/// ### CASE 2 : autof < 0
8525///
8526/// When filling the Tree the branch buffers will be flushed to disk when
8527/// more than autof bytes have been written to the file. At the first FlushBaskets
8528/// TTree::Fill will replace fAutoFlush by the current value of fEntries.
8529///
8530/// Calling this function with autof<0 is interesting when it is hard to estimate
8531/// the size of one entry. This value is also independent of the Tree.
8532///
8533/// The Tree is initialized with fAutoFlush=-30000000, ie that, by default,
8534/// the first AutoFlush will be done when 30 MBytes of data are written to the file.
8535///
8536/// ### CASE 3 : autof = 0
8537///
8538/// The AutoFlush mechanism is disabled.
8539///
8540/// Flushing the buffers at regular intervals optimize the location of
8541/// consecutive entries on the disk by creating clusters of baskets.
8542///
8543/// A cluster of baskets is a set of baskets that contains all
8544/// the data for a (consecutive) set of entries and that is stored
8545/// consecutively on the disk. When reading all the branches, this
8546/// is the minimum set of baskets that the TTreeCache will read.
8548void TTree::SetAutoFlush(Long64_t autof /* = -30000000 */ )
8549{
8550 // Implementation note:
8551 //
8552 // A positive value of autoflush determines the size (in number of entries) of
8553 // a cluster of baskets.
8554 //
8555 // If the value of autoflush is changed over time (this happens in
8556 // particular when the TTree results from fast merging many trees),
8557 // we record the values of fAutoFlush in the data members:
8558 // fClusterRangeEnd and fClusterSize.
8559 // In the code we refer to a range of entries where the size of the
8560 // cluster of baskets is the same (i.e the value of AutoFlush was
8561 // constant) is called a ClusterRange.
8562 //
8563 // The 2 arrays (fClusterRangeEnd and fClusterSize) have fNClusterRange
8564 // active (used) values and have fMaxClusterRange allocated entries.
8565 //
8566 // fClusterRangeEnd contains the last entries number of a cluster range.
8567 // In particular this means that the 'next' cluster starts at fClusterRangeEnd[]+1
8568 // fClusterSize contains the size in number of entries of all the cluster
8569 // within the given range.
8570 // The last range (and the only one if fNClusterRange is zero) start at
8571 // fNClusterRange[fNClusterRange-1]+1 and ends at the end of the TTree. The
8572 // size of the cluster in this range is given by the value of fAutoFlush.
8573 //
8574 // For example printing the beginning and end of each the ranges can be done by:
8575 //
8576 // Printf("%-16s %-16s %-16s %5s",
8577 // "Cluster Range #", "Entry Start", "Last Entry", "Size");
8578 // Int_t index= 0;
8579 // Long64_t clusterRangeStart = 0;
8580 // if (fNClusterRange) {
8581 // for( ; index < fNClusterRange; ++index) {
8582 // Printf("%-16d %-16lld %-16lld %5lld",
8583 // index, clusterRangeStart, fClusterRangeEnd[index], fClusterSize[index]);
8584 // clusterRangeStart = fClusterRangeEnd[index] + 1;
8585 // }
8586 // }
8587 // Printf("%-16d %-16lld %-16lld %5lld",
8588 // index, prevEntry, fEntries - 1, fAutoFlush);
8589 //
8590
8591 // Note: We store the entry number corresponding to the end of the cluster
8592 // rather than its start in order to avoid using the array if the cluster
8593 // size never varies (If there is only one value of AutoFlush for the whole TTree).
8594
8595 if( fAutoFlush != autof) {
8596 if ((fAutoFlush > 0 || autof > 0) && fFlushedBytes) {
8597 // The mechanism was already enabled, let's record the previous
8598 // cluster if needed.
8600 }
8601 fAutoFlush = autof;
8602 }
8603}
8604
8605////////////////////////////////////////////////////////////////////////////////
8606/// Mark the previous event as being at the end of the event cluster.
8607///
8608/// So, if fEntries is set to 10 (and this is the first cluster) when MarkEventCluster
8609/// is called, then the first cluster has 9 events.
8611{
8612 if (!fEntries) return;
8613
8614 if ( (fNClusterRange+1) > fMaxClusterRange ) {
8615 if (fMaxClusterRange) {
8616 // Resize arrays to hold a larger event cluster.
8619 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
8621 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
8623 } else {
8624 // Cluster ranges have never been initialized; create them now.
8625 fMaxClusterRange = 2;
8628 }
8629 }
8631 // If we are auto-flushing, then the cluster size is the same as the current auto-flush setting.
8632 if (fAutoFlush > 0) {
8633 // Even if the user triggers MarkEventRange prior to fAutoFlush being present, the TClusterIterator
8634 // will appropriately go to the next event range.
8636 // Otherwise, assume there is one cluster per event range (e.g., user is manually controlling the flush).
8637 } else if (fNClusterRange == 0) {
8639 } else {
8641 }
8643}
8644
8645/// Estimate the median cluster size for the TTree.
8646/// This value provides e.g. a reasonable cache size default if other heuristics fail.
8647/// Clusters with size 0 and the very last cluster range, that might not have been committed to fClusterSize yet,
8648/// are ignored for the purposes of the calculation.
8650{
8651 std::vector<Long64_t> clusterSizesPerRange;
8653
8654 // We ignore cluster sizes of 0 for the purposes of this function.
8655 // We also ignore the very last cluster range which might not have been committed to fClusterSize.
8656 std::copy_if(fClusterSize, fClusterSize + fNClusterRange, std::back_inserter(clusterSizesPerRange),
8657 [](Long64_t size) { return size != 0; });
8658
8659 std::vector<double> nClustersInRange; // we need to store doubles because of the signature of TMath::Median
8660 nClustersInRange.reserve(clusterSizesPerRange.size());
8661
8662 auto clusterRangeStart = 0ll;
8663 for (int i = 0; i < fNClusterRange; ++i) {
8664 const auto size = fClusterSize[i];
8665 R__ASSERT(size >= 0);
8666 if (fClusterSize[i] == 0)
8667 continue;
8668 const auto nClusters = (1 + fClusterRangeEnd[i] - clusterRangeStart) / fClusterSize[i];
8669 nClustersInRange.emplace_back(nClusters);
8671 }
8672
8674 const auto medianClusterSize =
8676 return medianClusterSize;
8677}
8678
8679////////////////////////////////////////////////////////////////////////////////
8680/// In case of a program crash, it will be possible to recover the data in the
8681/// tree up to the last AutoSave point.
8682/// This function may be called before filling a TTree to specify when the
8683/// branch buffers and TTree header are flushed to disk as part of
8684/// TTree::Fill().
8685/// The default is -300000000, ie the TTree will write data to disk once it
8686/// exceeds 300 MBytes.
8687/// CASE 1: If fAutoSave is positive the watermark is reached when a multiple of
8688/// fAutoSave entries have been filled.
8689/// CASE 2: If fAutoSave is negative the watermark is reached when -fAutoSave
8690/// bytes can be written to the file.
8691/// CASE 3: If fAutoSave is 0, AutoSave() will never be called automatically
8692/// as part of TTree::Fill().
8697}
8698
8699////////////////////////////////////////////////////////////////////////////////
8700/// Set a branch's basket size.
8701///
8702/// bname is the name of a branch.
8703///
8704/// - if bname="*", apply to all branches.
8705/// - if bname="xxx*", apply to all branches with name starting with xxx
8706///
8707/// see TRegexp for wildcarding options
8708/// bufsize = branch basket size
8710void TTree::SetBasketSize(const char* bname, Int_t bufsize)
8711{
8713 TRegexp re(bname, true);
8714 Int_t nb = 0;
8715 for (Int_t i = 0; i < nleaves; i++) {
8717 TBranch* branch = (TBranch*) leaf->GetBranch();
8718 TString s = branch->GetName();
8719 if (strcmp(bname, branch->GetName()) && (s.Index(re) == kNPOS)) {
8720 continue;
8721 }
8722 nb++;
8723 branch->SetBasketSize(bufsize);
8724 }
8725 if (!nb) {
8726 Error("SetBasketSize", "unknown branch -> '%s'", bname);
8727 }
8728}
8729
8730////////////////////////////////////////////////////////////////////////////////
8731/// Change branch address, dealing with clone trees properly.
8732/// See TTree::CheckBranchAddressType for the semantic of the return value.
8733///
8734/// Note: See the comments in TBranchElement::SetAddress() for the
8735/// meaning of the addr parameter and the object ownership policy.
8737Int_t TTree::SetBranchAddress(const char* bname, void* addr, TBranch** ptr)
8738{
8739 TBranch* branch = GetBranch(bname);
8740 if (!branch) {
8741 if (ptr) *ptr = nullptr;
8742 Error("SetBranchAddress", "unknown branch -> %s", bname);
8743 return kMissingBranch;
8744 }
8745 return SetBranchAddressImp(branch,addr,ptr);
8746}
8747
8748////////////////////////////////////////////////////////////////////////////////
8749/// Verify the validity of the type of addr before calling SetBranchAddress.
8750/// See TTree::CheckBranchAddressType for the semantic of the return value.
8751///
8752/// Note: See the comments in TBranchElement::SetAddress() for the
8753/// meaning of the addr parameter and the object ownership policy.
8755Int_t TTree::SetBranchAddress(const char* bname, void* addr, TClass* ptrClass, EDataType datatype, bool isptr)
8756{
8757 return SetBranchAddress(bname, addr, nullptr, ptrClass, datatype, isptr);
8758}
8761 bool isptr)
8762{
8763 if (auto *branchFromSelf = GetBranchFromSelf(bname)) {
8765
8766 // This will set the value of *ptr to branch.
8767 if (res >= 0) {
8768 // The check succeeded.
8769 if ((res & kNeedEnableDecomposedObj) && !branchFromSelf->GetMakeClass())
8770 branchFromSelf->SetMakeClass(true);
8772 } else {
8773 if (ptr)
8774 *ptr = nullptr;
8775 }
8776 return res;
8777 }
8778
8779 // Check friends
8780 if (fFriends) {
8781 int status{kMissingBranch};
8783 if (auto *tree = fe->GetTree()) {
8784 status = tree->SetBranchAddress(bname, addr, ptr, ptrClass, datatype, isptr, true);
8785 // We exit early from visiting all friends only if a perfect match was found
8786 if (status == kMatch)
8787 return status;
8788 }
8789 }
8790 // This allows for the valid case of friend TChain(s) which might hold
8791 // the requested branch, but might not know it yet since they haven't loaded
8792 // the tree. This is encoded in the kNoCheck == 5 value.
8793 if (status != kMissingBranch)
8794 return status;
8795 }
8796
8797 // Branch not found
8798 if (ptr)
8799 *ptr = nullptr;
8800
8801 return kMissingBranch;
8802}
8803
8804////////////////////////////////////////////////////////////////////////////////
8805/// Verify the validity of the type of addr before calling SetBranchAddress.
8806/// See TTree::CheckBranchAddressType for the semantic of the return value.
8807///
8808/// Note: See the comments in TBranchElement::SetAddress() for the
8809/// meaning of the addr parameter and the object ownership policy.
8811Int_t TTree::SetBranchAddress(const char *bname, void *addr, TBranch **ptr, TClass *ptrClass, EDataType datatype,
8812 bool isptr)
8813{
8814 auto res = SetBranchAddressImp(bname, addr, ptr, ptrClass, datatype, isptr);
8815 if (res == kMissingBranch)
8816 Error("SetBranchAddress", "unknown branch -> %s", bname);
8817 return res;
8818}
8820Int_t TTree::SetBranchAddress(const char *bname, void *addr, TBranch **ptr, TClass *ptrClass, EDataType datatype,
8821 bool isptr, bool)
8822{
8823 // This has been called while setting the branch address of friends of a TTree. We can't know a priori
8824 // which friend actually has the branch bname, so we avoid printing an error in case of missing branch
8825 return SetBranchAddressImp(bname, addr, ptr, ptrClass, datatype, isptr);
8826}
8827
8828////////////////////////////////////////////////////////////////////////////////
8829/// Change branch address, dealing with clone trees properly.
8830/// See TTree::CheckBranchAddressType for the semantic of the return value.
8831///
8832/// Note: See the comments in TBranchElement::SetAddress() for the
8833/// meaning of the addr parameter and the object ownership policy.
8836{
8837 if (ptr) {
8838 *ptr = branch;
8839 }
8840 if (fClones) {
8841 void* oldAddr = branch->GetAddress();
8842 TIter next(fClones);
8843 TTree* clone = nullptr;
8844 const char *bname = branch->GetName();
8845 while ((clone = (TTree*) next())) {
8846 TBranch* cloneBr = clone->GetBranch(bname);
8847 if (cloneBr && (cloneBr->GetAddress() == oldAddr)) {
8848 cloneBr->SetAddress(addr);
8849 }
8850 }
8851 }
8852 branch->SetAddress(addr);
8853 return kVoidPtr;
8854}
8855
8856////////////////////////////////////////////////////////////////////////////////
8857/// Set branch status to Process or DoNotProcess.
8858///
8859/// When reading a Tree, by default, all branches are read.
8860/// One can speed up considerably the analysis phase by activating
8861/// only the branches that hold variables involved in a query.
8862///
8863/// bname is the name of a branch.
8864///
8865/// - if bname="*", apply to all branches.
8866/// - if bname="xxx*", apply to all branches with name starting with xxx
8867///
8868/// see TRegexp for wildcarding options
8869///
8870/// - status = 1 branch will be processed
8871/// - = 0 branch will not be processed
8872///
8873/// Example:
8874///
8875/// Assume a tree T with sub-branches a,b,c,d,e,f,g,etc..
8876/// when doing T.GetEntry(i) all branches are read for entry i.
8877/// to read only the branches c and e, one can do
8878/// ~~~ {.cpp}
8879/// T.SetBranchStatus("*",0); //disable all branches
8880/// T.SetBranchStatus("c",1);
8881/// T.setBranchStatus("e",1);
8882/// T.GetEntry(i);
8883/// ~~~
8884/// bname is interpreted as a wild-carded TRegexp (see TRegexp::MakeWildcard).
8885/// Thus, "a*b" or "a.*b" matches branches starting with "a" and ending with
8886/// "b", but not any other branch with an "a" followed at some point by a
8887/// "b". For this second behavior, use "*a*b*". Note that TRegExp does not
8888/// support '|', and so you cannot select, e.g. track and shower branches
8889/// with "track|shower".
8890///
8891/// __WARNING! WARNING! WARNING!__
8892///
8893/// SetBranchStatus is matching the branch based on match of the branch
8894/// 'name' and not on the branch hierarchy! In order to be able to
8895/// selectively enable a top level object that is 'split' you need to make
8896/// sure the name of the top level branch is prefixed to the sub-branches'
8897/// name (by adding a dot ('.') at the end of the Branch creation and use the
8898/// corresponding bname.
8899///
8900/// I.e If your Tree has been created in split mode with a parent branch "parent."
8901/// (note the trailing dot).
8902/// ~~~ {.cpp}
8903/// T.SetBranchStatus("parent",1);
8904/// ~~~
8905/// will not activate the sub-branches of "parent". You should do:
8906/// ~~~ {.cpp}
8907/// T.SetBranchStatus("parent*",1);
8908/// ~~~
8909/// Without the trailing dot in the branch creation you have no choice but to
8910/// call SetBranchStatus explicitly for each of the sub branches.
8911///
8912/// An alternative to this function is to read directly and only
8913/// the interesting branches. Example:
8914/// ~~~ {.cpp}
8915/// TBranch *brc = T.GetBranch("c");
8916/// TBranch *bre = T.GetBranch("e");
8917/// brc->GetEntry(i);
8918/// bre->GetEntry(i);
8919/// ~~~
8920/// If found is not 0, the number of branch(es) found matching the regular
8921/// expression is returned in *found AND the error message 'unknown branch'
8922/// is suppressed.
8924void TTree::SetBranchStatus(const char* bname, bool status, UInt_t* found)
8925{
8926 // We already have been visited while recursively looking
8927 // through the friends tree, let return
8929 return;
8930 }
8931
8932 if (!bname || !*bname) {
8933 Error("SetBranchStatus", "Input regexp is an empty string: no match against branch names will be attempted.");
8934 return;
8935 }
8936
8938 TLeaf *leaf, *leafcount;
8939
8940 Int_t i,j;
8942 TRegexp re(bname,true);
8943 Int_t nb = 0;
8944
8945 // first pass, loop on all branches
8946 // for leafcount branches activate/deactivate in function of status
8947 for (i=0;i<nleaves;i++) {
8949 branch = (TBranch*)leaf->GetBranch();
8950 TString s = branch->GetName();
8951 if (strcmp(bname,"*")) { //Regexp gives wrong result for [] in name
8953 longname.Form("%s.%s",GetName(),branch->GetName());
8954 if (strcmp(bname,branch->GetName())
8955 && longname != bname
8956 && s.Index(re) == kNPOS) continue;
8957 }
8958 nb++;
8959 if (status) branch->ResetBit(kDoNotProcess);
8960 else branch->SetBit(kDoNotProcess);
8961 leafcount = leaf->GetLeafCount();
8962 if (leafcount) {
8963 bcount = leafcount->GetBranch();
8964 if (status) bcount->ResetBit(kDoNotProcess);
8965 else bcount->SetBit(kDoNotProcess);
8966 }
8967 }
8968 if (nb==0 && !strchr(bname,'*')) {
8969 branch = GetBranch(bname);
8970 if (branch) {
8971 if (status) branch->ResetBit(kDoNotProcess);
8972 else branch->SetBit(kDoNotProcess);
8973 ++nb;
8974 }
8975 }
8976
8977 //search in list of friends
8979 if (fFriends) {
8980 TFriendLock lock(this,kSetBranchStatus);
8983 TString name;
8984 while ((fe = (TFriendElement*)nextf())) {
8985 TTree *t = fe->GetTree();
8986 if (!t) continue;
8987
8988 // If the alias is present replace it with the real name.
8989 const char *subbranch = strstr(bname,fe->GetName());
8990 if (subbranch!=bname) subbranch = nullptr;
8991 if (subbranch) {
8992 subbranch += strlen(fe->GetName());
8993 if ( *subbranch != '.' ) subbranch = nullptr;
8994 else subbranch ++;
8995 }
8996 if (subbranch) {
8997 name.Form("%s.%s",t->GetName(),subbranch);
8998 } else {
8999 name = bname;
9000 }
9001 t->SetBranchStatus(name,status, &foundInFriend);
9002 }
9003 }
9004 if (!nb && !foundInFriend) {
9005 if (!found) {
9006 if (status) {
9007 if (strchr(bname,'*') != nullptr)
9008 Error("SetBranchStatus", "No branch name is matching wildcard -> %s", bname);
9009 else
9010 Error("SetBranchStatus", "unknown branch -> %s", bname);
9011 } else {
9012 if (strchr(bname,'*') != nullptr)
9013 Warning("SetBranchStatus", "No branch name is matching wildcard -> %s", bname);
9014 else
9015 Warning("SetBranchStatus", "unknown branch -> %s", bname);
9016 }
9017 }
9018 return;
9019 }
9020 if (found) *found = nb + foundInFriend;
9021
9022 // second pass, loop again on all branches
9023 // activate leafcount branches for active branches only
9024 for (i = 0; i < nleaves; i++) {
9026 branch = (TBranch*)leaf->GetBranch();
9027 if (!branch->TestBit(kDoNotProcess)) {
9028 leafcount = leaf->GetLeafCount();
9029 if (leafcount) {
9030 bcount = leafcount->GetBranch();
9031 bcount->ResetBit(kDoNotProcess);
9032 }
9033 } else {
9034 //Int_t nbranches = branch->GetListOfBranches()->GetEntriesFast();
9035 Int_t nbranches = branch->GetListOfBranches()->GetEntries();
9036 for (j=0;j<nbranches;j++) {
9037 bson = (TBranch*)branch->GetListOfBranches()->UncheckedAt(j);
9038 if (!bson) continue;
9039 if (!bson->TestBit(kDoNotProcess)) {
9040 if (bson->GetNleaves() <= 0) continue;
9041 branch->ResetBit(kDoNotProcess);
9042 break;
9043 }
9044 }
9045 }
9046 }
9047}
9048
9049////////////////////////////////////////////////////////////////////////////////
9050/// Set the current branch style. (static function)
9051///
9052/// - style = 0 old Branch
9053/// - style = 1 new Bronch
9058}
9059
9060////////////////////////////////////////////////////////////////////////////////
9061/// Set maximum size of the file cache (TTreeCache) in bytes.
9062//
9063/// - if cachesize = 0 the existing cache (if any) is disabled (deleted if any).
9064/// - if cachesize > 0, the cache is enabled or extended, if necessary
9065/// - if cachesize = -1 (default) it is set to the AutoFlush value when writing
9066/// the Tree (default is 30 MBytes).
9067///
9068/// The cacheSize might be clamped, see TFileCacheRead::SetBufferSize
9069///
9070/// TTreeCache's 'real' job is to actually prefetch (early grab from disk) the compressed data.
9071/// The cachesize controls the size of the read bytes from disk.
9072///
9073/// Returns:
9074/// - 0 size set, cache was created if possible
9075/// - -1 on error
9078{
9079 // remember that the user has requested an explicit cache setup
9080 fCacheUserSet = true;
9081
9082 return SetCacheSizeAux(false, cacheSize);
9083}
9084
9085////////////////////////////////////////////////////////////////////////////////
9086/// Set the maximum size of the file cache (TTreeCache) in bytes and create it if possible.
9087///
9088/// If autocache is true:
9089/// this may be an autocreated cache, possibly enlarging an existing
9090/// autocreated cache. The size is calculated. The value passed in cacheSize:
9091/// - cacheSize = 0 make cache if default cache creation is enabled.
9092/// - cachesize > 0 the cache is enabled or extended, if necessary
9093/// - cacheSize = -1 make a default sized cache in any case
9094///
9095/// If autocache is false:
9096/// this is a user requested cache. cacheSize is used to size the cache.
9097/// This cache should never be automatically adjusted. If cachesize is
9098/// 0, the cache is disabled (deleted if any).
9099///
9100/// The cacheSize might be clamped, see TFileCacheRead::SetBufferSize
9101///
9102/// TTreeCache's 'real' job is to actually prefetch (early grab from disk) the compressed data.
9103/// The cachesize controls the size of the read bytes from disk.
9104///
9105/// Returns:
9106/// - 0 size set, or existing autosized cache almost large enough.
9107/// (cache was created if possible)
9108/// - -1 on error
9110Int_t TTree::SetCacheSizeAux(bool autocache /* = true */, Long64_t cacheSize /* = 0 */ )
9111{
9112 if (autocache) {
9113 // used as a once only control for automatic cache setup
9114 fCacheDoAutoInit = false;
9115 }
9116
9117 if (!autocache) {
9118 // negative size means the user requests the default
9119 if (cacheSize < 0) {
9120 cacheSize = GetCacheAutoSize(true);
9121 }
9122 } else {
9123 if (cacheSize == 0) {
9124 cacheSize = GetCacheAutoSize();
9125 } else if (cacheSize < 0) {
9126 cacheSize = GetCacheAutoSize(true);
9127 }
9128 }
9129
9130 TFile* file = GetCurrentFile();
9131 if (!file || GetTree() != this) {
9132 // if there's no file or we are not a plain tree (e.g. if we're a TChain)
9133 // do not create a cache, only record the size if one was given
9134 if (!autocache) {
9135 fCacheSize = cacheSize;
9136 }
9137 if (GetTree() != this) {
9138 return 0;
9139 }
9140 if (!autocache && cacheSize>0) {
9141 Warning("SetCacheSizeAux", "A TTreeCache could not be created because the TTree has no file");
9142 }
9143 return 0;
9144 }
9145
9146 // Check for an existing cache
9147 TTreeCache* pf = GetReadCache(file);
9148 if (pf) {
9149 if (autocache) {
9150 // reset our cache status tracking in case existing cache was added
9151 // by the user without using one of the TTree methods
9152 fCacheSize = pf->GetBufferSize();
9153 fCacheUserSet = !pf->IsAutoCreated();
9154
9155 if (fCacheUserSet) {
9156 // existing cache was created by the user, don't change it
9157 return 0;
9158 }
9159 } else {
9160 // update the cache to ensure it records the user has explicitly
9161 // requested it
9162 pf->SetAutoCreated(false);
9163 }
9164
9165 // if we're using an automatically calculated size and the existing
9166 // cache is already almost large enough don't resize
9167 if (autocache && Long64_t(0.80*cacheSize) < fCacheSize) {
9168 // already large enough
9169 return 0;
9170 }
9171
9172 if (cacheSize == fCacheSize) {
9173 return 0;
9174 }
9175
9176 if (cacheSize == 0) {
9177 // delete existing cache
9178 pf->WaitFinishPrefetch();
9179 file->SetCacheRead(nullptr,this);
9180 delete pf;
9181 pf = nullptr;
9182 } else {
9183 // resize
9184 Int_t res = pf->SetBufferSize(cacheSize);
9185 if (res < 0) {
9186 return -1;
9187 }
9188 cacheSize = pf->GetBufferSize(); // update after potential clamp
9189 }
9190 } else {
9191 // no existing cache
9192 if (autocache) {
9193 if (fCacheUserSet) {
9194 // value was already set manually.
9195 if (fCacheSize == 0) return 0;
9196 // Expected a cache should exist; perhaps the user moved it
9197 // Do nothing more here.
9198 if (cacheSize) {
9199 Error("SetCacheSizeAux", "Not setting up an automatically sized TTreeCache because of missing cache previously set");
9200 }
9201 return -1;
9202 }
9203 }
9204 }
9205
9206 fCacheSize = cacheSize;
9207 if (cacheSize == 0 || pf) {
9208 return 0;
9209 }
9210
9211#ifdef R__USE_IMT
9213 pf = new TTreeCacheUnzip(this, cacheSize);
9214 else
9215#endif
9216 pf = new TTreeCache(this, cacheSize);
9217
9218 pf->SetAutoCreated(autocache);
9219
9220 return 0;
9221}
9222
9223////////////////////////////////////////////////////////////////////////////////
9224///interface to TTreeCache to set the cache entry range
9225///
9226/// Returns:
9227/// - 0 entry range set
9228/// - -1 on error
9231{
9232 if (!GetTree()) {
9233 if (LoadTree(0)<0) {
9234 Error("SetCacheEntryRange","Could not load a tree");
9235 return -1;
9236 }
9237 }
9238 if (GetTree()) {
9239 if (GetTree() != this) {
9240 return GetTree()->SetCacheEntryRange(first, last);
9241 }
9242 } else {
9243 Error("SetCacheEntryRange", "No tree is available. Could not set cache entry range");
9244 return -1;
9245 }
9246
9247 TFile *f = GetCurrentFile();
9248 if (!f) {
9249 Error("SetCacheEntryRange", "No file is available. Could not set cache entry range");
9250 return -1;
9251 }
9252 TTreeCache *tc = GetReadCache(f,true);
9253 if (!tc) {
9254 Error("SetCacheEntryRange", "No cache is available. Could not set entry range");
9255 return -1;
9256 }
9257 tc->SetEntryRange(first,last);
9258 return 0;
9259}
9260
9261////////////////////////////////////////////////////////////////////////////////
9262/// Interface to TTreeCache to set the number of entries for the learning phase
9267}
9268
9269////////////////////////////////////////////////////////////////////////////////
9270/// Enable/Disable circularity for this tree.
9271///
9272/// if maxEntries > 0 a maximum of maxEntries is kept in one buffer/basket
9273/// per branch in memory.
9274/// Note that when this function is called (maxEntries>0) the Tree
9275/// must be empty or having only one basket per branch.
9276/// if maxEntries <= 0 the tree circularity is disabled.
9277///
9278/// #### NOTE 1:
9279/// Circular Trees are interesting in online real time environments
9280/// to store the results of the last maxEntries events.
9281/// #### NOTE 2:
9282/// Calling SetCircular with maxEntries <= 0 is necessary before
9283/// merging circular Trees that have been saved on files.
9284/// #### NOTE 3:
9285/// SetCircular with maxEntries <= 0 is automatically called
9286/// by TChain::Merge
9287/// #### NOTE 4:
9288/// A circular Tree can still be saved in a file. When read back,
9289/// it is still a circular Tree and can be filled again.
9292{
9293 if (maxEntries <= 0) {
9294 // Disable circularity.
9295 fMaxEntries = 1000000000;
9296 fMaxEntries *= 1000;
9298 //in case the Tree was originally created in gROOT, the branch
9299 //compression level was set to -1. If the Tree is now associated to
9300 //a file, reset the compression level to the file compression level
9301 if (fDirectory) {
9304 if (bfile) {
9305 compress = bfile->GetCompressionSettings();
9306 }
9308 for (Int_t i = 0; i < nb; i++) {
9310 branch->SetCompressionSettings(compress);
9311 }
9312 }
9313 } else {
9314 // Enable circularity.
9317 }
9318}
9319
9320////////////////////////////////////////////////////////////////////////////////
9321/// Set the debug level and the debug range.
9322///
9323/// For entries in the debug range, the functions TBranchElement::Fill
9324/// and TBranchElement::GetEntry will print the number of bytes filled
9325/// or read for each branch.
9327void TTree::SetDebug(Int_t level, Long64_t min, Long64_t max)
9328{
9329 fDebug = level;
9330 fDebugMin = min;
9331 fDebugMax = max;
9332}
9333
9334////////////////////////////////////////////////////////////////////////////////
9335/// Update the default value for the branch's fEntryOffsetLen.
9336/// If updateExisting is true, also update all the existing branches.
9337/// If newdefault is less than 10, the new default value will be 10.
9340{
9341 if (newdefault < 10) {
9342 newdefault = 10;
9343 }
9345 if (updateExisting) {
9346 TIter next( GetListOfBranches() );
9347 TBranch *b;
9348 while ( ( b = (TBranch*)next() ) ) {
9349 b->SetEntryOffsetLen( newdefault, true );
9350 }
9351 if (fBranchRef) {
9353 }
9354 }
9355}
9356
9357////////////////////////////////////////////////////////////////////////////////
9358/// Change the tree's directory.
9359///
9360/// Remove reference to this tree from current directory and
9361/// add reference to new directory dir. The dir parameter can
9362/// be 0 in which case the tree does not belong to any directory.
9363///
9366{
9367 if (fDirectory == dir) {
9368 return;
9369 }
9370 if (fDirectory) {
9371 fDirectory->Remove(this);
9372
9373 // Delete or move the file cache if it points to this Tree
9374 TFile *file = fDirectory->GetFile();
9375 MoveReadCache(file,dir);
9376 }
9377 fDirectory = dir;
9378 if (fDirectory) {
9379 fDirectory->Append(this);
9380 }
9381 TFile* file = nullptr;
9382 if (fDirectory) {
9383 file = fDirectory->GetFile();
9384 }
9385 if (fBranchRef) {
9386 fBranchRef->SetFile(file);
9387 }
9388 TBranch* b = nullptr;
9389 TIter next(GetListOfBranches());
9390 while((b = (TBranch*) next())) {
9391 b->SetFile(file);
9392 }
9393}
9394
9395////////////////////////////////////////////////////////////////////////////////
9396/// Change number of entries in the tree.
9397///
9398/// If n >= 0, set number of entries in the tree = n.
9399///
9400/// If n < 0, set number of entries in the tree to match the
9401/// number of entries in each branch. (default for n is -1)
9402///
9403/// This function should be called only when one fills each branch
9404/// independently via TBranch::Fill without calling TTree::Fill.
9405/// Calling TTree::SetEntries() make sense only if the number of entries
9406/// in each branch is identical, a warning is issued otherwise.
9407/// The function returns the number of entries.
9408///
9411{
9412 // case 1 : force number of entries to n
9413 if (n >= 0) {
9414 fEntries = n;
9415 return n;
9416 }
9417
9418 // case 2; compute the number of entries from the number of entries in the branches
9419 TBranch* b(nullptr), *bMin(nullptr), *bMax(nullptr);
9421 Long64_t nMax = 0;
9422 TIter next(GetListOfBranches());
9423 while((b = (TBranch*) next())){
9424 Long64_t n2 = b->GetEntries();
9425 if (!bMin || n2 < nMin) {
9426 nMin = n2;
9427 bMin = b;
9428 }
9429 if (!bMax || n2 > nMax) {
9430 nMax = n2;
9431 bMax = b;
9432 }
9433 }
9434 if (bMin && nMin != nMax) {
9435 Warning("SetEntries", "Tree branches have different numbers of entries, eg %s has %lld entries while %s has %lld entries.",
9436 bMin->GetName(), nMin, bMax->GetName(), nMax);
9437 }
9438 fEntries = nMax;
9439 return fEntries;
9440}
9441
9442////////////////////////////////////////////////////////////////////////////////
9443/// Set an EntryList
9446{
9447 if (fEntryList) {
9448 //check if the previous entry list is owned by the tree
9450 delete fEntryList;
9451 }
9452 }
9453 fEventList = nullptr;
9454 if (!enlist) {
9455 fEntryList = nullptr;
9456 return;
9457 }
9459 fEntryList->SetTree(this);
9460
9461}
9462
9463////////////////////////////////////////////////////////////////////////////////
9464/// This function transfroms the given TEventList into a TEntryList
9465/// The new TEntryList is owned by the TTree and gets deleted when the tree
9466/// is deleted. This TEntryList can be returned by GetEntryList() function.
9469{
9471 if (fEntryList){
9474 fEntryList = nullptr; // Avoid problem with RecursiveRemove.
9475 delete tmp;
9476 } else {
9477 fEntryList = nullptr;
9478 }
9479 }
9480
9481 if (!evlist) {
9482 fEntryList = nullptr;
9483 fEventList = nullptr;
9484 return;
9485 }
9486
9488 char enlistname[100];
9489 snprintf(enlistname,100, "%s_%s", evlist->GetName(), "entrylist");
9490 fEntryList = new TEntryList(enlistname, evlist->GetTitle());
9491 fEntryList->SetDirectory(nullptr); // We own this.
9492 Int_t nsel = evlist->GetN();
9493 fEntryList->SetTree(this);
9495 for (Int_t i=0; i<nsel; i++){
9496 entry = evlist->GetEntry(i);
9498 }
9499 fEntryList->SetReapplyCut(evlist->GetReapplyCut());
9501}
9502
9503////////////////////////////////////////////////////////////////////////////////
9504/// Set number of entries to estimate variable limits.
9505/// If n is -1, the estimate is set to be the current maximum
9506/// for the tree (i.e. GetEntries() + 1)
9507/// If n is less than -1, the behavior is undefined.
9509void TTree::SetEstimate(Long64_t n /* = 1000000 */)
9510{
9511 if (n == 0) {
9512 n = 10000;
9513 } else if (n < 0) {
9514 n = fEntries - n;
9515 }
9516 fEstimate = n;
9517 GetPlayer();
9518 if (fPlayer) {
9520 }
9521}
9522
9523////////////////////////////////////////////////////////////////////////////////
9524/// Provide the end-user with the ability to enable/disable various experimental
9525/// IO features for this TTree.
9526///
9527/// Returns all the newly-set IO settings.
9530{
9531 // Purposely ignore all unsupported bits; TIOFeatures implementation already warned the user about the
9532 // error of their ways; this is just a safety check.
9534
9539
9541 return newSettings;
9542}
9543
9544////////////////////////////////////////////////////////////////////////////////
9545/// Set fFileNumber to number.
9546/// fFileNumber is used by TTree::Fill to set the file name
9547/// for a new file to be created when the current file exceeds fgTreeMaxSize.
9548/// (see TTree::ChangeFile)
9549/// if fFileNumber=10, the new file name will have a suffix "_11",
9550/// ie, fFileNumber is incremented before setting the file name
9552void TTree::SetFileNumber(Int_t number)
9553{
9554 if (fFileNumber < 0) {
9555 Warning("SetFileNumber", "file number must be positive. Set to 0");
9556 fFileNumber = 0;
9557 return;
9558 }
9559 fFileNumber = number;
9560}
9561
9562////////////////////////////////////////////////////////////////////////////////
9563/// Set all the branches in this TTree to be in decomposed object mode
9564/// (also known as MakeClass mode).
9565///
9566/// For MakeClass mode 0, the TTree expects the address where the data is stored
9567/// to be set by either the user or the TTree to the address of a full object
9568/// through the top level branch.
9569/// For MakeClass mode 1, this address is expected to point to a numerical type
9570/// or C-style array (variable or not) of numerical type, representing the
9571/// primitive data members.
9572/// The function's primary purpose is to allow the user to access the data
9573/// directly with numerical type variable rather than having to have the original
9574/// set of classes (or a reproduction thereof).
9575/// In other words, SetMakeClass sets the branch(es) into a
9576/// mode that allow its reading via a set of independent variables
9577/// (see the result of running TTree::MakeClass on your TTree) by changing the
9578/// interpretation of the address passed to SetAddress from being the beginning
9579/// of the object containing the data to being the exact location where the data
9580/// should be loaded. If you have the shared library corresponding to your object,
9581/// it is better if you do
9582/// `MyClass *objp = 0; tree->SetBranchAddress("toplevel",&objp);`, whereas
9583/// if you do not have the shared library but know your branch data type, e.g.
9584/// `Int_t* ptr = new Int_t[10];`, then:
9585/// `tree->SetMakeClass(1); tree->GetBranch("x")->SetAddress(ptr)` is the way to go.
9587void TTree::SetMakeClass(Int_t make)
9588{
9589 fMakeClass = make;
9590
9592 for (Int_t i = 0; i < nb; ++i) {
9594 branch->SetMakeClass(make);
9595 }
9596}
9597
9598////////////////////////////////////////////////////////////////////////////////
9599/// Set the maximum size in bytes of a Tree file (static function).
9600/// The default size is 100000000000LL, ie 100 Gigabytes.
9601///
9602/// In TTree::Fill, when the file has a size > fgMaxTreeSize,
9603/// the function closes the current file and starts writing into
9604/// a new file with a name of the style "file_1.root" if the original
9605/// requested file name was "file.root".
9610}
9611
9612////////////////////////////////////////////////////////////////////////////////
9613/// Change the name of this tree.
9615void TTree::SetName(const char* name)
9616{
9617 if (gPad) {
9618 gPad->Modified();
9619 }
9620 // Trees are named objects in a THashList.
9621 // We must update hashlists if we change the name.
9622 TFile *file = nullptr;
9623 TTreeCache *pf = nullptr;
9624 if (fDirectory) {
9625 fDirectory->Remove(this);
9626 if ((file = GetCurrentFile())) {
9627 pf = GetReadCache(file);
9628 file->SetCacheRead(nullptr,this,TFile::kDoNotDisconnect);
9629 }
9630 }
9631 // This changes our hash value.
9632 fName = name;
9633 if (fDirectory) {
9634 fDirectory->Append(this);
9635 if (pf) {
9637 }
9638 }
9639}
9641void TTree::SetNotify(TObject *obj)
9642{
9643 if (obj && fNotify && dynamic_cast<TNotifyLinkBase *>(fNotify)) {
9644 auto *oldLink = static_cast<TNotifyLinkBase *>(fNotify);
9645 auto *newLink = dynamic_cast<TNotifyLinkBase *>(obj);
9646 if (!newLink) {
9647 Warning("TTree::SetNotify",
9648 "The tree or chain already has a fNotify registered and it is a TNotifyLink, while the new object is "
9649 "not a TNotifyLink. Setting fNotify to the new value will lead to an orphan linked list of "
9650 "TNotifyLinks and it is most likely not intended. If this is the intended goal, please call "
9651 "SetNotify(nullptr) first to silence this warning.");
9652 } else if (newLink->GetNext() != oldLink && oldLink->GetNext() != newLink) {
9653 // If newLink->GetNext() == oldLink then we are prepending the new head, as in TNotifyLink::PrependLink
9654 // If oldLink->GetNext() == newLink then we are removing the head of the list, as in TNotifyLink::RemoveLink
9655 // Otherwise newLink and oldLink are unrelated:
9656 Warning("TTree::SetNotify",
9657 "The tree or chain already has a TNotifyLink registered, and the new TNotifyLink `obj` does not link "
9658 "to it. Setting fNotify to the new value will lead to an orphan linked list of TNotifyLinks and it is "
9659 "most likely not intended. If this is the intended goal, please call SetNotify(nullptr) first to "
9660 "silence this warning.");
9661 }
9662 }
9663
9664 fNotify = obj;
9665}
9666
9667////////////////////////////////////////////////////////////////////////////////
9668/// Change the name and title of this tree.
9670void TTree::SetObject(const char* name, const char* title)
9671{
9672 if (gPad) {
9673 gPad->Modified();
9674 }
9675
9676 // Trees are named objects in a THashList.
9677 // We must update hashlists if we change the name
9678 TFile *file = nullptr;
9679 TTreeCache *pf = nullptr;
9680 if (fDirectory) {
9681 fDirectory->Remove(this);
9682 if ((file = GetCurrentFile())) {
9683 pf = GetReadCache(file);
9684 file->SetCacheRead(nullptr,this,TFile::kDoNotDisconnect);
9685 }
9686 }
9687 // This changes our hash value.
9688 fName = name;
9689 fTitle = title;
9690 if (fDirectory) {
9691 fDirectory->Append(this);
9692 if (pf) {
9694 }
9695 }
9696}
9697
9698////////////////////////////////////////////////////////////////////////////////
9699/// Enable or disable parallel unzipping of Tree buffers.
9702{
9703#ifdef R__USE_IMT
9704 if (GetTree() == nullptr) {
9706 if (!GetTree())
9707 return;
9708 }
9709 if (GetTree() != this) {
9710 GetTree()->SetParallelUnzip(opt, RelSize);
9711 return;
9712 }
9713 TFile* file = GetCurrentFile();
9714 if (!file)
9715 return;
9716
9717 TTreeCache* pf = GetReadCache(file);
9718 if (pf && !( opt ^ (nullptr != dynamic_cast<TTreeCacheUnzip*>(pf)))) {
9719 // done with opt and type are in agreement.
9720 return;
9721 }
9722 delete pf;
9723 auto cacheSize = GetCacheAutoSize(true);
9724 if (opt) {
9725 auto unzip = new TTreeCacheUnzip(this, cacheSize);
9726 unzip->SetUnzipBufferSize( Long64_t(cacheSize * RelSize) );
9727 } else {
9728 pf = new TTreeCache(this, cacheSize);
9729 }
9730#else
9731 (void)opt;
9732 (void)RelSize;
9733#endif
9734}
9735
9736////////////////////////////////////////////////////////////////////////////////
9737/// Set perf stats
9742}
9743
9744////////////////////////////////////////////////////////////////////////////////
9745/// The current TreeIndex is replaced by the new index.
9746/// Note that this function does not delete the previous index.
9747/// This gives the possibility to play with more than one index, e.g.,
9748/// ~~~ {.cpp}
9749/// TVirtualIndex* oldIndex = tree.GetTreeIndex();
9750/// tree.SetTreeIndex(newIndex);
9751/// tree.Draw();
9752/// tree.SetTreeIndex(oldIndex);
9753/// tree.Draw(); etc
9754/// ~~~
9757{
9758 if (fTreeIndex) {
9759 fTreeIndex->SetTree(nullptr);
9760 }
9761 fTreeIndex = index;
9762}
9763
9764////////////////////////////////////////////////////////////////////////////////
9765/// Set tree weight.
9766///
9767/// The weight is used by TTree::Draw to automatically weight each
9768/// selected entry in the resulting histogram.
9769///
9770/// For example the equivalent of:
9771/// ~~~ {.cpp}
9772/// T.Draw("x", "w")
9773/// ~~~
9774/// is:
9775/// ~~~ {.cpp}
9776/// T.SetWeight(w);
9777/// T.Draw("x");
9778/// ~~~
9779/// This function is redefined by TChain::SetWeight. In case of a
9780/// TChain, an option "global" may be specified to set the same weight
9781/// for all trees in the TChain instead of the default behaviour
9782/// using the weights of each tree in the chain (see TChain::SetWeight).
9785{
9786 fWeight = w;
9787}
9788
9789////////////////////////////////////////////////////////////////////////////////
9790/// Print values of all active leaves for entry.
9791///
9792/// - if entry==-1, print current entry (default)
9793/// - if a leaf is an array, a maximum of lenmax elements is printed.
9796{
9797 if (entry != -1) {
9799 if (ret == -2) {
9800 Error("Show()", "Cannot read entry %lld (entry does not exist)", entry);
9801 return;
9802 } else if (ret == -1) {
9803 Error("Show()", "Cannot read entry %lld (I/O error)", entry);
9804 return;
9805 }
9806 ret = GetEntry(entry);
9807 if (ret == -1) {
9808 Error("Show()", "Cannot read entry %lld (I/O error)", entry);
9809 return;
9810 } else if (ret == 0) {
9811 Error("Show()", "Cannot read entry %lld (no data read)", entry);
9812 return;
9813 }
9814 }
9815 printf("======> EVENT:%lld\n", fReadEntry);
9817 Int_t nleaves = leaves->GetEntriesFast();
9818 Int_t ltype;
9819 for (Int_t i = 0; i < nleaves; i++) {
9820 TLeaf* leaf = (TLeaf*) leaves->UncheckedAt(i);
9821 TBranch* branch = leaf->GetBranch();
9822 if (branch->TestBit(kDoNotProcess)) {
9823 continue;
9824 }
9825 Int_t len = leaf->GetLen();
9826 if (len <= 0) {
9827 continue;
9828 }
9830 if (leaf->IsA() == TLeafElement::Class()) {
9831 leaf->PrintValue(lenmax);
9832 continue;
9833 }
9834 if (branch->GetListOfBranches()->GetEntriesFast() > 0) {
9835 continue;
9836 }
9837 ltype = 10;
9838 if (leaf->IsA() == TLeafF::Class()) {
9839 ltype = 5;
9840 }
9841 if (leaf->IsA() == TLeafD::Class()) {
9842 ltype = 5;
9843 }
9844 if (leaf->IsA() == TLeafC::Class()) {
9845 len = 1;
9846 ltype = 5;
9847 };
9848 printf(" %-15s = ", leaf->GetName());
9849 for (Int_t l = 0; l < len; l++) {
9850 leaf->PrintValue(l);
9851 if (l == (len - 1)) {
9852 printf("\n");
9853 continue;
9854 }
9855 printf(", ");
9856 if ((l % ltype) == 0) {
9857 printf("\n ");
9858 }
9859 }
9860 }
9861}
9862
9863////////////////////////////////////////////////////////////////////////////////
9864/// Start the TTreeViewer on this tree.
9865///
9866/// - ww is the width of the canvas in pixels
9867/// - wh is the height of the canvas in pixels
9869void TTree::StartViewer()
9870{
9871 GetPlayer();
9872 if (fPlayer) {
9873 fPlayer->StartViewer(600, 400);
9874 }
9875}
9876
9877////////////////////////////////////////////////////////////////////////////////
9878/// Stop the cache learning phase
9879///
9880/// Returns:
9881/// - 0 learning phase stopped or not active
9882/// - -1 on error
9885{
9886 if (!GetTree()) {
9887 if (LoadTree(0)<0) {
9888 Error("StopCacheLearningPhase","Could not load a tree");
9889 return -1;
9890 }
9891 }
9892 if (GetTree()) {
9893 if (GetTree() != this) {
9894 return GetTree()->StopCacheLearningPhase();
9895 }
9896 } else {
9897 Error("StopCacheLearningPhase", "No tree is available. Could not stop cache learning phase");
9898 return -1;
9899 }
9900
9901 TFile *f = GetCurrentFile();
9902 if (!f) {
9903 Error("StopCacheLearningPhase", "No file is available. Could not stop cache learning phase");
9904 return -1;
9905 }
9906 TTreeCache *tc = GetReadCache(f,true);
9907 if (!tc) {
9908 Error("StopCacheLearningPhase", "No cache is available. Could not stop learning phase");
9909 return -1;
9910 }
9911 tc->StopLearningPhase();
9912 return 0;
9913}
9914
9915////////////////////////////////////////////////////////////////////////////////
9916/// Set the fTree member for all branches and sub branches.
9919{
9920 Int_t nb = branches.GetEntriesFast();
9921 for (Int_t i = 0; i < nb; ++i) {
9922 TBranch* br = (TBranch*) branches.UncheckedAt(i);
9923 br->SetTree(tree);
9924
9925 Int_t writeBasket = br->GetWriteBasket();
9926 for (Int_t j = writeBasket; j >= 0; --j) {
9927 TBasket *bk = (TBasket*)br->GetListOfBaskets()->UncheckedAt(j);
9928 if (bk) {
9929 tree->IncrementTotalBuffers(bk->GetBufferSize());
9930 }
9931 }
9932
9933 tree->RegisterBranchFullName({std::string{br->GetFullName()}, br});
9934
9935 ROOT::Internal::TreeUtils::TBranch__SetTree(tree, *br->GetListOfBranches());
9936 }
9937}
9938
9939////////////////////////////////////////////////////////////////////////////////
9940/// Set the fTree member for all friend elements.
9943{
9944 if (frlist) {
9945 TObjLink *lnk = frlist->FirstLink();
9946 while (lnk) {
9947 TFriendElement *elem = (TFriendElement*)lnk->GetObject();
9948 elem->fParentTree = tree;
9949 lnk = lnk->Next();
9950 }
9951 }
9952}
9953
9954////////////////////////////////////////////////////////////////////////////////
9955/// Stream a class object.
9958{
9959 if (b.IsReading()) {
9960 UInt_t R__s, R__c;
9961 if (fDirectory) {
9962 fDirectory->Remove(this);
9963 //delete the file cache if it points to this Tree
9964 TFile *file = fDirectory->GetFile();
9965 MoveReadCache(file,nullptr);
9966 }
9967 fDirectory = nullptr;
9968 fCacheDoAutoInit = true;
9969 fCacheUserSet = false;
9970 fNamesToBranches.clear();
9971 Version_t R__v = b.ReadVersion(&R__s, &R__c);
9972 if (R__v > 4) {
9973 b.ReadClassBuffer(TTree::Class(), this, R__v, R__s, R__c);
9974
9975 fBranches.SetOwner(true); // True needed only for R__v < 19 and most R__v == 19
9976
9977 if (fBranchRef) fBranchRef->SetTree(this);
9980
9981 if (fTreeIndex) {
9982 fTreeIndex->SetTree(this);
9983 }
9984 if (fIndex.fN) {
9985 Warning("Streamer", "Old style index in this tree is deleted. Rebuild the index via TTree::BuildIndex");
9986 fIndex.Set(0);
9987 fIndexValues.Set(0);
9988 }
9989 if (fEstimate <= 10000) {
9990 fEstimate = 1000000;
9991 }
9992
9993 if (fNClusterRange) {
9994 // The I/O allocated just enough memory to hold the
9995 // current set of ranges.
9997 }
9998
9999 // Throughs calls to `GetCacheAutoSize` or `EnableCache` (for example
10000 // by TTreePlayer::Process, the cache size will be automatically
10001 // determined unless the user explicitly call `SetCacheSize`
10002 fCacheSize = 0;
10003 fCacheUserSet = false;
10004
10006 return;
10007 }
10008 //====process old versions before automatic schema evolution
10009 Stat_t djunk;
10010 Int_t ijunk;
10015 b >> fScanField;
10018 b >> djunk; fEntries = (Long64_t)djunk;
10023 if (fEstimate <= 10000) fEstimate = 1000000;
10025 if (fBranchRef) fBranchRef->SetTree(this);
10029 if (R__v > 1) fIndexValues.Streamer(b);
10030 if (R__v > 2) fIndex.Streamer(b);
10031 if (R__v > 3) {
10033 OldInfoList.Streamer(b);
10034 OldInfoList.Delete();
10035 }
10036 fNClusterRange = 0;
10039 b.CheckByteCount(R__s, R__c, TTree::IsA());
10040 //====end of old versions
10041 } else {
10042 if (fBranchRef) {
10043 fBranchRef->Clear();
10044 }
10046 if (table) TRefTable::SetRefTable(nullptr);
10047
10048 b.WriteClassBuffer(TTree::Class(), this);
10049
10050 if (table) TRefTable::SetRefTable(table);
10051 }
10052}
10053
10054////////////////////////////////////////////////////////////////////////////////
10055/// Unbinned fit of one or more variable(s) from a tree.
10056///
10057/// funcname is a TF1 function.
10058///
10059/// \note see TTree::Draw for explanations of the other parameters.
10060///
10061/// Fit the variable varexp using the function funcname using the
10062/// selection cuts given by selection.
10063///
10064/// The list of fit options is given in parameter option.
10065///
10066/// - option = "Q" Quiet mode (minimum printing)
10067/// - option = "V" Verbose mode (default is between Q and V)
10068/// - option = "E" Perform better Errors estimation using Minos technique
10069/// - option = "M" More. Improve fit results
10070///
10071/// You can specify boundary limits for some or all parameters via
10072/// ~~~ {.cpp}
10073/// func->SetParLimits(p_number, parmin, parmax);
10074/// ~~~
10075/// if parmin>=parmax, the parameter is fixed
10076///
10077/// Note that you are not forced to fix the limits for all parameters.
10078/// For example, if you fit a function with 6 parameters, you can do:
10079/// ~~~ {.cpp}
10080/// func->SetParameters(0,3.1,1.e-6,0.1,-8,100);
10081/// func->SetParLimits(4,-10,-4);
10082/// func->SetParLimits(5, 1,1);
10083/// ~~~
10084/// With this setup:
10085///
10086/// - Parameters 0->3 can vary freely
10087/// - Parameter 4 has boundaries [-10,-4] with initial value -8
10088/// - Parameter 5 is fixed to 100.
10089///
10090/// For the fit to be meaningful, the function must be self-normalized.
10091///
10092/// i.e. It must have the same integral regardless of the parameter
10093/// settings. Otherwise the fit will effectively just maximize the
10094/// area.
10095///
10096/// It is mandatory to have a normalization variable
10097/// which is fixed for the fit. e.g.
10098/// ~~~ {.cpp}
10099/// TF1* f1 = new TF1("f1", "gaus(0)/sqrt(2*3.14159)/[2]", 0, 5);
10100/// f1->SetParameters(1, 3.1, 0.01);
10101/// f1->SetParLimits(0, 1, 1); // fix the normalization parameter to 1
10102/// data->UnbinnedFit("f1", "jpsimass", "jpsipt>3.0");
10103/// ~~~
10104/// 1, 2 and 3 Dimensional fits are supported. See also TTree::Fit
10105///
10106/// Return status:
10107///
10108/// - The function return the status of the fit in the following form
10109/// fitResult = migradResult + 10*minosResult + 100*hesseResult + 1000*improveResult
10110/// - The fitResult is 0 is the fit is OK.
10111/// - The fitResult is negative in case of an error not connected with the fit.
10112/// - The number of entries used in the fit can be obtained via mytree.GetSelectedRows();
10113/// - If the number of selected entries is null the function returns -1
10116{
10117 GetPlayer();
10118 if (fPlayer) {
10120 }
10121 return -1;
10122}
10123
10124////////////////////////////////////////////////////////////////////////////////
10125/// Replace current attributes by current style.
10148}
10149
10150////////////////////////////////////////////////////////////////////////////////
10151/// Write this object to the current directory. For more see TObject::Write
10152/// If option & kFlushBasket, call FlushBasket before writing the tree.
10154Int_t TTree::Write(const char *name, Int_t option, Int_t bufsize) const
10155{
10158 return 0;
10160}
10161
10162////////////////////////////////////////////////////////////////////////////////
10163/// Write this object to the current directory. For more see TObject::Write
10164/// If option & kFlushBasket, call FlushBasket before writing the tree.
10167{
10168 return ((const TTree*)this)->Write(name, option, bufsize);
10169}
10170
10171////////////////////////////////////////////////////////////////////////////////
10172/// \class TTreeFriendLeafIter
10173///
10174/// Iterator on all the leaves in a TTree and its friend
10175
10176
10177////////////////////////////////////////////////////////////////////////////////
10178/// Create a new iterator. By default the iteration direction
10179/// is kIterForward. To go backward use kIterBackward.
10182: fTree(const_cast<TTree*>(tree))
10183, fLeafIter(nullptr)
10184, fTreeIter(nullptr)
10185, fDirection(dir)
10186{
10187}
10188
10189////////////////////////////////////////////////////////////////////////////////
10190/// Copy constructor. Does NOT copy the 'cursor' location!
10193: TIterator(iter)
10194, fTree(iter.fTree)
10195, fLeafIter(nullptr)
10196, fTreeIter(nullptr)
10197, fDirection(iter.fDirection)
10198{
10199}
10200
10201////////////////////////////////////////////////////////////////////////////////
10202/// Overridden assignment operator. Does NOT copy the 'cursor' location!
10205{
10206 if (this != &rhs && rhs.IsA() == TTreeFriendLeafIter::Class()) {
10208 fDirection = rhs1.fDirection;
10209 }
10210 return *this;
10211}
10212
10213////////////////////////////////////////////////////////////////////////////////
10214/// Overridden assignment operator. Does NOT copy the 'cursor' location!
10217{
10218 if (this != &rhs) {
10219 fDirection = rhs.fDirection;
10220 }
10221 return *this;
10222}
10223
10224////////////////////////////////////////////////////////////////////////////////
10225/// Go the next friend element
10228{
10229 if (!fTree) return nullptr;
10230
10231 TObject * next;
10232 TTree * nextTree;
10233
10234 if (!fLeafIter) {
10235 TObjArray *list = fTree->GetListOfLeaves();
10236 if (!list) return nullptr; // Can happen with an empty chain.
10237 fLeafIter = list->MakeIterator(fDirection);
10238 if (!fLeafIter) return nullptr;
10239 }
10240
10241 next = fLeafIter->Next();
10242 if (!next) {
10243 if (!fTreeIter) {
10245 if (!list) return next;
10246 fTreeIter = list->MakeIterator(fDirection);
10247 if (!fTreeIter) return nullptr;
10248 }
10250 ///nextTree = (TTree*)fTreeIter->Next();
10251 if (nextFriend) {
10252 nextTree = const_cast<TTree*>(nextFriend->GetTree());
10253 if (!nextTree) return Next();
10255 fLeafIter = nextTree->GetListOfLeaves()->MakeIterator(fDirection);
10256 if (!fLeafIter) return nullptr;
10257 next = fLeafIter->Next();
10258 }
10259 }
10260 return next;
10261}
10262
10263////////////////////////////////////////////////////////////////////////////////
10264/// Returns the object option stored in the list.
10267{
10268 if (fLeafIter) return fLeafIter->GetOption();
10269 return "";
10270}
10276}
10282}
#define R__unlikely(expr)
Definition RConfig.hxx:584
#define SafeDelete(p)
Definition RConfig.hxx:523
#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:2584
R__EXTERN TStyle * gStyle
Definition TStyle.h:442
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
constexpr Int_t kNEntriesResort
Definition TTree.cxx:474
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:4863
static char DataTypeToChar(EDataType datatype)
Definition TTree.cxx:485
void TFriendElement__SetTree(TTree *tree, TList *frlist)
Set the fTree member for all friend elements.
Definition TTree.cxx:9941
bool CheckReshuffling(TTree &mainTree, TTree &friendTree)
Definition TTree.cxx:1267
constexpr Float_t kNEntriesResortInv
Definition TTree.cxx:475
#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:2673
virtual void SetFile(TFile *file=nullptr)
Set file where this branch writes/reads its buffers.
Definition TBranch.cxx:2875
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:2833
virtual void UpdateFile()
Refresh the value of fDirectory (i.e.
Definition TBranch.cxx:3324
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:2332
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition TClass.cxx:2913
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition TClass.cxx:5112
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:5534
void BuildRealData(void *pointer=nullptr, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition TClass.cxx:2044
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:3700
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:6107
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:4721
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4996
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2924
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:3000
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:2430
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:3503
@ kDoNotDisconnect
Definition TFile.h:148
virtual void Flush()
Synchronize a file's in-memory and on-disk states.
Definition TFile.cxx:1164
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:3800
virtual void WriteHeader()
Write File Header.
Definition TFile.cxx:2680
@ kCancelTTreeChangeRequest
Definition TFile.h:275
TFileCacheRead * GetCacheRead(const TObject *tree=nullptr) const
Return a pointer to the current read cache.
Definition TFile.cxx:1285
<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:138
Ssiz_t Length() const
Definition TString.h:427
void ToLower()
Change string to lower-case.
Definition TString.cxx:1189
static constexpr Ssiz_t kNPOS
Definition TString.h:286
Double_t Atof() const
Return floating-point value contained in string.
Definition TString.cxx:2134
const char * Data() const
Definition TString.h:386
Bool_t EqualTo(const char *cs, ECaseCompare cmp=kExact) const
Definition TString.h:656
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:715
@ kLeading
Definition TString.h:284
@ kTrailing
Definition TString.h:284
@ kIgnoreCase
Definition TString.h:285
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:2459
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2437
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:643
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:662
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:84
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:10203
TObject * Next() override
Go the next friend element.
Definition TTree.cxx:10226
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:10265
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:638
Long64_t Previous()
Move on to the previous cluster and return the starting entry of this previous cluster.
Definition TTree.cxx:721
Long64_t Next()
Move on to the next cluster and return the starting entry of this next cluster.
Definition TTree.cxx:677
Long64_t GetNextEntry()
Definition TTree.h:359
TClusterIterator(TTree *tree, Long64_t firstEntry)
Regular constructor.
Definition TTree.cxx:587
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:553
TFriendLock(const TFriendLock &)
Copy constructor.
Definition TTree.cxx:543
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:566
A TTree represents a columnar dataset.
Definition TTree.h:89
virtual Int_t Fill()
Fill all branches.
Definition TTree.cxx:4675
virtual TFriendElement * AddFriend(const char *treename, const char *filename="")
Add a TFriendElement to the list of friends.
Definition TTree.cxx:1359
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:6457
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:2682
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:5406
virtual Int_t SetBranchAddress(const char *bname, void *add, TBranch **ptr, TClass *realClass, EDataType datatype, bool isptr, bool suppressMissingBranchError)
Definition TTree.cxx:8819
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:4970
virtual void SetBranchStatus(const char *bname, bool status=true, UInt_t *found=nullptr)
Set branch status to Process or DoNotProcess.
Definition TTree.cxx:8923
bool EnableCache()
Enable the TTreeCache unless explicitly disabled for this TTree by a prior call to SetCacheSize(0).
Definition TTree.cxx:2715
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition TTree.cxx:5458
static Int_t GetBranchStyle()
Static function returning the current branch style.
Definition TTree.cxx:5499
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:5484
@ 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:5206
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:9794
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:9883
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:5746
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:9290
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:1086
Long64_t GetMedianClusterSize()
Estimate the median cluster size for the TTree.
Definition TTree.cxx:8648
virtual TClusterIterator GetClusterIterator(Long64_t firstentry)
Return an iterator over the cluster of baskets starting at firstentry.
Definition TTree.cxx:5571
virtual void ResetBranchAddress(TBranch *)
Tell a branch to set its address to zero.
Definition TTree.cxx:8402
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:7925
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:6018
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:9409
virtual TObjArray * GetListOfLeaves()
Definition TTree.h:584
TLeaf * SearchLeafInListOfLeaves(const char *branchName, const char *leafName)
Definition TTree.cxx:6226
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:2104
virtual Int_t GetEntryWithIndex(Long64_t major, Long64_t minor=0)
Read entry corresponding to major and minor number.
Definition TTree.cxx:6036
Long64_t GetCacheAutoSize(bool withDefault=false)
Used for automatic sizing of the cache.
Definition TTree.cxx:5511
virtual TBranch * BranchRef()
Build the optional branch supporting the TRefTable.
Definition TTree.cxx:2358
TFile * GetCurrentFile() const
Return pointer to the current file.
Definition TTree.cxx:5583
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:3759
virtual Int_t DropBranchFromCache(const char *bname, bool subbranches=false)
Remove the branch with name 'bname' from the Tree cache.
Definition TTree.cxx:1169
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:5156
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:9956
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:8218
TVirtualTreePlayer * GetPlayer()
Load the TTreePlayer (if not already done).
Definition TTree.cxx:6560
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:7031
virtual Long64_t ReadStream(std::istream &inputStream, const char *branchDescriptor="", char delimiter=' ')
Create or simply read branches from an input stream.
Definition TTree.cxx:7952
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:9326
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:6084
virtual void SetNotify(TObject *obj)
Sets the address of the object to be notified when the tree is loaded.
Definition TTree.cxx:9640
virtual Double_t GetMaximum(const char *columname)
Return maximum of column with name columname.
Definition TTree.cxx:6534
virtual Long64_t GetEntryNumberWithBestIndex(Long64_t major, Long64_t minor=0) const
Return entry number corresponding to major and minor number.
Definition TTree.cxx:5998
static void SetMaxTreeSize(Long64_t maxsize=100000000000LL)
Set the maximum size in bytes of a Tree file (static function).
Definition TTree.cxx:9606
void Print(Option_t *option="") const override
Print a summary of the tree contents.
Definition TTree.cxx:7558
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:10114
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:7710
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:6221
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:9586
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:7351
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:6573
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:2779
virtual TEntryList * GetEntryList()
Returns the entry list assigned to this tree.
Definition TTree.cxx:5962
virtual void SetWeight(Double_t w=1, Option_t *option="")
Set tree weight.
Definition TTree.cxx:9783
void InitializeBranchLists(bool checkLeafCount)
Divides the top-level branches into two vectors: (i) branches to be processed sequentially and (ii) b...
Definition TTree.cxx:5889
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:9738
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:9263
TEntryList * fEntryList
! Pointer to event selection list (if one)
Definition TTree.h:136
TBranch * FindBranchFromFriends(const char *branchName)
Definition TTree.cxx:4926
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:7165
virtual void SetMaxVirtualSize(Long64_t size=0)
Definition TTree.h:725
virtual void DropBaskets()
Remove some baskets from memory.
Definition TTree.cxx:4590
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:8693
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:9700
virtual void SetDirectory(TDirectory *dir)
Change the tree's directory.
Definition TTree.cxx:9364
void SortBranchesByTime()
Sorts top-level branches by the last average task time recorded per branch.
Definition TTree.cxx:5942
void Delete(Option_t *option="") override
Delete this tree from memory or/and disk.
Definition TTree.cxx:3787
virtual TBranchRef * GetBranchRef() const
Definition TTree.h:505
TLeaf * SearchLeafInListOfFriends(const char *branchName, const char *leafName)
Definition TTree.cxx:6275
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:7788
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:1662
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:9467
void MoveReadCache(TFile *src, TDirectory *dir)
Move a cache from a file to the current file in dir.
Definition TTree.cxx:7322
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:8371
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:9508
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:9109
virtual Long64_t AutoSave(Option_t *option="")
AutoSave tree header every fAutoSave bytes.
Definition TTree.cxx:1527
virtual Long64_t GetEntryNumber(Long64_t entry) const
Return entry number corresponding to entry.
Definition TTree.cxx:5973
virtual TTree * CloneTree(Long64_t nentries=-1, Option_t *option="")
Create a clone of this tree and copy nentries.
Definition TTree.cxx:3173
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:6326
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:8340
virtual void KeepCircular()
Keep a maximum of fMaxEntries in memory.
Definition TTree.cxx:6670
virtual void SetDefaultEntryOffsetLen(Int_t newdefault, bool updateExisting=false)
Update the default value for the branch's fEntryOffsetLen.
Definition TTree.cxx:9338
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:3859
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:7085
virtual void SetObject(const char *name, const char *title)
Change the name and title of this tree.
Definition TTree.cxx:9669
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:5370
TTree()
Default constructor and I/O constructor.
Definition TTree.cxx:764
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:7116
bool MemoryFull(Int_t nbytes)
Check if adding nbytes to memory we are still below MaxVirtualsize.
Definition TTree.cxx:7100
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:9444
bool Notify() override
Function called when loading a new class library.
Definition TTree.cxx:7372
virtual void AddZipBytes(Int_t zip)
Definition TTree.h:384
virtual Long64_t LoadTree(Long64_t entry)
Set current entry.
Definition TTree.cxx:6728
virtual Long64_t ReadFile(const char *filename, const char *branchDescriptor="", char delimiter=' ')
Create or simply read branches from filename.
Definition TTree.cxx:7901
virtual const char * GetAlias(const char *aliasName) const
Returns the expanded value of the alias. Search in the friends if any.
Definition TTree.cxx:5303
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:9528
virtual TBasket * CreateBasket(TBranch *)
Create a basket for this tree and given branch.
Definition TTree.cxx:3771
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:6552
virtual void RemoveFriend(TTree *)
Remove a friend from the list of friends.
Definition TTree.cxx:8314
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:2639
virtual TList * GetUserInfo()
Return a pointer to the list containing user objects associated to this tree.
Definition TTree.cxx:6611
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:5618
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:7849
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:2434
virtual void SetBasketSize(const char *bname, Int_t buffsize=16000)
Set a branch's basket size.
Definition TTree.cxx:8709
static void SetBranchStyle(Int_t style=1)
Set the current branch style.
Definition TTree.cxx:9054
~TTree() override
Destructor.
Definition TTree.cxx:947
void ImportClusterRanges(TTree *fromtree)
Appends the cluster range information stored in 'fromtree' to this tree, including the value of fAuto...
Definition TTree.cxx:6627
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:5223
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:6820
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:10165
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:10126
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:1581
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:9755
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:7396
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:7834
virtual Int_t SetCacheEntryRange(Long64_t first, Long64_t last)
interface to TTreeCache to set the cache entry range
Definition TTree.cxx:9229
static Long64_t GetMaxTreeSize()
Static function which returns the tree file size limit in bytes.
Definition TTree.cxx:6542
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:8492
virtual void CopyAddresses(TTree *, bool undo=false)
Set branch addresses of passed tree equal to ours.
Definition TTree.cxx:3339
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:2667
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:4603
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:8253
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:8547
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:8609
TBranch * FindBranchFromSelf(const char *branchName)
Definition TTree.cxx:4906
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:9551
virtual TLeaf * FindLeaf(const char *name)
Find first leaf containing searchname.
Definition TTree.cxx:4993
virtual void StartViewer()
Start the TTreeViewer on this tree.
Definition TTree.cxx:9868
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:6903
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:8412
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:9614
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:8294
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:8759
virtual Int_t SetCacheSize(Long64_t cachesize=-1)
Set maximum size of the file cache (TTreeCache) in bytes.
Definition TTree.cxx:9076
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:1246
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:2901
TBuffer * GetTransientBuffer(Int_t size)
Returns the transient buffer currently used by this TTree for reading/writing baskets.
Definition TTree.cxx:1064
ROOT::TIOFeatures GetIOFeatures() const
Returns the current set of IO settings.
Definition TTree.cxx:6213
virtual Int_t MakeClass(const char *classname=nullptr, Option_t *option="")
Generate a skeleton analysis class for this tree.
Definition TTree.cxx:6870
virtual const char * GetFriendAlias(TTree *) const
If the 'tree' is a friend, this method returns its alias name.
Definition TTree.cxx:6141
virtual void RemoveExternalFriend(TFriendElement *)
Removes external friend.
Definition TTree.cxx:8305
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:1758
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:8450
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:2442
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:3574
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:6706
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:7539
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:10277
TBranch * CallBranchImpRef(TTree &tree, const char *branchname, TClass *ptrClass, EDataType datatype, void *addobj, Int_t bufsize=32000, Int_t splitlevel=99)
Definition TTree.cxx:10271
void TBranch__SetTree(TTree *tree, TObjArray &branches)
Set the fTree member for all branches and sub branches.
Definition TTree.cxx:9917
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