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 Tree Library
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 <ROOT/StringUtils.hxx>
460
461#include <chrono>
462#include <cstddef>
463#include <iostream>
464#include <fstream>
465#include <sstream>
466#include <string>
467#include <cstdio>
468#include <climits>
469#include <algorithm>
470#include <set>
471
472#ifdef R__USE_IMT
474#include <thread>
475#endif
477constexpr Int_t kNEntriesResort = 100;
479
480Int_t TTree::fgBranchStyle = 1; // Use new TBranch style with TBranchElement.
481Long64_t TTree::fgMaxTreeSize = 100000000000LL;
482
483
484////////////////////////////////////////////////////////////////////////////////
485////////////////////////////////////////////////////////////////////////////////
486////////////////////////////////////////////////////////////////////////////////
489{
490 // Return the leaflist 'char' for a given datatype.
491
492 switch(datatype) {
493 case kChar_t: return 'B';
494 case kUChar_t: return 'b';
495 case kBool_t: return 'O';
496 case kShort_t: return 'S';
497 case kUShort_t: return 's';
498 case kCounter:
499 case kInt_t: return 'I';
500 case kUInt_t: return 'i';
501 case kDouble_t: return 'D';
502 case kDouble32_t: return 'd';
503 case kFloat_t: return 'F';
504 case kFloat16_t: return 'f';
505 case kLong_t: return 'G';
506 case kULong_t: return 'g';
507 case kchar: return 0; // unsupported
508 case kLong64_t: return 'L';
509 case kULong64_t: return 'l';
510
511 case kCharStar: return 'C';
512 case kBits: return 0; //unsupported
513
514 case kOther_t:
515 case kNoType_t:
516 default:
517 return 0;
518 }
519 return 0;
520}
521
522////////////////////////////////////////////////////////////////////////////////
523/// \class TTree::TFriendLock
524/// Helper class to prevent infinite recursion in the usage of TTree Friends.
525
526////////////////////////////////////////////////////////////////////////////////
527/// Record in tree that it has been used while recursively looks through the friends.
530: fTree(tree)
531{
532 // We could also add some code to acquire an actual
533 // lock to prevent multi-thread issues
535 if (fTree) {
538 } else {
539 fPrevious = false;
540 }
541}
542
543////////////////////////////////////////////////////////////////////////////////
544/// Copy constructor.
547 fTree(tfl.fTree),
548 fMethodBit(tfl.fMethodBit),
549 fPrevious(tfl.fPrevious)
550{
551}
552
553////////////////////////////////////////////////////////////////////////////////
554/// Assignment operator.
557{
558 if(this!=&tfl) {
559 fTree=tfl.fTree;
560 fMethodBit=tfl.fMethodBit;
561 fPrevious=tfl.fPrevious;
562 }
563 return *this;
564}
565
566////////////////////////////////////////////////////////////////////////////////
567/// Restore the state of tree the same as before we set the lock.
570{
571 if (fTree) {
572 if (!fPrevious) {
573 fTree->fFriendLockStatus &= ~(fMethodBit & kBitMask);
574 }
575 }
576}
577
578////////////////////////////////////////////////////////////////////////////////
579/// \class TTree::TClusterIterator
580/// Helper class to iterate over cluster of baskets.
581/// \note In contrast to class TListIter, looping here must NOT be done using
582/// `while (iter())` or `while (iter.Next())` that would lead to an infinite loop, but rather using
583/// `while( (auto clusterStart = iter()) < tree->GetEntries() )`.
584/// \see TTree::GetClusterIterator
585
586////////////////////////////////////////////////////////////////////////////////
587/// Regular constructor.
588/// TTree is not set as const, since we might modify if it is a TChain.
590TTree::TClusterIterator::TClusterIterator(TTree *tree, Long64_t firstEntry) : fTree(tree), fClusterRange(0), fStartEntry(0), fNextEntry(0), fEstimatedSize(-1)
591{
592 if (fTree->fNClusterRange) {
593 // Find the correct cluster range.
594 //
595 // Since fClusterRangeEnd contains the inclusive upper end of the range, we need to search for the
596 // range that was containing the previous entry and add 1 (because BinarySearch consider the values
597 // to be the inclusive start of the bucket).
599
602 if (fClusterRange == 0) {
603 pedestal = 0;
605 } else {
608 }
612 } else {
614 }
615 if (autoflush <= 0) {
617 }
619 } else if ( fTree->GetAutoFlush() <= 0 ) {
620 // Case of old files before November 9 2009 *or* small tree where AutoFlush was never set.
622 } else {
624 }
625 fNextEntry = fStartEntry; // Position correctly for the first call to Next()
626}
627
628////////////////////////////////////////////////////////////////////////////////
629/// Estimate the cluster size.
630///
631/// In almost all cases, this quickly returns the size of the auto-flush
632/// in the TTree.
633///
634/// However, in the case where the cluster size was not fixed (old files and
635/// case where autoflush was explicitly set to zero), we need estimate
636/// a cluster size in relation to the size of the cache.
637///
638/// After this value is calculated once for the TClusterIterator, it is
639/// cached and reused in future calls.
642{
643 auto autoFlush = fTree->GetAutoFlush();
644 if (autoFlush > 0) return autoFlush;
645 if (fEstimatedSize > 0) return fEstimatedSize;
646
647 Long64_t zipBytes = fTree->GetZipBytes();
648 if (zipBytes == 0) {
649 fEstimatedSize = fTree->GetEntries() - 1;
650 if (fEstimatedSize <= 0)
651 fEstimatedSize = 1;
652 } else {
654 Long64_t cacheSize = fTree->GetCacheSize();
655 if (cacheSize == 0) {
656 // Humm ... let's double check on the file.
657 TFile *file = fTree->GetCurrentFile();
658 if (file) {
659 TFileCacheRead *cache = fTree->GetReadCache(file);
660 if (cache) {
661 cacheSize = cache->GetBufferSize();
662 }
663 }
664 }
665 // If neither file nor tree has a cache, use the current default.
666 if (cacheSize <= 0) {
667 cacheSize = 30000000;
668 }
669 clusterEstimate = fTree->GetEntries() * cacheSize / zipBytes;
670 // If there are no entries, then just default to 1.
671 fEstimatedSize = clusterEstimate ? clusterEstimate : 1;
672 }
673 return fEstimatedSize;
674}
675
676////////////////////////////////////////////////////////////////////////////////
677/// Move on to the next cluster and return the starting entry
678/// of this next cluster
681{
682 fStartEntry = fNextEntry;
683 if (fTree->fNClusterRange || fTree->GetAutoFlush() > 0) {
684 if (fClusterRange == fTree->fNClusterRange) {
685 // We are looking at a range which size
686 // is defined by AutoFlush itself and goes to the GetEntries.
687 fNextEntry += GetEstimatedClusterSize();
688 } else {
689 if (fStartEntry > fTree->fClusterRangeEnd[fClusterRange]) {
690 ++fClusterRange;
691 }
692 if (fClusterRange == fTree->fNClusterRange) {
693 // We are looking at the last range which size
694 // is defined by AutoFlush itself and goes to the GetEntries.
695 fNextEntry += GetEstimatedClusterSize();
696 } else {
697 Long64_t clusterSize = fTree->fClusterSize[fClusterRange];
698 if (clusterSize == 0) {
699 clusterSize = GetEstimatedClusterSize();
700 }
701 fNextEntry += clusterSize;
702 if (fNextEntry > fTree->fClusterRangeEnd[fClusterRange]) {
703 // The last cluster of the range was a partial cluster,
704 // so the next cluster starts at the beginning of the
705 // next range.
706 fNextEntry = fTree->fClusterRangeEnd[fClusterRange] + 1;
707 }
708 }
709 }
710 } else {
711 // Case of old files before November 9 2009
712 fNextEntry = fStartEntry + GetEstimatedClusterSize();
713 }
714 if (fNextEntry > fTree->GetEntries()) {
715 fNextEntry = fTree->GetEntries();
716 }
717 return fStartEntry;
718}
719
720////////////////////////////////////////////////////////////////////////////////
721/// Move on to the previous cluster and return the starting entry
722/// of this previous cluster
725{
726 fNextEntry = fStartEntry;
727 if (fTree->fNClusterRange || fTree->GetAutoFlush() > 0) {
728 if (fClusterRange == 0 || fTree->fNClusterRange == 0) {
729 // We are looking at a range which size
730 // is defined by AutoFlush itself.
731 fStartEntry -= GetEstimatedClusterSize();
732 } else {
733 if (fNextEntry <= fTree->fClusterRangeEnd[fClusterRange]) {
734 --fClusterRange;
735 }
736 if (fClusterRange == 0) {
737 // We are looking at the first range.
738 fStartEntry = 0;
739 } else {
740 Long64_t clusterSize = fTree->fClusterSize[fClusterRange];
741 if (clusterSize == 0) {
742 clusterSize = GetEstimatedClusterSize();
743 }
744 fStartEntry -= clusterSize;
745 }
746 }
747 } else {
748 // Case of old files before November 9 2009 or trees that never auto-flushed.
749 fStartEntry = fNextEntry - GetEstimatedClusterSize();
750 }
751 if (fStartEntry < 0) {
752 fStartEntry = 0;
753 }
754 return fStartEntry;
755}
756
757////////////////////////////////////////////////////////////////////////////////
758////////////////////////////////////////////////////////////////////////////////
759////////////////////////////////////////////////////////////////////////////////
760
761////////////////////////////////////////////////////////////////////////////////
762/// Default constructor and I/O constructor.
763///
764/// Note: We do *not* insert ourself into the current directory.
765///
768: TNamed()
769, TAttLine()
770, TAttFill()
771, TAttMarker()
772, fEntries(0)
773, fTotBytes(0)
774, fZipBytes(0)
775, fSavedBytes(0)
776, fFlushedBytes(0)
777, fWeight(1)
779, fScanField(25)
780, fUpdate(0)
784, fMaxEntries(0)
785, fMaxEntryLoop(0)
787, fAutoSave( -300000000)
788, fAutoFlush(-30000000)
789, fEstimate(1000000)
790, fClusterRangeEnd(nullptr)
791, fClusterSize(nullptr)
792, fCacheSize(0)
793, fChainOffset(0)
794, fReadEntry(-1)
795, fTotalBuffers(0)
796, fPacketSize(100)
797, fNfill(0)
798, fDebug(0)
799, fDebugMin(0)
800, fDebugMax(9999999)
801, fMakeClass(0)
802, fFileNumber(0)
803, fNotify(nullptr)
804, fDirectory(nullptr)
805, fBranches()
806, fLeaves()
807, fAliases(nullptr)
808, fEventList(nullptr)
809, fEntryList(nullptr)
810, fIndexValues()
811, fIndex()
812, fTreeIndex(nullptr)
813, fFriends(nullptr)
814, fExternalFriends(nullptr)
815, fPerfStats(nullptr)
816, fUserInfo(nullptr)
817, fPlayer(nullptr)
818, fClones(nullptr)
819, fBranchRef(nullptr)
821, fTransientBuffer(nullptr)
825, fIMTEnabled(ROOT::IsImplicitMTEnabled())
827{
828 fMaxEntries = 1000000000;
829 fMaxEntries *= 1000;
830
831 fMaxEntryLoop = 1000000000;
832 fMaxEntryLoop *= 1000;
833
834 fBranches.SetOwner(true);
835}
836
837////////////////////////////////////////////////////////////////////////////////
838/// Normal tree constructor.
839///
840/// The tree is created in the current directory.
841/// Use the various functions Branch below to add branches to this tree.
842///
843/// If the first character of title is a "/", the function assumes a folder name.
844/// In this case, it creates automatically branches following the folder hierarchy.
845/// splitlevel may be used in this case to control the split level.
847TTree::TTree(const char* name, const char* title, Int_t splitlevel /* = 99 */,
848 TDirectory* dir /* = gDirectory*/)
849: TNamed(name, title)
850, TAttLine()
851, TAttFill()
852, TAttMarker()
853, fEntries(0)
854, fTotBytes(0)
855, fZipBytes(0)
856, fSavedBytes(0)
857, fFlushedBytes(0)
858, fWeight(1)
859, fTimerInterval(0)
860, fScanField(25)
861, fUpdate(0)
862, fDefaultEntryOffsetLen(1000)
863, fNClusterRange(0)
864, fMaxClusterRange(0)
865, fMaxEntries(0)
866, fMaxEntryLoop(0)
867, fMaxVirtualSize(0)
868, fAutoSave( -300000000)
869, fAutoFlush(-30000000)
870, fEstimate(1000000)
871, fClusterRangeEnd(nullptr)
872, fClusterSize(nullptr)
873, fCacheSize(0)
874, fChainOffset(0)
875, fReadEntry(-1)
876, fTotalBuffers(0)
877, fPacketSize(100)
878, fNfill(0)
879, fDebug(0)
880, fDebugMin(0)
881, fDebugMax(9999999)
882, fMakeClass(0)
883, fFileNumber(0)
884, fNotify(nullptr)
885, fDirectory(dir)
886, fBranches()
887, fLeaves()
888, fAliases(nullptr)
889, fEventList(nullptr)
890, fEntryList(nullptr)
891, fIndexValues()
892, fIndex()
893, fTreeIndex(nullptr)
894, fFriends(nullptr)
895, fExternalFriends(nullptr)
896, fPerfStats(nullptr)
897, fUserInfo(nullptr)
898, fPlayer(nullptr)
899, fClones(nullptr)
900, fBranchRef(nullptr)
901, fFriendLockStatus(0)
902, fTransientBuffer(nullptr)
903, fCacheDoAutoInit(true)
904, fCacheDoClusterPrefetch(false)
905, fCacheUserSet(false)
906, fIMTEnabled(ROOT::IsImplicitMTEnabled())
907, fNEntriesSinceSorting(0)
908{
909 // TAttLine state.
913
914 // TAttFill state.
917
918 // TAttMarkerState.
922
923 fMaxEntries = 1000000000;
924 fMaxEntries *= 1000;
925
926 fMaxEntryLoop = 1000000000;
927 fMaxEntryLoop *= 1000;
928
929 // Insert ourself into the current directory.
930 // FIXME: This is very annoying behaviour, we should
931 // be able to choose to not do this like we
932 // can with a histogram.
933 if (fDirectory) fDirectory->Append(this);
934
935 fBranches.SetOwner(true);
936
937 // If title starts with "/" and is a valid folder name, a superbranch
938 // is created.
939 // FIXME: Why?
940 if (strlen(title) > 2) {
941 if (title[0] == '/') {
942 Branch(title+1,32000,splitlevel);
943 }
944 }
945}
946
947////////////////////////////////////////////////////////////////////////////////
948/// Destructor.
951{
952 if (auto link = dynamic_cast<TNotifyLinkBase*>(fNotify)) {
953 link->Clear();
954 }
955 if (fAllocationCount && (gDebug > 0)) {
956 Info("TTree::~TTree", "For tree %s, allocation count is %u.", GetName(), fAllocationCount.load());
957#ifdef R__TRACK_BASKET_ALLOC_TIME
958 Info("TTree::~TTree", "For tree %s, allocation time is %lluus.", GetName(), fAllocationTime.load());
959#endif
960 }
961
962 if (fDirectory) {
963 // We are in a directory, which may possibly be a file.
964 if (fDirectory->GetList()) {
965 // Remove us from the directory listing.
966 fDirectory->Remove(this);
967 }
968 //delete the file cache if it points to this Tree
969 TFile *file = fDirectory->GetFile();
970 MoveReadCache(file,nullptr);
971 }
972
973 // Remove the TTree from any list (linked to to the list of Cleanups) to avoid the unnecessary call to
974 // this RecursiveRemove while we delete our content.
976 ResetBit(kMustCleanup); // Don't redo it.
977
978 // We don't own the leaves in fLeaves, the branches do.
979 fLeaves.Clear();
980 // I'm ready to destroy any objects allocated by
981 // SetAddress() by my branches. If I have clones,
982 // tell them to zero their pointers to this shared
983 // memory.
984 if (fClones && fClones->GetEntries()) {
985 // I have clones.
986 // I am about to delete the objects created by
987 // SetAddress() which we are sharing, so tell
988 // the clones to release their pointers to them.
989 for (TObjLink* lnk = fClones->FirstLink(); lnk; lnk = lnk->Next()) {
990 TTree* clone = (TTree*) lnk->GetObject();
991 // clone->ResetBranchAddresses();
992
993 // Reset only the branch we have set the address of.
994 CopyAddresses(clone,true);
995 }
996 }
997 // Get rid of our branches, note that this will also release
998 // any memory allocated by TBranchElement::SetAddress().
1000
1001 // The TBranch destructor is using fDirectory to detect whether it
1002 // owns the TFile that contains its data (See TBranch::~TBranch)
1003 fDirectory = nullptr;
1004
1005 // FIXME: We must consider what to do with the reset of these if we are a clone.
1006 delete fPlayer;
1007 fPlayer = nullptr;
1008 if (fExternalFriends) {
1009 using namespace ROOT::Detail;
1011 fetree->Reset();
1012 fExternalFriends->Clear("nodelete");
1014 }
1015 if (fFriends) {
1016 fFriends->Delete();
1017 delete fFriends;
1018 fFriends = nullptr;
1019 }
1020 if (fAliases) {
1021 fAliases->Delete();
1022 delete fAliases;
1023 fAliases = nullptr;
1024 }
1025 if (fUserInfo) {
1026 fUserInfo->Delete();
1027 delete fUserInfo;
1028 fUserInfo = nullptr;
1029 }
1030 if (fClones) {
1031 // Clone trees should no longer be removed from fClones when they are deleted.
1032 {
1034 gROOT->GetListOfCleanups()->Remove(fClones);
1035 }
1036 // Note: fClones does not own its content.
1037 delete fClones;
1038 fClones = nullptr;
1039 }
1040 if (fEntryList) {
1041 if (fEntryList->TestBit(kCanDelete) && fEntryList->GetDirectory()==nullptr) {
1042 // Delete the entry list if it is marked to be deleted and it is not also
1043 // owned by a directory. (Otherwise we would need to make sure that a
1044 // TDirectoryFile that has a TTree in it does a 'slow' TList::Delete.
1045 delete fEntryList;
1046 fEntryList=nullptr;
1047 }
1048 }
1049 delete fTreeIndex;
1050 fTreeIndex = nullptr;
1051 delete fBranchRef;
1052 fBranchRef = nullptr;
1053 delete [] fClusterRangeEnd;
1054 fClusterRangeEnd = nullptr;
1055 delete [] fClusterSize;
1056 fClusterSize = nullptr;
1057
1058 if (fTransientBuffer) {
1059 delete fTransientBuffer;
1060 fTransientBuffer = nullptr;
1061 }
1062}
1063
1064////////////////////////////////////////////////////////////////////////////////
1065/// Returns the transient buffer currently used by this TTree for reading/writing baskets.
1077}
1078
1079////////////////////////////////////////////////////////////////////////////////
1080/// Add branch with name bname to the Tree cache.
1081/// If bname="*" all branches are added to the cache.
1082/// if subbranches is true all the branches of the subbranches are
1083/// also put to the cache.
1084///
1085/// Returns:
1086/// - 0 branch added or already included
1087/// - -1 on error
1089Int_t TTree::AddBranchToCache(const char*bname, bool subbranches)
1090{
1091 if (!GetTree()) {
1092 if (LoadTree(0)<0) {
1093 Error("AddBranchToCache","Could not load a tree");
1094 return -1;
1095 }
1096 }
1097 if (GetTree()) {
1098 if (GetTree() != this) {
1099 return GetTree()->AddBranchToCache(bname, subbranches);
1100 }
1101 } else {
1102 Error("AddBranchToCache", "No tree is available. Branch was not added to the cache");
1103 return -1;
1104 }
1105
1106 TFile *f = GetCurrentFile();
1107 if (!f) {
1108 Error("AddBranchToCache", "No file is available. Branch was not added to the cache");
1109 return -1;
1110 }
1111 TTreeCache *tc = GetReadCache(f,true);
1112 if (!tc) {
1113 Error("AddBranchToCache", "No cache is available, branch not added");
1114 return -1;
1115 }
1116 return tc->AddBranch(bname,subbranches);
1117}
1118
1119////////////////////////////////////////////////////////////////////////////////
1120/// Add branch b to the Tree cache.
1121/// if subbranches is true all the branches of the subbranches are
1122/// also put to the cache.
1123///
1124/// Returns:
1125/// - 0 branch added or already included
1126/// - -1 on error
1129{
1130 if (!GetTree()) {
1131 if (LoadTree(0)<0) {
1132 Error("AddBranchToCache","Could not load a tree");
1133 return -1;
1134 }
1135 }
1136 if (GetTree()) {
1137 if (GetTree() != this) {
1138 Int_t res = GetTree()->AddBranchToCache(b, subbranches);
1139 if (res<0) {
1140 Error("AddBranchToCache", "Error adding branch");
1141 }
1142 return res;
1143 }
1144 } else {
1145 Error("AddBranchToCache", "No tree is available. Branch was not added to the cache");
1146 return -1;
1147 }
1148
1149 TFile *f = GetCurrentFile();
1150 if (!f) {
1151 Error("AddBranchToCache", "No file is available. Branch was not added to the cache");
1152 return -1;
1153 }
1154 TTreeCache *tc = GetReadCache(f,true);
1155 if (!tc) {
1156 Error("AddBranchToCache", "No cache is available, branch not added");
1157 return -1;
1158 }
1159 return tc->AddBranch(b,subbranches);
1160}
1161
1162////////////////////////////////////////////////////////////////////////////////
1163/// Remove the branch with name 'bname' from the Tree cache.
1164/// If bname="*" all branches are removed from the cache.
1165/// if subbranches is true all the branches of the subbranches are
1166/// also removed from the cache.
1167///
1168/// Returns:
1169/// - 0 branch dropped or not in cache
1170/// - -1 on error
1172Int_t TTree::DropBranchFromCache(const char*bname, bool subbranches)
1173{
1174 if (!GetTree()) {
1175 if (LoadTree(0)<0) {
1176 Error("DropBranchFromCache","Could not load a tree");
1177 return -1;
1178 }
1179 }
1180 if (GetTree()) {
1181 if (GetTree() != this) {
1182 return GetTree()->DropBranchFromCache(bname, subbranches);
1183 }
1184 } else {
1185 Error("DropBranchFromCache", "No tree is available. Branch was not dropped from the cache");
1186 return -1;
1187 }
1188
1189 TFile *f = GetCurrentFile();
1190 if (!f) {
1191 Error("DropBranchFromCache", "No file is available. Branch was not dropped from the cache");
1192 return -1;
1193 }
1194 TTreeCache *tc = GetReadCache(f,true);
1195 if (!tc) {
1196 Error("DropBranchFromCache", "No cache is available, branch not dropped");
1197 return -1;
1198 }
1199 return tc->DropBranch(bname,subbranches);
1200}
1201
1202////////////////////////////////////////////////////////////////////////////////
1203/// Remove the branch b from the Tree cache.
1204/// if subbranches is true all the branches of the subbranches are
1205/// also removed from the cache.
1206///
1207/// Returns:
1208/// - 0 branch dropped or not in cache
1209/// - -1 on error
1212{
1213 if (!GetTree()) {
1214 if (LoadTree(0)<0) {
1215 Error("DropBranchFromCache","Could not load a tree");
1216 return -1;
1217 }
1218 }
1219 if (GetTree()) {
1220 if (GetTree() != this) {
1221 Int_t res = GetTree()->DropBranchFromCache(b, subbranches);
1222 if (res<0) {
1223 Error("DropBranchFromCache", "Error dropping branch");
1224 }
1225 return res;
1226 }
1227 } else {
1228 Error("DropBranchFromCache", "No tree is available. Branch was not dropped from the cache");
1229 return -1;
1230 }
1231
1232 TFile *f = GetCurrentFile();
1233 if (!f) {
1234 Error("DropBranchFromCache", "No file is available. Branch was not dropped from the cache");
1235 return -1;
1236 }
1237 TTreeCache *tc = GetReadCache(f,true);
1238 if (!tc) {
1239 Error("DropBranchFromCache", "No cache is available, branch not dropped");
1240 return -1;
1241 }
1242 return tc->DropBranch(b,subbranches);
1243}
1244
1245////////////////////////////////////////////////////////////////////////////////
1246/// Add a cloned tree to our list of trees to be notified whenever we change
1247/// our branch addresses or when we are deleted.
1249void TTree::AddClone(TTree* clone)
1250{
1251 if (!fClones) {
1252 fClones = new TList();
1253 fClones->SetOwner(false);
1254 // So that the clones are automatically removed from the list when
1255 // they are deleted.
1256 {
1258 gROOT->GetListOfCleanups()->Add(fClones);
1259 }
1260 }
1261 if (!fClones->FindObject(clone)) {
1262 fClones->Add(clone);
1263 }
1264}
1265
1266// Check whether mainTree and friendTree can be friends w.r.t. the kEntriesReshuffled bit.
1267// In particular, if any has the bit set, then friendTree must have a TTreeIndex and the
1268// branches used for indexing must be present in mainTree.
1269// Return true if the trees can be friends, false otherwise.
1271{
1274 const auto friendHasValidIndex = [&] {
1275 auto idx = friendTree.GetTreeIndex();
1276 return idx ? idx->IsValidFor(&mainTree) : false;
1277 }();
1278
1280 const auto reshuffledTreeName = isMainReshuffled ? mainTree.GetName() : friendTree.GetName();
1281 const auto msg =
1282 "Tree '%s' has the kEntriesReshuffled bit set and cannot have friends nor can be added as a friend unless the "
1283 "main tree has a TTreeIndex on the friend tree '%s'. You can also unset the bit manually if you know what you "
1284 "are doing; note that you risk associating wrong TTree entries of the friend with those of the main TTree!";
1285 Error("AddFriend", msg, reshuffledTreeName, friendTree.GetName());
1286 return false;
1287 }
1288 return true;
1289}
1290
1291////////////////////////////////////////////////////////////////////////////////
1292/// Add a TFriendElement to the list of friends.
1293///
1294/// This function:
1295/// - opens a file if filename is specified
1296/// - reads a Tree with name treename from the file (current directory)
1297/// - adds the Tree to the list of friends
1298/// see other AddFriend functions
1299///
1300/// A TFriendElement TF describes a TTree object TF in a file.
1301/// When a TFriendElement TF is added to the list of friends of an
1302/// existing TTree T, any variable from TF can be referenced in a query
1303/// to T.
1304///
1305/// A tree keeps a list of friends. In the context of a tree (or a chain),
1306/// friendship means unrestricted access to the friends data. In this way
1307/// it is much like adding another branch to the tree without taking the risk
1308/// of damaging it. To add a friend to the list, you can use the TTree::AddFriend
1309/// method. The tree in the diagram below has two friends (friend_tree1 and
1310/// friend_tree2) and now has access to the variables a,b,c,i,j,k,l and m.
1311///
1312/// \image html ttree_friend1.png
1313///
1314/// The AddFriend method has two parameters, the first is the tree name and the
1315/// second is the name of the ROOT file where the friend tree is saved.
1316/// AddFriend automatically opens the friend file. If no file name is given,
1317/// the tree called ft1 is assumed to be in the same file as the original tree.
1318///
1319/// tree.AddFriend("ft1","friendfile1.root");
1320/// If the friend tree has the same name as the original tree, you can give it
1321/// an alias in the context of the friendship:
1322///
1323/// tree.AddFriend("tree1 = tree","friendfile1.root");
1324/// Once the tree has friends, we can use TTree::Draw as if the friend's
1325/// variables were in the original tree. To specify which tree to use in
1326/// the Draw method, use the syntax:
1327/// ~~~ {.cpp}
1328/// <treeName>.<branchname>.<varname>
1329/// ~~~
1330/// If the variablename is enough to uniquely identify the variable, you can
1331/// leave out the tree and/or branch name.
1332/// For example, these commands generate a 3-d scatter plot of variable "var"
1333/// in the TTree tree versus variable v1 in TTree ft1 versus variable v2 in
1334/// TTree ft2.
1335/// ~~~ {.cpp}
1336/// tree.AddFriend("ft1","friendfile1.root");
1337/// tree.AddFriend("ft2","friendfile2.root");
1338/// tree.Draw("var:ft1.v1:ft2.v2");
1339/// ~~~
1340/// \image html ttree_friend2.png
1341///
1342/// The picture illustrates the access of the tree and its friends with a
1343/// Draw command.
1344/// When AddFriend is called, the ROOT file is automatically opened and the
1345/// friend tree (ft1) is read into memory. The new friend (ft1) is added to
1346/// the list of friends of tree.
1347/// The number of entries in the friend must be equal or greater to the number
1348/// of entries of the original tree. If the friend tree has fewer entries a
1349/// warning is given and the missing entries are not included in the histogram.
1350/// To retrieve the list of friends from a tree use TTree::GetListOfFriends.
1351/// When the tree is written to file (TTree::Write), the friends list is saved
1352/// with it. And when the tree is retrieved, the trees on the friends list are
1353/// also retrieved and the friendship restored.
1354/// When a tree is deleted, the elements of the friend list are also deleted.
1355/// It is possible to declare a friend tree that has the same internal
1356/// structure (same branches and leaves) as the original tree, and compare the
1357/// same values by specifying the tree.
1358/// ~~~ {.cpp}
1359/// tree.Draw("var:ft1.var:ft2.var")
1360/// ~~~
1362TFriendElement *TTree::AddFriend(const char *treename, const char *filename)
1363{
1364 if (!fFriends) {
1365 fFriends = new TList();
1366 }
1368
1369 TTree *t = fe->GetTree();
1370 bool canAddFriend = true;
1371 if (t) {
1372 canAddFriend = CheckReshuffling(*this, *t);
1373 if (!t->GetTreeIndex() && (t->GetEntries() < fEntries)) {
1374 Warning("AddFriend", "FriendElement %s in file %s has less entries %lld than its parent Tree: %lld", treename,
1376 }
1377 } else {
1378 Error("AddFriend", "Cannot find tree '%s' in file '%s', friend not added", treename, filename);
1379 canAddFriend = false;
1380 }
1381
1382 if (canAddFriend)
1383 fFriends->Add(fe);
1384 return fe;
1385}
1386
1387////////////////////////////////////////////////////////////////////////////////
1388/// Add a TFriendElement to the list of friends.
1389///
1390/// The TFile is managed by the user (e.g. the user must delete the file).
1391/// For complete description see AddFriend(const char *, const char *).
1392/// This function:
1393/// - reads a Tree with name treename from the file
1394/// - adds the Tree to the list of friends
1396TFriendElement *TTree::AddFriend(const char *treename, TFile *file)
1397{
1398 if (!fFriends) {
1399 fFriends = new TList();
1400 }
1401 TFriendElement *fe = new TFriendElement(this, treename, file);
1402 R__ASSERT(fe);
1403 TTree *t = fe->GetTree();
1404 bool canAddFriend = true;
1405 if (t) {
1406 canAddFriend = CheckReshuffling(*this, *t);
1407 if (!t->GetTreeIndex() && (t->GetEntries() < fEntries)) {
1408 Warning("AddFriend", "FriendElement %s in file %s has less entries %lld than its parent tree: %lld", treename,
1409 file->GetName(), t->GetEntries(), fEntries);
1410 }
1411 } else {
1412 Error("AddFriend", "Cannot find tree '%s' in file '%s', friend not added", treename, file->GetName());
1413 canAddFriend = false;
1414 }
1415
1416 if (canAddFriend)
1417 fFriends->Add(fe);
1418 return fe;
1419}
1420
1421////////////////////////////////////////////////////////////////////////////////
1422/// Add a TFriendElement to the list of friends.
1423///
1424/// The TTree is managed by the user (e.g., the user must delete the file).
1425/// For a complete description see AddFriend(const char *, const char *).
1427TFriendElement *TTree::AddFriend(TTree *tree, const char *alias, bool warn)
1428{
1429 if (!tree) {
1430 return nullptr;
1431 }
1432 if (!fFriends) {
1433 fFriends = new TList();
1434 }
1435 TFriendElement *fe = new TFriendElement(this, tree, alias);
1436 R__ASSERT(fe); // this assert is for historical reasons. Don't remove it unless you understand all the consequences.
1437 TTree *t = fe->GetTree();
1438 if (warn && (t->GetEntries() < fEntries)) {
1439 Warning("AddFriend", "FriendElement '%s' in file '%s' has less entries %lld than its parent tree: %lld",
1440 tree->GetName(), fe->GetFile() ? fe->GetFile()->GetName() : "(memory resident)", t->GetEntries(),
1441 fEntries);
1442 }
1443 if (CheckReshuffling(*this, *t))
1444 fFriends->Add(fe);
1445 else
1446 tree->RemoveExternalFriend(fe);
1447 return fe;
1448}
1449
1450////////////////////////////////////////////////////////////////////////////////
1451/// AutoSave tree header every fAutoSave bytes.
1452///
1453/// When large Trees are produced, it is safe to activate the AutoSave
1454/// procedure. Some branches may have buffers holding many entries.
1455/// If fAutoSave is negative, AutoSave is automatically called by
1456/// TTree::Fill when the number of bytes generated since the previous
1457/// AutoSave is greater than -fAutoSave bytes.
1458/// If fAutoSave is positive, AutoSave is automatically called by
1459/// TTree::Fill every N entries.
1460/// This function may also be invoked by the user.
1461/// Each AutoSave generates a new key on the file.
1462/// Once the key with the tree header has been written, the previous cycle
1463/// (if any) is deleted.
1464///
1465/// Note that calling TTree::AutoSave too frequently (or similarly calling
1466/// TTree::SetAutoSave with a small value) is an expensive operation.
1467/// You should make tests for your own application to find a compromise
1468/// between speed and the quantity of information you may loose in case of
1469/// a job crash.
1470///
1471/// In case your program crashes before closing the file holding this tree,
1472/// the file will be automatically recovered when you will connect the file
1473/// in UPDATE mode.
1474/// The Tree will be recovered at the status corresponding to the last AutoSave.
1475///
1476/// if option contains "SaveSelf", gDirectory->SaveSelf() is called.
1477/// This allows another process to analyze the Tree while the Tree is being filled.
1478///
1479/// if option contains "FlushBaskets", TTree::FlushBaskets is called and all
1480/// the current basket are closed-out and written to disk individually.
1481///
1482/// By default the previous header is deleted after having written the new header.
1483/// if option contains "Overwrite", the previous Tree header is deleted
1484/// before written the new header. This option is slightly faster, but
1485/// the default option is safer in case of a problem (disk quota exceeded)
1486/// when writing the new header.
1487///
1488/// The function returns the number of bytes written to the file.
1489/// if the number of bytes is null, an error has occurred while writing
1490/// the header to the file.
1491///
1492/// ## How to write a Tree in one process and view it from another process
1493///
1494/// The following two scripts illustrate how to do this.
1495/// The script treew.C is executed by process1, treer.C by process2
1496///
1497/// script treew.C:
1498/// ~~~ {.cpp}
1499/// void treew() {
1500/// TFile f("test.root","recreate");
1501/// TNtuple *ntuple = new TNtuple("ntuple","Demo","px:py:pz:random:i");
1502/// Float_t px, py, pz;
1503/// for ( Int_t i=0; i<10000000; i++) {
1504/// gRandom->Rannor(px,py);
1505/// pz = px*px + py*py;
1506/// Float_t random = gRandom->Rndm(1);
1507/// ntuple->Fill(px,py,pz,random,i);
1508/// if (i%1000 == 1) ntuple->AutoSave("SaveSelf");
1509/// }
1510/// }
1511/// ~~~
1512/// script treer.C:
1513/// ~~~ {.cpp}
1514/// void treer() {
1515/// TFile f("test.root");
1516/// TTree *ntuple = (TTree*)f.Get("ntuple");
1517/// TCanvas c1;
1518/// Int_t first = 0;
1519/// while(1) {
1520/// if (first == 0) ntuple->Draw("px>>hpx", "","",10000000,first);
1521/// else ntuple->Draw("px>>+hpx","","",10000000,first);
1522/// first = (Int_t)ntuple->GetEntries();
1523/// c1.Update();
1524/// gSystem->Sleep(1000); //sleep 1 second
1525/// ntuple->Refresh();
1526/// }
1527/// }
1528/// ~~~
1531{
1532 if (!fDirectory || fDirectory == gROOT || !fDirectory->IsWritable()) return 0;
1533 if (gDebug > 0) {
1534 Info("AutoSave", "Tree:%s after %lld bytes written\n",GetName(),GetTotBytes());
1535 }
1536 TString opt = option;
1537 opt.ToLower();
1538
1539 if (opt.Contains("flushbaskets")) {
1540 if (gDebug > 0) Info("AutoSave", "calling FlushBaskets \n");
1542 }
1543
1545
1546 TKey *key = (TKey*)fDirectory->GetListOfKeys()->FindObject(GetName());
1548 if (opt.Contains("overwrite")) {
1549 nbytes = fDirectory->WriteTObject(this,"","overwrite");
1550 } else {
1551 nbytes = fDirectory->WriteTObject(this); //nbytes will be 0 if Write failed (disk space exceeded)
1552 if (nbytes && key && strcmp(ClassName(), key->GetClassName()) == 0) {
1553 key->Delete();
1554 delete key;
1555 }
1556 }
1557 // save StreamerInfo
1558 TFile *file = fDirectory->GetFile();
1559 if (file) file->WriteStreamerInfo();
1560
1561 if (opt.Contains("saveself")) {
1563 //the following line is required in case GetUserInfo contains a user class
1564 //for which the StreamerInfo must be written. One could probably be a bit faster (Rene)
1565 if (file) file->WriteHeader();
1566 }
1567
1568 return nbytes;
1569}
1570
1571namespace {
1572 // This error message is repeated several times in the code. We write it once.
1573 const char* writeStlWithoutProxyMsg = "The class requested (%s) for the branch \"%s\""
1574 " is an instance of an stl collection and does not have a compiled CollectionProxy."
1575 " Please generate the dictionary for this collection (%s) to avoid to write corrupted data.";
1576}
1577
1578////////////////////////////////////////////////////////////////////////////////
1579/// Same as TTree::Branch() with added check that addobj matches className.
1580///
1581/// \see TTree::Branch()
1582///
1584TBranch* TTree::BranchImp(const char* branchname, const char* classname, TClass* ptrClass, void* addobj, Int_t bufsize, Int_t splitlevel)
1585{
1586 TClass* claim = TClass::GetClass(classname);
1587 if (!ptrClass) {
1588 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1590 claim->GetName(), branchname, claim->GetName());
1591 return nullptr;
1592 }
1593 return Branch(branchname, classname, (void*) addobj, bufsize, splitlevel);
1594 }
1595 TClass* actualClass = nullptr;
1596 void** addr = (void**) addobj;
1597 if (addr) {
1598 actualClass = ptrClass->GetActualClass(*addr);
1599 }
1600 if (ptrClass && claim) {
1601 if (!(claim->InheritsFrom(ptrClass) || ptrClass->InheritsFrom(claim))) {
1602 // Note we currently do not warn in case of splicing or over-expectation).
1603 if (claim->IsLoaded() && ptrClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), ptrClass->GetTypeInfo()->name() ) == 0) {
1604 // The type is the same according to the C++ type_info, we must be in the case of
1605 // a template of Double32_t. This is actually a correct case.
1606 } else {
1607 Error("Branch", "The class requested (%s) for \"%s\" is different from the type of the pointer passed (%s)",
1608 claim->GetName(), branchname, ptrClass->GetName());
1609 }
1610 } else if (actualClass && (claim != actualClass) && !actualClass->InheritsFrom(claim)) {
1611 if (claim->IsLoaded() && actualClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), actualClass->GetTypeInfo()->name() ) == 0) {
1612 // The type is the same according to the C++ type_info, we must be in the case of
1613 // a template of Double32_t. This is actually a correct case.
1614 } else {
1615 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s",
1616 actualClass->GetName(), branchname, claim->GetName());
1617 }
1618 }
1619 }
1620 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1622 claim->GetName(), branchname, claim->GetName());
1623 return nullptr;
1624 }
1625 return Branch(branchname, classname, (void*) addobj, bufsize, splitlevel);
1626}
1627
1628////////////////////////////////////////////////////////////////////////////////
1629/// Same as TTree::Branch but automatic detection of the class name.
1630/// \see TTree::Branch
1633{
1634 if (!ptrClass) {
1635 Error("Branch", "The pointer specified for %s is not of a class known to ROOT", branchname);
1636 return nullptr;
1637 }
1638 TClass* actualClass = nullptr;
1639 void** addr = (void**) addobj;
1640 if (addr && *addr) {
1641 actualClass = ptrClass->GetActualClass(*addr);
1642 if (!actualClass) {
1643 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",
1644 branchname, ptrClass->GetName());
1646 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1647 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());
1648 return nullptr;
1649 }
1650 } else {
1652 }
1653 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1655 actualClass->GetName(), branchname, actualClass->GetName());
1656 return nullptr;
1657 }
1658 return Branch(branchname, actualClass->GetName(), (void*) addobj, bufsize, splitlevel);
1659}
1660
1661////////////////////////////////////////////////////////////////////////////////
1662/// Same as TTree::Branch but automatic detection of the class name.
1663/// \see TTree::Branch
1665TBranch* TTree::BranchImpRef(const char* branchname, const char *classname, TClass* ptrClass, void *addobj, Int_t bufsize, Int_t splitlevel)
1666{
1667 TClass* claim = TClass::GetClass(classname);
1668 if (!ptrClass) {
1669 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1671 claim->GetName(), branchname, claim->GetName());
1672 return nullptr;
1673 } else if (claim == nullptr) {
1674 Error("Branch", "The pointer specified for %s is not of a class known to ROOT and %s is not a known class", branchname, classname);
1675 return nullptr;
1676 }
1677 ptrClass = claim;
1678 }
1679 TClass* actualClass = nullptr;
1680 if (!addobj) {
1681 Error("Branch", "Reference interface requires a valid object (for branch: %s)!", branchname);
1682 return nullptr;
1683 }
1684 actualClass = ptrClass->GetActualClass(addobj);
1685 if (ptrClass && claim) {
1686 if (!(claim->InheritsFrom(ptrClass) || ptrClass->InheritsFrom(claim))) {
1687 // Note we currently do not warn in case of splicing or over-expectation).
1688 if (claim->IsLoaded() && ptrClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), ptrClass->GetTypeInfo()->name() ) == 0) {
1689 // The type is the same according to the C++ type_info, we must be in the case of
1690 // a template of Double32_t. This is actually a correct case.
1691 } else {
1692 Error("Branch", "The class requested (%s) for \"%s\" is different from the type of the object passed (%s)",
1693 claim->GetName(), branchname, ptrClass->GetName());
1694 }
1695 } else if (actualClass && (claim != actualClass) && !actualClass->InheritsFrom(claim)) {
1696 if (claim->IsLoaded() && actualClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), actualClass->GetTypeInfo()->name() ) == 0) {
1697 // The type is the same according to the C++ type_info, we must be in the case of
1698 // a template of Double32_t. This is actually a correct case.
1699 } else {
1700 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s",
1701 actualClass->GetName(), branchname, claim->GetName());
1702 }
1703 }
1704 }
1705 if (!actualClass) {
1706 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",
1707 branchname, ptrClass->GetName());
1709 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1710 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());
1711 return nullptr;
1712 }
1713 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1715 actualClass->GetName(), branchname, actualClass->GetName());
1716 return nullptr;
1717 }
1718 return BronchExec(branchname, actualClass->GetName(), (void*) addobj, false, bufsize, splitlevel);
1719}
1720
1721////////////////////////////////////////////////////////////////////////////////
1722/// Same as TTree::Branch but automatic detection of the class name.
1723/// \see TTree::Branch
1726{
1727 if (!ptrClass) {
1728 if (datatype == kOther_t || datatype == kNoType_t) {
1729 Error("Branch", "The pointer specified for %s is not of a class or type known to ROOT", branchname);
1730 } else {
1732 return Branch(branchname,addobj,varname.Data(),bufsize);
1733 }
1734 return nullptr;
1735 }
1736 TClass* actualClass = nullptr;
1737 if (!addobj) {
1738 Error("Branch", "Reference interface requires a valid object (for branch: %s)!", branchname);
1739 return nullptr;
1740 }
1741 actualClass = ptrClass->GetActualClass(addobj);
1742 if (!actualClass) {
1743 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",
1744 branchname, ptrClass->GetName());
1746 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1747 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());
1748 return nullptr;
1749 }
1750 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1752 actualClass->GetName(), branchname, actualClass->GetName());
1753 return nullptr;
1754 }
1755 return BronchExec(branchname, actualClass->GetName(), (void*) addobj, false, bufsize, splitlevel);
1756}
1757
1758////////////////////////////////////////////////////////////////////////////////
1759// Wrapper to turn Branch call with an std::array into the relevant leaf list
1760// call
1761TBranch *TTree::BranchImpArr(const char *branchname, EDataType datatype, std::size_t N, void *addobj, Int_t bufsize,
1762 Int_t /* splitlevel */)
1763{
1764 if (datatype == kOther_t || datatype == kNoType_t) {
1765 Error("Branch",
1766 "The inner type of the std::array passed specified for %s is not of a class or type known to ROOT",
1767 branchname);
1768 } else {
1770 varname.Form("%s[%d]/%c", branchname, (int)N, DataTypeToChar(datatype));
1771 return Branch(branchname, addobj, varname.Data(), bufsize);
1772 }
1773 return nullptr;
1774}
1775
1776////////////////////////////////////////////////////////////////////////////////
1777/// Deprecated function. Use next function instead.
1779Int_t TTree::Branch(TList* li, Int_t bufsize /* = 32000 */ , Int_t splitlevel /* = 99 */)
1780{
1781 return Branch((TCollection*) li, bufsize, splitlevel);
1782}
1783
1784////////////////////////////////////////////////////////////////////////////////
1785/// Create one branch for each element in the collection.
1786///
1787/// Each entry in the collection becomes a top level branch if the
1788/// corresponding class is not a collection. If it is a collection, the entry
1789/// in the collection becomes in turn top level branches, etc.
1790/// The splitlevel is decreased by 1 every time a new collection is found.
1791/// For example if list is a TObjArray*
1792/// - if splitlevel = 1, one top level branch is created for each element
1793/// of the TObjArray.
1794/// - if splitlevel = 2, one top level branch is created for each array element.
1795/// if, in turn, one of the array elements is a TCollection, one top level
1796/// branch will be created for each element of this collection.
1797///
1798/// In case a collection element is a TClonesArray, the special Tree constructor
1799/// for TClonesArray is called.
1800/// The collection itself cannot be a TClonesArray.
1801///
1802/// The function returns the total number of branches created.
1803///
1804/// If name is given, all branch names will be prefixed with name_.
1805///
1806/// IMPORTANT NOTE1: This function should not be called with splitlevel < 1.
1807///
1808/// IMPORTANT NOTE2: The branches created by this function will have names
1809/// corresponding to the collection or object names. It is important
1810/// to give names to collections to avoid misleading branch names or
1811/// identical branch names. By default collections have a name equal to
1812/// the corresponding class name, e.g. the default name for a TList is "TList".
1813///
1814/// And in general, in case two or more master branches contain subbranches
1815/// with identical names, one must add a "." (dot) character at the end
1816/// of the master branch name. This will force the name of the subbranches
1817/// to be of the form `master.subbranch` instead of simply `subbranch`.
1818/// This situation happens when the top level object
1819/// has two or more members referencing the same class.
1820/// Without the dot, the prefix will not be there and that might cause ambiguities.
1821/// For example, if a Tree has two branches B1 and B2 corresponding
1822/// to objects of the same class MyClass, one can do:
1823/// ~~~ {.cpp}
1824/// tree.Branch("B1.","MyClass",&b1,8000,1);
1825/// tree.Branch("B2.","MyClass",&b2,8000,1);
1826/// ~~~
1827/// if MyClass has 3 members a,b,c, the two instructions above will generate
1828/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
1829/// In other words, the trailing dot of the branch name is semantically relevant
1830/// and recommended.
1831///
1832/// Example:
1833/// ~~~ {.cpp}
1834/// {
1835/// TTree T("T","test list");
1836/// TList *list = new TList();
1837///
1838/// TObjArray *a1 = new TObjArray();
1839/// a1->SetName("a1");
1840/// list->Add(a1);
1841/// TH1F *ha1a = new TH1F("ha1a","ha1",100,0,1);
1842/// TH1F *ha1b = new TH1F("ha1b","ha1",100,0,1);
1843/// a1->Add(ha1a);
1844/// a1->Add(ha1b);
1845/// TObjArray *b1 = new TObjArray();
1846/// b1->SetName("b1");
1847/// list->Add(b1);
1848/// TH1F *hb1a = new TH1F("hb1a","hb1",100,0,1);
1849/// TH1F *hb1b = new TH1F("hb1b","hb1",100,0,1);
1850/// b1->Add(hb1a);
1851/// b1->Add(hb1b);
1852///
1853/// TObjArray *a2 = new TObjArray();
1854/// a2->SetName("a2");
1855/// list->Add(a2);
1856/// TH1S *ha2a = new TH1S("ha2a","ha2",100,0,1);
1857/// TH1S *ha2b = new TH1S("ha2b","ha2",100,0,1);
1858/// a2->Add(ha2a);
1859/// a2->Add(ha2b);
1860///
1861/// T.Branch(list,16000,2);
1862/// T.Print();
1863/// }
1864/// ~~~
1866Int_t TTree::Branch(TCollection* li, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */, const char* name /* = "" */)
1867{
1868
1869 if (!li) {
1870 return 0;
1871 }
1872 TObject* obj = nullptr;
1873 Int_t nbranches = GetListOfBranches()->GetEntries();
1874 if (li->InheritsFrom(TClonesArray::Class())) {
1875 Error("Branch", "Cannot call this constructor for a TClonesArray");
1876 return 0;
1877 }
1878 Int_t nch = strlen(name);
1880 TIter next(li);
1881 while ((obj = next())) {
1883 TCollection* col = (TCollection*) obj;
1884 if (nch) {
1885 branchname.Form("%s_%s_", name, col->GetName());
1886 } else {
1887 branchname.Form("%s_", col->GetName());
1888 }
1889 Branch(col, bufsize, splitlevel - 1, branchname);
1890 } else {
1891 if (nch && (name[nch-1] == '_')) {
1892 branchname.Form("%s%s", name, obj->GetName());
1893 } else {
1894 if (nch) {
1895 branchname.Form("%s_%s", name, obj->GetName());
1896 } else {
1897 branchname.Form("%s", obj->GetName());
1898 }
1899 }
1900 if (splitlevel > 99) {
1901 branchname += ".";
1902 }
1903 Bronch(branchname, obj->ClassName(), li->GetObjectRef(obj), bufsize, splitlevel - 1);
1904 }
1905 }
1906 return GetListOfBranches()->GetEntries() - nbranches;
1907}
1908
1909////////////////////////////////////////////////////////////////////////////////
1910/// Create one branch for each element in the folder.
1911/// Returns the total number of branches created.
1913Int_t TTree::Branch(const char* foldername, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
1914{
1915 TObject* ob = gROOT->FindObjectAny(foldername);
1916 if (!ob) {
1917 return 0;
1918 }
1919 if (ob->IsA() != TFolder::Class()) {
1920 return 0;
1921 }
1922 Int_t nbranches = GetListOfBranches()->GetEntries();
1923 TFolder* folder = (TFolder*) ob;
1924 TIter next(folder->GetListOfFolders());
1925 TObject* obj = nullptr;
1926 char* curname = new char[1000];
1927 char occur[20];
1928 while ((obj = next())) {
1929 snprintf(curname,1000, "%s/%s", foldername, obj->GetName());
1930 if (obj->IsA() == TFolder::Class()) {
1932 } else {
1933 void* add = (void*) folder->GetListOfFolders()->GetObjectRef(obj);
1934 for (Int_t i = 0; i < 1000; ++i) {
1935 if (curname[i] == 0) {
1936 break;
1937 }
1938 if (curname[i] == '/') {
1939 curname[i] = '.';
1940 }
1941 }
1942 Int_t noccur = folder->Occurence(obj);
1943 if (noccur > 0) {
1944 snprintf(occur,20, "_%d", noccur);
1945 strlcat(curname, occur,1000);
1946 }
1948 if (br) br->SetBranchFolder();
1949 }
1950 }
1951 delete[] curname;
1952 return GetListOfBranches()->GetEntries() - nbranches;
1953}
1954
1955////////////////////////////////////////////////////////////////////////////////
1956/// Create a new TTree Branch.
1957///
1958/// This Branch constructor is provided to support non-objects in
1959/// a Tree. The variables described in leaflist may be simple
1960/// variables or structures. // See the two following
1961/// constructors for writing objects in a Tree.
1962///
1963/// By default the branch buffers are stored in the same file as the Tree.
1964/// use TBranch::SetFile to specify a different file
1965///
1966/// * address is the address of the first item of a structure.
1967/// * leaflist is the concatenation of all the variable names and types
1968/// separated by a colon character :
1969/// The variable name and the variable type are separated by a slash (/).
1970/// The variable type may be 0,1 or 2 characters. If no type is given,
1971/// the type of the variable is assumed to be the same as the previous
1972/// variable. If the first variable does not have a type, it is assumed
1973/// of type `F` by default. The list of currently supported types is given below:
1974/// - `C` : a character string terminated by the 0 character
1975/// - `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.
1976/// - `b` : an 8 bit unsigned integer (`UChar_t`)
1977/// - `S` : a 16 bit signed integer (`Short_t`)
1978/// - `s` : a 16 bit unsigned integer (`UShort_t`)
1979/// - `I` : a 32 bit signed integer (`Int_t`)
1980/// - `i` : a 32 bit unsigned integer (`UInt_t`)
1981/// - `F` : a 32 bit floating point (`Float_t`)
1982/// - `f` : a 24 bit floating point with truncated mantissa (`Float16_t`)
1983/// - `D` : a 64 bit floating point (`Double_t`)
1984/// - `d` : a 24 bit truncated floating point (`Double32_t`)
1985/// - `L` : a 64 bit signed integer (`Long64_t`)
1986/// - `l` : a 64 bit unsigned integer (`ULong64_t`)
1987/// - `G` : a long signed integer, stored as 64 bit (`Long_t`)
1988/// - `g` : a long unsigned integer, stored as 64 bit (`ULong_t`)
1989/// - `O` : [the letter `o`, not a zero] a boolean (`bool`)
1990///
1991/// Arrays of values are supported with the following syntax:
1992/// - If leaf name has the form var[nelem], where nelem is alphanumeric, then
1993/// if nelem is a leaf name, it is used as the variable size of the array,
1994/// otherwise return 0.
1995/// The leaf referred to by nelem **MUST** be an int (/I),
1996/// - If leaf name has the form var[nelem], where nelem is a non-negative integer, then
1997/// it is used as the fixed size of the array.
1998/// - If leaf name has the form of a multi-dimensional array (e.g. var[nelem][nelem2])
1999/// where nelem and nelem2 are non-negative integer) then
2000/// it is used as a 2 dimensional array of fixed size.
2001/// - In case of the truncated floating point types (Float16_t and Double32_t) you can
2002/// furthermore specify the range in the style [xmin,xmax] or [xmin,xmax,nbits] after
2003/// the type character. See `TStreamerElement::GetRange()` for further information.
2004///
2005/// Any of other form is not supported.
2006///
2007/// Note that the TTree will assume that all the item are contiguous in memory.
2008/// On some platform, this is not always true of the member of a struct or a class,
2009/// due to padding and alignment. Sorting your data member in order of decreasing
2010/// sizeof usually leads to their being contiguous in memory.
2011///
2012/// * bufsize is the buffer size in bytes for this branch
2013/// The default value is 32000 bytes and should be ok for most cases.
2014/// You can specify a larger value (e.g. 256000) if your Tree is not split
2015/// and each entry is large (Megabytes)
2016/// A small value for bufsize is optimum if you intend to access
2017/// the entries in the Tree randomly and your Tree is in split mode.
2019TBranch* TTree::Branch(const char* name, void* address, const char* leaflist, Int_t bufsize /* = 32000 */)
2020{
2021 TBranch* branch = new TBranch(this, name, address, leaflist, bufsize);
2022 if (branch->IsZombie()) {
2023 delete branch;
2024 branch = nullptr;
2025 return nullptr;
2026 }
2028 return branch;
2029}
2030
2031////////////////////////////////////////////////////////////////////////////////
2032/// Create a new branch with the object of class classname at address addobj.
2033///
2034/// WARNING:
2035///
2036/// Starting with Root version 3.01, the Branch function uses the new style
2037/// branches (TBranchElement). To get the old behaviour, you can:
2038/// - call BranchOld or
2039/// - call TTree::SetBranchStyle(0)
2040///
2041/// Note that with the new style, classname does not need to derive from TObject.
2042/// It must derived from TObject if the branch style has been set to 0 (old)
2043///
2044/// Note: See the comments in TBranchElement::SetAddress() for a more
2045/// detailed discussion of the meaning of the addobj parameter in
2046/// the case of new-style branches.
2047///
2048/// Use splitlevel < 0 instead of splitlevel=0 when the class
2049/// has a custom Streamer
2050///
2051/// Note: if the split level is set to the default (99), TTree::Branch will
2052/// not issue a warning if the class can not be split.
2054TBranch* TTree::Branch(const char* name, const char* classname, void* addobj, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2055{
2056 if (fgBranchStyle == 1) {
2057 return Bronch(name, classname, addobj, bufsize, splitlevel);
2058 } else {
2059 if (splitlevel < 0) {
2060 splitlevel = 0;
2061 }
2062 return BranchOld(name, classname, addobj, bufsize, splitlevel);
2063 }
2064}
2065
2066////////////////////////////////////////////////////////////////////////////////
2067/// Create a new TTree BranchObject.
2068///
2069/// Build a TBranchObject for an object of class classname.
2070/// addobj is the address of a pointer to an object of class classname.
2071/// IMPORTANT: classname must derive from TObject.
2072/// The class dictionary must be available (ClassDef in class header).
2073///
2074/// This option requires access to the library where the corresponding class
2075/// is defined. Accessing one single data member in the object implies
2076/// reading the full object.
2077/// See the next Branch constructor for a more efficient storage
2078/// in case the entry consists of arrays of identical objects.
2079///
2080/// By default the branch buffers are stored in the same file as the Tree.
2081/// use TBranch::SetFile to specify a different file
2082///
2083/// IMPORTANT NOTE about branch names:
2084///
2085/// And in general, in case two or more master branches contain subbranches
2086/// with identical names, one must add a "." (dot) character at the end
2087/// of the master branch name. This will force the name of the subbranches
2088/// to be of the form `master.subbranch` instead of simply `subbranch`.
2089/// This situation happens when the top level object
2090/// has two or more members referencing the same class.
2091/// For example, if a Tree has two branches B1 and B2 corresponding
2092/// to objects of the same class MyClass, one can do:
2093/// ~~~ {.cpp}
2094/// tree.Branch("B1.","MyClass",&b1,8000,1);
2095/// tree.Branch("B2.","MyClass",&b2,8000,1);
2096/// ~~~
2097/// if MyClass has 3 members a,b,c, the two instructions above will generate
2098/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
2099///
2100/// bufsize is the buffer size in bytes for this branch
2101/// The default value is 32000 bytes and should be ok for most cases.
2102/// You can specify a larger value (e.g. 256000) if your Tree is not split
2103/// and each entry is large (Megabytes)
2104/// A small value for bufsize is optimum if you intend to access
2105/// the entries in the Tree randomly and your Tree is in split mode.
2107TBranch* TTree::BranchOld(const char* name, const char* classname, void* addobj, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 1 */)
2108{
2109 TClass* cl = TClass::GetClass(classname);
2110 if (!cl) {
2111 Error("BranchOld", "Cannot find class: '%s'", classname);
2112 return nullptr;
2113 }
2114 if (!cl->IsTObject()) {
2115 if (fgBranchStyle == 0) {
2116 Fatal("BranchOld", "The requested class ('%s') does not inherit from TObject.\n"
2117 "\tfgBranchStyle is set to zero requesting by default to use BranchOld.\n"
2118 "\tIf this is intentional use Bronch instead of Branch or BranchOld.", classname);
2119 } else {
2120 Fatal("BranchOld", "The requested class ('%s') does not inherit from TObject.\n"
2121 "\tYou can not use BranchOld to store objects of this type.",classname);
2122 }
2123 return nullptr;
2124 }
2125 TBranch* branch = new TBranchObject(this, name, classname, addobj, bufsize, splitlevel);
2127 if (!splitlevel) {
2128 return branch;
2129 }
2130 // We are going to fully split the class now.
2131 TObjArray* blist = branch->GetListOfBranches();
2132 const char* rdname = nullptr;
2133 const char* dname = nullptr;
2135 char** apointer = (char**) addobj;
2136 TObject* obj = (TObject*) *apointer;
2137 bool delobj = false;
2138 if (!obj) {
2139 obj = (TObject*) cl->New();
2140 delobj = true;
2141 }
2142 // Build the StreamerInfo if first time for the class.
2143 BuildStreamerInfo(cl, obj);
2144 // Loop on all public data members of the class and its base classes.
2146 Int_t isDot = 0;
2147 if (name[lenName-1] == '.') {
2148 isDot = 1;
2149 }
2150 TBranch* branch1 = nullptr;
2151 TRealData* rd = nullptr;
2152 TRealData* rdi = nullptr;
2154 TIter next(cl->GetListOfRealData());
2155 // Note: This loop results in a full split because the
2156 // real data list includes all data members of
2157 // data members.
2158 while ((rd = (TRealData*) next())) {
2159 if (rd->TestBit(TRealData::kTransient)) continue;
2160
2161 // Loop over all data members creating branches for each one.
2162 TDataMember* dm = rd->GetDataMember();
2163 if (!dm->IsPersistent()) {
2164 // Do not process members with an "!" as the first character in the comment field.
2165 continue;
2166 }
2167 if (rd->IsObject()) {
2168 // We skip data members of class type.
2169 // But we do build their real data, their
2170 // streamer info, and write their streamer
2171 // info to the current directory's file.
2172 // Oh yes, and we also do this for all of
2173 // their base classes.
2175 if (clm) {
2176 BuildStreamerInfo(clm, (char*) obj + rd->GetThisOffset());
2177 }
2178 continue;
2179 }
2180 rdname = rd->GetName();
2181 dname = dm->GetName();
2182 if (cl->CanIgnoreTObjectStreamer()) {
2183 // Skip the TObject base class data members.
2184 // FIXME: This prevents a user from ever
2185 // using these names themself!
2186 if (!strcmp(dname, "fBits")) {
2187 continue;
2188 }
2189 if (!strcmp(dname, "fUniqueID")) {
2190 continue;
2191 }
2192 }
2193 TDataType* dtype = dm->GetDataType();
2194 Int_t code = 0;
2195 if (dtype) {
2196 code = dm->GetDataType()->GetType();
2197 }
2198 // Encode branch name. Use real data member name
2200 if (isDot) {
2201 if (dm->IsaPointer()) {
2202 // FIXME: This is wrong! The asterisk is not usually in the front!
2203 branchname.Form("%s%s", name, &rdname[1]);
2204 } else {
2205 branchname.Form("%s%s", name, &rdname[0]);
2206 }
2207 }
2208 // FIXME: Change this to a string stream.
2210 Int_t offset = rd->GetThisOffset();
2211 char* pointer = ((char*) obj) + offset;
2212 if (dm->IsaPointer()) {
2213 // We have a pointer to an object or a pointer to an array of basic types.
2214 TClass* clobj = nullptr;
2215 if (!dm->IsBasic()) {
2217 }
2218 if (clobj && clobj->InheritsFrom(TClonesArray::Class())) {
2219 // We have a pointer to a clones array.
2220 char* cpointer = (char*) pointer;
2221 char** ppointer = (char**) cpointer;
2223 if (splitlevel != 2) {
2224 if (isDot) {
2226 } else {
2227 // FIXME: This is wrong! The asterisk is not usually in the front!
2228 branch1 = new TBranchClones(branch,&branchname.Data()[1], pointer, bufsize);
2229 }
2230 blist->Add(branch1);
2231 } else {
2232 if (isDot) {
2233 branch1 = new TBranchObject(branch, branchname, li->ClassName(), pointer, bufsize);
2234 } else {
2235 // FIXME: This is wrong! The asterisk is not usually in the front!
2236 branch1 = new TBranchObject(branch, &branchname.Data()[1], li->ClassName(), pointer, bufsize);
2237 }
2238 blist->Add(branch1);
2239 }
2240 } else if (clobj) {
2241 // We have a pointer to an object.
2242 //
2243 // It must be a TObject object.
2244 if (!clobj->IsTObject()) {
2245 continue;
2246 }
2247 branch1 = new TBranchObject(branch, dname, clobj->GetName(), pointer, bufsize, 0);
2248 if (isDot) {
2249 branch1->SetName(branchname);
2250 } else {
2251 // FIXME: This is wrong! The asterisk is not usually in the front!
2252 // Do not use the first character (*).
2253 branch1->SetName(&branchname.Data()[1]);
2254 }
2255 blist->Add(branch1);
2256 } else {
2257 // We have a pointer to an array of basic types.
2258 //
2259 // Check the comments in the text of the code for an index specification.
2260 const char* index = dm->GetArrayIndex();
2261 if (index[0]) {
2262 // We are a pointer to a varying length array of basic types.
2263 //check that index is a valid data member name
2264 //if member is part of an object (e.g. fA and index=fN)
2265 //index must be changed from fN to fA.fN
2266 TString aindex (rd->GetName());
2267 Ssiz_t rdot = aindex.Last('.');
2268 if (rdot>=0) {
2269 aindex.Remove(rdot+1);
2270 aindex.Append(index);
2271 }
2272 nexti.Reset();
2273 while ((rdi = (TRealData*) nexti())) {
2274 if (rdi->TestBit(TRealData::kTransient)) continue;
2275
2276 if (!strcmp(rdi->GetName(), index)) {
2277 break;
2278 }
2279 if (!strcmp(rdi->GetName(), aindex)) {
2280 index = rdi->GetName();
2281 break;
2282 }
2283 }
2284
2285 char vcode = DataTypeToChar((EDataType)code);
2286 // Note that we differentiate between strings and
2287 // char array by the fact that there is NO specified
2288 // size for a string (see next if (code == 1)
2289
2290 if (vcode) {
2291 leaflist.Form("%s[%s]/%c", &rdname[0], index, vcode);
2292 } else {
2293 Error("BranchOld", "Cannot create branch for rdname: %s code: %d", branchname.Data(), code);
2294 leaflist = "";
2295 }
2296 } else {
2297 // We are possibly a character string.
2298 if (code == 1) {
2299 // We are a character string.
2300 leaflist.Form("%s/%s", dname, "C");
2301 } else {
2302 // Invalid array specification.
2303 // FIXME: We need an error message here.
2304 continue;
2305 }
2306 }
2307 // There are '*' in both the branchname and leaflist, remove them.
2308 TString bname( branchname );
2309 bname.ReplaceAll("*","");
2310 leaflist.ReplaceAll("*","");
2311 // Add the branch to the tree and indicate that the address
2312 // is that of a pointer to be dereferenced before using.
2313 branch1 = new TBranch(branch, bname, *((void**) pointer), leaflist, bufsize);
2314 TLeaf* leaf = (TLeaf*) branch1->GetListOfLeaves()->At(0);
2316 leaf->SetAddress((void**) pointer);
2317 blist->Add(branch1);
2318 }
2319 } else if (dm->IsBasic()) {
2320 // We have a basic type.
2321
2322 char vcode = DataTypeToChar((EDataType)code);
2323 if (vcode) {
2324 leaflist.Form("%s/%c", rdname, vcode);
2325 } else {
2326 Error("BranchOld", "Cannot create branch for rdname: %s code: %d", branchname.Data(), code);
2327 leaflist = "";
2328 }
2329 branch1 = new TBranch(branch, branchname, pointer, leaflist, bufsize);
2330 branch1->SetTitle(rdname);
2331 blist->Add(branch1);
2332 } else {
2333 // We have a class type.
2334 // Note: This cannot happen due to the rd->IsObject() test above.
2335 // FIXME: Put an error message here just in case.
2336 }
2337 if (branch1) {
2338 branch1->SetOffset(offset);
2339 } else {
2340 Warning("BranchOld", "Cannot process member: '%s'", rdname);
2341 }
2342 }
2343 if (delobj) {
2344 delete obj;
2345 obj = nullptr;
2346 }
2347 return branch;
2348}
2349
2350////////////////////////////////////////////////////////////////////////////////
2351/// Build the optional branch supporting the TRefTable.
2352/// This branch will keep all the information to find the branches
2353/// containing referenced objects.
2354///
2355/// At each Tree::Fill, the branch numbers containing the
2356/// referenced objects are saved to the TBranchRef basket.
2357/// When the Tree header is saved (via TTree::Write), the branch
2358/// is saved keeping the information with the pointers to the branches
2359/// having referenced objects.
2362{
2363 if (!fBranchRef) {
2364 fBranchRef = new TBranchRef(this);
2365 }
2366 return fBranchRef;
2367}
2368
2369////////////////////////////////////////////////////////////////////////////////
2370/// Create a new TTree BranchElement.
2371///
2372/// ## WARNING about this new function
2373///
2374/// This function is designed to replace the internal
2375/// implementation of the old TTree::Branch (whose implementation
2376/// has been moved to BranchOld).
2377///
2378/// NOTE: The 'Bronch' method supports only one possible calls
2379/// signature (where the object type has to be specified
2380/// explicitly and the address must be the address of a pointer).
2381/// For more flexibility use 'Branch'. Use Bronch only in (rare)
2382/// cases (likely to be legacy cases) where both the new and old
2383/// implementation of Branch needs to be used at the same time.
2384///
2385/// This function is far more powerful than the old Branch
2386/// function. It supports the full C++, including STL and has
2387/// the same behaviour in split or non-split mode. classname does
2388/// not have to derive from TObject. The function is based on
2389/// the new TStreamerInfo.
2390///
2391/// Build a TBranchElement for an object of class classname.
2392///
2393/// addr is the address of a pointer to an object of class
2394/// classname. The class dictionary must be available (ClassDef
2395/// in class header).
2396///
2397/// Note: See the comments in TBranchElement::SetAddress() for a more
2398/// detailed discussion of the meaning of the addr parameter.
2399///
2400/// This option requires access to the library where the
2401/// corresponding class is defined. Accessing one single data
2402/// member in the object implies reading the full object.
2403///
2404/// By default the branch buffers are stored in the same file as the Tree.
2405/// use TBranch::SetFile to specify a different file
2406///
2407/// IMPORTANT NOTE about branch names:
2408///
2409/// And in general, in case two or more master branches contain subbranches
2410/// with identical names, one must add a "." (dot) character at the end
2411/// of the master branch name. This will force the name of the subbranches
2412/// to be of the form `master.subbranch` instead of simply `subbranch`.
2413/// This situation happens when the top level object
2414/// has two or more members referencing the same class.
2415/// For example, if a Tree has two branches B1 and B2 corresponding
2416/// to objects of the same class MyClass, one can do:
2417/// ~~~ {.cpp}
2418/// tree.Branch("B1.","MyClass",&b1,8000,1);
2419/// tree.Branch("B2.","MyClass",&b2,8000,1);
2420/// ~~~
2421/// if MyClass has 3 members a,b,c, the two instructions above will generate
2422/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
2423///
2424/// bufsize is the buffer size in bytes for this branch
2425/// The default value is 32000 bytes and should be ok for most cases.
2426/// You can specify a larger value (e.g. 256000) if your Tree is not split
2427/// and each entry is large (Megabytes)
2428/// A small value for bufsize is optimum if you intend to access
2429/// the entries in the Tree randomly and your Tree is in split mode.
2430///
2431/// Use splitlevel < 0 instead of splitlevel=0 when the class
2432/// has a custom Streamer
2433///
2434/// Note: if the split level is set to the default (99), TTree::Branch will
2435/// not issue a warning if the class can not be split.
2437TBranch* TTree::Bronch(const char* name, const char* classname, void* addr, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2438{
2439 return BronchExec(name, classname, addr, true, bufsize, splitlevel);
2440}
2441
2442////////////////////////////////////////////////////////////////////////////////
2443/// Helper function implementing TTree::Bronch and TTree::Branch(const char *name, T &obj);
2445TBranch* TTree::BronchExec(const char* name, const char* classname, void* addr, bool isptrptr, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2446{
2447 TClass* cl = TClass::GetClass(classname);
2448 if (!cl) {
2449 Error("Bronch", "Cannot find class:%s", classname);
2450 return nullptr;
2451 }
2452
2453 //if splitlevel <= 0 and class has a custom Streamer, we must create
2454 //a TBranchObject. We cannot assume that TClass::ReadBuffer is consistent
2455 //with the custom Streamer. The penalty is that one cannot process
2456 //this Tree without the class library containing the class.
2457
2458 char* objptr = nullptr;
2459 if (!isptrptr) {
2460 objptr = (char*)addr;
2461 } else if (addr) {
2462 objptr = *((char**) addr);
2463 }
2464
2465 if (cl == TClonesArray::Class()) {
2467 if (!clones) {
2468 Error("Bronch", "Pointer to TClonesArray is null");
2469 return nullptr;
2470 }
2471 if (!clones->GetClass()) {
2472 Error("Bronch", "TClonesArray with no class defined in branch: %s", name);
2473 return nullptr;
2474 }
2475 if (!clones->GetClass()->HasDataMemberInfo()) {
2476 Error("Bronch", "TClonesArray with no dictionary defined in branch: %s", name);
2477 return nullptr;
2478 }
2479 bool hasCustomStreamer = clones->GetClass()->HasCustomStreamerMember();
2480 if (splitlevel > 0) {
2482 Warning("Bronch", "Using split mode on a class: %s with a custom Streamer", clones->GetClass()->GetName());
2483 } else {
2484 if (hasCustomStreamer) clones->BypassStreamer(false);
2485 TBranchObject *branch = new TBranchObject(this,name,classname,addr,bufsize,0,/*compress=*/ -1,isptrptr);
2487 return branch;
2488 }
2489 }
2490
2491 if (cl->GetCollectionProxy()) {
2493 //if (!collProxy) {
2494 // Error("Bronch", "%s is missing its CollectionProxy (for branch %s)", classname, name);
2495 //}
2496 TClass* inklass = collProxy->GetValueClass();
2497 if (!inklass && (collProxy->GetType() == 0)) {
2498 Error("Bronch", "%s with no class defined in branch: %s", classname, name);
2499 return nullptr;
2500 }
2501 if ((splitlevel > 0) && inklass && (inklass->GetCollectionProxy() == nullptr)) {
2503 if ((stl != ROOT::kSTLmap) && (stl != ROOT::kSTLmultimap)) {
2504 if (!inklass->HasDataMemberInfo()) {
2505 Error("Bronch", "Container with no dictionary defined in branch: %s", name);
2506 return nullptr;
2507 }
2508 if (inklass->HasCustomStreamerMember()) {
2509 Warning("Bronch", "Using split mode on a class: %s with a custom Streamer", inklass->GetName());
2510 }
2511 }
2512 }
2513 //-------------------------------------------------------------------------
2514 // If the splitting switch is enabled, the split level is big enough and
2515 // the collection contains pointers we can split it
2516 //////////////////////////////////////////////////////////////////////////
2517
2518 TBranch *branch;
2519 if( splitlevel > kSplitCollectionOfPointers && collProxy->HasPointers() )
2521 else
2524 if (isptrptr) {
2525 branch->SetAddress(addr);
2526 } else {
2527 branch->SetObject(addr);
2528 }
2529 return branch;
2530 }
2531
2532 bool hasCustomStreamer = false;
2533 if (!cl->HasDataMemberInfo() && !cl->GetCollectionProxy()) {
2534 Error("Bronch", "Cannot find dictionary for class: %s", classname);
2535 return nullptr;
2536 }
2537
2538 if (!cl->GetCollectionProxy() && cl->HasCustomStreamerMember()) {
2539 // Not an STL container and the linkdef file had a "-" after the class name.
2540 hasCustomStreamer = true;
2541 }
2542
2543 if (splitlevel < 0 || ((splitlevel == 0) && hasCustomStreamer && cl->IsTObject())) {
2546 return branch;
2547 }
2548
2549 if (cl == TClonesArray::Class()) {
2550 // Special case of TClonesArray.
2551 // No dummy object is created.
2552 // The streamer info is not rebuilt unoptimized.
2553 // No dummy top-level branch is created.
2554 // No splitting is attempted.
2557 if (isptrptr) {
2558 branch->SetAddress(addr);
2559 } else {
2560 branch->SetObject(addr);
2561 }
2562 return branch;
2563 }
2564
2565 //
2566 // If we are not given an object to use as an i/o buffer
2567 // then create a temporary one which we will delete just
2568 // before returning.
2569 //
2570
2571 bool delobj = false;
2572
2573 if (!objptr) {
2574 objptr = (char*) cl->New();
2575 delobj = true;
2576 }
2577
2578 //
2579 // Avoid splitting unsplittable classes.
2580 //
2581
2582 if ((splitlevel > 0) && !cl->CanSplit()) {
2583 if (splitlevel != 99) {
2584 Warning("Bronch", "%s cannot be split, resetting splitlevel to 0", cl->GetName());
2585 }
2586 splitlevel = 0;
2587 }
2588
2589 //
2590 // Make sure the streamer info is built and fetch it.
2591 //
2592 // If we are splitting, then make sure the streamer info
2593 // is built unoptimized (data members are not combined).
2594 //
2595
2597 if (!sinfo) {
2598 Error("Bronch", "Cannot build the StreamerInfo for class: %s", cl->GetName());
2599 return nullptr;
2600 }
2601
2602 //
2603 // Create a dummy top level branch object.
2604 //
2605
2606 Int_t id = -1;
2607 if (splitlevel > 0) {
2608 id = -2;
2609 }
2612
2613 //
2614 // Do splitting, if requested.
2615 //
2616
2618 branch->Unroll(name, cl, sinfo, objptr, bufsize, splitlevel);
2619 }
2620
2621 //
2622 // Setup our offsets into the user's i/o buffer.
2623 //
2624
2625 if (isptrptr) {
2626 branch->SetAddress(addr);
2627 } else {
2628 branch->SetObject(addr);
2629 }
2630
2631 if (delobj) {
2632 cl->Destructor(objptr);
2633 objptr = nullptr;
2634 }
2635
2636 return branch;
2637}
2638
2639////////////////////////////////////////////////////////////////////////////////
2640/// Browse content of the TTree.
2643{
2645 if (fUserInfo) {
2646 if (strcmp("TList",fUserInfo->GetName())==0) {
2647 fUserInfo->SetName("UserInfo");
2648 b->Add(fUserInfo);
2649 fUserInfo->SetName("TList");
2650 } else {
2651 b->Add(fUserInfo);
2652 }
2653 }
2654}
2655
2656////////////////////////////////////////////////////////////////////////////////
2657/// Build a Tree Index (default is TTreeIndex).
2658/// See a description of the parameters and functionality in
2659/// TTreeIndex::TTreeIndex().
2660///
2661/// The return value is the number of entries in the Index (< 0 indicates failure).
2662///
2663/// A TTreeIndex object pointed by fTreeIndex is created.
2664/// This object will be automatically deleted by the TTree destructor.
2665/// If an index is already existing, this is replaced by the new one without being
2666/// deleted. This behaviour prevents the deletion of a previously external index
2667/// assigned to the TTree via the TTree::SetTreeIndex() method.
2668/// \see TTree::SetTreeIndex()
2670Int_t TTree::BuildIndex(const char* majorname, const char* minorname /* = "0" */, bool long64major, bool long64minor)
2671{
2673 if (fTreeIndex->IsZombie()) {
2674 delete fTreeIndex;
2675 fTreeIndex = nullptr;
2676 return 0;
2677 }
2678 return fTreeIndex->GetN();
2679}
2680
2681////////////////////////////////////////////////////////////////////////////////
2682/// Build StreamerInfo for class cl.
2683/// pointer is an optional argument that may contain a pointer to an object of cl.
2685TStreamerInfo* TTree::BuildStreamerInfo(TClass* cl, void* pointer /* = 0 */, bool canOptimize /* = true */ )
2686{
2687 if (!cl) {
2688 return nullptr;
2689 }
2690 cl->BuildRealData(pointer);
2692
2693 // Create StreamerInfo for all base classes.
2694 TBaseClass* base = nullptr;
2695 TIter nextb(cl->GetListOfBases());
2696 while((base = (TBaseClass*) nextb())) {
2697 if (base->IsSTLContainer()) {
2698 continue;
2699 }
2700 TClass* clm = TClass::GetClass(base->GetName());
2702 }
2703 if (sinfo && fDirectory) {
2704 sinfo->ForceWriteInfo(fDirectory->GetFile());
2705 }
2706 return sinfo;
2707}
2708
2709////////////////////////////////////////////////////////////////////////////////
2710/// Enable the TTreeCache unless explicitly disabled for this TTree by
2711/// a prior call to `SetCacheSize(0)`.
2712/// If the environment variable `ROOT_TTREECACHE_SIZE` or the rootrc config
2713/// `TTreeCache.Size` has been set to zero, this call will over-ride them with
2714/// a value of 1.0 (i.e. use a cache size to hold 1 cluster)
2715///
2716/// Return true if there is a cache attached to the `TTree` (either pre-exisiting
2717/// or created as part of this call)
2718bool TTree::EnableCache()
2719{
2720 TFile* file = GetCurrentFile();
2721 if (!file)
2722 return false;
2723 // Check for an existing cache
2724 TTreeCache* pf = GetReadCache(file);
2725 if (pf)
2726 return true;
2727 if (fCacheUserSet && fCacheSize == 0)
2728 return false;
2729 return (0 == SetCacheSizeAux(true, -1));
2730}
2731
2732////////////////////////////////////////////////////////////////////////////////
2733/// Called by TTree::Fill() when file has reached its maximum fgMaxTreeSize.
2734/// Create a new file. If the original file is named "myfile.root",
2735/// subsequent files are named "myfile_1.root", "myfile_2.root", etc.
2736///
2737/// Returns a pointer to the new file.
2738///
2739/// Currently, the automatic change of file is restricted
2740/// to the case where the tree is in the top level directory.
2741/// The file should not contain sub-directories.
2742///
2743/// Before switching to a new file, the tree header is written
2744/// to the current file, then the current file is closed.
2745///
2746/// To process the multiple files created by ChangeFile, one must use
2747/// a TChain.
2748///
2749/// The new file name has a suffix "_N" where N is equal to fFileNumber+1.
2750/// By default a Root session starts with fFileNumber=0. One can set
2751/// fFileNumber to a different value via TTree::SetFileNumber.
2752/// In case a file named "_N" already exists, the function will try
2753/// a file named "__N", then "___N", etc.
2754///
2755/// fgMaxTreeSize can be set via the static function TTree::SetMaxTreeSize.
2756/// The default value of fgMaxTreeSize is 100 Gigabytes.
2757///
2758/// If the current file contains other objects like TH1 and TTree,
2759/// these objects are automatically moved to the new file.
2760///
2761/// \warning Be careful when writing the final Tree header to the file!
2762/// Don't do:
2763/// ~~~ {.cpp}
2764/// TFile *file = new TFile("myfile.root","recreate");
2765/// TTree *T = new TTree("T","title");
2766/// T->Fill(); // Loop
2767/// file->Write();
2768/// file->Close();
2769/// ~~~
2770/// \warning but do the following:
2771/// ~~~ {.cpp}
2772/// TFile *file = new TFile("myfile.root","recreate");
2773/// TTree *T = new TTree("T","title");
2774/// T->Fill(); // Loop
2775/// file = T->GetCurrentFile(); // To get the pointer to the current file
2776/// file->Write();
2777/// file->Close();
2778/// ~~~
2779///
2780/// \note This method is never called if the input file is a `TMemFile` or derivate.
2783{
2784 // Changing file clashes with the design of TMemFile and derivates, see #6523,
2785 // as well as with TFileMerger operations, see #6640.
2786 if ((dynamic_cast<TMemFile *>(file)) || file->TestBit(TFile::kCancelTTreeChangeRequest))
2787 return file;
2788 file->cd();
2789 Write();
2790 Reset();
2791 constexpr auto kBufSize = 2000;
2792 char* fname = new char[kBufSize];
2793 ++fFileNumber;
2794 char uscore[10];
2795 for (Int_t i = 0; i < 10; ++i) {
2796 uscore[i] = 0;
2797 }
2798 Int_t nus = 0;
2799 // Try to find a suitable file name that does not already exist.
2800 while (nus < 10) {
2801 uscore[nus] = '_';
2802 fname[0] = 0;
2803 strlcpy(fname, file->GetName(), kBufSize);
2804
2805 if (fFileNumber > 1) {
2806 char* cunder = strrchr(fname, '_');
2807 if (cunder) {
2809 const char* cdot = strrchr(file->GetName(), '.');
2810 if (cdot) {
2812 }
2813 } else {
2814 char fcount[21];
2815 snprintf(fcount,21, "%s%d", uscore, fFileNumber);
2817 }
2818 } else {
2819 char* cdot = strrchr(fname, '.');
2820 if (cdot) {
2822 strlcat(fname, strrchr(file->GetName(), '.'), kBufSize);
2823 } else {
2824 char fcount[21];
2825 snprintf(fcount,21, "%s%d", uscore, fFileNumber);
2827 }
2828 }
2830 break;
2831 }
2832 ++nus;
2833 Warning("ChangeFile", "file %s already exists, trying with %d underscores", fname, nus + 1);
2834 }
2836 TFile* newfile = TFile::Open(fname, "recreate", "chain files", compress);
2837 if (newfile == nullptr) {
2838 Error("Fill","Failed to open new file %s, continuing as a memory tree.",fname);
2839 } else {
2840 Printf("Fill: Switching to new file: %s", fname);
2841 }
2842 // The current directory may contain histograms and trees.
2843 // These objects must be moved to the new file.
2844 TBranch* branch = nullptr;
2845 TObject* obj = nullptr;
2846 while ((obj = file->GetList()->First())) {
2847 file->Remove(obj);
2848 // Histogram: just change the directory.
2849 if (obj->InheritsFrom("TH1")) {
2850 gROOT->ProcessLine(TString::Format("((%s*)0x%zx)->SetDirectory((TDirectory*)0x%zx);", obj->ClassName(), (size_t) obj, (size_t) newfile));
2851 continue;
2852 }
2853 // Tree: must save all trees in the old file, reset them.
2854 if (obj->InheritsFrom(TTree::Class())) {
2855 TTree* t = (TTree*) obj;
2856 if (t != this) {
2857 t->AutoSave();
2858 t->Reset();
2860 }
2863 while ((branch = (TBranch*)nextb())) {
2864 branch->SetFile(newfile);
2865 }
2866 if (t->GetBranchRef()) {
2867 t->GetBranchRef()->SetFile(newfile);
2868 }
2869 continue;
2870 }
2871 // Not a TH1 or a TTree, move object to new file.
2872 if (newfile) newfile->Append(obj);
2873 file->Remove(obj);
2874 }
2875 file->TObject::Delete();
2876 file = nullptr;
2877 delete[] fname;
2878 fname = nullptr;
2879 return newfile;
2880}
2881
2882////////////////////////////////////////////////////////////////////////////////
2883/// Check whether or not the address described by the last 3 parameters
2884/// matches the content of the branch. If a Data Model Evolution conversion
2885/// is involved, reset the fInfo of the branch.
2886/// The return values are:
2887//
2888/// - kMissingBranch (-5) : Missing branch
2889/// - kInternalError (-4) : Internal error (could not find the type corresponding to a data type number)
2890/// - kMissingCompiledCollectionProxy (-3) : Missing compiled collection proxy for a compiled collection
2891/// - kMismatch (-2) : Non-Class Pointer type given does not match the type expected by the branch
2892/// - kClassMismatch (-1) : Class Pointer type given does not match the type expected by the branch
2893/// - kMatch (0) : perfect match
2894/// - kMatchConversion (1) : match with (I/O) conversion
2895/// - kMatchConversionCollection (2) : match with (I/O) conversion of the content of a collection
2896/// - kMakeClass (3) : MakeClass mode so we can not check.
2897/// - kVoidPtr (4) : void* passed so no check was made.
2898/// - kNoCheck (5) : Underlying TBranch not yet available so no check was made.
2899/// In addition this can be multiplexed with the two bits:
2900/// - kNeedEnableDecomposedObj : in order for the address (type) to be 'usable' the branch needs to be in Decomposed Object (aka MakeClass) mode.
2901/// - kNeedDisableDecomposedObj : in order for the address (type) to be 'usable' the branch needs to not be in Decomposed Object (aka MakeClass) mode.
2902/// This bits can be masked out by using kDecomposedObjMask
2905{
2906 if (GetMakeClass()) {
2907 // If we are in MakeClass mode so we do not really use classes.
2908 return kMakeClass;
2909 }
2910
2911 // Let's determine what we need!
2912 TClass* expectedClass = nullptr;
2914 if (0 != branch->GetExpectedType(expectedClass,expectedType) ) {
2915 // Something went wrong, the warning message has already been issued.
2916 return kInternalError;
2917 }
2918 bool isBranchElement = branch->InheritsFrom( TBranchElement::Class() );
2919 if (expectedClass && datatype == kOther_t && ptrClass == nullptr) {
2920 if (isBranchElement) {
2922 bEl->SetTargetClass( expectedClass->GetName() );
2923 }
2924 if (expectedClass && expectedClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(expectedClass->GetCollectionProxy())) {
2925 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2926 "The class expected (%s) refers to an stl collection and do not have a compiled CollectionProxy. "
2927 "Please generate the dictionary for this class (%s)",
2928 branch->GetName(), expectedClass->GetName(), expectedClass->GetName());
2930 }
2931 if (!expectedClass->IsLoaded()) {
2932 // The originally expected class does not have a dictionary, it is then plausible that the pointer being passed is the right type
2933 // (we really don't know). So let's express that.
2934 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2935 "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."
2936 "Please generate the dictionary for this class (%s)",
2937 branch->GetName(), expectedClass->GetName(), expectedClass->GetName());
2938 } else {
2939 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2940 "This is probably due to a missing dictionary, the original data class for this branch is %s.", branch->GetName(), expectedClass->GetName());
2941 }
2942 return kClassMismatch;
2943 }
2944 if (expectedClass && ptrClass && (branch->GetMother() == branch)) {
2945 // Top Level branch
2946 if (!isptr) {
2947 Error("SetBranchAddress", "The address for \"%s\" should be the address of a pointer!", branch->GetName());
2948 }
2949 }
2950 if (expectedType == kFloat16_t) {
2952 }
2953 if (expectedType == kDouble32_t) {
2955 }
2956 if (datatype == kFloat16_t) {
2958 }
2959 if (datatype == kDouble32_t) {
2961 }
2962
2963 /////////////////////////////////////////////////////////////////////////////
2964 // Deal with the class renaming
2965 /////////////////////////////////////////////////////////////////////////////
2966
2967 if( expectedClass && ptrClass &&
2970 ptrClass->GetSchemaRules() &&
2971 ptrClass->GetSchemaRules()->HasRuleWithSourceClass( expectedClass->GetName() ) ) {
2973
2974 if ( ptrClass->GetCollectionProxy() && expectedClass->GetCollectionProxy() ) {
2975 if (gDebug > 7)
2976 Info("SetBranchAddress", "Matching STL collection (at least according to the SchemaRuleSet when "
2977 "reading a %s into a %s",expectedClass->GetName(),ptrClass->GetName());
2978
2979 bEl->SetTargetClass( ptrClass->GetName() );
2980 return kMatchConversion;
2981
2982 } else if ( !ptrClass->GetConversionStreamerInfo( expectedClass, bEl->GetClassVersion() ) &&
2983 !ptrClass->FindConversionStreamerInfo( expectedClass, bEl->GetCheckSum() ) ) {
2984 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());
2985
2986 bEl->SetTargetClass( expectedClass->GetName() );
2987 return kClassMismatch;
2988 }
2989 else {
2990
2991 bEl->SetTargetClass( ptrClass->GetName() );
2992 return kMatchConversion;
2993 }
2994
2995 } else if (expectedClass && ptrClass && !expectedClass->InheritsFrom(ptrClass)) {
2996
2997 if (expectedClass->GetCollectionProxy() && ptrClass->GetCollectionProxy() &&
2999 expectedClass->GetCollectionProxy()->GetValueClass() &&
3000 ptrClass->GetCollectionProxy()->GetValueClass() )
3001 {
3002 // In case of collection, we know how to convert them, if we know how to convert their content.
3003 // NOTE: we need to extend this to std::pair ...
3004
3005 TClass *onfileValueClass = expectedClass->GetCollectionProxy()->GetValueClass();
3006 TClass *inmemValueClass = ptrClass->GetCollectionProxy()->GetValueClass();
3007
3008 if (inmemValueClass->GetSchemaRules() &&
3009 inmemValueClass->GetSchemaRules()->HasRuleWithSourceClass(onfileValueClass->GetName() ) )
3010 {
3012 bEl->SetTargetClass( ptrClass->GetName() );
3014 }
3015 }
3016
3017 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());
3018 if (isBranchElement) {
3020 bEl->SetTargetClass( expectedClass->GetName() );
3021 }
3022 return kClassMismatch;
3023
3024 } else if ((expectedType != kOther_t) && (datatype != kOther_t) && (expectedType != kNoType_t) && (datatype != kNoType_t) && (expectedType != datatype)) {
3025 if (datatype != kChar_t) {
3026 // For backward compatibility we assume that (char*) was just a cast and/or a generic address
3027 Error("SetBranchAddress", "The pointer type given \"%s\" (%d) does not correspond to the type needed \"%s\" (%d) by the branch: %s",
3029 return kMismatch;
3030 }
3031 } else if ((expectedClass && (datatype != kOther_t && datatype != kNoType_t && datatype != kInt_t)) ||
3033 // Sometime a null pointer can look an int, avoid complaining in that case.
3034 if (expectedClass) {
3035 Error("SetBranchAddress", "The pointer type given \"%s\" (%d) does not correspond to the type needed \"%s\" by the branch: %s",
3036 TDataType::GetTypeName(datatype), datatype, expectedClass->GetName(), branch->GetName());
3037 if (isBranchElement) {
3039 bEl->SetTargetClass( expectedClass->GetName() );
3040 }
3041 } else {
3042 // 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
3043 // a struct).
3044 bool found = false;
3045 if (ptrClass->IsLoaded()) {
3046 TIter next(ptrClass->GetListOfRealData());
3047 TRealData *rdm;
3048 while ((rdm = (TRealData*)next())) {
3049 if (rdm->GetThisOffset() == 0) {
3050 TDataType *dmtype = rdm->GetDataMember()->GetDataType();
3051 if (dmtype) {
3052 EDataType etype = (EDataType)dmtype->GetType();
3053 if (etype == expectedType) {
3054 found = true;
3055 }
3056 }
3057 break;
3058 }
3059 }
3060 } else {
3061 TIter next(ptrClass->GetListOfDataMembers());
3062 TDataMember *dm;
3063 while ((dm = (TDataMember*)next())) {
3064 if (dm->GetOffset() == 0) {
3065 TDataType *dmtype = dm->GetDataType();
3066 if (dmtype) {
3067 EDataType etype = (EDataType)dmtype->GetType();
3068 if (etype == expectedType) {
3069 found = true;
3070 }
3071 }
3072 break;
3073 }
3074 }
3075 }
3076 if (found) {
3077 // let's check the size.
3078 TLeaf *last = (TLeaf*)branch->GetListOfLeaves()->Last();
3079 long len = last->GetOffset() + last->GetLenType() * last->GetLen();
3080 if (len <= ptrClass->Size()) {
3081 return kMatch;
3082 }
3083 }
3084 Error("SetBranchAddress", "The pointer type given \"%s\" does not correspond to the type needed \"%s\" (%d) by the branch: %s",
3086 }
3087 return kMismatch;
3088 }
3089 if (expectedClass && expectedClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(expectedClass->GetCollectionProxy())) {
3090 Error("SetBranchAddress", writeStlWithoutProxyMsg,
3091 expectedClass->GetName(), branch->GetName(), expectedClass->GetName());
3092 if (isBranchElement) {
3094 bEl->SetTargetClass( expectedClass->GetName() );
3095 }
3097 }
3098 if (isBranchElement) {
3099 if (expectedClass) {
3101 bEl->SetTargetClass( expectedClass->GetName() );
3102 } else if (expectedType != kNoType_t && expectedType != kOther_t) {
3104 }
3105 }
3106 return kMatch;
3107}
3108
3109////////////////////////////////////////////////////////////////////////////////
3110/// Create a clone of this tree and copy nentries.
3111///
3112/// By default copy all entries.
3113/// The compression level of the cloned tree is set to the destination
3114/// file's compression level.
3115///
3116/// NOTE: Only active branches are copied. See TTree::SetBranchStatus for more
3117/// information and usage regarding the (de)activation of branches. More
3118/// examples are provided in the tutorials listed below.
3119///
3120/// NOTE: If the TTree is a TChain, the structure of the first TTree
3121/// is used for the copy.
3122///
3123/// IMPORTANT: The cloned tree stays connected with this tree until
3124/// this tree is deleted. In particular, any changes in
3125/// branch addresses in this tree are forwarded to the
3126/// clone trees, unless a branch in a clone tree has had
3127/// its address changed, in which case that change stays in
3128/// effect. When this tree is deleted, all the addresses of
3129/// the cloned tree are reset to their default values.
3130///
3131/// If 'option' contains the word 'fast' and nentries is -1, the
3132/// cloning will be done without unzipping or unstreaming the baskets
3133/// (i.e., a direct copy of the raw bytes on disk).
3134///
3135/// When 'fast' is specified, 'option' can also contain a sorting
3136/// order for the baskets in the output file.
3137///
3138/// There are currently 3 supported sorting order:
3139///
3140/// - SortBasketsByOffset (the default)
3141/// - SortBasketsByBranch
3142/// - SortBasketsByEntry
3143///
3144/// When using SortBasketsByOffset the baskets are written in the
3145/// output file in the same order as in the original file (i.e. the
3146/// baskets are sorted by their offset in the original file; Usually
3147/// this also means that the baskets are sorted by the index/number of
3148/// the _last_ entry they contain)
3149///
3150/// When using SortBasketsByBranch all the baskets of each individual
3151/// branches are stored contiguously. This tends to optimize reading
3152/// speed when reading a small number (1->5) of branches, since all
3153/// their baskets will be clustered together instead of being spread
3154/// across the file. However it might decrease the performance when
3155/// reading more branches (or the full entry).
3156///
3157/// When using SortBasketsByEntry the baskets with the lowest starting
3158/// entry are written first. (i.e. the baskets are sorted by the
3159/// index/number of the first entry they contain). This means that on
3160/// the file the baskets will be in the order in which they will be
3161/// needed when reading the whole tree sequentially.
3162///
3163/// For examples of CloneTree, see tutorials:
3164///
3165/// - copytree.C:
3166/// A macro to copy a subset of a TTree to a new TTree.
3167/// The input file has been generated by the program in
3168/// $ROOTSYS/test/Event with: Event 1000 1 1 1
3169///
3170/// - copytree2.C:
3171/// A macro to copy a subset of a TTree to a new TTree.
3172/// One branch of the new Tree is written to a separate file.
3173/// The input file has been generated by the program in
3174/// $ROOTSYS/test/Event with: Event 1000 1 1 1
3176TTree* TTree::CloneTree(Long64_t nentries /* = -1 */, Option_t* option /* = "" */)
3177{
3178 // Options
3179 bool fastClone = false;
3180
3181 TString opt = option;
3182 opt.ToLower();
3183 if (opt.Contains("fast")) {
3184 fastClone = true;
3185 }
3186
3187 // If we are a chain, switch to the first tree.
3188 if (fEntries > 0) {
3189 const auto res = LoadTree(0);
3190 if (res < -2 || res == -1) {
3191 // -1 is not accepted, it happens when no trees were defined
3192 // -2 is the only acceptable error, when the chain has zero entries, but tree(s) were defined
3193 // Other errors (-3, ...) are not accepted
3194 Error("CloneTree", "returning nullptr since LoadTree failed with code %lld.", res);
3195 return nullptr;
3196 }
3197 }
3198
3199 // Note: For a tree we get the this pointer, for
3200 // a chain we get the chain's current tree.
3201 TTree* thistree = GetTree();
3202
3203 // We will use this to override the IO features on the cloned branches.
3205 ;
3206
3207 // Note: For a chain, the returned clone will be
3208 // a clone of the chain's first tree.
3209 TTree* newtree = (TTree*) thistree->Clone();
3210 if (!newtree) {
3211 return nullptr;
3212 }
3213
3214 // The clone should not delete any objects allocated by SetAddress().
3215 TObjArray* branches = newtree->GetListOfBranches();
3216 Int_t nb = branches->GetEntriesFast();
3217 for (Int_t i = 0; i < nb; ++i) {
3218 TBranch* br = (TBranch*) branches->UncheckedAt(i);
3219 if (br->InheritsFrom(TBranchElement::Class())) {
3220 ((TBranchElement*) br)->ResetDeleteObject();
3221 }
3222 }
3223
3224 // Add the new tree to the list of clones so that
3225 // we can later inform it of changes to branch addresses.
3226 thistree->AddClone(newtree);
3227 if (thistree != this) {
3228 // In case this object is a TChain, add the clone
3229 // also to the TChain's list of clones.
3231 }
3232
3233 newtree->Reset();
3234
3235 TDirectory* ndir = newtree->GetDirectory();
3236 TFile* nfile = nullptr;
3237 if (ndir) {
3238 nfile = ndir->GetFile();
3239 }
3240 Int_t newcomp = -1;
3241 if (nfile) {
3242 newcomp = nfile->GetCompressionSettings();
3243 }
3244
3245 //
3246 // Delete non-active branches from the clone.
3247 //
3248 // Note: If we are a chain, this does nothing
3249 // since chains have no leaves.
3250 TObjArray* leaves = newtree->GetListOfLeaves();
3251 Int_t nleaves = leaves->GetEntriesFast();
3252 for (Int_t lndx = 0; lndx < nleaves; ++lndx) {
3253 TLeaf* leaf = (TLeaf*) leaves->UncheckedAt(lndx);
3254 if (!leaf) {
3255 continue;
3256 }
3257 TBranch* branch = leaf->GetBranch();
3258 if (branch && (newcomp > -1)) {
3259 branch->SetCompressionSettings(newcomp);
3260 }
3261 if (branch) branch->SetIOFeatures(features);
3262 if (!branch || !branch->TestBit(kDoNotProcess)) {
3263 continue;
3264 }
3265 // size might change at each iteration of the loop over the leaves.
3266 nb = branches->GetEntriesFast();
3267 for (Long64_t i = 0; i < nb; ++i) {
3268 TBranch* br = (TBranch*) branches->UncheckedAt(i);
3269 if (br == branch) {
3270 branches->RemoveAt(i);
3271 delete br;
3272 br = nullptr;
3273 branches->Compress();
3274 break;
3275 }
3276 TObjArray* lb = br->GetListOfBranches();
3277 Int_t nb1 = lb->GetEntriesFast();
3278 for (Int_t j = 0; j < nb1; ++j) {
3279 TBranch* b1 = (TBranch*) lb->UncheckedAt(j);
3280 if (!b1) {
3281 continue;
3282 }
3283 if (b1 == branch) {
3284 lb->RemoveAt(j);
3285 delete b1;
3286 b1 = nullptr;
3287 lb->Compress();
3288 break;
3289 }
3291 Int_t nb2 = lb1->GetEntriesFast();
3292 for (Int_t k = 0; k < nb2; ++k) {
3293 TBranch* b2 = (TBranch*) lb1->UncheckedAt(k);
3294 if (!b2) {
3295 continue;
3296 }
3297 if (b2 == branch) {
3298 lb1->RemoveAt(k);
3299 delete b2;
3300 b2 = nullptr;
3301 lb1->Compress();
3302 break;
3303 }
3304 }
3305 }
3306 }
3307 }
3308 leaves->Compress();
3309
3310 // Copy MakeClass status.
3311 newtree->SetMakeClass(fMakeClass);
3312
3313 // Copy branch addresses.
3315
3316 //
3317 // Copy entries if requested.
3318 //
3319
3320 if (nentries != 0) {
3321 if (fastClone && (nentries < 0)) {
3322 if ( newtree->CopyEntries( this, -1, option, false ) < 0 ) {
3323 // There was a problem!
3324 Error("CloneTTree", "TTree has not been cloned\n");
3325 delete newtree;
3326 newtree = nullptr;
3327 return nullptr;
3328 }
3329 } else {
3330 newtree->CopyEntries( this, nentries, option, false );
3331 }
3332 }
3333
3334 return newtree;
3335}
3336
3337////////////////////////////////////////////////////////////////////////////////
3338/// Set branch addresses of passed tree equal to ours.
3339/// If undo is true, reset the branch addresses instead of copying them.
3340/// This ensures 'separation' of a cloned tree from its original.
3342void TTree::CopyAddresses(TTree* tree, bool undo)
3343{
3344 // Copy branch addresses starting from branches.
3346 Int_t nbranches = branches->GetEntriesFast();
3347 for (Int_t i = 0; i < nbranches; ++i) {
3348 TBranch* branch = (TBranch*) branches->UncheckedAt(i);
3349 if (branch->TestBit(kDoNotProcess)) {
3350 continue;
3351 }
3352 if (undo) {
3353 TBranch* br = tree->GetBranch(branch->GetName());
3354 tree->ResetBranchAddress(br);
3355 } else {
3356 char* addr = branch->GetAddress();
3357 if (!addr) {
3358 if (branch->IsA() == TBranch::Class()) {
3359 // If the branch was created using a leaflist, the branch itself may not have
3360 // an address but the leaf might already.
3361 TLeaf *firstleaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
3362 if (!firstleaf || firstleaf->GetValuePointer()) {
3363 // Either there is no leaf (and thus no point in copying the address)
3364 // or the leaf has an address but we can not copy it via the branche
3365 // this will be copied via the next loop (over the leaf).
3366 continue;
3367 }
3368 }
3369 // Note: This may cause an object to be allocated.
3370 branch->SetAddress(nullptr);
3371 addr = branch->GetAddress();
3372 }
3373 TBranch* br = tree->GetBranch(branch->GetFullName());
3374 if (br) {
3375 if (br->GetMakeClass() != branch->GetMakeClass())
3376 br->SetMakeClass(branch->GetMakeClass());
3377 br->SetAddress(addr);
3378 // The copy does not own any object allocated by SetAddress().
3379 if (br->InheritsFrom(TBranchElement::Class())) {
3380 ((TBranchElement*) br)->ResetDeleteObject();
3381 }
3382 } else {
3383 Warning("CopyAddresses", "Could not find branch named '%s' in tree named '%s'", branch->GetName(), tree->GetName());
3384 }
3385 }
3386 }
3387
3388 // Copy branch addresses starting from leaves.
3390 Int_t ntleaves = tleaves->GetEntriesFast();
3391 std::set<TLeaf*> updatedLeafCount;
3392 for (Int_t i = 0; i < ntleaves; ++i) {
3393 TLeaf* tleaf = (TLeaf*) tleaves->UncheckedAt(i);
3394 TBranch* tbranch = tleaf->GetBranch();
3395 TBranch* branch = GetBranch(tbranch->GetName());
3396 if (!branch) {
3397 continue;
3398 }
3399 TLeaf* leaf = branch->GetLeaf(tleaf->GetName());
3400 if (!leaf) {
3401 continue;
3402 }
3403 if (branch->TestBit(kDoNotProcess)) {
3404 continue;
3405 }
3406 if (undo) {
3407 // Now we know whether the address has been transferred
3409 } else {
3410 TBranchElement *mother = dynamic_cast<TBranchElement*>(leaf->GetBranch()->GetMother());
3411 bool needAddressReset = false;
3412 if (leaf->GetLeafCount() && (leaf->TestBit(TLeaf::kNewValue) || !leaf->GetValuePointer() || (mother && mother->IsObjectOwner())) && tleaf->GetLeafCount())
3413 {
3414 // If it is an array and it was allocated by the leaf itself,
3415 // let's make sure it is large enough for the incoming data.
3416 if (leaf->GetLeafCount()->GetMaximum() < tleaf->GetLeafCount()->GetMaximum()) {
3417 leaf->GetLeafCount()->IncludeRange( tleaf->GetLeafCount() );
3418 updatedLeafCount.insert(leaf->GetLeafCount());
3419 needAddressReset = true;
3420 } else {
3421 needAddressReset = (updatedLeafCount.find(leaf->GetLeafCount()) != updatedLeafCount.end());
3422 }
3423 }
3424 if (needAddressReset && leaf->GetValuePointer()) {
3425 if (leaf->IsA() == TLeafElement::Class() && mother)
3426 mother->ResetAddress();
3427 else
3428 leaf->SetAddress(nullptr);
3429 }
3430 if (!branch->GetAddress() && !leaf->GetValuePointer()) {
3431 // We should attempts to set the address of the branch.
3432 // something like:
3433 //(TBranchElement*)branch->GetMother()->SetAddress(0)
3434 //plus a few more subtleties (see TBranchElement::GetEntry).
3435 //but for now we go the simplest route:
3436 //
3437 // Note: This may result in the allocation of an object.
3438 branch->SetupAddresses();
3439 }
3440 if (branch->GetAddress()) {
3441 tree->SetBranchAddress(branch->GetName(), (void*) branch->GetAddress());
3442 TBranch* br = tree->GetBranch(branch->GetName());
3443 if (br) {
3444 if (br->IsA() != branch->IsA()) {
3445 Error(
3446 "CopyAddresses",
3447 "Branch kind mismatch between input tree '%s' and output tree '%s' for branch '%s': '%s' vs '%s'",
3448 tree->GetName(), br->GetTree()->GetName(), br->GetName(), branch->IsA()->GetName(),
3449 br->IsA()->GetName());
3450 }
3451 // The copy does not own any object allocated by SetAddress().
3452 // FIXME: We do too much here, br may not be a top-level branch.
3453 if (br->InheritsFrom(TBranchElement::Class())) {
3454 ((TBranchElement*) br)->ResetDeleteObject();
3455 }
3456 } else {
3457 Warning("CopyAddresses", "Could not find branch named '%s' in tree named '%s'", branch->GetName(), tree->GetName());
3458 }
3459 } else {
3460 tleaf->SetAddress(leaf->GetValuePointer());
3461 }
3462 }
3463 }
3464
3465 if (undo &&
3466 ( tree->IsA()->InheritsFrom("TNtuple") || tree->IsA()->InheritsFrom("TNtupleD") )
3467 ) {
3468 tree->ResetBranchAddresses();
3469 }
3470}
3471
3472namespace {
3473
3474 enum EOnIndexError { kDrop, kKeep, kBuild };
3475
3476 bool R__HandleIndex(EOnIndexError onIndexError, TTree *newtree, TTree *oldtree)
3477 {
3478 // Return true if we should continue to handle indices, false otherwise.
3479
3480 bool withIndex = true;
3481
3482 if ( newtree->GetTreeIndex() ) {
3483 if ( oldtree->GetTree()->GetTreeIndex() == nullptr ) {
3484 switch (onIndexError) {
3485 case kDrop:
3486 delete newtree->GetTreeIndex();
3487 newtree->SetTreeIndex(nullptr);
3488 withIndex = false;
3489 break;
3490 case kKeep:
3491 // Nothing to do really.
3492 break;
3493 case kBuild:
3494 // Build the index then copy it
3495 if (oldtree->GetTree()->BuildIndex(newtree->GetTreeIndex()->GetMajorName(), newtree->GetTreeIndex()->GetMinorName())) {
3496 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3497 // Clean up
3498 delete oldtree->GetTree()->GetTreeIndex();
3499 oldtree->GetTree()->SetTreeIndex(nullptr);
3500 }
3501 break;
3502 }
3503 } else {
3504 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3505 }
3506 } else if ( oldtree->GetTree()->GetTreeIndex() != nullptr ) {
3507 // We discover the first index in the middle of the chain.
3508 switch (onIndexError) {
3509 case kDrop:
3510 // Nothing to do really.
3511 break;
3512 case kKeep: {
3513 TVirtualIndex *index = (TVirtualIndex*) oldtree->GetTree()->GetTreeIndex()->Clone();
3514 index->SetTree(newtree);
3515 newtree->SetTreeIndex(index);
3516 break;
3517 }
3518 case kBuild:
3519 if (newtree->GetEntries() == 0) {
3520 // Start an index.
3521 TVirtualIndex *index = (TVirtualIndex*) oldtree->GetTree()->GetTreeIndex()->Clone();
3522 index->SetTree(newtree);
3523 newtree->SetTreeIndex(index);
3524 } else {
3525 // Build the index so far.
3526 if (newtree->BuildIndex(oldtree->GetTree()->GetTreeIndex()->GetMajorName(), oldtree->GetTree()->GetTreeIndex()->GetMinorName())) {
3527 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3528 }
3529 }
3530 break;
3531 }
3532 } else if ( onIndexError == kDrop ) {
3533 // There is no index on this or on tree->GetTree(), we know we have to ignore any further
3534 // index
3535 withIndex = false;
3536 }
3537 return withIndex;
3538 }
3539}
3540
3541////////////////////////////////////////////////////////////////////////////////
3542/// Copy nentries from given tree to this tree.
3543/// This routines assumes that the branches that intended to be copied are
3544/// already connected. The typical case is that this tree was created using
3545/// tree->CloneTree(0).
3546///
3547/// By default copy all entries.
3548///
3549/// Returns number of bytes copied to this tree.
3550///
3551/// If 'option' contains the word 'fast' and nentries is -1, the cloning will be
3552/// done without unzipping or unstreaming the baskets (i.e., a direct copy of the
3553/// raw bytes on disk).
3554///
3555/// When 'fast' is specified, 'option' can also contains a sorting order for the
3556/// baskets in the output file.
3557///
3558/// There are currently 3 supported sorting order:
3559///
3560/// - SortBasketsByOffset (the default)
3561/// - SortBasketsByBranch
3562/// - SortBasketsByEntry
3563///
3564/// See TTree::CloneTree for a detailed explanation of the semantics of these 3 options.
3565///
3566/// If the tree or any of the underlying tree of the chain has an index, that index and any
3567/// index in the subsequent underlying TTree objects will be merged.
3568///
3569/// There are currently three 'options' to control this merging:
3570/// - NoIndex : all the TTreeIndex object are dropped.
3571/// - DropIndexOnError : if any of the underlying TTree object do no have a TTreeIndex,
3572/// they are all dropped.
3573/// - AsIsIndexOnError [default]: In case of missing TTreeIndex, the resulting TTree index has gaps.
3574/// - BuildIndexOnError : If any of the underlying TTree objects do not have a TTreeIndex,
3575/// all TTreeIndex are 'ignored' and the missing piece are rebuilt.
3577Long64_t TTree::CopyEntries(TTree* tree, Long64_t nentries /* = -1 */, Option_t* option /* = "" */, bool needCopyAddresses /* = false */)
3578{
3579 if (!tree) {
3580 return 0;
3581 }
3582 // Options
3583 TString opt = option;
3584 opt.ToLower();
3585 bool fastClone = opt.Contains("fast");
3586 bool withIndex = !opt.Contains("noindex");
3587 EOnIndexError onIndexError;
3588 if (opt.Contains("asisindex")) {
3590 } else if (opt.Contains("buildindex")) {
3592 } else if (opt.Contains("dropindex")) {
3594 } else {
3596 }
3597 Ssiz_t cacheSizeLoc = opt.Index("cachesize=");
3598 Long64_t cacheSize = -1;
3600 // If the parse faile, cacheSize stays at -1.
3601 Ssiz_t cacheSizeEnd = opt.Index(" ",cacheSizeLoc+10) - (cacheSizeLoc+10);
3605 Warning("CopyEntries","The cachesize option can not be parsed: %s. The default size will be used.",cacheSizeStr.String().Data());
3607 double m;
3608 const char *munit = nullptr;
3609 ROOT::ToHumanReadableSize(std::numeric_limits<decltype(cacheSize)>::max(),false,&m,&munit);
3610
3611 Warning("CopyEntries","The cachesize option is too large: %s (%g%s max). The default size will be used.",cacheSizeStr.String().Data(),m,munit);
3612 }
3613 }
3614 if (gDebug > 0 && cacheSize != -1) Info("CopyEntries","Using Cache size: %lld\n",cacheSize);
3615
3616 Long64_t nbytes = 0;
3618 if (nentries < 0) {
3620 } else if (nentries > treeEntries) {
3622 }
3623
3625 // Quickly copy the basket without decompression and streaming.
3627 for (Long64_t i = 0; i < nentries; i += tree->GetTree()->GetEntries()) {
3628 if (tree->LoadTree(i) < 0) {
3629 break;
3630 }
3631 if ( withIndex ) {
3632 withIndex = R__HandleIndex( onIndexError, this, tree );
3633 }
3634 if (this->GetDirectory()) {
3635 TFile* file2 = this->GetDirectory()->GetFile();
3636 if (file2 && (file2->GetEND() > TTree::GetMaxTreeSize())) {
3637 if (this->GetDirectory() == (TDirectory*) file2) {
3638 this->ChangeFile(file2);
3639 }
3640 }
3641 }
3643 if (cloner.IsValid()) {
3644 this->SetEntries(this->GetEntries() + tree->GetTree()->GetEntries());
3645 if (cacheSize != -1) cloner.SetCacheSize(cacheSize);
3646 cloner.Exec();
3647 } else {
3648 if (i == 0) {
3649 Warning("CopyEntries","%s",cloner.GetWarning());
3650 // If the first cloning does not work, something is really wrong
3651 // (since apriori the source and target are exactly the same structure!)
3652 return -1;
3653 } else {
3654 if (cloner.NeedConversion()) {
3655 TTree *localtree = tree->GetTree();
3656 Long64_t tentries = localtree->GetEntries();
3657 if (needCopyAddresses) {
3658 // Copy MakeClass status.
3659 tree->SetMakeClass(fMakeClass);
3660 // Copy branch addresses.
3661 CopyAddresses(tree);
3662 }
3663 for (Long64_t ii = 0; ii < tentries; ii++) {
3664 if (localtree->GetEntry(ii) <= 0) {
3665 break;
3666 }
3667 this->Fill();
3668 }
3669 if (needCopyAddresses)
3670 tree->ResetBranchAddresses();
3671 if (this->GetTreeIndex()) {
3672 this->GetTreeIndex()->Append(tree->GetTree()->GetTreeIndex(), true);
3673 }
3674 } else {
3675 Warning("CopyEntries","%s",cloner.GetWarning());
3676 if (tree->GetDirectory() && tree->GetDirectory()->GetFile()) {
3677 Warning("CopyEntries", "Skipped file %s\n", tree->GetDirectory()->GetFile()->GetName());
3678 } else {
3679 Warning("CopyEntries", "Skipped file number %d\n", tree->GetTreeNumber());
3680 }
3681 }
3682 }
3683 }
3684
3685 }
3686 if (this->GetTreeIndex()) {
3687 this->GetTreeIndex()->Append(nullptr,false); // Force the sorting
3688 }
3689 nbytes = GetTotBytes() - totbytes;
3690 } else {
3691 if (nentries < 0) {
3693 } else if (nentries > treeEntries) {
3695 }
3696 if (needCopyAddresses) {
3697 // Copy MakeClass status.
3698 tree->SetMakeClass(fMakeClass);
3699 // Copy branch addresses.
3700 CopyAddresses(tree);
3701 }
3702 Int_t treenumber = -1;
3703 for (Long64_t i = 0; i < nentries; i++) {
3704 if (tree->LoadTree(i) < 0) {
3705 break;
3706 }
3707 if (treenumber != tree->GetTreeNumber()) {
3708 if ( withIndex ) {
3709 withIndex = R__HandleIndex( onIndexError, this, tree );
3710 }
3711 treenumber = tree->GetTreeNumber();
3712 }
3713 if (tree->GetEntry(i) <= 0) {
3714 break;
3715 }
3716 nbytes += this->Fill();
3717 }
3718 if (needCopyAddresses)
3719 tree->ResetBranchAddresses();
3720 if (this->GetTreeIndex()) {
3721 this->GetTreeIndex()->Append(nullptr,false); // Force the sorting
3722 }
3723 }
3724 return nbytes;
3725}
3726
3727////////////////////////////////////////////////////////////////////////////////
3728/// Copy a tree with selection.
3729///
3730/// ### Important:
3731///
3732/// The returned copied tree stays connected with the original tree
3733/// until the original tree is deleted. In particular, any changes
3734/// to the branch addresses in the original tree are also made to
3735/// the copied tree. Any changes made to the branch addresses of the
3736/// copied tree are overridden anytime the original tree changes its
3737/// branch addresses. When the original tree is deleted, all the
3738/// branch addresses of the copied tree are set to zero.
3739///
3740/// For examples of CopyTree, see the tutorials:
3741///
3742/// - copytree.C:
3743/// Example macro to copy a subset of a tree to a new tree.
3744/// The input file was generated by running the program in
3745/// $ROOTSYS/test/Event in this way:
3746/// ~~~ {.cpp}
3747/// ./Event 1000 1 1 1
3748/// ~~~
3749/// - copytree2.C
3750/// Example macro to copy a subset of a tree to a new tree.
3751/// One branch of the new tree is written to a separate file.
3752/// The input file was generated by running the program in
3753/// $ROOTSYS/test/Event in this way:
3754/// ~~~ {.cpp}
3755/// ./Event 1000 1 1 1
3756/// ~~~
3757/// - copytree3.C
3758/// Example macro to copy a subset of a tree to a new tree.
3759/// Only selected entries are copied to the new tree.
3760/// NOTE that only the active branches are copied.
3762TTree* TTree::CopyTree(const char* selection, Option_t* option /* = 0 */, Long64_t nentries /* = TTree::kMaxEntries */, Long64_t firstentry /* = 0 */)
3763{
3764 GetPlayer();
3765 if (fPlayer) {
3767 }
3768 return nullptr;
3769}
3770
3771////////////////////////////////////////////////////////////////////////////////
3772/// Create a basket for this tree and given branch.
3775{
3776 if (!branch) {
3777 return nullptr;
3778 }
3779 return new TBasket(branch->GetName(), GetName(), branch);
3780}
3781
3782////////////////////////////////////////////////////////////////////////////////
3783/// Delete this tree from memory or/and disk.
3784///
3785/// - if option == "all" delete Tree object from memory AND from disk
3786/// all baskets on disk are deleted. All keys with same name
3787/// are deleted.
3788/// - if option =="" only Tree object in memory is deleted.
3790void TTree::Delete(Option_t* option /* = "" */)
3791{
3792 TFile *file = GetCurrentFile();
3793
3794 // delete all baskets and header from file
3795 if (file && option && !strcmp(option,"all")) {
3796 if (!file->IsWritable()) {
3797 Error("Delete","File : %s is not writable, cannot delete Tree:%s", file->GetName(),GetName());
3798 return;
3799 }
3800
3801 //find key and import Tree header in memory
3802 TKey *key = fDirectory->GetKey(GetName());
3803 if (!key) return;
3804
3806 file->cd();
3807
3808 //get list of leaves and loop on all the branches baskets
3809 TIter next(GetListOfLeaves());
3810 TLeaf *leaf;
3811 char header[16];
3812 Int_t ntot = 0;
3813 Int_t nbask = 0;
3815 while ((leaf = (TLeaf*)next())) {
3816 TBranch *branch = leaf->GetBranch();
3817 Int_t nbaskets = branch->GetMaxBaskets();
3818 for (Int_t i=0;i<nbaskets;i++) {
3819 Long64_t pos = branch->GetBasketSeek(i);
3820 if (!pos) continue;
3821 TFile *branchFile = branch->GetFile();
3822 if (!branchFile) continue;
3823 branchFile->GetRecordHeader(header,pos,16,nbytes,objlen,keylen);
3824 if (nbytes <= 0) continue;
3825 branchFile->MakeFree(pos,pos+nbytes-1);
3826 ntot += nbytes;
3827 nbask++;
3828 }
3829 }
3830
3831 // delete Tree header key and all keys with the same name
3832 // A Tree may have been saved many times. Previous cycles are invalid.
3833 while (key) {
3834 ntot += key->GetNbytes();
3835 key->Delete();
3836 delete key;
3837 key = fDirectory->GetKey(GetName());
3838 }
3839 if (dirsav) dirsav->cd();
3840 if (gDebug) Info("TTree::Delete", "Deleting Tree: %s: %d baskets deleted. Total space freed = %d bytes\n",GetName(),nbask,ntot);
3841 }
3842
3843 if (fDirectory) {
3844 fDirectory->Remove(this);
3845 //delete the file cache if it points to this Tree
3846 MoveReadCache(file,nullptr);
3847 fDirectory = nullptr;
3849 }
3850
3851 // Delete object from Cling symbol table so it can not be used anymore.
3852 gCling->DeleteGlobal(this);
3853
3854 // Warning: We have intentional invalidated this object while inside a member function!
3855 delete this;
3856}
3857
3858 ///////////////////////////////////////////////////////////////////////////////
3859 /// Called by TKey and TObject::Clone to automatically add us to a directory
3860 /// when we are read from a file.
3863{
3864 if (fDirectory == dir) return;
3865 if (fDirectory) {
3866 fDirectory->Remove(this);
3867 // Delete or move the file cache if it points to this Tree
3868 TFile *file = fDirectory->GetFile();
3869 MoveReadCache(file,dir);
3870 }
3871 fDirectory = dir;
3872 TBranch* b = nullptr;
3873 TIter next(GetListOfBranches());
3874 while((b = (TBranch*) next())) {
3875 b->UpdateFile();
3876 }
3877 if (fBranchRef) {
3879 }
3880 if (fDirectory) fDirectory->Append(this);
3881}
3882
3883////////////////////////////////////////////////////////////////////////////////
3884/// Draw expression varexp for specified entries.
3885///
3886/// \return -1 in case of error or number of selected events in case of success.
3887/// If `selection` involves an array variable `x[n]`, for example `x[] > 0` or
3888/// `x > 0`, then we return the number of selected instances rather than number of events.
3889/// In the output of `tree.Scan()`, instances are shown in individual printed rows, thus
3890/// each event (tree entry) is split across the various instances (lines) of the array.
3891/// In contrast, the function `GetEntries(selection)` always returns the number of entries selected.
3892///
3893/// This function accepts TCut objects as arguments.
3894/// Useful to use the string operator +
3895///
3896/// Example:
3897///
3898/// ~~~ {.cpp}
3899/// ntuple.Draw("x",cut1+cut2+cut3);
3900/// ~~~
3901
3906}
3907
3908/////////////////////////////////////////////////////////////////////////////////////////
3909/// \brief Draw expression varexp for entries and objects that pass a (optional) selection.
3910///
3911/// \return -1 in case of error or number of selected events in case of success.
3912/// If `selection` involves an array variable `x[n]`, for example `x[] > 0` or
3913/// `x > 0`, then we return the number of selected instances rather than number of events.
3914/// In the output of `tree.Scan()`, instances are shown in individual printed rows, thus
3915/// each event (tree entry) is split across the various instances (lines) of the array.
3916/// In contrast, the function `GetEntries(selection)` always returns the number of entries selected.
3917///
3918/// \param [in] varexp
3919/// \parblock
3920/// A string that takes one of these general forms:
3921/// - "e1" produces a 1-d histogram (TH1F) of expression "e1"
3922/// - "e1:e2" produces an unbinned 2-d scatter-plot (TGraph) of "e1"
3923/// on the y-axis versus "e2" on the x-axis
3924/// - "e1:e2:e3" produces an unbinned 3-d scatter-plot (TPolyMarker3D) of "e1"
3925/// vs "e2" vs "e3" on the z-, y-, x-axis, respectively
3926/// - "e1:e2:e3:e4" produces an unbinned 3-d scatter-plot (TPolyMarker3D) of "e1"
3927/// vs "e2" vs "e3" and "e4" mapped on the current color palette.
3928/// (to create histograms in the 2, 3, and 4 dimensional case,
3929/// see section "Saving the result of Draw to an histogram")
3930/// - "e1:e2:e3:e4:e5" with option "GL5D" produces a 5D plot using OpenGL. `gStyle->SetCanvasPreferGL(true)` is needed.
3931/// - Any number of variables no fewer than two can be used with the options "CANDLE" and "PARA"
3932/// - An arbitrary number of variables can be used with the option "GOFF"
3933///
3934/// Examples:
3935/// - "x": the simplest case, it draws a 1-Dim histogram of column x
3936/// - "sqrt(x)", "x*y/z": draw histogram with the values of the specified numerical expression across TTree events
3937/// - "y:sqrt(x)": 2-Dim histogram of y versus sqrt(x)
3938/// - "px:py:pz:2.5*E": produces a 3-d scatter-plot of px vs py ps pz
3939/// and the color number of each marker will be 2.5*E.
3940/// If the color number is negative it is set to 0.
3941/// If the color number is greater than the current number of colors
3942/// it is set to the highest color number. The default number of
3943/// colors is 50. See TStyle::SetPalette for setting a new color palette.
3944///
3945/// The expressions can use all the operations and built-in functions
3946/// supported by TFormula (see TFormula::Analyze()), including free
3947/// functions taking numerical arguments (e.g. TMath::Bessel()).
3948/// In addition, you can call member functions taking numerical
3949/// arguments. For example, these are two valid expressions:
3950/// ~~~ {.cpp}
3951/// TMath::BreitWigner(fPx,3,2)
3952/// event.GetHistogram()->GetXaxis()->GetXmax()
3953/// ~~~
3954/// \endparblock
3955/// \param [in] selection
3956/// \parblock
3957/// A string containing a selection expression.
3958/// In a selection all usual C++ mathematical and logical operators are allowed.
3959/// The value corresponding to the selection expression is used as a weight
3960/// to fill the histogram (a weight of 0 is equivalent to not filling the histogram).\n
3961/// \n
3962/// Examples:
3963/// - "x<y && sqrt(z)>3.2": returns a weight = 0 or 1
3964/// - "(x+y)*(sqrt(z)>3.2)": returns a weight = x+y if sqrt(z)>3.2, 0 otherwise\n
3965/// \n
3966/// If the selection expression returns an array, it is iterated over in sync with the
3967/// array returned by the varexp argument (as described below in "Drawing expressions using arrays and array
3968/// elements"). For example, if, for a given event, varexp evaluates to
3969/// `{1., 2., 3.}` and selection evaluates to `{0, 1, 0}`, the resulting histogram is filled with the value 2. For 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 value if fResults[j][k] is used as the second index of fMatrix.|
4045///
4046///
4047/// In summary, TTree::Draw loops through all unspecified dimensions. To
4048/// figure out the range of each loop, we match each unspecified dimension
4049/// from left to right (ignoring ALL dimensions for which an index has been
4050/// specified), in the equivalent loop matched dimensions use the same index
4051/// and are restricted to the smallest range (of only the matched dimensions).
4052/// When involving variable arrays, the range can of course be different
4053/// for each entry of the tree.
4054///
4055/// So the loop equivalent to "fMatrix[][2] - fResults[3][]" is:
4056/// ~~~ {.cpp}
4057/// for (Int_t i0; i < min(3,2); i++) {
4058/// use the value of (fMatrix[i0][2] - fMatrix[3][i0])
4059/// }
4060/// ~~~
4061/// So the loop equivalent to "fMatrix[][2] - fResults[][]" is:
4062/// ~~~ {.cpp}
4063/// for (Int_t i0; i < min(3,5); i++) {
4064/// for (Int_t i1; i1 < 2; i1++) {
4065/// use the value of (fMatrix[i0][2] - fMatrix[i0][i1])
4066/// }
4067/// }
4068/// ~~~
4069/// So the loop equivalent to "fMatrix[][] - fResults[][]" is:
4070/// ~~~ {.cpp}
4071/// for (Int_t i0; i < min(3,5); i++) {
4072/// for (Int_t i1; i1 < min(3,2); i1++) {
4073/// use the value of (fMatrix[i0][i1] - fMatrix[i0][i1])
4074/// }
4075/// }
4076/// ~~~
4077/// So the loop equivalent to "fMatrix[][fResults[][]]" is:
4078/// ~~~ {.cpp}
4079/// for (Int_t i0; i0 < 3; i0++) {
4080/// for (Int_t j2; j2 < 5; j2++) {
4081/// for (Int_t j3; j3 < 2; j3++) {
4082/// i1 = fResults[j2][j3];
4083/// use the value of fMatrix[i0][i1]
4084/// }
4085/// }
4086/// ~~~
4087/// ### Retrieving the result of Draw
4088///
4089/// By default a temporary histogram called `htemp` is created. It will be:
4090///
4091/// - A TH1F* in case of a mono-dimensional distribution: `Draw("e1")`,
4092/// - A TH2F* in case of a bi-dimensional distribution: `Draw("e1:e2")`,
4093/// - A TH3F* in case of a three-dimensional distribution: `Draw("e1:e2:e3")`.
4094///
4095/// In the one dimensional case the `htemp` is filled and drawn whatever the drawing
4096/// option is.
4097///
4098/// In the two and three dimensional cases, with the default drawing option (`""`),
4099/// a cloud of points is drawn and the histogram `htemp` is not filled. For all the other
4100/// drawing options `htemp` will be filled.
4101///
4102/// In all cases `htemp` can be retrieved by calling:
4103///
4104/// ~~~ {.cpp}
4105/// auto htemp = (TH1F*)gPad->GetPrimitive("htemp"); // 1D
4106/// auto htemp = (TH2F*)gPad->GetPrimitive("htemp"); // 2D
4107/// auto htemp = (TH3F*)gPad->GetPrimitive("htemp"); // 3D
4108/// ~~~
4109///
4110/// In the two dimensional case (`Draw("e1;e2")`), with the default drawing option, the
4111/// data is filled into a TGraph named `Graph`. This TGraph can be retrieved by
4112/// calling
4113///
4114/// ~~~ {.cpp}
4115/// auto graph = (TGraph*)gPad->GetPrimitive("Graph");
4116/// ~~~
4117///
4118/// For the three and four dimensional cases, with the default drawing option, an unnamed
4119/// TPolyMarker3D is produced, and therefore cannot be retrieved.
4120///
4121/// In all cases `htemp` can be used to access the axes. For instance in the 2D case:
4122///
4123/// ~~~ {.cpp}
4124/// auto htemp = (TH2F*)gPad->GetPrimitive("htemp");
4125/// auto xaxis = htemp->GetXaxis();
4126/// ~~~
4127///
4128/// When the option `"A"` is used (with TGraph painting option) to draw a 2D
4129/// distribution:
4130/// ~~~ {.cpp}
4131/// tree.Draw("e1:e2","","A*");
4132/// ~~~
4133/// a scatter plot is produced (with stars in that case) but the axis creation is
4134/// delegated to TGraph and `htemp` is not created.
4135///
4136/// ### Saving the result of Draw to a histogram
4137///
4138/// If `varexp` contains `>>hnew` (following the variable(s) name(s)),
4139/// the new histogram called `hnew` is created and it is kept in the current
4140/// directory (and also the current pad). This works for all dimensions.
4141///
4142/// Example:
4143/// ~~~ {.cpp}
4144/// tree.Draw("sqrt(x)>>hsqrt","y>0")
4145/// ~~~
4146/// will draw `sqrt(x)` and save the histogram as "hsqrt" in the current
4147/// directory. To retrieve it do:
4148/// ~~~ {.cpp}
4149/// TH1F *hsqrt = (TH1F*)gDirectory->Get("hsqrt");
4150/// ~~~
4151/// The binning information is taken from the environment variables
4152/// ~~~ {.cpp}
4153/// Hist.Binning.?D.?
4154/// ~~~
4155/// In addition, the name of the histogram can be followed by up to 9
4156/// numbers between '(' and ')', where the numbers describe the
4157/// following:
4158///
4159/// - 1 - bins in x-direction
4160/// - 2 - lower limit in x-direction
4161/// - 3 - upper limit in x-direction
4162/// - 4-6 same for y-direction
4163/// - 7-9 same for z-direction
4164///
4165/// When a new binning is used the new value will become the default.
4166/// Values can be skipped.
4167///
4168/// Example:
4169/// ~~~ {.cpp}
4170/// tree.Draw("sqrt(x)>>hsqrt(500,10,20)")
4171/// // plot sqrt(x) between 10 and 20 using 500 bins
4172/// tree.Draw("sqrt(x):sin(y)>>hsqrt(100,10,60,50,.1,.5)")
4173/// // plot sqrt(x) against sin(y)
4174/// // 100 bins in x-direction; lower limit on x-axis is 10; upper limit is 60
4175/// // 50 bins in y-direction; lower limit on y-axis is .1; upper limit is .5
4176/// ~~~
4177/// By default, the specified histogram is reset.
4178/// To continue to append data to an existing histogram, use "+" in front
4179/// of the histogram name.
4180///
4181/// A '+' in front of the histogram name is ignored, when the name is followed by
4182/// binning information as described in the previous paragraph.
4183/// ~~~ {.cpp}
4184/// tree.Draw("sqrt(x)>>+hsqrt","y>0")
4185/// ~~~
4186/// will not reset `hsqrt`, but will continue filling. This works for 1-D, 2-D
4187/// and 3-D histograms.
4188///
4189/// ### Accessing collection objects
4190///
4191/// TTree::Draw default's handling of collections is to assume that any
4192/// request on a collection pertain to it content. For example, if fTracks
4193/// is a collection of Track objects, the following:
4194/// ~~~ {.cpp}
4195/// tree->Draw("event.fTracks.fPx");
4196/// ~~~
4197/// will plot the value of fPx for each Track objects inside the collection.
4198/// Also
4199/// ~~~ {.cpp}
4200/// tree->Draw("event.fTracks.size()");
4201/// ~~~
4202/// would plot the result of the member function Track::size() for each
4203/// Track object inside the collection.
4204/// To access information about the collection itself, TTree::Draw support
4205/// the '@' notation. If a variable which points to a collection is prefixed
4206/// or postfixed with '@', the next part of the expression will pertain to
4207/// the collection object. For example:
4208/// ~~~ {.cpp}
4209/// tree->Draw("event.@fTracks.size()");
4210/// ~~~
4211/// will plot the size of the collection referred to by `fTracks` (i.e the number
4212/// of Track objects).
4213///
4214/// ### Drawing 'objects'
4215///
4216/// When a class has a member function named AsDouble or AsString, requesting
4217/// to directly draw the object will imply a call to one of the 2 functions.
4218/// If both AsDouble and AsString are present, AsDouble will be used.
4219/// AsString can return either a char*, a std::string or a TString.s
4220/// For example, the following
4221/// ~~~ {.cpp}
4222/// tree->Draw("event.myTTimeStamp");
4223/// ~~~
4224/// will draw the same histogram as
4225/// ~~~ {.cpp}
4226/// tree->Draw("event.myTTimeStamp.AsDouble()");
4227/// ~~~
4228/// In addition, when the object is a type TString or std::string, TTree::Draw
4229/// will call respectively `TString::Data` and `std::string::c_str()`
4230///
4231/// If the object is a TBits, the histogram will contain the index of the bit
4232/// that are turned on.
4233///
4234/// ### Retrieving information about the tree itself.
4235///
4236/// You can refer to the tree (or chain) containing the data by using the
4237/// string 'This'.
4238/// You can then could any TTree methods. For example:
4239/// ~~~ {.cpp}
4240/// tree->Draw("This->GetReadEntry()");
4241/// ~~~
4242/// will display the local entry numbers be read.
4243/// ~~~ {.cpp}
4244/// tree->Draw("This->GetUserInfo()->At(0)->GetName()");
4245/// ~~~
4246/// will display the name of the first 'user info' object.
4247///
4248/// ### Special functions and variables
4249///
4250/// `Entry$`: A TTree::Draw formula can use the special variable `Entry$`
4251/// to access the entry number being read. For example to draw every
4252/// other entry use:
4253/// ~~~ {.cpp}
4254/// tree.Draw("myvar","Entry$%2==0");
4255/// ~~~
4256/// - `Entry$` : return the current entry number (`== TTree::GetReadEntry()`)
4257/// - `LocalEntry$` : return the current entry number in the current tree of a
4258/// chain (`== GetTree()->GetReadEntry()`)
4259/// - `Entries$` : return the total number of entries (== TTree::GetEntries())
4260/// - `LocalEntries$` : return the total number of entries in the current tree
4261/// of a chain (== GetTree()->TTree::GetEntries())
4262/// - `Length$` : return the total number of element of this formula for this
4263/// entry (`==TTreeFormula::GetNdata()`)
4264/// - `Iteration$` : return the current iteration over this formula for this
4265/// entry (i.e. varies from 0 to `Length$ - 1`).
4266/// - `Length$(formula )` : return the total number of element of the formula
4267/// given as a parameter.
4268/// - `Sum$(formula )` : return the sum of the value of the elements of the
4269/// formula given as a parameter. For example the mean for all the elements in
4270/// one entry can be calculated with: `Sum$(formula )/Length$(formula )`
4271/// - `Min$(formula )` : return the minimum (within one TTree entry) of the value of the
4272/// elements of the formula given as a parameter.
4273/// - `Max$(formula )` : return the maximum (within one TTree entry) of the value of the
4274/// elements of the formula given as a parameter.
4275/// - `MinIf$(formula,condition)`
4276/// - `MaxIf$(formula,condition)` : return the minimum (maximum) (within one TTree entry)
4277/// of the value of the elements of the formula given as a parameter
4278/// if they match the condition. If no element matches the condition,
4279/// the result is zero. To avoid the resulting peak at zero, use the
4280/// pattern:
4281/// ~~~ {.cpp}
4282/// tree->Draw("MinIf$(formula,condition)","condition");
4283/// ~~~
4284/// which will avoid calculation `MinIf$` for the entries that have no match
4285/// for the condition.
4286/// - `Alt$(primary,alternate)` : return the value of "primary" if it is available
4287/// for the current iteration otherwise return the value of "alternate".
4288/// For example, with arr1[3] and arr2[2]
4289/// ~~~ {.cpp}
4290/// tree->Draw("arr1+Alt$(arr2,0)");
4291/// ~~~
4292/// will draw arr1[0]+arr2[0] ; arr1[1]+arr2[1] and arr1[2]+0
4293/// Or with a variable size array arr3
4294/// ~~~ {.cpp}
4295/// tree->Draw("Alt$(arr3[0],0)+Alt$(arr3[1],0)+Alt$(arr3[2],0)");
4296/// ~~~
4297/// will draw the sum arr3 for the index 0 to min(2,actual_size_of_arr3-1)
4298/// As a comparison
4299/// ~~~ {.cpp}
4300/// tree->Draw("arr3[0]+arr3[1]+arr3[2]");
4301/// ~~~
4302/// will draw the sum arr3 for the index 0 to 2 only if the
4303/// actual_size_of_arr3 is greater or equal to 3.
4304/// Note that the array in 'primary' is flattened/linearized thus using
4305/// `Alt$` with multi-dimensional arrays of different dimensions is unlikely
4306/// to yield the expected results. To visualize a bit more what elements
4307/// would be matched by TTree::Draw, TTree::Scan can be used:
4308/// ~~~ {.cpp}
4309/// tree->Scan("arr1:Alt$(arr2,0)");
4310/// ~~~
4311/// will print on one line the value of arr1 and (arr2,0) that will be
4312/// matched by
4313/// ~~~ {.cpp}
4314/// tree->Draw("arr1-Alt$(arr2,0)");
4315/// ~~~
4316/// The ternary operator is not directly supported in TTree::Draw however, to plot the
4317/// equivalent of `var2<20 ? -99 : var1`, you can use:
4318/// ~~~ {.cpp}
4319/// tree->Draw("(var2<20)*99+(var2>=20)*var1","");
4320/// ~~~
4321///
4322/// ### Drawing a user function accessing the TTree data directly
4323///
4324/// If the formula contains a file name, TTree::MakeProxy will be used
4325/// to load and execute this file. In particular it will draw the
4326/// result of a function with the same name as the file. The function
4327/// will be executed in a context where the name of the branches can
4328/// be used as a C++ variable.
4329///
4330/// For example draw px using the file hsimple.root (generated by the
4331/// hsimple.C tutorial), we need a file named hsimple.cxx:
4332/// ~~~ {.cpp}
4333/// double hsimple() {
4334/// return px;
4335/// }
4336/// ~~~
4337/// MakeProxy can then be used indirectly via the TTree::Draw interface
4338/// as follow:
4339/// ~~~ {.cpp}
4340/// new TFile("hsimple.root")
4341/// ntuple->Draw("hsimple.cxx");
4342/// ~~~
4343/// A more complete example is available in the tutorials directory:
4344/// `h1analysisProxy.cxx`, `h1analysProxy.h` and `h1analysisProxyCut.C`
4345/// which reimplement the selector found in `h1analysis.C`
4346///
4347/// The main features of this facility are:
4348///
4349/// * on-demand loading of branches
4350/// * ability to use the 'branchname' as if it was a data member
4351/// * protection against array out-of-bound
4352/// * ability to use the branch data as object (when the user code is available)
4353///
4354/// See TTree::MakeProxy for more details.
4355///
4356/// ### Making a Profile histogram
4357///
4358/// In case of a 2-Dim expression, one can generate a TProfile histogram
4359/// instead of a TH2F histogram by specifying option=prof or option=profs
4360/// or option=profi or option=profg ; the trailing letter select the way
4361/// the bin error are computed, See TProfile2D::SetErrorOption for
4362/// details on the differences.
4363/// The option=prof is automatically selected in case of y:x>>pf
4364/// where pf is an existing TProfile histogram.
4365///
4366/// ### Making a 2D Profile histogram
4367///
4368/// In case of a 3-Dim expression, one can generate a TProfile2D histogram
4369/// instead of a TH3F 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 z:y:x>>pf
4374/// where pf is an existing TProfile2D histogram.
4375///
4376/// ### Making a 5D plot using GL
4377///
4378/// If option GL5D is specified together with 5 variables, a 5D plot is drawn
4379/// using OpenGL. See tree502_staff.C as example.
4380///
4381/// ### Making a parallel coordinates plot
4382///
4383/// In case of a 2-Dim or more expression with the option=para, one can generate
4384/// a parallel coordinates plot. With that option, the number of dimensions is
4385/// arbitrary. Giving more than 4 variables without the option=para or
4386/// option=candle or option=goff will produce an error.
4387///
4388/// ### Making a candle sticks chart
4389///
4390/// In case of a 2-Dim or more expression with the option=candle, one can generate
4391/// a candle sticks chart. With that option, the number of dimensions is
4392/// arbitrary. Giving more than 4 variables without the option=para or
4393/// option=candle or option=goff will produce an error.
4394///
4395/// ### Normalizing the output histogram to 1
4396///
4397/// When option contains "norm" the output histogram is normalized to 1.
4398///
4399/// ### Saving the result of Draw to a TEventList, a TEntryList or a TEntryListArray
4400///
4401/// TTree::Draw can be used to fill a TEventList object (list of entry numbers)
4402/// instead of histogramming one variable.
4403/// If varexp0 has the form >>elist , a TEventList object named "elist"
4404/// is created in the current directory. elist will contain the list
4405/// of entry numbers satisfying the current selection.
4406/// If option "entrylist" is used, a TEntryList object is created
4407/// If the selection contains arrays, vectors or any container class and option
4408/// "entrylistarray" is used, a TEntryListArray object is created
4409/// containing also the subentries satisfying the selection, i.e. the indices of
4410/// the branches which hold containers classes.
4411/// Example:
4412/// ~~~ {.cpp}
4413/// tree.Draw(">>yplus","y>0")
4414/// ~~~
4415/// will create a TEventList object named "yplus" in the current directory.
4416/// In an interactive session, one can type (after TTree::Draw)
4417/// ~~~ {.cpp}
4418/// yplus.Print("all")
4419/// ~~~
4420/// to print the list of entry numbers in the list.
4421/// ~~~ {.cpp}
4422/// tree.Draw(">>yplus", "y>0", "entrylist")
4423/// ~~~
4424/// will create a TEntryList object names "yplus" in the current directory
4425/// ~~~ {.cpp}
4426/// tree.Draw(">>yplus", "y>0", "entrylistarray")
4427/// ~~~
4428/// will create a TEntryListArray object names "yplus" in the current directory
4429///
4430/// By default, the specified entry list is reset.
4431/// To continue to append data to an existing list, use "+" in front
4432/// of the list name;
4433/// ~~~ {.cpp}
4434/// tree.Draw(">>+yplus","y>0")
4435/// ~~~
4436/// will not reset yplus, but will enter the selected entries at the end
4437/// of the existing list.
4438///
4439/// ### Using a TEventList, TEntryList or TEntryListArray as Input
4440///
4441/// Once a TEventList or a TEntryList object has been generated, it can be used as input
4442/// for TTree::Draw. Use TTree::SetEventList or TTree::SetEntryList to set the
4443/// current event list
4444///
4445/// Example 1:
4446/// ~~~ {.cpp}
4447/// TEventList *elist = (TEventList*)gDirectory->Get("yplus");
4448/// tree->SetEventList(elist);
4449/// tree->Draw("py");
4450/// ~~~
4451/// Example 2:
4452/// ~~~ {.cpp}
4453/// TEntryList *elist = (TEntryList*)gDirectory->Get("yplus");
4454/// tree->SetEntryList(elist);
4455/// tree->Draw("py");
4456/// ~~~
4457/// If a TEventList object is used as input, a new TEntryList object is created
4458/// inside the SetEventList function. In case of a TChain, all tree headers are loaded
4459/// for this transformation. This new object is owned by the chain and is deleted
4460/// with it, unless the user extracts it by calling GetEntryList() function.
4461/// See also comments to SetEventList() function of TTree and TChain.
4462///
4463/// If arrays are used in the selection criteria and TEntryListArray is not used,
4464/// all the entries that have at least one element of the array that satisfy the selection
4465/// are entered in the list.
4466///
4467/// Example:
4468/// ~~~ {.cpp}
4469/// tree.Draw(">>pyplus","fTracks.fPy>0");
4470/// tree->SetEventList(pyplus);
4471/// tree->Draw("fTracks.fPy");
4472/// ~~~
4473/// will draw the fPy of ALL tracks in event with at least one track with
4474/// a positive fPy.
4475///
4476/// To select only the elements that did match the original selection
4477/// use TEventList::SetReapplyCut or TEntryList::SetReapplyCut.
4478///
4479/// Example:
4480/// ~~~ {.cpp}
4481/// tree.Draw(">>pyplus","fTracks.fPy>0");
4482/// pyplus->SetReapplyCut(true);
4483/// tree->SetEventList(pyplus);
4484/// tree->Draw("fTracks.fPy");
4485/// ~~~
4486/// will draw the fPy of only the tracks that have a positive fPy.
4487///
4488/// To draw only the elements that match a selection in case of arrays,
4489/// you can also use TEntryListArray (faster in case of a more general selection).
4490///
4491/// Example:
4492/// ~~~ {.cpp}
4493/// tree.Draw(">>pyplus","fTracks.fPy>0", "entrylistarray");
4494/// tree->SetEntryList(pyplus);
4495/// tree->Draw("fTracks.fPy");
4496/// ~~~
4497/// will draw the fPy of only the tracks that have a positive fPy,
4498/// but without redoing the selection.
4499///
4500/// Note: Use tree->SetEventList(0) if you do not want use the list as input.
4501///
4502/// ### How to obtain more info from TTree::Draw
4503///
4504/// Once TTree::Draw has been called, it is possible to access useful
4505/// information still stored in the TTree object via the following functions:
4506///
4507/// - GetSelectedRows() // return the number of values accepted by the selection expression. In case where no selection was specified, returns the number of values processed.
4508/// - GetV1() // returns a pointer to the double array of V1
4509/// - GetV2() // returns a pointer to the double array of V2
4510/// - GetV3() // returns a pointer to the double array of V3
4511/// - GetV4() // returns a pointer to the double array of V4
4512/// - GetW() // returns a pointer to the double array of Weights where weight equal the result of the selection expression.
4513///
4514/// where V1,V2,V3 correspond to the expressions in
4515/// ~~~ {.cpp}
4516/// TTree::Draw("V1:V2:V3:V4",selection);
4517/// ~~~
4518/// If the expression has more than 4 component use GetVal(index)
4519///
4520/// Example:
4521/// ~~~ {.cpp}
4522/// Root > ntuple->Draw("py:px","pz>4");
4523/// Root > TGraph *gr = new TGraph(ntuple->GetSelectedRows(),
4524/// ntuple->GetV2(), ntuple->GetV1());
4525/// Root > gr->Draw("ap"); //draw graph in current pad
4526/// ~~~
4527///
4528/// A more complete complete tutorial (treegetval.C) shows how to use the
4529/// GetVal() method.
4530///
4531/// creates a TGraph object with a number of points corresponding to the
4532/// number of entries selected by the expression "pz>4", the x points of the graph
4533/// being the px values of the Tree and the y points the py values.
4534///
4535/// Important note: By default TTree::Draw creates the arrays obtained
4536/// with GetW, GetV1, GetV2, GetV3, GetV4, GetVal with a length corresponding
4537/// to the parameter fEstimate. The content will be the last `GetSelectedRows() % GetEstimate()`
4538/// values calculated.
4539/// By default fEstimate=1000000 and can be modified
4540/// via TTree::SetEstimate. To keep in memory all the results (in case
4541/// where there is only one result per entry), use
4542/// ~~~ {.cpp}
4543/// tree->SetEstimate(tree->GetEntries()+1); // same as tree->SetEstimate(-1);
4544/// ~~~
4545/// You must call SetEstimate if the expected number of selected rows
4546/// you need to look at is greater than 1000000.
4547///
4548/// You can use the option "goff" to turn off the graphics output
4549/// of TTree::Draw in the above example.
4550///
4551/// ### Automatic interface to TTree::Draw via the TTreeViewer
4552///
4553/// A complete graphical interface to this function is implemented
4554/// in the class TTreeViewer.
4555/// To start the TTreeViewer, three possibilities:
4556/// - select TTree context menu item "StartViewer"
4557/// - type the command "TTreeViewer TV(treeName)"
4558/// - execute statement "tree->StartViewer();"
4561{
4562 GetPlayer();
4563 if (fPlayer)
4565 return -1;
4566}
4567
4568////////////////////////////////////////////////////////////////////////////////
4569/// Remove some baskets from memory.
4571void TTree::DropBaskets()
4572{
4573 TBranch* branch = nullptr;
4575 for (Int_t i = 0; i < nb; ++i) {
4577 branch->DropBaskets("all");
4578 }
4579}
4580
4581////////////////////////////////////////////////////////////////////////////////
4582/// Drop branch buffers to accommodate nbytes below MaxVirtualsize.
4585{
4586 // Be careful not to remove current read/write buffers.
4588 for (Int_t i = 0; i < nleaves; ++i) {
4590 TBranch* branch = (TBranch*) leaf->GetBranch();
4591 Int_t nbaskets = branch->GetListOfBaskets()->GetEntries();
4592 for (Int_t j = 0; j < nbaskets - 1; ++j) {
4593 if ((j == branch->GetReadBasket()) || (j == branch->GetWriteBasket())) {
4594 continue;
4595 }
4596 TBasket* basket = (TBasket*)branch->GetListOfBaskets()->UncheckedAt(j);
4597 if (basket) {
4598 basket->DropBuffers();
4600 return;
4601 }
4602 }
4603 }
4604 }
4605}
4606
4607////////////////////////////////////////////////////////////////////////////////
4608/// Fill all branches.
4609///
4610/// This function loops on all the branches of this tree. For
4611/// each branch, it copies to the branch buffer (basket) the current
4612/// values of the leaves data types. If a leaf is a simple data type,
4613/// a simple conversion to a machine independent format has to be done.
4614///
4615/// This machine independent version of the data is copied into a
4616/// basket (each branch has its own basket). When a basket is full
4617/// (32k worth of data by default), it is then optionally compressed
4618/// and written to disk (this operation is also called committing or
4619/// 'flushing' the basket). The committed baskets are then
4620/// immediately removed from memory.
4621///
4622/// The function returns the number of bytes committed to the
4623/// individual branches.
4624///
4625/// If a write error occurs, the number of bytes returned is -1.
4626///
4627/// If no data are written, because, e.g., the branch is disabled,
4628/// the number of bytes returned is 0.
4629///
4630/// __The baskets are flushed and the Tree header saved at regular intervals__
4631///
4632/// At regular intervals, when the amount of data written so far is
4633/// greater than fAutoFlush (see SetAutoFlush) all the baskets are flushed to disk.
4634/// This makes future reading faster as it guarantees that baskets belonging to nearby
4635/// entries will be on the same disk region.
4636/// When the first call to flush the baskets happen, we also take this opportunity
4637/// to optimize the baskets buffers.
4638/// We also check if the amount of data written is greater than fAutoSave (see SetAutoSave).
4639/// In this case we also write the Tree header. This makes the Tree recoverable up to this point
4640/// in case the program writing the Tree crashes.
4641/// The decisions to FlushBaskets and Auto Save can be made based either on the number
4642/// of bytes written (fAutoFlush and fAutoSave negative) or on the number of entries
4643/// written (fAutoFlush and fAutoSave positive).
4644/// Note that the user can decide to call FlushBaskets and AutoSave in her event loop
4645/// base on the number of events written instead of the number of bytes written.
4646///
4647/// \note Calling `TTree::FlushBaskets` too often increases the IO time.
4648///
4649/// \note Calling `TTree::AutoSave` too often increases the IO time and also the
4650/// file size.
4651///
4652/// \note This method calls `TTree::ChangeFile` when the tree reaches a size
4653/// greater than `TTree::fgMaxTreeSize`. This doesn't happen if the tree is
4654/// attached to a `TMemFile` or derivate.
4657{
4658 Int_t nbytes = 0;
4659 Int_t nwrite = 0;
4660 Int_t nerror = 0;
4662
4663 // Case of one single super branch. Automatically update
4664 // all the branch addresses if a new object was created.
4665 if (nbranches == 1)
4666 ((TBranch *)fBranches.UncheckedAt(0))->UpdateAddress();
4667
4668 if (fBranchRef)
4669 fBranchRef->Clear();
4670
4671#ifdef R__USE_IMT
4674 if (useIMT) {
4675 fIMTFlush = true;
4676 fIMTZipBytes.store(0);
4677 fIMTTotBytes.store(0);
4678 }
4679#endif
4680
4681 for (Int_t i = 0; i < nbranches; ++i) {
4682 // Loop over all branches, filling and accumulating bytes written and error counts.
4684
4685 if (branch->TestBit(kDoNotProcess))
4686 continue;
4687
4688#ifndef R__USE_IMT
4689 nwrite = branch->FillImpl(nullptr);
4690#else
4691 nwrite = branch->FillImpl(useIMT ? &imtHelper : nullptr);
4692#endif
4693 if (nwrite < 0) {
4694 if (nerror < 2) {
4695 Error("Fill", "Failed filling branch:%s.%s, nbytes=%d, entry=%lld\n"
4696 " This error is symptomatic of a Tree created as a memory-resident Tree\n"
4697 " Instead of doing:\n"
4698 " TTree *T = new TTree(...)\n"
4699 " TFile *f = new TFile(...)\n"
4700 " you should do:\n"
4701 " TFile *f = new TFile(...)\n"
4702 " TTree *T = new TTree(...)\n\n",
4703 GetName(), branch->GetName(), nwrite, fEntries + 1);
4704 } else {
4705 Error("Fill", "Failed filling branch:%s.%s, nbytes=%d, entry=%lld", GetName(), branch->GetName(), nwrite,
4706 fEntries + 1);
4707 }
4708 ++nerror;
4709 } else {
4710 nbytes += nwrite;
4711 }
4712 }
4713
4714#ifdef R__USE_IMT
4715 if (fIMTFlush) {
4716 imtHelper.Wait();
4717 fIMTFlush = false;
4718 const_cast<TTree *>(this)->AddTotBytes(fIMTTotBytes);
4719 const_cast<TTree *>(this)->AddZipBytes(fIMTZipBytes);
4720 nbytes += imtHelper.GetNbytes();
4721 nerror += imtHelper.GetNerrors();
4722 }
4723#endif
4724
4725 if (fBranchRef)
4726 fBranchRef->Fill();
4727
4728 ++fEntries;
4729
4730 if (fEntries > fMaxEntries)
4731 KeepCircular();
4732
4733 if (gDebug > 0)
4734 Info("TTree::Fill", " - A: %d %lld %lld %lld %lld %lld %lld \n", nbytes, fEntries, fAutoFlush, fAutoSave,
4736
4737 bool autoFlush = false;
4738 bool autoSave = false;
4739
4740 if (fAutoFlush != 0 || fAutoSave != 0) {
4741 // Is it time to flush or autosave baskets?
4742 if (fFlushedBytes == 0) {
4743 // If fFlushedBytes == 0, it means we never flushed or saved, so
4744 // we need to check if it's time to do it and recompute the values
4745 // of fAutoFlush and fAutoSave in terms of the number of entries.
4746 // Decision can be based initially either on the number of bytes
4747 // or the number of entries written.
4749
4750 if (fAutoFlush)
4752
4753 if (fAutoSave)
4754 autoSave = fAutoSave < 0 ? (zipBytes > -fAutoSave) : fEntries % fAutoSave == 0;
4755
4756 if (autoFlush || autoSave) {
4757 // First call FlushBasket to make sure that fTotBytes is up to date.
4759 autoFlush = false; // avoid auto flushing again later
4760
4761 // When we are in one-basket-per-cluster mode, there is no need to optimize basket:
4762 // they will automatically grow to the size needed for an event cluster (with the basket
4763 // shrinking preventing them from growing too much larger than the actually-used space).
4765 OptimizeBaskets(GetTotBytes(), 1, "");
4766 if (gDebug > 0)
4767 Info("TTree::Fill", "OptimizeBaskets called at entry %lld, fZipBytes=%lld, fFlushedBytes=%lld\n",
4769 }
4771 fAutoFlush = fEntries; // Use test on entries rather than bytes
4772
4773 // subsequently in run
4774 if (fAutoSave < 0) {
4775 // Set fAutoSave to the largest integer multiple of
4776 // fAutoFlush events such that fAutoSave*fFlushedBytes
4777 // < (minus the input value of fAutoSave)
4779 if (zipBytes != 0) {
4781 } else if (totBytes != 0) {
4783 } else {
4785 TTree::Class()->WriteBuffer(b, (TTree *)this);
4786 Long64_t total = b.Length();
4788 }
4789 } else if (fAutoSave > 0) {
4791 }
4792
4793 if (fAutoSave != 0 && fEntries >= fAutoSave)
4794 autoSave = true;
4795
4796 if (gDebug > 0)
4797 Info("TTree::Fill", "First AutoFlush. fAutoFlush = %lld, fAutoSave = %lld\n", fAutoFlush, fAutoSave);
4798 }
4799 } else {
4800 // Check if we need to auto flush
4801 if (fAutoFlush) {
4802 if (fNClusterRange == 0)
4803 autoFlush = fEntries > 1 && fEntries % fAutoFlush == 0;
4804 else
4806 }
4807 // Check if we need to auto save
4808 if (fAutoSave)
4809 autoSave = fEntries % fAutoSave == 0;
4810 }
4811 }
4812
4813 if (autoFlush) {
4815 if (gDebug > 0)
4816 Info("TTree::Fill", "FlushBaskets() called at entry %lld, fZipBytes=%lld, fFlushedBytes=%lld\n", fEntries,
4819 }
4820
4821 if (autoSave) {
4822 AutoSave(); // does not call FlushBasketsImpl() again
4823 if (gDebug > 0)
4824 Info("TTree::Fill", "AutoSave called at entry %lld, fZipBytes=%lld, fSavedBytes=%lld\n", fEntries,
4826 }
4827
4828 // Check that output file is still below the maximum size.
4829 // If above, close the current file and continue on a new file.
4830 // Currently, the automatic change of file is restricted
4831 // to the case where the tree is in the top level directory.
4832 if (fDirectory)
4833 if (TFile *file = fDirectory->GetFile())
4834 if (static_cast<TDirectory *>(file) == fDirectory && (file->GetEND() > fgMaxTreeSize))
4835 ChangeFile(file);
4836
4837 return nerror == 0 ? nbytes : -1;
4838}
4839
4840////////////////////////////////////////////////////////////////////////////////
4841/// Search in the array for a branch matching the branch name,
4842/// with the branch possibly expressed as a 'full' path name (with dots).
4844static TBranch *R__FindBranchHelper(TObjArray *list, const char *branchname) {
4845 if (list==nullptr || branchname == nullptr || branchname[0] == '\0') return nullptr;
4846
4847 Int_t nbranches = list->GetEntries();
4848
4850
4851 for(Int_t index = 0; index < nbranches; ++index) {
4852 TBranch *where = (TBranch*)list->UncheckedAt(index);
4853
4854 const char *name = where->GetName();
4855 UInt_t len = strlen(name);
4856 if (len && name[len - 1] == ']' && (brlen == 0 || branchname[brlen - 1] != ']')) {
4857 const char *dim = strchr(name,'[');
4858 if (dim) {
4859 len = dim - name;
4860 }
4861 }
4862 if (brlen == len && strncmp(branchname,name,len)==0) {
4863 return where;
4864 }
4865 TBranch *next = nullptr;
4866 if ((brlen >= len) && (branchname[len] == '.')
4867 && strncmp(name, branchname, len) == 0) {
4868 // The prefix subbranch name match the branch name.
4869
4870 next = where->FindBranch(branchname);
4871 if (!next) {
4872 next = where->FindBranch(branchname+len+1);
4873 }
4874 if (next) return next;
4875 }
4876 const char *dot = strchr((char*)branchname,'.');
4877 if (dot) {
4878 if (len==(size_t)(dot-branchname) &&
4879 strncmp(branchname,name,dot-branchname)==0 ) {
4880 return R__FindBranchHelper(where->GetListOfBranches(),dot+1);
4881 }
4882 }
4883 }
4884 return nullptr;
4885}
4887TBranch *TTree::FindBranchFromSelf(const char *branchName)
4888{
4889 // If the first part of the name match the TTree name, look for the right part in the
4890 // list of branches. This will allow the branchName to be preceded by the name of this tree.
4891 if (strncmp(fName.Data(), branchName, fName.Length()) == 0 && branchName[fName.Length()] == '.')
4892 if (auto *br = R__FindBranchHelper(GetListOfBranches(), branchName + fName.Length() + 1))
4893 return br;
4894
4895 // If we did not find it, let's try to find the full name in the list of branches.
4896 if (auto *br = R__FindBranchHelper(GetListOfBranches(), branchName))
4897 return br;
4898
4899 // If we still did not find, let's try to find it within each branch assuming it does not contain the branch name.
4901 if (auto *nestedbranch = branch->FindBranch(branchName))
4902 return nestedbranch;
4903
4904 return nullptr;
4905}
4907TBranch *TTree::FindBranchFromFriends(const char *branchName)
4908{
4909 if (!fFriends) {
4910 return nullptr;
4911 }
4912
4913 TFriendLock lock(this, kFindBranch);
4915 TTree *t = frEl->GetTree();
4916 if (!t) {
4917 continue;
4918 }
4919 // If the alias is present replace it with the real name.
4920 const char *subbranch = strstr(branchName, frEl->GetName());
4921 if (subbranch != branchName) {
4922 subbranch = nullptr;
4923 }
4924 if (subbranch) {
4925 subbranch += strlen(frEl->GetName());
4926 if (*subbranch != '.') {
4927 subbranch = nullptr;
4928 } else {
4929 ++subbranch;
4930 }
4931 }
4932 std::ostringstream name;
4933 if (subbranch) {
4934 name << t->GetName() << "." << subbranch;
4935 } else {
4936 name << branchName;
4937 }
4938 if (auto *br = t->FindBranch(name.str().c_str()))
4939 return br;
4940 }
4941
4942 return nullptr;
4943}
4944
4945////////////////////////////////////////////////////////////////////////////////
4946/// Return the branch that correspond to the path 'branchname', which can
4947/// include the name of the tree or the omitted name of the parent branches.
4948/// In case of ambiguity, returns the first match.
4949/// \sa TTree::GetBranch
4952{
4953 // We already have been visited while recursively looking
4954 // through the friends tree, let return
4956 return nullptr;
4957 }
4958
4959 if (!branchname)
4960 return nullptr;
4961
4962 if (auto *br = FindBranchFromSelf(branchname))
4963 return br;
4964
4965 if (auto *br = FindBranchFromFriends(branchname))
4966 return br;
4967
4968 return nullptr;
4969}
4970
4971////////////////////////////////////////////////////////////////////////////////
4972/// Find first leaf containing searchname.
4974TLeaf* TTree::FindLeaf(const char* searchname)
4975{
4976 if (!searchname)
4977 return nullptr;
4978
4979 // We already have been visited while recursively looking
4980 // through the friends tree, let's return.
4982 return nullptr;
4983 }
4984
4985 // This will allow the branchname to be preceded by
4986 // the name of this tree.
4987 const char* subsearchname = strstr(searchname, GetName());
4988 if (subsearchname != searchname) {
4989 subsearchname = nullptr;
4990 }
4991 if (subsearchname) {
4993 if (*subsearchname != '.') {
4994 subsearchname = nullptr;
4995 } else {
4996 ++subsearchname;
4997 if (subsearchname[0] == 0) {
4998 subsearchname = nullptr;
4999 }
5000 }
5001 }
5002
5007
5008 const bool searchnameHasDot = strchr(searchname, '.') != nullptr;
5009
5010 // For leaves we allow for one level up to be prefixed to the name.
5011 TIter next(GetListOfLeaves());
5012 TLeaf* leaf = nullptr;
5013 while ((leaf = (TLeaf*) next())) {
5014 leafname = leaf->GetName();
5015 Ssiz_t dim = leafname.First('[');
5016 if (dim >= 0) leafname.Remove(dim);
5017
5018 if (leafname == searchname) {
5019 return leaf;
5020 }
5022 return leaf;
5023 }
5024 // The TLeafElement contains the branch name
5025 // in its name, let's use the title.
5026 leaftitle = leaf->GetTitle();
5027 dim = leaftitle.First('[');
5028 if (dim >= 0) leaftitle.Remove(dim);
5029
5030 if (leaftitle == searchname) {
5031 return leaf;
5032 }
5034 return leaf;
5035 }
5036 if (!searchnameHasDot)
5037 continue;
5038 TBranch* branch = leaf->GetBranch();
5039 if (branch) {
5040 longname.Form("%s.%s",branch->GetName(),leafname.Data());
5041 dim = longname.First('[');
5042 if (dim>=0) longname.Remove(dim);
5043 if (longname == searchname) {
5044 return leaf;
5045 }
5047 return leaf;
5048 }
5049 longtitle.Form("%s.%s",branch->GetName(),leaftitle.Data());
5050 dim = longtitle.First('[');
5051 if (dim>=0) longtitle.Remove(dim);
5052 if (longtitle == searchname) {
5053 return leaf;
5054 }
5056 return leaf;
5057 }
5058 // The following is for the case where the branch is only
5059 // a sub-branch. Since we do not see it through
5060 // TTree::GetListOfBranches, we need to see it indirectly.
5061 // This is the less sturdy part of this search ... it may
5062 // need refining ...
5063 if (strstr(searchname, ".") && !strcmp(searchname, branch->GetName())) {
5064 return leaf;
5065 }
5066 if (subsearchname && strstr(subsearchname, ".") && !strcmp(subsearchname, branch->GetName())) {
5067 return leaf;
5068 }
5069 }
5070 }
5071 // Search in list of friends.
5072 if (!fFriends) {
5073 return nullptr;
5074 }
5075 TFriendLock lock(this, kFindLeaf);
5077 TFriendElement* fe = nullptr;
5078 while ((fe = (TFriendElement*) nextf())) {
5079 TTree* t = fe->GetTree();
5080 if (!t) {
5081 continue;
5082 }
5083 // If the alias is present replace it with the real name.
5084 subsearchname = strstr(searchname, fe->GetName());
5085 if (subsearchname != searchname) {
5086 subsearchname = nullptr;
5087 }
5088 if (subsearchname) {
5089 subsearchname += strlen(fe->GetName());
5090 if (*subsearchname != '.') {
5091 subsearchname = nullptr;
5092 } else {
5093 ++subsearchname;
5094 }
5095 }
5096 if (subsearchname) {
5097 leafname.Form("%s.%s",t->GetName(),subsearchname);
5098 } else {
5100 }
5101 leaf = t->FindLeaf(leafname);
5102 if (leaf) {
5103 return leaf;
5104 }
5105 }
5106 return nullptr;
5107}
5108
5109////////////////////////////////////////////////////////////////////////////////
5110/// Fit a projected item(s) from a tree.
5111///
5112/// funcname is a TF1 function.
5113///
5114/// See TTree::Draw() for explanations of the other parameters.
5115///
5116/// By default the temporary histogram created is called htemp.
5117/// If varexp contains >>hnew , the new histogram created is called hnew
5118/// and it is kept in the current directory.
5119///
5120/// The function returns the number of selected entries.
5121///
5122/// Example:
5123/// ~~~ {.cpp}
5124/// tree.Fit(pol4,"sqrt(x)>>hsqrt","y>0")
5125/// ~~~
5126/// will fit sqrt(x) and save the histogram as "hsqrt" in the current
5127/// directory.
5128///
5129/// See also TTree::UnbinnedFit
5130///
5131/// ## Return status
5132///
5133/// The function returns the status of the histogram fit (see TH1::Fit)
5134/// If no entries were selected, the function returns -1;
5135/// (i.e. fitResult is null if the fit is OK)
5138{
5139 GetPlayer();
5140 if (fPlayer) {
5142 }
5143 return -1;
5144}
5145
5146namespace {
5147struct BoolRAIIToggle {
5148 bool &m_val;
5149
5150 BoolRAIIToggle(bool &val) : m_val(val) { m_val = true; }
5151 ~BoolRAIIToggle() { m_val = false; }
5152};
5153}
5154
5155////////////////////////////////////////////////////////////////////////////////
5156/// Write to disk all the basket that have not yet been individually written and
5157/// create an event cluster boundary (by default).
5158///
5159/// If the caller wishes to flush the baskets but not create an event cluster,
5160/// then set create_cluster to false.
5161///
5162/// If ROOT has IMT-mode enabled, this will launch multiple TBB tasks in parallel
5163/// via TThreadExecutor to do this operation; one per basket compression. If the
5164/// caller utilizes TBB also, care must be taken to prevent deadlocks.
5165///
5166/// For example, let's say the caller holds mutex A and calls FlushBaskets; while
5167/// TBB is waiting for the ROOT compression tasks to complete, it may decide to
5168/// run another one of the user's tasks in this thread. If the second user task
5169/// tries to acquire A, then a deadlock will occur. The example call sequence
5170/// looks like this:
5171///
5172/// - User acquires mutex A
5173/// - User calls FlushBaskets.
5174/// - ROOT launches N tasks and calls wait.
5175/// - TBB schedules another user task, T2.
5176/// - T2 tries to acquire mutex A.
5177///
5178/// At this point, the thread will deadlock: the code may function with IMT-mode
5179/// disabled if the user assumed the legacy code never would run their own TBB
5180/// tasks.
5181///
5182/// SO: users of TBB who want to enable IMT-mode should carefully review their
5183/// locking patterns and make sure they hold no coarse-grained application
5184/// locks when they invoke ROOT.
5185///
5186/// Return the number of bytes written or -1 in case of write error.
5188{
5190 if (retval == -1) return retval;
5191
5192 if (create_cluster) const_cast<TTree *>(this)->MarkEventCluster();
5193 return retval;
5194}
5195
5196////////////////////////////////////////////////////////////////////////////////
5197/// Internal implementation of the FlushBaskets algorithm.
5198/// Unlike the public interface, this does NOT create an explicit event cluster
5199/// boundary; it is up to the (internal) caller to determine whether that should
5200/// done.
5201///
5202/// Otherwise, the comments for FlushBaskets applies.
5205{
5206 if (!fDirectory) return 0;
5207 Int_t nbytes = 0;
5208 Int_t nerror = 0;
5209 TObjArray *lb = const_cast<TTree*>(this)->GetListOfBranches();
5210 Int_t nb = lb->GetEntriesFast();
5211
5212#ifdef R__USE_IMT
5214 if (useIMT) {
5215 // ROOT-9668: here we need to check if the size of fSortedBranches is different from the
5216 // size of the list of branches before triggering the initialisation of the fSortedBranches
5217 // container to cover two cases:
5218 // 1. This is the first time we flush. fSortedBranches is empty and we need to fill it.
5219 // 2. We flushed at least once already but a branch has been be added to the tree since then
5220 if (fSortedBranches.size() != unsigned(nb)) { const_cast<TTree*>(this)->InitializeBranchLists(false); }
5221
5222 BoolRAIIToggle sentry(fIMTFlush);
5223 fIMTZipBytes.store(0);
5224 fIMTTotBytes.store(0);
5225 std::atomic<Int_t> nerrpar(0);
5226 std::atomic<Int_t> nbpar(0);
5227 std::atomic<Int_t> pos(0);
5228
5229 auto mapFunction = [&]() {
5230 // The branch to process is obtained when the task starts to run.
5231 // This way, since branches are sorted, we make sure that branches
5232 // leading to big tasks are processed first. If we assigned the
5233 // branch at task creation time, the scheduler would not necessarily
5234 // respect our sorting.
5235 Int_t j = pos.fetch_add(1);
5236
5237 auto branch = fSortedBranches[j].second;
5238 if (R__unlikely(!branch)) { return; }
5239
5240 if (R__unlikely(gDebug > 0)) {
5241 std::stringstream ss;
5242 ss << std::this_thread::get_id();
5243 Info("FlushBaskets", "[IMT] Thread %s", ss.str().c_str());
5244 Info("FlushBaskets", "[IMT] Running task for branch #%d: %s", j, branch->GetName());
5245 }
5246
5247 Int_t nbtask = branch->FlushBaskets();
5248
5249 if (nbtask < 0) { nerrpar++; }
5250 else { nbpar += nbtask; }
5251 };
5252
5254 pool.Foreach(mapFunction, nb);
5255
5256 fIMTFlush = false;
5257 const_cast<TTree*>(this)->AddTotBytes(fIMTTotBytes);
5258 const_cast<TTree*>(this)->AddZipBytes(fIMTZipBytes);
5259
5260 return nerrpar ? -1 : nbpar.load();
5261 }
5262#endif
5263 for (Int_t j = 0; j < nb; j++) {
5264 TBranch* branch = (TBranch*) lb->UncheckedAt(j);
5265 if (branch) {
5266 Int_t nwrite = branch->FlushBaskets();
5267 if (nwrite<0) {
5268 ++nerror;
5269 } else {
5270 nbytes += nwrite;
5271 }
5272 }
5273 }
5274 if (nerror) {
5275 return -1;
5276 } else {
5277 return nbytes;
5278 }
5279}
5280
5281////////////////////////////////////////////////////////////////////////////////
5282/// Returns the expanded value of the alias. Search in the friends if any.
5284const char* TTree::GetAlias(const char* aliasName) const
5285{
5286 // We already have been visited while recursively looking
5287 // through the friends tree, let's return.
5289 return nullptr;
5290 }
5291 if (fAliases) {
5293 if (alias) {
5294 return alias->GetTitle();
5295 }
5296 }
5297 if (!fFriends) {
5298 return nullptr;
5299 }
5300 TFriendLock lock(const_cast<TTree*>(this), kGetAlias);
5302 TFriendElement* fe = nullptr;
5303 while ((fe = (TFriendElement*) nextf())) {
5304 TTree* t = fe->GetTree();
5305 if (t) {
5306 const char* alias = t->GetAlias(aliasName);
5307 if (alias) {
5308 return alias;
5309 }
5310 const char* subAliasName = strstr(aliasName, fe->GetName());
5311 if (subAliasName && (subAliasName[strlen(fe->GetName())] == '.')) {
5312 alias = t->GetAlias(aliasName + strlen(fe->GetName()) + 1);
5313 if (alias) {
5314 return alias;
5315 }
5316 }
5317 }
5318 }
5319 return nullptr;
5320}
5321
5322namespace {
5323/// Do a breadth first search through the implied hierarchy
5324/// of branches.
5325/// To avoid scanning through the list multiple time
5326/// we also remember the 'depth-first' match.
5327TBranch *R__GetBranch(const TObjArray &branches, const char *name)
5328{
5329 TBranch *result = nullptr;
5330 Int_t nb = branches.GetEntriesFast();
5331 for (Int_t i = 0; i < nb; i++) {
5332 TBranch* b = (TBranch*)branches.UncheckedAt(i);
5333 if (!b)
5334 continue;
5335 if (!strcmp(b->GetName(), name)) {
5336 return b;
5337 }
5338 if (!strcmp(b->GetFullName(), name)) {
5339 return b;
5340 }
5341 if (!result)
5342 result = R__GetBranch(*(b->GetListOfBranches()), name);
5343 }
5344 return result;
5345}
5346}
5347
5348////////////////////////////////////////////////////////////////////////////////
5349/// Returns a pointer to the branch with the given name, if it can be found in
5350/// this tree. Otherwise, returns nullptr.
5351TBranch *TTree::GetBranchFromSelf(const char *branchName)
5352{
5353 // Look for an exact match in the list of top level
5354 // branches.
5355 if (auto *br = static_cast<TBranch *>(fBranches.FindObject(branchName)))
5356 return br;
5357
5358 // Look for an exact match in the mapping from branch name to TBranch *
5359 // gathered when first reading the TTree from disk.
5360 if (auto it = fNamesToBranches.find(branchName); it != fNamesToBranches.end())
5361 return it->second;
5362
5363 // Search using branches, breadth first.
5364 if (auto *br = R__GetBranch(fBranches, branchName))
5365 return br;
5366
5367 // Search using leaves.
5369 Int_t nleaves = leaves->GetEntriesFast();
5370 for (Int_t i = 0; i < nleaves; i++) {
5371 TLeaf *leaf = (TLeaf *)leaves->UncheckedAt(i);
5372 TBranch *branch = leaf->GetBranch();
5373 if (!strcmp(branch->GetName(), branchName)) {
5374 return branch;
5375 }
5376 if (!strcmp(branch->GetFullName(), branchName)) {
5377 return branch;
5378 }
5379 }
5380
5381 return nullptr;
5382}
5383
5384////////////////////////////////////////////////////////////////////////////////
5385/// Returns a pointer to the branch with the given name, if it can be found in
5386/// the list of friends of this tree. Otherwise, returns nullptr.
5387TBranch *TTree::GetBranchFromFriends(const char *branchName)
5388{
5389 if (!fFriends) {
5390 return nullptr;
5391 }
5392
5393 // Search in list of friends.
5394 TFriendLock lock(this, kGetBranch);
5395 TIter next(fFriends);
5396 TFriendElement *fe = nullptr;
5397 while ((fe = (TFriendElement *)next())) {
5398 TTree *t = fe->GetTree();
5399 if (t) {
5400 TBranch *branch = t->GetBranch(branchName);
5401 if (branch) {
5402 return branch;
5403 }
5404 }
5405 }
5406
5407 // Second pass in the list of friends when
5408 // the branch name is prefixed by the tree name.
5409 next.Reset();
5410 while ((fe = (TFriendElement *)next())) {
5411 TTree *t = fe->GetTree();
5412 if (!t) {
5413 continue;
5414 }
5415 const char *subname = strstr(branchName, fe->GetName());
5416 if (subname != branchName) {
5417 continue;
5418 }
5419 Int_t l = strlen(fe->GetName());
5420 subname += l;
5421 if (*subname != '.') {
5422 continue;
5423 }
5424 subname++;
5426 if (branch) {
5427 return branch;
5428 }
5429 }
5430
5431 return nullptr;
5432}
5433
5434////////////////////////////////////////////////////////////////////////////////
5435/// Return pointer to the branch with the given name in this tree or its friends.
5436/// The search is done breadth first.
5437/// \sa TTree::FindBranch
5439TBranch *TTree::GetBranch(const char *name)
5440{
5441 // We already have been visited while recursively
5442 // looking through the friends tree, let's return.
5444 return nullptr;
5445 }
5446
5447 if (!name)
5448 return nullptr;
5449
5450 if (auto *br = GetBranchFromSelf(name))
5451 return br;
5452
5453 if (auto *br = GetBranchFromFriends(name))
5454 return br;
5455
5456 return nullptr;
5457}
5458
5459////////////////////////////////////////////////////////////////////////////////
5460/// Return status of branch with name branchname.
5461///
5462/// - 0 if branch is not activated
5463/// - 1 if branch is activated
5465bool TTree::GetBranchStatus(const char* branchname) const
5466{
5467 TBranch* br = const_cast<TTree*>(this)->GetBranch(branchname);
5468 if (br) {
5469 return br->TestBit(kDoNotProcess) == 0;
5470 }
5471 return false;
5472}
5473
5474////////////////////////////////////////////////////////////////////////////////
5475/// Static function returning the current branch style.
5476///
5477/// - style = 0 old Branch
5478/// - style = 1 new Bronch
5483}
5484
5485////////////////////////////////////////////////////////////////////////////////
5486/// Used for automatic sizing of the cache.
5487///
5488/// Estimates a suitable size in bytes for the tree cache based on AutoFlush.
5489/// A cache sizing factor is taken from the configuration. If this yields zero
5490/// and withDefault is true the historical algorithm for default size is used.
5492Long64_t TTree::GetCacheAutoSize(bool withDefault /* = false */ )
5493{
5495 {
5496 Long64_t cacheSize = 0;
5497 if (fAutoFlush < 0) {
5498 cacheSize = Long64_t(-cacheFactor * fAutoFlush);
5499 } else if (fAutoFlush == 0) {
5501 if (medianClusterSize > 0)
5502 cacheSize = Long64_t(cacheFactor * 1.5 * medianClusterSize * GetZipBytes() / (fEntries + 1));
5503 else
5504 cacheSize = Long64_t(cacheFactor * 1.5 * 30000000); // use the default value of fAutoFlush
5505 } else {
5506 cacheSize = Long64_t(cacheFactor * 1.5 * fAutoFlush * GetZipBytes() / (fEntries + 1));
5507 }
5508 if (cacheSize >= (INT_MAX / 4)) {
5509 cacheSize = INT_MAX / 4;
5510 }
5511 return cacheSize;
5512 };
5513
5514 const char *stcs;
5515 Double_t cacheFactor = 0.0;
5516 if (!(stcs = gSystem->Getenv("ROOT_TTREECACHE_SIZE")) || !*stcs) {
5517 cacheFactor = gEnv->GetValue("TTreeCache.Size", 1.0);
5518 } else {
5520 }
5521
5522 if (cacheFactor < 0.0) {
5523 // ignore negative factors
5524 cacheFactor = 0.0;
5525 }
5526
5528
5529 if (cacheSize < 0) {
5530 cacheSize = 0;
5531 }
5532
5533 if (cacheSize == 0 && withDefault) {
5534 cacheSize = calculateCacheSize(1.0);
5535 }
5536
5537 return cacheSize;
5538}
5539
5540////////////////////////////////////////////////////////////////////////////////
5541/// Return an iterator over the cluster of baskets starting at firstentry.
5542///
5543/// This iterator is not yet supported for TChain object.
5544/// ~~~ {.cpp}
5545/// TTree::TClusterIterator clusterIter = tree->GetClusterIterator(entry);
5546/// Long64_t clusterStart;
5547/// while( (clusterStart = clusterIter()) < tree->GetEntries() ) {
5548/// printf("The cluster starts at %lld and ends at %lld (inclusive)\n",clusterStart,clusterIter.GetNextEntry()-1);
5549/// }
5550/// ~~~
5553{
5554 // create cache if wanted
5555 if (fCacheDoAutoInit)
5557
5558 return TClusterIterator(this,firstentry);
5559}
5560
5561////////////////////////////////////////////////////////////////////////////////
5562/// Return pointer to the current file.
5565{
5566 if (!fDirectory || fDirectory==gROOT) {
5567 return nullptr;
5568 }
5569 return fDirectory->GetFile();
5570}
5571
5572////////////////////////////////////////////////////////////////////////////////
5573/// Return the number of entries matching the selection.
5574/// Return -1 in case of errors.
5575///
5576/// If the selection uses any arrays or containers, we return the number
5577/// of entries where at least one element match the selection.
5578/// GetEntries is implemented using the selector class TSelectorEntries,
5579/// which can be used directly (see code in TTreePlayer::GetEntries) for
5580/// additional option.
5581/// If SetEventList was used on the TTree or TChain, only that subset
5582/// of entries will be considered.
5585{
5586 GetPlayer();
5587 if (fPlayer) {
5588 return fPlayer->GetEntries(selection);
5589 }
5590 return -1;
5591}
5592
5593////////////////////////////////////////////////////////////////////////////////
5594/// Returns a number corresponding to:
5595/// - The number of entries in this tree, if greater than zero
5596/// - The number of entries in the first friend tree, if there are any friends
5597/// - 0 otherwise
5600{
5601 if (fEntries) return fEntries;
5602 if (!fFriends) return 0;
5604 if (!fr) return 0;
5605 TTree *t = fr->GetTree();
5606 if (t==nullptr) return 0;
5607 return t->GetEntriesFriend();
5608}
5609
5610////////////////////////////////////////////////////////////////////////////////
5611/// Read all branches of entry and return total number of bytes read.
5612///
5613/// - `getall = 0` : get only active branches
5614/// - `getall = 1` : get all branches
5615///
5616/// The function returns the number of bytes read from the input buffer.
5617/// If entry does not exist the function returns 0.
5618/// If an I/O error occurs, the function returns -1.
5619/// If all branches are disabled and getall == 0, it also returns 0
5620/// even if the specified entry exists in the tree, since zero bytes were read.
5621///
5622/// If the Tree has friends, also read the friends entry.
5623///
5624/// To activate/deactivate one or more branches, use TBranch::SetBranchStatus
5625/// For example, if you have a Tree with several hundred branches, and you
5626/// are interested only by branches named "a" and "b", do
5627/// ~~~ {.cpp}
5628/// mytree.SetBranchStatus("*",0); //disable all branches
5629/// mytree.SetBranchStatus("a",1);
5630/// mytree.SetBranchStatus("b",1);
5631/// ~~~
5632/// when calling mytree.GetEntry(i); only branches "a" and "b" will be read.
5633///
5634/// __WARNING!!__
5635/// If your Tree has been created in split mode with a parent branch "parent.",
5636/// ~~~ {.cpp}
5637/// mytree.SetBranchStatus("parent",1);
5638/// ~~~
5639/// will not activate the sub-branches of "parent". You should do:
5640/// ~~~ {.cpp}
5641/// mytree.SetBranchStatus("parent*",1);
5642/// ~~~
5643/// Without the trailing dot in the branch creation you have no choice but to
5644/// call SetBranchStatus explicitly for each of the sub branches.
5645///
5646/// An alternative is to call directly
5647/// ~~~ {.cpp}
5648/// brancha.GetEntry(i)
5649/// branchb.GetEntry(i);
5650/// ~~~
5651/// ## IMPORTANT NOTE
5652///
5653/// By default, GetEntry reuses the space allocated by the previous object
5654/// for each branch. You can force the previous object to be automatically
5655/// deleted if you call mybranch.SetAutoDelete(true) (default is false).
5656///
5657/// Example:
5658///
5659/// Consider the example in $ROOTSYS/test/Event.h
5660/// The top level branch in the tree T is declared with:
5661/// ~~~ {.cpp}
5662/// Event *event = 0; //event must be null or point to a valid object
5663/// //it must be initialized
5664/// T.SetBranchAddress("event",&event);
5665/// ~~~
5666/// When reading the Tree, one can choose one of these 3 options:
5667///
5668/// ## OPTION 1
5669///
5670/// ~~~ {.cpp}
5671/// for (Long64_t i=0;i<nentries;i++) {
5672/// T.GetEntry(i);
5673/// // the object event has been filled at this point
5674/// }
5675/// ~~~
5676/// The default (recommended). At the first entry an object of the class
5677/// Event will be created and pointed by event. At the following entries,
5678/// event will be overwritten by the new data. All internal members that are
5679/// TObject* are automatically deleted. It is important that these members
5680/// be in a valid state when GetEntry is called. Pointers must be correctly
5681/// initialized. However these internal members will not be deleted if the
5682/// characters "->" are specified as the first characters in the comment
5683/// field of the data member declaration.
5684///
5685/// If "->" is specified, the pointer member is read via pointer->Streamer(buf).
5686/// In this case, it is assumed that the pointer is never null (case of
5687/// pointer TClonesArray *fTracks in the Event example). If "->" is not
5688/// specified, the pointer member is read via buf >> pointer. In this case
5689/// the pointer may be null. Note that the option with "->" is faster to
5690/// read or write and it also consumes less space in the file.
5691///
5692/// ## OPTION 2
5693///
5694/// The option AutoDelete is set
5695/// ~~~ {.cpp}
5696/// TBranch *branch = T.GetBranch("event");
5697/// branch->SetAddress(&event);
5698/// branch->SetAutoDelete(true);
5699/// for (Long64_t i=0;i<nentries;i++) {
5700/// T.GetEntry(i);
5701/// // the object event has been filled at this point
5702/// }
5703/// ~~~
5704/// In this case, at each iteration, the object event is deleted by GetEntry
5705/// and a new instance of Event is created and filled.
5706///
5707/// ## OPTION 3
5708///
5709/// ~~~ {.cpp}
5710/// Same as option 1, but you delete yourself the event.
5711///
5712/// for (Long64_t i=0;i<nentries;i++) {
5713/// delete event;
5714/// event = 0; // EXTREMELY IMPORTANT
5715/// T.GetEntry(i);
5716/// // the object event has been filled at this point
5717/// }
5718/// ~~~
5719/// It is strongly recommended to use the default option 1. It has the
5720/// additional advantage that functions like TTree::Draw (internally calling
5721/// TTree::GetEntry) will be functional even when the classes in the file are
5722/// not available.
5723///
5724/// Note: See the comments in TBranchElement::SetAddress() for the
5725/// object ownership policy of the underlying (user) data.
5728{
5729 // We already have been visited while recursively looking
5730 // through the friends tree, let return
5731 if (kGetEntry & fFriendLockStatus) return 0;
5732
5733 if (entry < 0 || entry >= fEntries) return 0;
5734 Int_t i;
5735 Int_t nbytes = 0;
5736 fReadEntry = entry;
5737
5738 // create cache if wanted
5739 if (fCacheDoAutoInit)
5741
5743 Int_t nb=0;
5744
5745 auto seqprocessing = [&]() {
5746 TBranch *branch;
5747 for (i=0;i<nbranches;i++) {
5749 nb = branch->GetEntry(entry, getall);
5750 if (nb < 0) break;
5751 nbytes += nb;
5752 }
5753 };
5754
5755#ifdef R__USE_IMT
5757 if (fSortedBranches.empty())
5759
5760 // Count branches are processed first and sequentially
5761 for (auto branch : fSeqBranches) {
5762 nb = branch->GetEntry(entry, getall);
5763 if (nb < 0) break;
5764 nbytes += nb;
5765 }
5766 if (nb < 0) return nb;
5767
5768 // Enable this IMT use case (activate its locks)
5770
5771 Int_t errnb = 0;
5772 std::atomic<Int_t> pos(0);
5773 std::atomic<Int_t> nbpar(0);
5774
5775 auto mapFunction = [&]() {
5776 // The branch to process is obtained when the task starts to run.
5777 // This way, since branches are sorted, we make sure that branches
5778 // leading to big tasks are processed first. If we assigned the
5779 // branch at task creation time, the scheduler would not necessarily
5780 // respect our sorting.
5781 Int_t j = pos.fetch_add(1);
5782
5783 Int_t nbtask = 0;
5784 auto branch = fSortedBranches[j].second;
5785
5786 if (gDebug > 0) {
5787 std::stringstream ss;
5788 ss << std::this_thread::get_id();
5789 Info("GetEntry", "[IMT] Thread %s", ss.str().c_str());
5790 Info("GetEntry", "[IMT] Running task for branch #%d: %s", j, branch->GetName());
5791 }
5792
5793 std::chrono::time_point<std::chrono::system_clock> start, end;
5794
5795 start = std::chrono::system_clock::now();
5796 nbtask = branch->GetEntry(entry, getall);
5797 end = std::chrono::system_clock::now();
5798
5799 Long64_t tasktime = (Long64_t)std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
5800 fSortedBranches[j].first += tasktime;
5801
5802 if (nbtask < 0) errnb = nbtask;
5803 else nbpar += nbtask;
5804 };
5805
5807 pool.Foreach(mapFunction, fSortedBranches.size());
5808
5809 if (errnb < 0) {
5810 nb = errnb;
5811 }
5812 else {
5813 // Save the number of bytes read by the tasks
5814 nbytes += nbpar;
5815
5816 // Re-sort branches if necessary
5820 }
5821 }
5822 }
5823 else {
5824 seqprocessing();
5825 }
5826#else
5827 seqprocessing();
5828#endif
5829 if (nb < 0) return nb;
5830
5831 // GetEntry in list of friends
5832 if (!fFriends) return nbytes;
5833 TFriendLock lock(this,kGetEntry);
5836 while ((fe = (TFriendElement*)nextf())) {
5837 TTree *t = fe->GetTree();
5838 if (t) {
5839 if (fe->TestBit(TFriendElement::kFromChain)) {
5840 nb = t->GetEntry(t->GetReadEntry(),getall);
5841 } else {
5842 if ( t->LoadTreeFriend(entry,this) >= 0 ) {
5843 nb = t->GetEntry(t->GetReadEntry(),getall);
5844 } else nb = 0;
5845 }
5846 if (nb < 0) return nb;
5847 nbytes += nb;
5848 }
5849 }
5850 return nbytes;
5851}
5852
5853
5854////////////////////////////////////////////////////////////////////////////////
5855/// Divides the top-level branches into two vectors: (i) branches to be
5856/// processed sequentially and (ii) branches to be processed in parallel.
5857/// Even if IMT is on, some branches might need to be processed first and in a
5858/// sequential fashion: in the parallelization of GetEntry, those are the
5859/// branches that store the size of another branch for every entry
5860/// (e.g. the size of an array branch). If such branches were processed
5861/// in parallel with the rest, there could be two threads invoking
5862/// TBranch::GetEntry on one of them at the same time, since a branch that
5863/// depends on a size (or count) branch will also invoke GetEntry on the latter.
5864/// This method can be invoked several times during the event loop if the TTree
5865/// is being written, for example when adding new branches. In these cases, the
5866/// `checkLeafCount` parameter is false.
5867/// \param[in] checkLeafCount True if we need to check whether some branches are
5868/// count leaves.
5871{
5873
5874 // The special branch fBranchRef needs to be processed sequentially:
5875 // we add it once only.
5876 if (fBranchRef && fBranchRef != fSeqBranches[0]) {
5877 fSeqBranches.push_back(fBranchRef);
5878 }
5879
5880 // The branches to be processed sequentially are those that are the leaf count of another branch
5881 if (checkLeafCount) {
5882 for (Int_t i = 0; i < nbranches; i++) {
5884 auto leafCount = ((TLeaf*)branch->GetListOfLeaves()->At(0))->GetLeafCount();
5885 if (leafCount) {
5886 auto countBranch = leafCount->GetBranch();
5887 if (std::find(fSeqBranches.begin(), fSeqBranches.end(), countBranch) == fSeqBranches.end()) {
5888 fSeqBranches.push_back(countBranch);
5889 }
5890 }
5891 }
5892 }
5893
5894 // Any branch that is not a leaf count can be safely processed in parallel when reading
5895 // We need to reset the vector to make sure we do not re-add several times the same branch.
5896 if (!checkLeafCount) {
5897 fSortedBranches.clear();
5898 }
5899 for (Int_t i = 0; i < nbranches; i++) {
5900 Long64_t bbytes = 0;
5902 if (std::find(fSeqBranches.begin(), fSeqBranches.end(), branch) == fSeqBranches.end()) {
5903 bbytes = branch->GetTotBytes("*");
5904 fSortedBranches.emplace_back(bbytes, branch);
5905 }
5906 }
5907
5908 // Initially sort parallel branches by size
5909 std::sort(fSortedBranches.begin(),
5910 fSortedBranches.end(),
5911 [](std::pair<Long64_t,TBranch*> a, std::pair<Long64_t,TBranch*> b) {
5912 return a.first > b.first;
5913 });
5914
5915 for (size_t i = 0; i < fSortedBranches.size(); i++) {
5916 fSortedBranches[i].first = 0LL;
5917 }
5918}
5919
5920////////////////////////////////////////////////////////////////////////////////
5921/// Sorts top-level branches by the last average task time recorded per branch.
5924{
5925 for (size_t i = 0; i < fSortedBranches.size(); i++) {
5927 }
5928
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///Returns the entry list assigned to this tree
5944{
5945 return fEntryList;
5946}
5947
5948////////////////////////////////////////////////////////////////////////////////
5949/// Return entry number corresponding to entry.
5950///
5951/// if no TEntryList set returns entry
5952/// else returns the entry number corresponding to the list index=entry
5955{
5956 if (!fEntryList) {
5957 return entry;
5958 }
5959
5960 return fEntryList->GetEntry(entry);
5961}
5962
5963////////////////////////////////////////////////////////////////////////////////
5964/// Return entry number corresponding to major and minor number.
5965/// Note that this function returns only the entry number, not the data
5966/// To read the data corresponding to an entry number, use TTree::GetEntryWithIndex
5967/// the BuildIndex function has created a table of Long64_t* of sorted values
5968/// corresponding to val = major<<31 + minor;
5969/// The function performs binary search in this sorted table.
5970/// If it finds a pair that matches val, it returns directly the
5971/// index in the table.
5972/// If an entry corresponding to major and minor is not found, the function
5973/// returns the index of the major,minor pair immediately lower than the
5974/// requested value, ie it will return -1 if the pair is lower than
5975/// the first entry in the index.
5976///
5977/// See also GetEntryNumberWithIndex
5985}
5986
5987////////////////////////////////////////////////////////////////////////////////
5988/// Return entry number corresponding to major and minor number.
5989/// Note that this function returns only the entry number, not the data
5990/// To read the data corresponding to an entry number, use TTree::GetEntryWithIndex
5991/// the BuildIndex function has created a table of Long64_t* of sorted values
5992/// corresponding to val = major<<31 + minor;
5993/// The function performs binary search in this sorted table.
5994/// If it finds a pair that matches val, it returns directly the
5995/// index in the table, otherwise it returns -1.
5996///
5997/// See also GetEntryNumberWithBestIndex
6000{
6001 if (!fTreeIndex) {
6002 return -1;
6003 }
6005}
6006
6007////////////////////////////////////////////////////////////////////////////////
6008/// Read entry corresponding to major and minor number.
6009///
6010/// The function returns the total number of bytes read; -1 if entry not found.
6011/// If the Tree has friend trees, the corresponding entry with
6012/// the index values (major,minor) is read. Note that the master Tree
6013/// and its friend may have different entry serial numbers corresponding
6014/// to (major,minor).
6015/// \note See TTreeIndex::GetEntryNumberWithIndex for information about the maximum values accepted for major and minor
6018{
6019 // We already have been visited while recursively looking
6020 // through the friends tree, let's return.
6022 return 0;
6023 }
6025 if (serial < 0) {
6026 return -1;
6027 }
6028 // create cache if wanted
6029 if (fCacheDoAutoInit)
6031
6032 Int_t i;
6033 Int_t nbytes = 0;
6034 fReadEntry = serial;
6035 TBranch *branch;
6037 Int_t nb;
6038 for (i = 0; i < nbranches; ++i) {
6040 nb = branch->GetEntry(serial);
6041 if (nb < 0) return nb;
6042 nbytes += nb;
6043 }
6044 // GetEntry in list of friends
6045 if (!fFriends) return nbytes;
6048 TFriendElement* fe = nullptr;
6049 while ((fe = (TFriendElement*) nextf())) {
6050 TTree *t = fe->GetTree();
6051 if (t) {
6052 serial = t->GetEntryNumberWithIndex(major,minor);
6053 if (serial <0) return -nbytes;
6054 nb = t->GetEntry(serial);
6055 if (nb < 0) return nb;
6056 nbytes += nb;
6057 }
6058 }
6059 return nbytes;
6060}
6061
6062////////////////////////////////////////////////////////////////////////////////
6063/// Return a pointer to the TTree friend whose name or alias is `friendname`.
6065TTree* TTree::GetFriend(const char *friendname) const
6066{
6067
6068 // We already have been visited while recursively
6069 // looking through the friends tree, let's return.
6071 return nullptr;
6072 }
6073 if (!fFriends) {
6074 return nullptr;
6075 }
6076 TFriendLock lock(const_cast<TTree*>(this), kGetFriend);
6078 TFriendElement* fe = nullptr;
6079 while ((fe = (TFriendElement*) nextf())) {
6080 if (strcmp(friendname,fe->GetName())==0
6081 || strcmp(friendname,fe->GetTreeName())==0) {
6082 return fe->GetTree();
6083 }
6084 }
6085 // After looking at the first level,
6086 // let's see if it is a friend of friends.
6087 nextf.Reset();
6088 fe = nullptr;
6089 while ((fe = (TFriendElement*) nextf())) {
6090 TTree *res = fe->GetTree()->GetFriend(friendname);
6091 if (res) {
6092 return res;
6093 }
6094 }
6095 return nullptr;
6096}
6097
6098////////////////////////////////////////////////////////////////////////////////
6099/// If the 'tree' is a friend, this method returns its alias name.
6100///
6101/// This alias is an alternate name for the tree.
6102///
6103/// It can be used in conjunction with a branch or leaf name in a TTreeFormula,
6104/// to specify in which particular tree the branch or leaf can be found if
6105/// the friend trees have branches or leaves with the same name as the master
6106/// tree.
6107///
6108/// It can also be used in conjunction with an alias created using
6109/// TTree::SetAlias in a TTreeFormula, e.g.:
6110/// ~~~ {.cpp}
6111/// maintree->Draw("treealias.fPx - treealias.myAlias");
6112/// ~~~
6113/// where fPx is a branch of the friend tree aliased as 'treealias' and 'myAlias'
6114/// was created using TTree::SetAlias on the friend tree.
6115///
6116/// However, note that 'treealias.myAlias' will be expanded literally,
6117/// without remembering that it comes from the aliased friend and thus
6118/// the branch name might not be disambiguated properly, which means
6119/// that you may not be able to take advantage of this feature.
6120///
6122const char *TTree::GetFriendAlias(TTree *tree) const
6123{
6124 if ((tree == this) || (tree == GetTree())) {
6125 return nullptr;
6126 }
6127
6128 // We already have been visited while recursively
6129 // looking through the friends tree, let's return.
6131 return nullptr;
6132 }
6133
6134 // This is a TTree and it does not have any friends, we can return early
6135 if (GetTree() == this && !fFriends)
6136 return nullptr;
6137
6138 TFriendLock lock(const_cast<TTree *>(this), kGetFriendAlias);
6139
6140 auto lookForFriendNameInListOfFriends = [tree](const TList &friends) -> const char * {
6142 auto *frElTree = frEl->GetTree();
6143 // Simplest case: we found a friend which tree is the same as the input tree
6144 if (frElTree == tree)
6145 return frEl->GetName();
6146 // Try again: the friend tree might be actually a TChain
6147 if (frElTree && frElTree->GetTree() == tree)
6148 return frEl->GetName();
6149 }
6150 return nullptr;
6151 };
6152
6153 // First, look for the immediate friends of this tree
6154 if (fFriends) {
6156 if (friendAlias)
6157 return friendAlias;
6158 }
6159
6160 // Then, check if this is a TChain and the current tree has friends
6161 // The non-redundant scenario here is that the currently-available
6162 // inner TTree of this TChain has a list of friends which the TChain
6163 // itself doesn't know anything about.
6164 if (const auto *innerListOfFriends = GetTree()->GetListOfFriends();
6167 if (friendAlias)
6168 return friendAlias;
6169 }
6170
6171 // Recursively look into the list of friends of this tree
6172 if (fFriends) {
6174 const char *friendAlias = frEl->GetTree()->GetFriendAlias(tree);
6175 if (friendAlias)
6176 return friendAlias;
6177 }
6178 }
6179
6180 // Recursively look into the list of friends of the inner tree
6181 if (const auto *innerListOfFriends = GetTree()->GetListOfFriends();
6184 const char *friendAlias = frEl->GetTree()->GetFriendAlias(tree);
6185 if (friendAlias)
6186 return friendAlias;
6187 }
6188 }
6189 return nullptr;
6190}
6191
6192////////////////////////////////////////////////////////////////////////////////
6193/// Returns the current set of IO settings
6195{
6196 return fIOFeatures;
6197}
6198
6199////////////////////////////////////////////////////////////////////////////////
6200/// Creates a new iterator that will go through all the leaves on the tree itself and its friend.
6203{
6204 return new TTreeFriendLeafIter(this, dir);
6205}
6207TLeaf *TTree::SearchLeafInListOfLeaves(const char *branchName, const char *leafName)
6208{
6210 if (strcmp(leaf->GetFullName(), leafName) != 0 && strcmp(leaf->GetName(), leafName) != 0)
6211 continue; // leafName does not match GetName() nor GetFullName(), this is not the right leaf
6212 if (branchName) {
6213 // check the branchName is also a match
6214 TBranch *br = leaf->GetBranch();
6215 // if a quick comparison with the branch full name is a match, we are done
6216 if (!strcmp(br->GetFullName(), branchName))
6217 return leaf;
6218 UInt_t nbch = strlen(branchName);
6219 const char* brname = br->GetName();
6220 TBranch *mother = br->GetMother();
6221 if (strncmp(brname, branchName, nbch)) {
6222 if (mother != br) {
6223 const char *mothername = mother->GetName();
6225 if (!strcmp(mothername, branchName)) {
6226 return leaf;
6227 } else if (nbch > motherlen && strncmp(mothername, branchName, motherlen) == 0 &&
6228 (mothername[motherlen - 1] == '.' || branchName[motherlen] == '.')) {
6229 // 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.
6230 if (strncmp(brname, branchName + motherlen + 1, nbch - motherlen - 1)) {
6231 // No it does not
6232 continue;
6233 } // else we have match so we can proceed.
6234 } else {
6235 // no match
6236 continue;
6237 }
6238 } else {
6239 continue;
6240 }
6241 }
6242 // The start of the branch name is identical to the content
6243 // of 'aname' before the first '/'.
6244 // Let's make sure that it is not longer (we are trying
6245 // to avoid having jet2/value match the branch jet23
6246 if ((strlen(brname) > nbch) && (brname[nbch] != '.') && (brname[nbch] != '[')) {
6247 continue;
6248 }
6249 }
6250 return leaf;
6251 }
6252
6253 return nullptr;
6254}
6256TLeaf *TTree::SearchLeafInListOfFriends(const char *branchName, const char *leafName)
6257{
6258 if (!fFriends) return nullptr;
6259 // The corresponding check is in GetLeaf
6260 TFriendLock lock(this, kGetLeaf);
6261
6263 if (auto *t = frEl->GetTree())
6264 if (auto *leaf = t->GetLeaf(branchName, leafName))
6265 return leaf;
6266
6267 // Second pass in the list of friends when the leaf name is prefixed by the tree name
6270 TTree *t = frEl->GetTree();
6271 if (!t) continue;
6272 const char *subLeafName = strstr(leafName, frEl->GetName());
6273 if (subLeafName != leafName)
6274 continue;
6275 Int_t l = strlen(frEl->GetName());
6276 subLeafName += l;
6277 if (*subLeafName != '.')
6278 continue;
6279 subLeafName++;
6281 if (auto *leaf = t->GetLeaf(branchName, subLeafName))
6282 return leaf;
6283 }
6284
6285 return nullptr;
6286}
6287
6288////////////////////////////////////////////////////////////////////////////////
6289/// Searches in this tree and any of its friends for a leaf named \p leafname in branch \p branchname , returns first
6290/// match or nullptr if no match.
6291///
6292/// Search order:
6293///
6294/// 1. Look for a \p branchname match (via FindBranch(branchname)):
6295/// a. In the list of branches of this tree
6296/// b. Recursively in nested branches of each branch of this tree
6297/// c. In the friends of this tree
6298/// 2. Look for matching \p branchname and \p leafname in list of leaves of this tree
6299/// 3. Look for matching \p branchname and \p leafname in friends of this tree (eventually calling GetLeaf on each
6300/// friend)
6301///
6302/// \note \p branchname can be an empty string, in which case the function will return the first leaf with matching
6303/// \p leafname in any branch of this tree or any of its friends following the search order above.
6304///
6305/// \note \p leafname can contain the name of a friend tree with the syntax: `friend_dir_and_tree.full_leaf_name`. In
6306/// particular, `friend_dir_and_tree` can be of the form `TDirectoryName/TreeName`.
6307TLeaf* TTree::GetLeaf(const char* branchname, const char *leafname)
6308{
6309 if (leafname == nullptr) return nullptr;
6310
6311 // We already have been visited while recursively looking
6312 // through the friends tree, let return
6314 return nullptr;
6315 }
6316
6317 if (auto *br = FindBranch(branchname))
6318 if (auto leaf = br->GetLeaf(leafname))
6319 return leaf;
6320
6322 return leaf;
6323
6325 return leaf;
6326
6327 return nullptr;
6328}
6329
6330////////////////////////////////////////////////////////////////////////////////
6331/// Searches in this tree and any of its friends for a leaf named \p leafname , returns first leaf matching in any
6332/// branch.
6333///
6334/// See TTree::GetLeaf(const char* branchname, const char *leafname) for a description of the search order.
6335///
6336/// \note \p name may be in the form `branch/leaf`
6338TLeaf* TTree::GetLeaf(const char *name)
6339{
6340 // Return nullptr if name is invalid or if we have
6341 // already been visited while searching friend trees
6342 if (!name || (kGetLeaf & fFriendLockStatus))
6343 return nullptr;
6344
6345 std::string path(name);
6346 const auto sep = path.find_last_of('/');
6347 if (sep != std::string::npos)
6348 return GetLeaf(path.substr(0, sep).c_str(), name + sep + 1);
6349
6350 return GetLeaf(nullptr, name);
6351}
6352
6353namespace {
6354
6355////////////////////////////////////////////////////////////////////////////////
6356/// \brief Helper detecting *any* file transition of a tree dataset
6357///
6358/// This is a generic helper, works if the dataset is a TTree or a TChain, and
6359/// transitively detects transitions in friends.
6360///
6361/// Comparing `TChain::GetTreeNumber()` before and after a call to
6362/// `TChain::LoadTree` only detects that the chain itself switched to another of
6363/// its own sub-trees. It does *not* detect that one of the (possibly indirect)
6364/// friends of the chain switched to a new file: in that case the cached
6365/// TLeaf/TBranch pointers become dangling even though the tree number of the
6366/// chain is unchanged.
6367///
6368/// `TChain::LoadTree` (both when the chain itself moves to a new tree and, via
6369/// `TChain::RefreshFriendAddresses`, when only a friend was updated) calls
6370/// `fNotify->Notify()`. Subscribing to that notification is therefore the
6371/// reliable way to know that anything in the friend graph moved.
6372///
6373/// This derives directly from TNotifyLinkBase rather than using TNotifyLink<T>
6374/// because the latter would require a dictionary for the instantiation.
6375///
6376/// We could also use
6377/// ```
6378/// struct TLeafRefresher {
6379/// bool fDirty = true;
6380/// bool Notify() { fDirty = true; return true; }
6381/// };
6382/// ```
6383/// declared in TChain.h or InternalTreeUtils.hxx and genereate a dictionary for
6384/// TNotifyLink<TLeafRefresher>.
6385class FileTransitionDetector final : public TNotifyLinkBase {
6386 /// Set to true initially so that the very first iteration performs the lookup.
6387 bool fChanged = true;
6388 TTree &fChain;
6389
6390public:
6391 FileTransitionDetector(TTree &chain) : fChain(chain) { PrependLink(fChain); }
6392
6393 ~FileTransitionDetector() override { RemoveLink(fChain); }
6394 FileTransitionDetector(const FileTransitionDetector &) = delete;
6395 FileTransitionDetector &operator=(const FileTransitionDetector &) = delete;
6396 FileTransitionDetector(FileTransitionDetector &&) = delete;
6397 FileTransitionDetector &operator=(FileTransitionDetector &&) = delete;
6398
6399 /// Must return true: returning false would make TChain::LoadTree fail with -6.
6400 Bool_t Notify() override
6401 {
6402 fChanged = true;
6403 // Propagate to the rest of the list of subscribers, as TNotifyLink does.
6404 if (fNext)
6405 return fNext->Notify();
6406 return true;
6407 }
6408
6409 /// Returns true (once) if the chain or any of its direct or indirect friends
6410 /// switched to a new tree since the last call.
6411 bool CheckAndReset()
6412 {
6413 bool changed = fChanged;
6414 fChanged = false;
6415 return changed;
6416 }
6417};
6418} // anonymous namespace
6419
6420////////////////////////////////////////////////////////////////////////////////
6421/// Computes the extremum (minimum or maximum) for the input column name
6422///
6423/// It takes into account the following situations:
6424///
6425/// * The dataset is a TTree and contains the input column
6426/// * The dataset is a TChain and contains the input column, in which case the methods detect file switching and update
6427/// the leaf pointer correctly.
6428/// * The dataset is a TChain, contains the input column, but some files miss it, in which case the methods skip the
6429/// entries from those files.
6430/// * The dataset has a friend TTree which contains the input column
6431/// * The dataset is a TChain and has a friend TChain which contains the input column, in which case the methods detect
6432/// file switching on the friend and update the leaf pointer correctly.
6433/// * The dataset is a TChain and has a friend TChain. The input column is partially available in either the main or the
6434/// friend chain. This can happen for example if the main chain has some files missing the input column and the user
6435/// knowingly injects the input column in the files of the friend chain. In this case, the methods detect file switching
6436/// at the boundary between files of the main chain, but also detect if there are file switches in the friend chain.
6437/// Notably, the entries must still be overall aligned between the main chain and the friend one.
6438double TTree::ComputeExtremum(const char *columname, double errVal, bool (*cmp)(double, double))
6439{
6440 // Ensure the TTree cursor is brought back to the current entry after computing the value
6441 struct CurrentEntryRAII {
6442
6443 Long64_t fCurrentEntry;
6444 TTree &fTree;
6445
6446 CurrentEntryRAII(TTree &tree) : fCurrentEntry(tree.GetReadEntry()), fTree(tree) {}
6447
6448 ~CurrentEntryRAII() { fTree.LoadTree(fCurrentEntry); }
6449 } raii{*this};
6450
6451 // Initial lookup of the leaf name, this will find it whether it's in the
6452 // current tree or in any of its friends
6454 if (!leaf) {
6455 return 0;
6456 }
6457 TBranch *branch = leaf->GetBranch();
6458 assert(branch); // leaf without a branch is not allowed by construction
6459
6460 // create cache if wanted
6461 if (fCacheDoAutoInit)
6463
6464 FileTransitionDetector fileTransition{*this};
6465 double extremum{errVal};
6466 for (Long64_t i = 0; i < fEntries; ++i) {
6467 const auto entryNumber = GetEntryNumber(i);
6468 if (entryNumber < 0) break;
6470 if (localEntryNumber < 0)
6471 break;
6472
6473 // At every entry, we check if the processing has triggered a switch to
6474 // a new file. We detect both a switch of the current tree in the chain
6475 // (if this tree is a TChain) as well as a switch in any of its direct
6476 // and indirect friends (if they are also a TChain)
6477 if (fileTransition.CheckAndReset()) {
6478 branch = nullptr;
6480 if (leaf) {
6481 branch = leaf->GetBranch();
6482 assert(branch); // leaf without a branch is not allowed by construction
6483 }
6484 }
6485
6486 // We accept that the leaf may not be present in one or more files in case
6487 // it was found in a chain, we just continue processing the next entry
6488 if (!leaf)
6489 continue;
6490
6491 // If the branch belongs to a friend, the local entry number of the friend
6492 // may differ from the one of the chain (e.g. when the friend is indexed).
6493 // The owning TTree has already been positioned by TChain::LoadTree, so
6494 // its read entry is the correct one to use.
6495 auto *owningTree = branch->GetTree();
6496 branch->GetEntry(owningTree->GetReadEntry());
6497
6498 auto leafLen{leaf->GetLen()};
6499 for (decltype(leafLen) j = 0; j < leafLen; ++j) {
6500 auto val = leaf->GetValue(j);
6501 if (cmp(val, extremum)) {
6502 extremum = val;
6503 }
6504 }
6505 }
6506
6507 return extremum;
6508}
6509
6510////////////////////////////////////////////////////////////////////////////////
6511/// Return maximum of column with name columname.
6512/// if the Tree has an associated TEventList or TEntryList, the maximum
6513/// is computed for the entries in this list.
6516{
6517 return ComputeExtremum(columname, std::numeric_limits<double>::lowest(), [](double a, double b) { return a > b; });
6518}
6519
6520////////////////////////////////////////////////////////////////////////////////
6521/// Static function which returns the tree file size limit in bytes.
6526}
6527
6528////////////////////////////////////////////////////////////////////////////////
6529/// Return minimum of column with name columname.
6530/// if the Tree has an associated TEventList or TEntryList, the minimum
6531/// is computed for the entries in this list.
6534{
6535 return ComputeExtremum(columname, std::numeric_limits<double>::max(), [](double a, double b) { return a < b; });
6536}
6537
6538////////////////////////////////////////////////////////////////////////////////
6539/// Load the TTreePlayer (if not already done).
6542{
6543 if (fPlayer) {
6544 return fPlayer;
6545 }
6547 return fPlayer;
6548}
6549
6550////////////////////////////////////////////////////////////////////////////////
6551/// Find and return the TTreeCache registered with the file and which may
6552/// contain branches for us.
6555{
6556 TTreeCache *pe = dynamic_cast<TTreeCache*>(file->GetCacheRead(GetTree()));
6557 if (pe && pe->GetTree() != GetTree())
6558 pe = nullptr;
6559 return pe;
6560}
6561
6562////////////////////////////////////////////////////////////////////////////////
6563/// Find and return the TTreeCache registered with the file and which may
6564/// contain branches for us. If create is true and there is no cache
6565/// a new cache is created with default size.
6567TTreeCache *TTree::GetReadCache(TFile *file, bool create)
6568{
6569 TTreeCache *pe = GetReadCache(file);
6570 if (create && !pe) {
6571 if (fCacheDoAutoInit)
6572 SetCacheSizeAux(true, -1);
6573 pe = dynamic_cast<TTreeCache*>(file->GetCacheRead(GetTree()));
6574 if (pe && pe->GetTree() != GetTree()) pe = nullptr;
6575 }
6576 return pe;
6577}
6578
6579////////////////////////////////////////////////////////////////////////////////
6580/// Return a pointer to the list containing user objects associated to this tree.
6581///
6582/// The list is automatically created if it does not exist.
6583///
6584/// WARNING: By default the TTree destructor will delete all objects added
6585/// to this list. If you do not want these objects to be deleted,
6586/// call:
6587///
6588/// mytree->GetUserInfo()->Clear();
6589///
6590/// before deleting the tree.
6593{
6594 if (!fUserInfo) {
6595 fUserInfo = new TList();
6596 fUserInfo->SetName("UserInfo");
6597 }
6598 return fUserInfo;
6599}
6600
6601////////////////////////////////////////////////////////////////////////////////
6602/// Appends the cluster range information stored in 'fromtree' to this tree,
6603/// including the value of fAutoFlush.
6604///
6605/// This is used when doing a fast cloning (by TTreeCloner).
6606/// See also fAutoFlush and fAutoSave if needed.
6609{
6610 Long64_t autoflush = fromtree->GetAutoFlush();
6611 if (fromtree->fNClusterRange == 0 && fromtree->fAutoFlush == fAutoFlush) {
6612 // nothing to do
6613 } else if (fNClusterRange || fromtree->fNClusterRange) {
6614 Int_t newsize = fNClusterRange + 1 + fromtree->fNClusterRange;
6615 if (newsize > fMaxClusterRange) {
6616 if (fMaxClusterRange) {
6618 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
6620 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
6622 } else {
6626 }
6627 }
6628 if (fEntries) {
6632 }
6633 for (Int_t i = 0 ; i < fromtree->fNClusterRange; ++i) {
6634 fClusterRangeEnd[fNClusterRange] = fEntries + fromtree->fClusterRangeEnd[i];
6635 fClusterSize[fNClusterRange] = fromtree->fClusterSize[i];
6637 }
6639 } else {
6641 }
6643 if (autoflush > 0 && autosave > 0) {
6645 }
6646}
6647
6648////////////////////////////////////////////////////////////////////////////////
6649/// Keep a maximum of fMaxEntries in memory.
6652{
6655 for (Int_t i = 0; i < nb; ++i) {
6657 branch->KeepCircular(maxEntries);
6658 }
6659 if (fNClusterRange) {
6662 for(Int_t i = 0, j = 0; j < oldsize; ++j) {
6665 ++i;
6666 } else {
6668 }
6669 }
6670 }
6672 fReadEntry = -1;
6673}
6674
6675////////////////////////////////////////////////////////////////////////////////
6676/// Read in memory all baskets from all branches up to the limit of maxmemory bytes.
6677///
6678/// If maxmemory is non null and positive SetMaxVirtualSize is called
6679/// with this value. Default for maxmemory is 2000000000 (2 Gigabytes).
6680/// The function returns the total number of baskets read into memory
6681/// if negative an error occurred while loading the branches.
6682/// This method may be called to force branch baskets in memory
6683/// when random access to branch entries is required.
6684/// If random access to only a few branches is required, you should
6685/// call directly TBranch::LoadBaskets.
6688{
6690
6691 TIter next(GetListOfLeaves());
6692 TLeaf *leaf;
6693 Int_t nimported = 0;
6694 while ((leaf=(TLeaf*)next())) {
6695 nimported += leaf->GetBranch()->LoadBaskets();//break;
6696 }
6697 return nimported;
6698}
6699
6700////////////////////////////////////////////////////////////////////////////////
6701/// Set current entry.
6702///
6703/// Returns -2 if entry does not exist (just as TChain::LoadTree()).
6704/// Returns -6 if an error occurs in the notification callback (just as TChain::LoadTree()).
6705///
6706/// Calls fNotify->Notify() (if fNotify is not null) when starting the processing of a new tree.
6707///
6708/// \note This function is overloaded in TChain.
6710{
6711 // We have already been visited while recursively looking
6712 // through the friend trees, let's return
6714 // We need to return a negative value to avoid a circular list of friends
6715 // to think that there is always an entry somewhere in the list.
6716 return -1;
6717 }
6718
6719 // create cache if wanted
6720 if (fCacheDoAutoInit && entry >=0)
6722
6723 if (fNotify) {
6724 if (fReadEntry < 0) {
6725 fNotify->Notify();
6726 }
6727 }
6728 fReadEntry = entry;
6729
6730 bool friendHasEntry = false;
6731 if (fFriends) {
6732 // Set current entry in friends as well.
6733 //
6734 // An alternative would move this code to each of the
6735 // functions calling LoadTree (and to overload a few more).
6736 bool needUpdate = false;
6737 {
6738 // This scope is need to insure the lock is released at the right time
6740 TFriendLock lock(this, kLoadTree);
6741 TFriendElement* fe = nullptr;
6742 while ((fe = (TFriendElement*) nextf())) {
6743 if (fe->TestBit(TFriendElement::kFromChain)) {
6744 // This friend element was added by the chain that owns this
6745 // tree, the chain will deal with loading the correct entry.
6746 continue;
6747 }
6748 TTree* friendTree = fe->GetTree();
6749 if (friendTree) {
6750 if (friendTree->LoadTreeFriend(entry, this) >= 0) {
6751 friendHasEntry = true;
6752 }
6753 }
6754 if (fe->IsUpdated()) {
6755 needUpdate = true;
6756 fe->ResetUpdated();
6757 }
6758 } // for each friend
6759 }
6760 if (needUpdate) {
6761 //update list of leaves in all TTreeFormula of the TTreePlayer (if any)
6762 if (fPlayer) {
6764 }
6765 //Notify user if requested
6766 if (fNotify) {
6767 if(!fNotify->Notify()) return -6;
6768 }
6769 // We cannot know a priori if the branch(es) of the friend TChain(s) that were just
6770 // updated were supposed to be connected to possibly a TChainElement of another chain
6771 // that has befriended this TTree (i.e., one of the "external friends"). Thus, we
6772 // forward the notification that one or more friend trees were updated to the friends
6773 // of this TTree.
6774 if (fExternalFriends)
6776 external_fe->MarkUpdated();
6777 }
6778 }
6779
6780 if ((fReadEntry >= fEntries) && !friendHasEntry) {
6781 fReadEntry = -1;
6782 return -2;
6783 }
6784 return fReadEntry;
6785}
6786
6787////////////////////////////////////////////////////////////////////////////////
6788/// Load entry on behalf of our master tree, we may use an index.
6789///
6790/// Called by LoadTree() when the masterTree looks for the entry
6791/// number in a friend tree (us) corresponding to the passed entry
6792/// number in the masterTree.
6793///
6794/// If we have no index, our entry number and the masterTree entry
6795/// number are the same.
6796///
6797/// If we *do* have an index, we must find the (major, minor) value pair
6798/// in masterTree to locate our corresponding entry.
6799///
6807}
6808
6809////////////////////////////////////////////////////////////////////////////////
6810/// Generate a skeleton analysis class for this tree.
6811///
6812/// The following files are produced: classname.h and classname.C.
6813/// If classname is 0, classname will be called "nameoftree".
6814///
6815/// The generated code in classname.h includes the following:
6816///
6817/// - Identification of the original tree and the input file name.
6818/// - Definition of an analysis class (data members and member functions).
6819/// - The following member functions:
6820/// - constructor (by default opening the tree file),
6821/// - GetEntry(Long64_t entry),
6822/// - Init(TTree* tree) to initialize a new TTree,
6823/// - Show(Long64_t entry) to read and dump entry.
6824///
6825/// The generated code in classname.C includes only the main
6826/// analysis function Loop.
6827///
6828/// To use this function:
6829///
6830/// - Open your tree file (eg: TFile f("myfile.root");)
6831/// - T->MakeClass("MyClass");
6832///
6833/// where T is the name of the TTree in file myfile.root,
6834/// and MyClass.h, MyClass.C the name of the files created by this function.
6835/// In a ROOT session, you can do:
6836/// ~~~ {.cpp}
6837/// root > .L MyClass.C
6838/// root > MyClass* t = new MyClass;
6839/// root > t->GetEntry(12); // Fill data members of t with entry number 12.
6840/// root > t->Show(); // Show values of entry 12.
6841/// root > t->Show(16); // Read and show values of entry 16.
6842/// root > t->Loop(); // Loop on all entries.
6843/// ~~~
6844/// NOTE: Do not use the code generated for a single TTree which is part
6845/// of a TChain to process that entire TChain. The maximum dimensions
6846/// calculated for arrays on the basis of a single TTree from the TChain
6847/// might be (will be!) too small when processing all of the TTrees in
6848/// the TChain. You must use myChain.MakeClass() to generate the code,
6849/// not myTree.MakeClass(...).
6851Int_t TTree::MakeClass(const char* classname, Option_t* option)
6852{
6853 GetPlayer();
6854 if (!fPlayer) {
6855 return 0;
6856 }
6857 return fPlayer->MakeClass(classname, option);
6858}
6859
6860////////////////////////////////////////////////////////////////////////////////
6861/// Generate a skeleton function for this tree.
6862///
6863/// The function code is written on filename.
6864/// If filename is 0, filename will be called nameoftree.C
6865///
6866/// The generated code includes the following:
6867/// - Identification of the original Tree and Input file name,
6868/// - Opening the Tree file,
6869/// - Declaration of Tree variables,
6870/// - Setting of branches addresses,
6871/// - A skeleton for the entry loop.
6872///
6873/// To use this function:
6874///
6875/// - Open your Tree file (eg: TFile f("myfile.root");)
6876/// - T->MakeCode("MyAnalysis.C");
6877///
6878/// where T is the name of the TTree in file myfile.root
6879/// and MyAnalysis.C the name of the file created by this function.
6880///
6881/// NOTE: Since the implementation of this function, a new and better
6882/// function TTree::MakeClass() has been developed.
6884Int_t TTree::MakeCode(const char* filename)
6885{
6886 Warning("MakeCode", "MakeCode is obsolete. Use MakeClass or MakeSelector instead");
6887
6888 GetPlayer();
6889 if (!fPlayer) return 0;
6890 return fPlayer->MakeCode(filename);
6891}
6892
6893////////////////////////////////////////////////////////////////////////////////
6894/// Generate a skeleton analysis class for this Tree using TBranchProxy.
6895///
6896/// TBranchProxy is the base of a class hierarchy implementing an
6897/// indirect access to the content of the branches of a TTree.
6898///
6899/// "proxyClassname" is expected to be of the form:
6900/// ~~~ {.cpp}
6901/// [path/]fileprefix
6902/// ~~~
6903/// The skeleton will then be generated in the file:
6904/// ~~~ {.cpp}
6905/// fileprefix.h
6906/// ~~~
6907/// located in the current directory or in 'path/' if it is specified.
6908/// The class generated will be named 'fileprefix'
6909///
6910/// "macrofilename" and optionally "cutfilename" are expected to point
6911/// to source files which will be included by the generated skeleton.
6912/// Method of the same name as the file(minus the extension and path)
6913/// will be called by the generated skeleton's Process method as follow:
6914/// ~~~ {.cpp}
6915/// [if (cutfilename())] htemp->Fill(macrofilename());
6916/// ~~~
6917/// "option" can be used select some of the optional features during
6918/// the code generation. The possible options are:
6919///
6920/// - nohist : indicates that the generated ProcessFill should not fill the histogram.
6921///
6922/// 'maxUnrolling' controls how deep in the class hierarchy does the
6923/// system 'unroll' classes that are not split. Unrolling a class
6924/// allows direct access to its data members (this emulates the behavior
6925/// of TTreeFormula).
6926///
6927/// The main features of this skeleton are:
6928///
6929/// * on-demand loading of branches
6930/// * ability to use the 'branchname' as if it was a data member
6931/// * protection against array out-of-bounds errors
6932/// * ability to use the branch data as an object (when the user code is available)
6933///
6934/// For example with Event.root, if
6935/// ~~~ {.cpp}
6936/// Double_t somePx = fTracks.fPx[2];
6937/// ~~~
6938/// is executed by one of the method of the skeleton,
6939/// somePx will updated with the current value of fPx of the 3rd track.
6940///
6941/// Both macrofilename and the optional cutfilename are expected to be
6942/// the name of source files which contain at least a free standing
6943/// function with the signature:
6944/// ~~~ {.cpp}
6945/// x_t macrofilename(); // i.e function with the same name as the file
6946/// ~~~
6947/// and
6948/// ~~~ {.cpp}
6949/// y_t cutfilename(); // i.e function with the same name as the file
6950/// ~~~
6951/// x_t and y_t needs to be types that can convert respectively to a double
6952/// and a bool (because the skeleton uses:
6953///
6954/// if (cutfilename()) htemp->Fill(macrofilename());
6955///
6956/// These two functions are run in a context such that the branch names are
6957/// available as local variables of the correct (read-only) type.
6958///
6959/// Note that if you use the same 'variable' twice, it is more efficient
6960/// to 'cache' the value. For example:
6961/// ~~~ {.cpp}
6962/// Int_t n = fEventNumber; // Read fEventNumber
6963/// if (n<10 || n>10) { ... }
6964/// ~~~
6965/// is more efficient than
6966/// ~~~ {.cpp}
6967/// if (fEventNumber<10 || fEventNumber>10)
6968/// ~~~
6969/// Also, optionally, the generated selector will also call methods named
6970/// macrofilename_methodname in each of 6 main selector methods if the method
6971/// macrofilename_methodname exist (Where macrofilename is stripped of its
6972/// extension).
6973///
6974/// Concretely, with the script named h1analysisProxy.C,
6975///
6976/// - The method calls the method (if it exist)
6977/// - Begin -> void h1analysisProxy_Begin(TTree*);
6978/// - SlaveBegin -> void h1analysisProxy_SlaveBegin(TTree*);
6979/// - Notify -> bool h1analysisProxy_Notify();
6980/// - Process -> bool h1analysisProxy_Process(Long64_t);
6981/// - SlaveTerminate -> void h1analysisProxy_SlaveTerminate();
6982/// - Terminate -> void h1analysisProxy_Terminate();
6983///
6984/// If a file name macrofilename.h (or .hh, .hpp, .hxx, .hPP, .hXX) exist
6985/// it is included before the declaration of the proxy class. This can
6986/// be used in particular to insure that the include files needed by
6987/// the macro file are properly loaded.
6988///
6989/// The default histogram is accessible via the variable named 'htemp'.
6990///
6991/// If the library of the classes describing the data in the branch is
6992/// loaded, the skeleton will add the needed `include` statements and
6993/// give the ability to access the object stored in the branches.
6994///
6995/// To draw px using the file hsimple.root (generated by the
6996/// hsimple.C tutorial), we need a file named hsimple.cxx:
6997/// ~~~ {.cpp}
6998/// double hsimple() {
6999/// return px;
7000/// }
7001/// ~~~
7002/// MakeProxy can then be used indirectly via the TTree::Draw interface
7003/// as follow:
7004/// ~~~ {.cpp}
7005/// new TFile("hsimple.root")
7006/// ntuple->Draw("hsimple.cxx");
7007/// ~~~
7008/// A more complete example is available in the tutorials directory:
7009/// h1analysisProxy.cxx , h1analysProxy.h and h1analysisProxyCut.C
7010/// which reimplement the selector found in h1analysis.C
7012Int_t TTree::MakeProxy(const char* proxyClassname, const char* macrofilename, const char* cutfilename, const char* option, Int_t maxUnrolling)
7013{
7014 GetPlayer();
7015 if (!fPlayer) return 0;
7017}
7018
7019////////////////////////////////////////////////////////////////////////////////
7020/// Generate skeleton selector class for this tree.
7021///
7022/// The following files are produced: selector.h and selector.C.
7023/// If selector is 0, the selector will be called "nameoftree".
7024/// The option can be used to specify the branches that will have a data member.
7025/// - If option is "=legacy", a pre-ROOT6 selector will be generated (data
7026/// members and branch pointers instead of TTreeReaders).
7027/// - If option is empty, readers will be generated for each leaf.
7028/// - If option is "@", readers will be generated for the topmost branches.
7029/// - Individual branches can also be picked by their name:
7030/// - "X" generates readers for leaves of X.
7031/// - "@X" generates a reader for X as a whole.
7032/// - "@X;Y" generates a reader for X as a whole and also readers for the
7033/// leaves of Y.
7034/// - For further examples see the figure below.
7035///
7036/// \image html ttree_makeselector_option_examples.png
7037///
7038/// The generated code in selector.h includes the following:
7039/// - Identification of the original Tree and Input file name
7040/// - Definition of selector class (data and functions)
7041/// - The following class functions:
7042/// - constructor and destructor
7043/// - void Begin(TTree *tree)
7044/// - void SlaveBegin(TTree *tree)
7045/// - void Init(TTree *tree)
7046/// - bool Notify()
7047/// - bool Process(Long64_t entry)
7048/// - void Terminate()
7049/// - void SlaveTerminate()
7050///
7051/// The class selector derives from TSelector.
7052/// The generated code in selector.C includes empty functions defined above.
7053///
7054/// To use this function:
7055///
7056/// - connect your Tree file (eg: `TFile f("myfile.root");`)
7057/// - `T->MakeSelector("myselect");`
7058///
7059/// where T is the name of the Tree in file myfile.root
7060/// and myselect.h, myselect.C the name of the files created by this function.
7061/// In a ROOT session, you can do:
7062/// ~~~ {.cpp}
7063/// root > T->Process("myselect.C")
7064/// ~~~
7066Int_t TTree::MakeSelector(const char* selector, Option_t* option)
7067{
7068 TString opt(option);
7069 if(opt.EqualTo("=legacy", TString::ECaseCompare::kIgnoreCase)) {
7070 return MakeClass(selector, "selector");
7071 } else {
7072 GetPlayer();
7073 if (!fPlayer) return 0;
7074 return fPlayer->MakeReader(selector, option);
7075 }
7076}
7077
7078////////////////////////////////////////////////////////////////////////////////
7079/// Check if adding nbytes to memory we are still below MaxVirtualsize.
7082{
7084 return false;
7085 }
7086 return true;
7087}
7088
7089////////////////////////////////////////////////////////////////////////////////
7090/// Static function merging the trees in the TList into a new tree.
7091///
7092/// Trees in the list can be memory or disk-resident trees.
7093/// The new tree is created in the current directory (memory if gROOT).
7094/// Trees with no branches will be skipped, the branch structure
7095/// will be taken from the first non-zero-branch Tree of {li}
7098{
7099 if (!li) return nullptr;
7100 TIter next(li);
7101 TTree *newtree = nullptr;
7102 TObject *obj;
7103
7104 while ((obj=next())) {
7105 if (!obj->InheritsFrom(TTree::Class())) continue;
7106 TTree *tree = (TTree*)obj;
7107 if (tree->GetListOfBranches()->IsEmpty()) {
7108 if (gDebug > 2) {
7109 tree->Warning("MergeTrees","TTree %s has no branches, skipping.", tree->GetName());
7110 }
7111 continue; // Completely ignore the empty trees.
7112 }
7113 Long64_t nentries = tree->GetEntries();
7114 if (newtree && nentries == 0)
7115 continue; // If we already have the structure and we have no entry, save time and skip
7116 if (!newtree) {
7117 newtree = (TTree*)tree->CloneTree(-1, options);
7118 if (!newtree) continue;
7119
7120 // Once the cloning is done, separate the trees,
7121 // to avoid as many side-effects as possible
7122 // The list of clones is guaranteed to exist since we
7123 // just cloned the tree.
7124 tree->GetListOfClones()->Remove(newtree);
7125 tree->ResetBranchAddresses();
7126 newtree->ResetBranchAddresses();
7127 continue;
7128 }
7129 if (nentries == 0)
7130 continue;
7131 newtree->CopyEntries(tree, -1, options, true);
7132 }
7133 if (newtree && newtree->GetTreeIndex()) {
7134 newtree->GetTreeIndex()->Append(nullptr,false); // Force the sorting
7135 }
7136 return newtree;
7137}
7138
7139////////////////////////////////////////////////////////////////////////////////
7140/// Merge the trees in the TList into this tree.
7141///
7142/// Returns the total number of entries in the merged tree.
7143/// Trees with no branches will be skipped, the branch structure
7144/// will be taken from the first non-zero-branch Tree of {this+li}
7147{
7148 if (fBranches.IsEmpty()) {
7149 if (!li || li->IsEmpty())
7150 return 0; // Nothing to do ....
7151 // Let's find the first non-empty
7152 TIter next(li);
7153 TTree *tree;
7154 while ((tree = (TTree *)next())) {
7155 if (tree == this || tree->GetListOfBranches()->IsEmpty()) {
7156 if (gDebug > 2) {
7157 Warning("Merge","TTree %s has no branches, skipping.", tree->GetName());
7158 }
7159 continue;
7160 }
7161 // We could come from a list made up of different names, the first one still wins
7162 tree->SetName(this->GetName());
7163 auto prevEntries = tree->GetEntries();
7164 auto result = tree->Merge(li, options);
7165 if (result != prevEntries) {
7166 // If there is no additional entries, the first write was enough.
7167 tree->Write();
7168 }
7169 // Make sure things are really written out to disk before attempting any reading.
7170 if (tree->GetCurrentFile()) {
7171 tree->GetCurrentFile()->Flush();
7172 // Read back the complete info in this TTree, so that caller does not
7173 // inadvertently write the empty tree.
7174 tree->GetDirectory()->ReadTObject(this, this->GetName());
7175 }
7176 return result;
7177 }
7178 return 0; // All trees have empty branches
7179 }
7180 if (!li) return 0;
7182 // Disable the autosave as the TFileMerge keeps a list of key and deleting the underlying
7183 // key would invalidate its iteration (or require costly measure to not use the deleted keys).
7184 // Also since this is part of a merging operation, the output file is not as precious as in
7185 // the general case since the input file should still be around.
7186 fAutoSave = 0;
7187 TIter next(li);
7188 TTree *tree;
7189 while ((tree = (TTree*)next())) {
7190 if (tree==this) continue;
7191 if (!tree->InheritsFrom(TTree::Class())) {
7192 Error("Add","Attempt to add object of class: %s to a %s", tree->ClassName(), ClassName());
7194 return -1;
7195 }
7196
7197 Long64_t nentries = tree->GetEntries();
7198 if (nentries == 0) continue;
7199
7200 CopyEntries(tree, -1, options, true);
7201 }
7203 return GetEntries();
7204}
7205
7206////////////////////////////////////////////////////////////////////////////////
7207/// Merge the trees in the TList into this tree.
7208/// If info->fIsFirst is true, first we clone this TTree info the directory
7209/// info->fOutputDirectory and then overlay the new TTree information onto
7210/// this TTree object (so that this TTree object is now the appropriate to
7211/// use for further merging).
7212/// Trees with no branches will be skipped, the branch structure
7213/// will be taken from the first non-zero-branch Tree of {this+li}
7214///
7215/// Returns the total number of entries in the merged tree.
7218{
7219 if (fBranches.IsEmpty()) {
7220 if (!li || li->IsEmpty())
7221 return 0; // Nothing to do ....
7222 // Let's find the first non-empty
7223 TIter next(li);
7224 TTree *tree;
7225 while ((tree = (TTree *)next())) {
7226 if (tree == this || tree->GetListOfBranches()->IsEmpty()) {
7227 if (gDebug > 2) {
7228 Warning("Merge","TTree %s has no branches, skipping.", tree->GetName());
7229 }
7230 continue;
7231 }
7232 // We could come from a list made up of different names, the first one still wins
7233 tree->SetName(this->GetName());
7234 auto prevEntries = tree->GetEntries();
7235 auto result = tree->Merge(li, info);
7236 if (result != prevEntries) {
7237 // If there is no additional entries, the first write was enough.
7238 tree->Write();
7239 }
7240 // Make sure things are really written out to disk before attempting any reading.
7241 info->fOutputDirectory->GetFile()->Flush();
7242 // Read back the complete info in this TTree, so that TFileMerge does not
7243 // inadvertently write the empty tree.
7244 info->fOutputDirectory->ReadTObject(this, this->GetName());
7245 return result;
7246 }
7247 return 0; // All trees have empty branches
7248 }
7249 const char *options = info ? info->fOptions.Data() : "";
7250 if (info && info->fIsFirst && info->fOutputDirectory && info->fOutputDirectory->GetFile() != GetCurrentFile()) {
7251 if (GetCurrentFile() == nullptr) {
7252 // In memory TTree, all we need to do is ... write it.
7253 SetDirectory(info->fOutputDirectory);
7255 fDirectory->WriteTObject(this);
7256 } else if (info->fOptions.Contains("fast")) {
7257 InPlaceClone(info->fOutputDirectory);
7258 } else {
7259 TDirectory::TContext ctxt(info->fOutputDirectory);
7261 TTree *newtree = CloneTree(-1, options);
7262 if (info->fIOFeatures)
7263 fIOFeatures = *(info->fIOFeatures);
7264 else
7266 if (newtree) {
7267 newtree->Write();
7268 delete newtree;
7269 }
7270 // Make sure things are really written out to disk before attempting any reading.
7271 info->fOutputDirectory->GetFile()->Flush();
7272 info->fOutputDirectory->ReadTObject(this,this->GetName());
7273 }
7274 }
7275 if (!li) return 0;
7277 // Disable the autosave as the TFileMerge keeps a list of key and deleting the underlying
7278 // key would invalidate its iteration (or require costly measure to not use the deleted keys).
7279 // Also since this is part of a merging operation, the output file is not as precious as in
7280 // the general case since the input file should still be around.
7281 fAutoSave = 0;
7282 TIter next(li);
7283 TTree *tree;
7284 while ((tree = (TTree*)next())) {
7285 if (tree==this) continue;
7286 if (!tree->InheritsFrom(TTree::Class())) {
7287 Error("Add","Attempt to add object of class: %s to a %s", tree->ClassName(), ClassName());
7289 return -1;
7290 }
7291
7292 CopyEntries(tree, -1, options, true);
7293 }
7295 return GetEntries();
7296}
7297
7298////////////////////////////////////////////////////////////////////////////////
7299/// Move a cache from a file to the current file in dir.
7300/// if src is null no operation is done, if dir is null or there is no
7301/// current file the cache is deleted.
7304{
7305 if (!src) return;
7306 TFile *dst = (dir && dir != gROOT) ? dir->GetFile() : nullptr;
7307 if (src == dst) return;
7308
7310 if (dst) {
7311 src->SetCacheRead(nullptr,this);
7312 dst->SetCacheRead(pf, this);
7313 } else {
7314 if (pf) {
7315 pf->WaitFinishPrefetch();
7316 }
7317 src->SetCacheRead(nullptr,this);
7318 delete pf;
7319 }
7320}
7321
7322////////////////////////////////////////////////////////////////////////////////
7323/// Copy the content to a new new file, update this TTree with the new
7324/// location information and attach this TTree to the new directory.
7325///
7326/// options: Indicates a basket sorting method, see TTreeCloner::TTreeCloner for
7327/// details
7328///
7329/// If new and old directory are in the same file, the data is untouched,
7330/// this "just" does a call to SetDirectory.
7331/// Equivalent to an "in place" cloning of the TTree.
7332bool TTree::InPlaceClone(TDirectory *newdirectory, const char *options)
7333{
7334 if (!newdirectory) {
7336 SetDirectory(nullptr);
7337 return true;
7338 }
7339 if (newdirectory->GetFile() == GetCurrentFile()) {
7341 return true;
7342 }
7343 TTreeCloner cloner(this, newdirectory, options);
7344 if (cloner.IsValid())
7345 return cloner.Exec();
7346 else
7347 return false;
7348}
7349
7350////////////////////////////////////////////////////////////////////////////////
7351/// Function called when loading a new class library.
7353bool TTree::Notify()
7354{
7355 TIter next(GetListOfLeaves());
7356 TLeaf* leaf = nullptr;
7357 while ((leaf = (TLeaf*) next())) {
7358 leaf->Notify();
7359 leaf->GetBranch()->Notify();
7360 }
7361 return true;
7362}
7363
7364////////////////////////////////////////////////////////////////////////////////
7365/// This function may be called after having filled some entries in a Tree.
7366/// Using the information in the existing branch buffers, it will reassign
7367/// new branch buffer sizes to optimize time and memory.
7368///
7369/// The function computes the best values for branch buffer sizes such that
7370/// the total buffer sizes is less than maxMemory and nearby entries written
7371/// at the same time.
7372/// In case the branch compression factor for the data written so far is less
7373/// than compMin, the compression is disabled.
7374///
7375/// if option ="d" an analysis report is printed.
7378{
7379 //Flush existing baskets if the file is writable
7380 if (this->GetDirectory()->IsWritable()) this->FlushBasketsImpl();
7381
7382 TString opt( option );
7383 opt.ToLower();
7384 bool pDebug = opt.Contains("d");
7385 TObjArray *leaves = this->GetListOfLeaves();
7386 Int_t nleaves = leaves->GetEntries();
7388
7389 if (nleaves == 0 || treeSize == 0) {
7390 // We're being called too early, we really have nothing to do ...
7391 return;
7392 }
7394 UInt_t bmin = 512;
7395 UInt_t bmax = 256000;
7396 Double_t memFactor = 1;
7399
7400 //we make two passes
7401 //one pass to compute the relative branch buffer sizes
7402 //a second pass to compute the absolute values
7403 for (Int_t pass =0;pass<2;pass++) {
7404 oldMemsize = 0; //to count size of baskets in memory with old buffer size
7405 newMemsize = 0; //to count size of baskets in memory with new buffer size
7406 oldBaskets = 0; //to count number of baskets with old buffer size
7407 newBaskets = 0; //to count number of baskets with new buffer size
7408 for (i=0;i<nleaves;i++) {
7409 TLeaf *leaf = (TLeaf*)leaves->At(i);
7410 TBranch *branch = leaf->GetBranch();
7411 Double_t totBytes = (Double_t)branch->GetTotBytes();
7414 if (branch->GetEntries() == 0) {
7415 // There is no data, so let's make a guess ...
7417 } else {
7418 sizeOfOneEntry = 1+(UInt_t)(totBytes / (Double_t)branch->GetEntries());
7419 }
7420 Int_t oldBsize = branch->GetBasketSize();
7423 Int_t nb = branch->GetListOfBranches()->GetEntries();
7424 if (nb > 0) {
7426 continue;
7427 }
7428 Double_t bsize = oldBsize*idealFactor*memFactor; //bsize can be very large !
7429 if (bsize < 0) bsize = bmax;
7430 if (bsize > bmax) bsize = bmax;
7432 if (pass) { // only on the second pass so that it doesn't interfere with scaling
7433 // If there is an entry offset, it will be stored in the same buffer as the object data; hence,
7434 // we must bump up the size of the branch to account for this extra footprint.
7435 // If fAutoFlush is not set yet, let's assume that it is 'in the process of being set' to
7436 // the value of GetEntries().
7437 Long64_t clusterSize = (fAutoFlush > 0) ? fAutoFlush : branch->GetEntries();
7438 if (branch->GetEntryOffsetLen()) {
7439 newBsize = newBsize + (clusterSize * sizeof(Int_t) * 2);
7440 }
7441 // We used ATLAS fully-split xAOD for testing, which is a rather unbalanced TTree, 10K branches,
7442 // with 8K having baskets smaller than 512 bytes. To achieve good I/O performance ATLAS uses auto-flush 100,
7443 // resulting in the smallest baskets being ~300-400 bytes, so this change increases their memory by about 8k*150B =~ 1MB,
7444 // at the same time it significantly reduces the number of total baskets because it ensures that all 100 entries can be
7445 // stored in a single basket (the old optimization tended to make baskets too small). In a toy example with fixed sized
7446 // structures we found a factor of 2 fewer baskets needed in the new scheme.
7447 // rounds up, increases basket size to ensure all entries fit into single basket as intended
7448 newBsize = newBsize - newBsize%512 + 512;
7449 }
7451 if (newBsize < bmin) newBsize = bmin;
7452 if (newBsize > 10000000) newBsize = bmax;
7453 if (pass) {
7454 if (pDebug) Info("OptimizeBaskets", "Changing buffer size from %6d to %6d bytes for %s\n",oldBsize,newBsize,branch->GetName());
7455 branch->SetBasketSize(newBsize);
7456 }
7458 // For this number to be somewhat accurate when newBsize is 'low'
7459 // we do not include any space for meta data in the requested size (newBsize) even-though SetBasketSize will
7460 // not let it be lower than 100+TBranch::fEntryOffsetLen.
7462 if (pass == 0) continue;
7463 //Reset the compression level in case the compression factor is small
7464 Double_t comp = 1;
7465 if (branch->GetZipBytes() > 0) comp = totBytes/Double_t(branch->GetZipBytes());
7466 if (comp > 1 && comp < minComp) {
7467 if (pDebug) Info("OptimizeBaskets", "Disabling compression for branch : %s\n",branch->GetName());
7469 }
7470 }
7471 // coverity[divide_by_zero] newMemsize can not be zero as there is at least one leaf
7473 if (memFactor > 100) memFactor = 100;
7476 static const UInt_t hardmax = 1*1024*1024*1024; // Really, really never give more than 1Gb to a single buffer.
7477
7478 // Really, really never go lower than 8 bytes (we use this number
7479 // so that the calculation of the number of basket is consistent
7480 // but in fact SetBasketSize will not let the size go below
7481 // TBranch::fEntryOffsetLen + (100 + strlen(branch->GetName())
7482 // (The 2nd part being a slight over estimate of the key length.
7483 static const UInt_t hardmin = 8;
7486 }
7487 if (pDebug) {
7488 Info("OptimizeBaskets", "oldMemsize = %d, newMemsize = %d\n",oldMemsize, newMemsize);
7489 Info("OptimizeBaskets", "oldBaskets = %d, newBaskets = %d\n",oldBaskets, newBaskets);
7490 }
7491}
7492
7493////////////////////////////////////////////////////////////////////////////////
7494/// Interface to the Principal Components Analysis class.
7495///
7496/// Create an instance of TPrincipal
7497///
7498/// Fill it with the selected variables
7499///
7500/// - if option "n" is specified, the TPrincipal object is filled with
7501/// normalized variables.
7502/// - If option "p" is specified, compute the principal components
7503/// - If option "p" and "d" print results of analysis
7504/// - If option "p" and "h" generate standard histograms
7505/// - If option "p" and "c" generate code of conversion functions
7506/// - return a pointer to the TPrincipal object. It is the user responsibility
7507/// - to delete this object.
7508/// - The option default value is "np"
7509///
7510/// see TTree::Draw for explanation of the other parameters.
7511///
7512/// The created object is named "principal" and a reference to it
7513/// is added to the list of specials Root objects.
7514/// you can retrieve a pointer to the created object via:
7515/// ~~~ {.cpp}
7516/// TPrincipal *principal =
7517/// (TPrincipal*)gROOT->GetListOfSpecials()->FindObject("principal");
7518/// ~~~
7521{
7522 GetPlayer();
7523 if (fPlayer) {
7525 }
7526 return nullptr;
7527}
7528
7529////////////////////////////////////////////////////////////////////////////////
7530/// Print a summary of the tree contents.
7531///
7532/// - If option contains "all" friend trees are also printed.
7533/// - If option contains "toponly" only the top level branches are printed.
7534/// - If option contains "clusters" information about the cluster of baskets is printed.
7535///
7536/// Wildcarding can be used to print only a subset of the branches, e.g.,
7537/// `T.Print("Elec*")` will print all branches with name starting with "Elec".
7539void TTree::Print(Option_t* option) const
7540{
7541 // We already have been visited while recursively looking
7542 // through the friends tree, let's return.
7543 if (kPrint & fFriendLockStatus) {
7544 return;
7545 }
7546 Int_t s = 0;
7547 Int_t skey = 0;
7548 if (fDirectory) {
7549 TKey* key = fDirectory->GetKey(GetName());
7550 if (key) {
7551 skey = key->GetKeylen();
7552 s = key->GetNbytes();
7553 }
7554 }
7557 if (zipBytes > 0) {
7558 total += GetTotBytes();
7559 }
7561 TTree::Class()->WriteBuffer(b, (TTree*) this);
7562 total += b.Length();
7563 Long64_t file = zipBytes + s;
7564 Float_t cx = 1;
7565 if (zipBytes) {
7566 cx = (GetTotBytes() + 0.00001) / zipBytes;
7567 }
7568 Printf("******************************************************************************");
7569 Printf("*Tree :%-10s: %-54s *", GetName(), GetTitle());
7570 Printf("*Entries : %8lld : Total = %15lld bytes File Size = %10lld *", fEntries, total, file);
7571 Printf("* : : Tree compression factor = %6.2f *", cx);
7572 Printf("******************************************************************************");
7573
7574 // Avoid many check of option validity
7575 if (!option)
7576 option = "";
7577
7578 if (strncmp(option,"clusters",std::char_traits<char>::length("clusters"))==0) {
7579 Printf("%-16s %-16s %-16s %8s %20s",
7580 "Cluster Range #", "Entry Start", "Last Entry", "Size", "Number of clusters");
7581 Int_t index= 0;
7584 bool estimated = false;
7585 bool unknown = false;
7587 Long64_t nclusters = 0;
7588 if (recordedSize > 0) {
7589 nclusters = TMath::Ceil(static_cast<double>(1 + end - start) / recordedSize);
7590 Printf("%-16d %-16lld %-16lld %8lld %10lld",
7591 ind, start, end, recordedSize, nclusters);
7592 } else {
7593 // NOTE: const_cast ... DO NOT Merge for now
7594 TClusterIterator iter((TTree*)this, start);
7595 iter.Next();
7596 auto estimated_size = iter.GetNextEntry() - start;
7597 if (estimated_size > 0) {
7598 nclusters = TMath::Ceil(static_cast<double>(1 + end - start) / estimated_size);
7599 Printf("%-16d %-16lld %-16lld %8lld %10lld (estimated)",
7600 ind, start, end, recordedSize, nclusters);
7601 estimated = true;
7602 } else {
7603 Printf("%-16d %-16lld %-16lld %8lld (unknown)",
7604 ind, start, end, recordedSize);
7605 unknown = true;
7606 }
7607 }
7608 start = end + 1;
7610 };
7611 if (fNClusterRange) {
7612 for( ; index < fNClusterRange; ++index) {
7615 }
7616 }
7618 if (unknown) {
7619 Printf("Total number of clusters: (unknown)");
7620 } else {
7621 Printf("Total number of clusters: %lld %s", totalClusters, estimated ? "(estimated)" : "");
7622 }
7623 return;
7624 }
7625
7626 Int_t nl = const_cast<TTree*>(this)->GetListOfLeaves()->GetEntries();
7627 Int_t l;
7628 TBranch* br = nullptr;
7629 TLeaf* leaf = nullptr;
7630 if (strstr(option, "toponly")) {
7631 Long64_t *count = new Long64_t[nl];
7632 Int_t keep =0;
7633 for (l=0;l<nl;l++) {
7634 leaf = (TLeaf *)const_cast<TTree*>(this)->GetListOfLeaves()->At(l);
7635 br = leaf->GetBranch();
7636 // branch is its own (top level) mother only for the top level branches.
7637 if (br != br->GetMother()) {
7638 count[l] = -1;
7639 count[keep] += br->GetZipBytes();
7640 } else {
7641 keep = l;
7642 count[keep] = br->GetZipBytes();
7643 }
7644 }
7645 for (l=0;l<nl;l++) {
7646 if (count[l] < 0) continue;
7647 leaf = (TLeaf *)const_cast<TTree*>(this)->GetListOfLeaves()->At(l);
7648 br = leaf->GetBranch();
7649 Printf("branch: %-20s %9lld",br->GetName(),count[l]);
7650 }
7651 delete [] count;
7652 } else {
7653 TString reg = "*";
7654 if (strlen(option) && strchr(option,'*')) reg = option;
7655 TRegexp re(reg,true);
7656 TIter next(const_cast<TTree*>(this)->GetListOfBranches());
7658 while ((br= (TBranch*)next())) {
7659 TString st = br->GetName();
7660 st.ReplaceAll("/","_");
7661 if (st.Index(re) == kNPOS) continue;
7662 br->Print(option);
7663 }
7664 }
7665
7666 //print TRefTable (if one)
7668
7669 //print friends if option "all"
7670 if (!fFriends || !strstr(option,"all")) return;
7672 TFriendLock lock(const_cast<TTree*>(this),kPrint);
7673 TFriendElement *fr;
7674 while ((fr = (TFriendElement*)nextf())) {
7675 TTree * t = fr->GetTree();
7676 if (t) t->Print(option);
7677 }
7678}
7679
7680////////////////////////////////////////////////////////////////////////////////
7681/// Print statistics about the TreeCache for this tree.
7682/// Like:
7683/// ~~~ {.cpp}
7684/// ******TreeCache statistics for file: cms2.root ******
7685/// Reading 73921562 bytes in 716 transactions
7686/// Average transaction = 103.242405 Kbytes
7687/// Number of blocks in current cache: 202, total size : 6001193
7688/// ~~~
7689/// if option = "a" the list of blocks in the cache is printed
7692{
7693 TFile *f = GetCurrentFile();
7694 if (!f) return;
7696 if (tc) tc->Print(option);
7697}
7698
7699////////////////////////////////////////////////////////////////////////////////
7700/// Process this tree executing the TSelector code in the specified filename.
7701/// The return value is -1 in case of error and TSelector::GetStatus() in
7702/// in case of success.
7703///
7704/// The code in filename is loaded (interpreted or compiled, see below),
7705/// filename must contain a valid class implementation derived from TSelector,
7706/// where TSelector has the following member functions:
7707///
7708/// - `Begin()`: called every time a loop on the tree starts,
7709/// a convenient place to create your histograms.
7710/// - `SlaveBegin()`: called after Begin()
7711/// - `Process()`: called for each event, in this function you decide what
7712/// to read and fill your histograms.
7713/// - `SlaveTerminate()`: called at the end of the loop on the tree
7714/// - `Terminate()`: called at the end of the loop on the tree,
7715/// a convenient place to draw/fit your histograms.
7716///
7717/// If filename is of the form file.C, the file will be interpreted.
7718///
7719/// If filename is of the form file.C++, the file file.C will be compiled
7720/// and dynamically loaded.
7721///
7722/// If filename is of the form file.C+, the file file.C will be compiled
7723/// and dynamically loaded. At next call, if file.C is older than file.o
7724/// and file.so, the file.C is not compiled, only file.so is loaded.
7725///
7726/// ## NOTE1
7727///
7728/// It may be more interesting to invoke directly the other Process function
7729/// accepting a TSelector* as argument.eg
7730/// ~~~ {.cpp}
7731/// MySelector *selector = (MySelector*)TSelector::GetSelector(filename);
7732/// selector->CallSomeFunction(..);
7733/// mytree.Process(selector,..);
7734/// ~~~
7735/// ## NOTE2
7736//
7737/// One should not call this function twice with the same selector file
7738/// in the same script. If this is required, proceed as indicated in NOTE1,
7739/// by getting a pointer to the corresponding TSelector,eg
7740///
7741/// ### Workaround 1
7742///
7743/// ~~~ {.cpp}
7744/// void stubs1() {
7745/// TSelector *selector = TSelector::GetSelector("h1test.C");
7746/// TFile *f1 = new TFile("stubs_nood_le1.root");
7747/// TTree *h1 = (TTree*)f1->Get("h1");
7748/// h1->Process(selector);
7749/// TFile *f2 = new TFile("stubs_nood_le1_coarse.root");
7750/// TTree *h2 = (TTree*)f2->Get("h1");
7751/// h2->Process(selector);
7752/// }
7753/// ~~~
7754/// or use ACLIC to compile the selector
7755///
7756/// ### Workaround 2
7757///
7758/// ~~~ {.cpp}
7759/// void stubs2() {
7760/// TFile *f1 = new TFile("stubs_nood_le1.root");
7761/// TTree *h1 = (TTree*)f1->Get("h1");
7762/// h1->Process("h1test.C+");
7763/// TFile *f2 = new TFile("stubs_nood_le1_coarse.root");
7764/// TTree *h2 = (TTree*)f2->Get("h1");
7765/// h2->Process("h1test.C+");
7766/// }
7767/// ~~~
7770{
7771 GetPlayer();
7772 if (fPlayer) {
7774 }
7775 return -1;
7776}
7777
7778////////////////////////////////////////////////////////////////////////////////
7779/// Process this tree executing the code in the specified selector.
7780/// The return value is -1 in case of error and TSelector::GetStatus() in
7781/// in case of success.
7782///
7783/// The TSelector class has the following member functions:
7784///
7785/// - `Begin()`: called every time a loop on the tree starts,
7786/// a convenient place to create your histograms.
7787/// - `SlaveBegin()`: called after Begin()
7788/// - `Process()`: called for each event, in this function you decide what
7789/// to read and fill your histograms.
7790/// - `SlaveTerminate()`: called at the end of the loop on the tree
7791/// - `Terminate()`: called at the end of the loop on the tree,
7792/// a convenient place to draw/fit your histograms.
7793///
7794/// If the Tree (Chain) has an associated EventList, the loop is on the nentries
7795/// of the EventList, starting at firstentry, otherwise the loop is on the
7796/// specified Tree entries.
7799{
7800 GetPlayer();
7801 if (fPlayer) {
7802 return fPlayer->Process(selector, option, nentries, firstentry);
7803 }
7804 return -1;
7805}
7806
7807////////////////////////////////////////////////////////////////////////////////
7808/// Make a projection of a tree using selections.
7809///
7810/// Depending on the value of varexp (described in Draw) a 1-D, 2-D, etc.,
7811/// projection of the tree will be filled in histogram hname.
7812/// Note that the dimension of hname must match with the dimension of varexp.
7813///
7816{
7817 TString var;
7818 var.Form("%s>>%s", varexp, hname);
7819 TString opt("goff");
7820 if (option) {
7821 opt.Form("%sgoff", option);
7822 }
7824 return nsel;
7825}
7826
7827////////////////////////////////////////////////////////////////////////////////
7828/// Loop over entries and return a TSQLResult object containing entries following selection.
7831{
7832 GetPlayer();
7833 if (fPlayer) {
7835 }
7836 return nullptr;
7837}
7838
7839////////////////////////////////////////////////////////////////////////////////
7840/// Create or simply read branches from filename.
7841///
7842/// if branchDescriptor = "" (default), it is assumed that the Tree descriptor
7843/// is given in the first line of the file with a syntax like
7844/// ~~~ {.cpp}
7845/// A/D:Table[2]/F:Ntracks/I:astring/C
7846/// ~~~
7847/// otherwise branchDescriptor must be specified with the above syntax.
7848/// See all available datatypes [here](\ref addcolumnoffundamentaltypes).
7849///
7850/// - If the type of the first variable is not specified, it is assumed to be "/F"
7851/// - If the type of any other variable is not specified, the type of the previous
7852/// variable is assumed. eg
7853/// - `x:y:z` (all variables are assumed of type "F")
7854/// - `x/D:y:z` (all variables are of type "D")
7855/// - `x:y/D:z` (x is type "F", y and z of type "D")
7856///
7857/// delimiter allows for the use of another delimiter besides whitespace.
7858/// This provides support for direct import of common data file formats
7859/// like csv. If delimiter != ' ' and branchDescriptor == "", then the
7860/// branch description is taken from the first line in the file, but
7861/// delimiter is used for the branch names tokenization rather than ':'.
7862/// Note however that if the values in the first line do not use the
7863/// /[type] syntax, all variables are assumed to be of type "F".
7864/// If the filename ends with extensions .csv or .CSV and a delimiter is
7865/// not specified (besides ' '), the delimiter is automatically set to ','.
7866///
7867/// Lines in the input file starting with "#" are ignored. Leading whitespace
7868/// for each column data is skipped. Empty lines are skipped.
7869///
7870/// A TBranch object is created for each variable in the expression.
7871/// The total number of rows read from the file is returned.
7872///
7873/// ## FILLING a TTree WITH MULTIPLE INPUT TEXT FILES
7874///
7875/// To fill a TTree with multiple input text files, proceed as indicated above
7876/// for the first input file and omit the second argument for subsequent calls
7877/// ~~~ {.cpp}
7878/// T.ReadFile("file1.dat","branch descriptor");
7879/// T.ReadFile("file2.dat");
7880/// ~~~
7882Long64_t TTree::ReadFile(const char* filename, const char* branchDescriptor, char delimiter)
7883{
7884 if (!filename || !*filename) {
7885 Error("ReadFile","File name not specified");
7886 return 0;
7887 }
7888
7889 std::ifstream in;
7890 in.open(filename);
7891 if (!in.good()) {
7892 Error("ReadFile","Cannot open file: %s",filename);
7893 return 0;
7894 }
7895 const char* ext = strrchr(filename, '.');
7896 if(ext && ((strcmp(ext, ".csv") == 0) || (strcmp(ext, ".CSV") == 0)) && delimiter == ' ') {
7897 delimiter = ',';
7898 }
7900}
7901
7902////////////////////////////////////////////////////////////////////////////////
7903/// Determine which newline this file is using.
7904/// Return '\\r' for Windows '\\r\\n' as that already terminates.
7906char TTree::GetNewlineValue(std::istream &inputStream)
7907{
7908 Long_t inPos = inputStream.tellg();
7909 char newline = '\n';
7910 while(true) {
7911 char c = 0;
7912 inputStream.get(c);
7913 if(!inputStream.good()) {
7914 Error("ReadStream","Error reading stream: no newline found.");
7915 return 0;
7916 }
7917 if(c == newline) break;
7918 if(c == '\r') {
7919 newline = '\r';
7920 break;
7921 }
7922 }
7923 inputStream.clear();
7924 inputStream.seekg(inPos);
7925 return newline;
7926}
7927
7928////////////////////////////////////////////////////////////////////////////////
7929/// Create or simply read branches from an input stream.
7930///
7931/// \see TTree::ReadFile
7933Long64_t TTree::ReadStream(std::istream& inputStream, const char *branchDescriptor, char delimiter)
7934{
7935 char newline = 0;
7936 std::stringstream ss;
7937 std::istream *inTemp;
7938 Long_t inPos = inputStream.tellg();
7939 if (!inputStream.good()) {
7940 Error("ReadStream","Error reading stream");
7941 return 0;
7942 }
7943 if (inPos == -1) {
7944 ss << std::cin.rdbuf();
7946 inTemp = &ss;
7947 } else {
7950 }
7951 std::istream& in = *inTemp;
7952 Long64_t nlines = 0;
7953
7954 TBranch *branch = nullptr;
7956 if (nbranches == 0) {
7957 char *bdname = new char[4000];
7958 char *bd = new char[100000];
7959 Int_t nch = 0;
7961 // branch Descriptor is null, read its definition from the first line in the file
7962 if (!nch) {
7963 do {
7964 in.getline(bd, 100000, newline);
7965 if (!in.good()) {
7966 delete [] bdname;
7967 delete [] bd;
7968 Error("ReadStream","Error reading stream");
7969 return 0;
7970 }
7971 char *cursor = bd;
7972 while( isspace(*cursor) && *cursor != '\n' && *cursor != '\0') {
7973 ++cursor;
7974 }
7975 if (*cursor != '#' && *cursor != '\n' && *cursor != '\0') {
7976 break;
7977 }
7978 } while (true);
7979 ++nlines;
7980 nch = strlen(bd);
7981 } else {
7982 strlcpy(bd,branchDescriptor,100000);
7983 }
7984
7985 //parse the branch descriptor and create a branch for each element
7986 //separated by ":"
7987 void *address = &bd[90000];
7988 char *bdcur = bd;
7989 TString desc="", olddesc="F";
7990 char bdelim = ':';
7991 if(delimiter != ' ') {
7992 bdelim = delimiter;
7993 if (strchr(bdcur,bdelim)==nullptr && strchr(bdcur,':') != nullptr) {
7994 // revert to the default
7995 bdelim = ':';
7996 }
7997 }
7998 while (bdcur) {
7999 char *colon = strchr(bdcur,bdelim);
8000 if (colon) *colon = 0;
8001 strlcpy(bdname,bdcur,4000);
8002 char *slash = strchr(bdname,'/');
8003 if (slash) {
8004 *slash = 0;
8005 desc = bdcur;
8006 olddesc = slash+1;
8007 } else {
8008 desc.Form("%s/%s",bdname,olddesc.Data());
8009 }
8010 char *bracket = strchr(bdname,'[');
8011 if (bracket) {
8012 *bracket = 0;
8013 }
8014 branch = new TBranch(this,bdname,address,desc.Data(),32000);
8015 if (branch->IsZombie()) {
8016 delete branch;
8017 Warning("ReadStream","Illegal branch definition: %s",bdcur);
8018 } else {
8020 branch->SetAddress(nullptr);
8021 }
8022 if (!colon)break;
8023 bdcur = colon+1;
8024 }
8025 delete [] bdname;
8026 delete [] bd;
8027 }
8028
8030
8031 if (gDebug > 1) {
8032 Info("ReadStream", "Will use branches:");
8033 for (int i = 0 ; i < nbranches; ++i) {
8034 TBranch* br = (TBranch*) fBranches.At(i);
8035 Info("ReadStream", " %s: %s [%s]", br->GetName(),
8036 br->GetTitle(), br->GetListOfLeaves()->At(0)->IsA()->GetName());
8037 }
8038 if (gDebug > 3) {
8039 Info("ReadStream", "Dumping read tokens, format:");
8040 Info("ReadStream", "LLLLL:BBB:gfbe:GFBE:T");
8041 Info("ReadStream", " L: line number");
8042 Info("ReadStream", " B: branch number");
8043 Info("ReadStream", " gfbe: good / fail / bad / eof of token");
8044 Info("ReadStream", " GFBE: good / fail / bad / eof of file");
8045 Info("ReadStream", " T: Token being read");
8046 }
8047 }
8048
8049 //loop on all lines in the file
8050 Long64_t nGoodLines = 0;
8051 std::string line;
8052 const char sDelimBuf[2] = { delimiter, 0 };
8053 const char* sDelim = sDelimBuf;
8054 if (delimiter == ' ') {
8055 // ' ' really means whitespace
8056 sDelim = "[ \t]";
8057 }
8058 while(in.good()) {
8059 if (newline == '\r' && in.peek() == '\n') {
8060 // Windows, skip '\n':
8061 in.get();
8062 }
8063 std::getline(in, line, newline);
8064 ++nlines;
8065
8067 sLine = sLine.Strip(TString::kLeading); // skip leading whitespace
8068 if (sLine.IsNull()) {
8069 if (gDebug > 2) {
8070 Info("ReadStream", "Skipping empty line number %lld", nlines);
8071 }
8072 continue; // silently skip empty lines
8073 }
8074 if (sLine[0] == '#') {
8075 if (gDebug > 2) {
8076 Info("ReadStream", "Skipping comment line number %lld: '%s'",
8077 nlines, line.c_str());
8078 }
8079 continue;
8080 }
8081 if (gDebug > 2) {
8082 Info("ReadStream", "Parsing line number %lld: '%s'",
8083 nlines, line.c_str());
8084 }
8085
8086 // Loop on branches and read the branch values into their buffer
8087 branch = nullptr;
8088 TString tok; // one column's data
8089 TString leafData; // leaf data, possibly multiple tokens for e.g. /I[2]
8090 std::stringstream sToken; // string stream feeding leafData into leaves
8091 Ssiz_t pos = 0;
8092 Int_t iBranch = 0;
8093 bool goodLine = true; // whether the row can be filled into the tree
8094 Int_t remainingLeafLen = 0; // remaining columns for the current leaf
8095 while (goodLine && iBranch < nbranches
8096 && sLine.Tokenize(tok, pos, sDelim)) {
8097 tok = tok.Strip(TString::kLeading); // skip leading whitespace
8098 if (tok.IsNull() && delimiter == ' ') {
8099 // 1 2 should not be interpreted as 1,,,2 but 1, 2.
8100 // Thus continue until we have a non-empty token.
8101 continue;
8102 }
8103
8104 if (!remainingLeafLen) {
8105 // next branch!
8107 }
8108 TLeaf *leaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
8109 if (!remainingLeafLen) {
8110 remainingLeafLen = leaf->GetLen();
8111 if (leaf->GetMaximum() > 0) {
8112 // This is a dynamic leaf length, i.e. most likely a TLeafC's
8113 // string size. This still translates into one token:
8114 remainingLeafLen = 1;
8115 }
8116
8117 leafData = tok;
8118 } else {
8119 // append token to laf data:
8120 leafData += " ";
8121 leafData += tok;
8122 }
8124 if (remainingLeafLen) {
8125 // need more columns for this branch:
8126 continue;
8127 }
8128 ++iBranch;
8129
8130 // initialize stringstream with token
8131 sToken.clear();
8132 sToken.seekp(0, std::ios_base::beg);
8133 sToken.str(leafData.Data());
8134 sToken.seekg(0, std::ios_base::beg);
8135 leaf->ReadValue(sToken, 0 /* 0 = "all" */);
8136 if (gDebug > 3) {
8137 Info("ReadStream", "%5lld:%3d:%d%d%d%d:%d%d%d%d:%s",
8138 nlines, iBranch,
8139 (int)sToken.good(), (int)sToken.fail(),
8140 (int)sToken.bad(), (int)sToken.eof(),
8141 (int)in.good(), (int)in.fail(),
8142 (int)in.bad(), (int)in.eof(),
8143 sToken.str().c_str());
8144 }
8145
8146 // Error handling
8147 if (sToken.bad()) {
8148 // How could that happen for a stringstream?
8149 Warning("ReadStream",
8150 "Buffer error while reading data for branch %s on line %lld",
8151 branch->GetName(), nlines);
8152 } else if (!sToken.eof()) {
8153 if (sToken.fail()) {
8154 Warning("ReadStream",
8155 "Couldn't read formatted data in \"%s\" for branch %s on line %lld; ignoring line",
8156 tok.Data(), branch->GetName(), nlines);
8157 goodLine = false;
8158 } else {
8159 std::string remainder;
8160 std::getline(sToken, remainder, newline);
8161 if (!remainder.empty()) {
8162 Warning("ReadStream",
8163 "Ignoring trailing \"%s\" while reading data for branch %s on line %lld",
8164 remainder.c_str(), branch->GetName(), nlines);
8165 }
8166 }
8167 }
8168 } // tokenizer loop
8169
8170 if (iBranch < nbranches) {
8171 Warning("ReadStream",
8172 "Read too few columns (%d < %d) in line %lld; ignoring line",
8174 goodLine = false;
8175 } else if (pos != kNPOS) {
8177 if (pos < sLine.Length()) {
8178 Warning("ReadStream",
8179 "Ignoring trailing \"%s\" while reading line %lld",
8180 sLine.Data() + pos - 1 /* also print delimiter */,
8181 nlines);
8182 }
8183 }
8184
8185 //we are now ready to fill the tree
8186 if (goodLine) {
8187 Fill();
8188 ++nGoodLines;
8189 }
8190 }
8191
8192 return nGoodLines;
8193}
8194
8195////////////////////////////////////////////////////////////////////////////////
8196/// Make sure that obj (which is being deleted or will soon be) is no
8197/// longer referenced by this TTree.
8200{
8201 if (obj == fEventList) {
8202 fEventList = nullptr;
8203 }
8204 if (obj == fEntryList) {
8205 fEntryList = nullptr;
8206 }
8207 if (fUserInfo) {
8209 }
8210 if (fPlayer == obj) {
8211 fPlayer = nullptr;
8212 }
8213 if (fTreeIndex == obj) {
8214 fTreeIndex = nullptr;
8215 }
8216 if (fAliases == obj) {
8217 fAliases = nullptr;
8218 } else if (fAliases) {
8220 }
8221 if (fFriends == obj) {
8222 fFriends = nullptr;
8223 } else if (fFriends) {
8225 }
8226}
8227
8228////////////////////////////////////////////////////////////////////////////////
8229/// Refresh contents of this tree and its branches from the current status on disk.
8230///
8231/// One can call this function in case the tree file is being
8232/// updated by another process.
8234void TTree::Refresh()
8235{
8236 if (!fDirectory->GetFile()) {
8237 return;
8238 }
8240 fDirectory->Remove(this);
8241 TTree* tree; fDirectory->GetObject(GetName(),tree);
8242 if (!tree) {
8243 return;
8244 }
8245 //copy info from tree header into this Tree
8246 fEntries = 0;
8247 fNClusterRange = 0;
8248 ImportClusterRanges(tree);
8249
8250 fAutoSave = tree->fAutoSave;
8251 fEntries = tree->fEntries;
8252 fTotBytes = tree->GetTotBytes();
8253 fZipBytes = tree->GetZipBytes();
8254 fSavedBytes = tree->fSavedBytes;
8255 fTotalBuffers = tree->fTotalBuffers.load();
8256
8257 //loop on all branches and update them
8259 for (Int_t i = 0; i < nleaves; i++) {
8261 TBranch* branch = (TBranch*) leaf->GetBranch();
8262 branch->Refresh(tree->GetBranch(branch->GetName()));
8263 }
8264 fDirectory->Remove(tree);
8265 fDirectory->Append(this);
8266 delete tree;
8267 tree = nullptr;
8268}
8269
8270////////////////////////////////////////////////////////////////////////////////
8271/// Record a TFriendElement that we need to warn when the chain switches to
8272/// a new file (typically this is because this chain is a friend of another
8273/// TChain)
8280}
8281
8282
8283////////////////////////////////////////////////////////////////////////////////
8284/// Removes external friend
8289}
8290
8291
8292////////////////////////////////////////////////////////////////////////////////
8293/// Remove a friend from the list of friends.
8296{
8297 // We already have been visited while recursively looking
8298 // through the friends tree, let return
8300 return;
8301 }
8302 if (!fFriends) {
8303 return;
8304 }
8305 TFriendLock lock(this, kRemoveFriend);
8307 TFriendElement* fe = nullptr;
8308 while ((fe = (TFriendElement*) nextf())) {
8309 TTree* friend_t = fe->GetTree();
8310 if (friend_t == oldFriend) {
8311 fFriends->Remove(fe);
8312 delete fe;
8313 fe = nullptr;
8314 }
8315 }
8316}
8317
8318////////////////////////////////////////////////////////////////////////////////
8319/// Reset baskets, buffers and entries count in all branches and leaves.
8322{
8323 fNotify = nullptr;
8324 fEntries = 0;
8325 fNClusterRange = 0;
8326 fTotBytes = 0;
8327 fZipBytes = 0;
8328 fFlushedBytes = 0;
8329 fSavedBytes = 0;
8330 fTotalBuffers = 0;
8331 fChainOffset = 0;
8332 fReadEntry = -1;
8333
8334 delete fTreeIndex;
8335 fTreeIndex = nullptr;
8336
8338 for (Int_t i = 0; i < nb; ++i) {
8340 branch->Reset(option);
8341 }
8342
8343 if (fBranchRef) {
8344 fBranchRef->Reset();
8345 }
8346}
8347
8348////////////////////////////////////////////////////////////////////////////////
8349/// Resets the state of this TTree after a merge (keep the customization but
8350/// forget the data).
8353{
8354 fEntries = 0;
8355 fNClusterRange = 0;
8356 fTotBytes = 0;
8357 fZipBytes = 0;
8358 fSavedBytes = 0;
8359 fFlushedBytes = 0;
8360 fTotalBuffers = 0;
8361 fChainOffset = 0;
8362 fReadEntry = -1;
8363
8364 delete fTreeIndex;
8365 fTreeIndex = nullptr;
8366
8368 for (Int_t i = 0; i < nb; ++i) {
8370 branch->ResetAfterMerge(info);
8371 }
8372
8373 if (fBranchRef) {
8375 }
8376}
8377
8378////////////////////////////////////////////////////////////////////////////////
8379/// Tell a branch to set its address to zero.
8380///
8381/// @note If the branch owns any objects, they are deleted.
8384{
8385 if (br && br->GetTree()) {
8386 br->ResetAddress();
8387 }
8388}
8389
8390////////////////////////////////////////////////////////////////////////////////
8391/// Tell all of our branches to drop their current objects and allocate new ones.
8394{
8395 // We already have been visited while recursively looking
8396 // through the friends tree, let return
8398 return;
8399 }
8401 Int_t nbranches = branches->GetEntriesFast();
8402 for (Int_t i = 0; i < nbranches; ++i) {
8403 TBranch* branch = (TBranch*) branches->UncheckedAt(i);
8404 branch->ResetAddress();
8405 }
8406 if (fFriends) {
8409 auto *frTree = frEl->GetTree();
8410 if (frTree) {
8411 frTree->ResetBranchAddresses();
8412 }
8413 }
8414 }
8415}
8416
8417////////////////////////////////////////////////////////////////////////////////
8418/// Loop over tree entries and print entries passing selection. Interactive
8419/// pagination break is on by default.
8420///
8421/// - If varexp is 0 (or "") then print only first 8 columns.
8422/// - If varexp = "*" print all columns.
8423///
8424/// Otherwise a columns selection can be made using "var1:var2:var3".
8425///
8426/// \param firstentry first entry to scan
8427/// \param nentries total number of entries to scan (starting from firstentry). Defaults to all entries.
8428/// \note see TTree::SetScanField to control how many lines are printed between pagination breaks (Use 0 to disable pagination)
8429/// \see TTreePlayer::Scan, TTreePlayer::SetScanFileName, TTreePlayer::SetScanRedirect
8432{
8433 GetPlayer();
8434 if (fPlayer) {
8436 }
8437 return -1;
8438}
8439
8440////////////////////////////////////////////////////////////////////////////////
8441/// Set a tree variable alias.
8442///
8443/// Set an alias for an expression/formula based on the tree 'variables'.
8444///
8445/// The content of 'aliasName' can be used in TTreeFormula (i.e. TTree::Draw,
8446/// TTree::Scan, TTreeViewer) and will be evaluated as the content of
8447/// 'aliasFormula'.
8448///
8449/// If the content of 'aliasFormula' only contains symbol names, periods and
8450/// array index specification (for example event.fTracks[3]), then
8451/// the content of 'aliasName' can be used as the start of symbol.
8452///
8453/// If the alias 'aliasName' already existed, it is replaced by the new
8454/// value.
8455///
8456/// When being used, the alias can be preceded by an eventual 'Friend Alias'
8457/// (see TTree::GetFriendAlias)
8458///
8459/// Return true if it was added properly.
8460///
8461/// For example:
8462/// ~~~ {.cpp}
8463/// tree->SetAlias("x1","(tdc1[1]-tdc1[0])/49");
8464/// tree->SetAlias("y1","(tdc1[3]-tdc1[2])/47");
8465/// tree->SetAlias("x2","(tdc2[1]-tdc2[0])/49");
8466/// tree->SetAlias("y2","(tdc2[3]-tdc2[2])/47");
8467/// tree->Draw("y2-y1:x2-x1");
8468///
8469/// tree->SetAlias("theGoodTrack","event.fTracks[3]");
8470/// tree->Draw("theGoodTrack.fPx"); // same as "event.fTracks[3].fPx"
8471/// ~~~
8473bool TTree::SetAlias(const char* aliasName, const char* aliasFormula)
8474{
8475 if (!aliasName || !aliasFormula) {
8476 return false;
8477 }
8478 if (!aliasName[0] || !aliasFormula[0]) {
8479 return false;
8480 }
8481 if (!fAliases) {
8482 fAliases = new TList;
8483 } else {
8485 if (oldHolder) {
8486 oldHolder->SetTitle(aliasFormula);
8487 return true;
8488 }
8489 }
8492 return true;
8493}
8494
8495////////////////////////////////////////////////////////////////////////////////
8496/// This function may be called at the start of a program to change
8497/// the default value for fAutoFlush.
8498///
8499/// ### CASE 1 : autof > 0
8500///
8501/// autof is the number of consecutive entries after which TTree::Fill will
8502/// flush all branch buffers to disk.
8503///
8504/// ### CASE 2 : autof < 0
8505///
8506/// When filling the Tree the branch buffers will be flushed to disk when
8507/// more than autof bytes have been written to the file. At the first FlushBaskets
8508/// TTree::Fill will replace fAutoFlush by the current value of fEntries.
8509///
8510/// Calling this function with autof<0 is interesting when it is hard to estimate
8511/// the size of one entry. This value is also independent of the Tree.
8512///
8513/// The Tree is initialized with fAutoFlush=-30000000, ie that, by default,
8514/// the first AutoFlush will be done when 30 MBytes of data are written to the file.
8515///
8516/// ### CASE 3 : autof = 0
8517///
8518/// The AutoFlush mechanism is disabled.
8519///
8520/// Flushing the buffers at regular intervals optimize the location of
8521/// consecutive entries on the disk by creating clusters of baskets.
8522///
8523/// A cluster of baskets is a set of baskets that contains all
8524/// the data for a (consecutive) set of entries and that is stored
8525/// consecutively on the disk. When reading all the branches, this
8526/// is the minimum set of baskets that the TTreeCache will read.
8528void TTree::SetAutoFlush(Long64_t autof /* = -30000000 */ )
8529{
8530 // Implementation note:
8531 //
8532 // A positive value of autoflush determines the size (in number of entries) of
8533 // a cluster of baskets.
8534 //
8535 // If the value of autoflush is changed over time (this happens in
8536 // particular when the TTree results from fast merging many trees),
8537 // we record the values of fAutoFlush in the data members:
8538 // fClusterRangeEnd and fClusterSize.
8539 // In the code we refer to a range of entries where the size of the
8540 // cluster of baskets is the same (i.e the value of AutoFlush was
8541 // constant) is called a ClusterRange.
8542 //
8543 // The 2 arrays (fClusterRangeEnd and fClusterSize) have fNClusterRange
8544 // active (used) values and have fMaxClusterRange allocated entries.
8545 //
8546 // fClusterRangeEnd contains the last entries number of a cluster range.
8547 // In particular this means that the 'next' cluster starts at fClusterRangeEnd[]+1
8548 // fClusterSize contains the size in number of entries of all the cluster
8549 // within the given range.
8550 // The last range (and the only one if fNClusterRange is zero) start at
8551 // fNClusterRange[fNClusterRange-1]+1 and ends at the end of the TTree. The
8552 // size of the cluster in this range is given by the value of fAutoFlush.
8553 //
8554 // For example printing the beginning and end of each the ranges can be done by:
8555 //
8556 // Printf("%-16s %-16s %-16s %5s",
8557 // "Cluster Range #", "Entry Start", "Last Entry", "Size");
8558 // Int_t index= 0;
8559 // Long64_t clusterRangeStart = 0;
8560 // if (fNClusterRange) {
8561 // for( ; index < fNClusterRange; ++index) {
8562 // Printf("%-16d %-16lld %-16lld %5lld",
8563 // index, clusterRangeStart, fClusterRangeEnd[index], fClusterSize[index]);
8564 // clusterRangeStart = fClusterRangeEnd[index] + 1;
8565 // }
8566 // }
8567 // Printf("%-16d %-16lld %-16lld %5lld",
8568 // index, prevEntry, fEntries - 1, fAutoFlush);
8569 //
8570
8571 // Note: We store the entry number corresponding to the end of the cluster
8572 // rather than its start in order to avoid using the array if the cluster
8573 // size never varies (If there is only one value of AutoFlush for the whole TTree).
8574
8575 if( fAutoFlush != autof) {
8576 if ((fAutoFlush > 0 || autof > 0) && fFlushedBytes) {
8577 // The mechanism was already enabled, let's record the previous
8578 // cluster if needed.
8580 }
8581 fAutoFlush = autof;
8582 }
8583}
8584
8585////////////////////////////////////////////////////////////////////////////////
8586/// Mark the previous event as being at the end of the event cluster.
8587///
8588/// So, if fEntries is set to 10 (and this is the first cluster) when MarkEventCluster
8589/// is called, then the first cluster has 9 events.
8591{
8592 if (!fEntries) return;
8593
8594 if ( (fNClusterRange+1) > fMaxClusterRange ) {
8595 if (fMaxClusterRange) {
8596 // Resize arrays to hold a larger event cluster.
8599 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
8601 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
8603 } else {
8604 // Cluster ranges have never been initialized; create them now.
8605 fMaxClusterRange = 2;
8608 }
8609 }
8611 // If we are auto-flushing, then the cluster size is the same as the current auto-flush setting.
8612 if (fAutoFlush > 0) {
8613 // Even if the user triggers MarkEventRange prior to fAutoFlush being present, the TClusterIterator
8614 // will appropriately go to the next event range.
8616 // Otherwise, assume there is one cluster per event range (e.g., user is manually controlling the flush).
8617 } else if (fNClusterRange == 0) {
8619 } else {
8621 }
8623}
8624
8625/// Estimate the median cluster size for the TTree.
8626/// This value provides e.g. a reasonable cache size default if other heuristics fail.
8627/// Clusters with size 0 and the very last cluster range, that might not have been committed to fClusterSize yet,
8628/// are ignored for the purposes of the calculation.
8630{
8631 std::vector<Long64_t> clusterSizesPerRange;
8633
8634 // We ignore cluster sizes of 0 for the purposes of this function.
8635 // We also ignore the very last cluster range which might not have been committed to fClusterSize.
8636 std::copy_if(fClusterSize, fClusterSize + fNClusterRange, std::back_inserter(clusterSizesPerRange),
8637 [](Long64_t size) { return size != 0; });
8638
8639 std::vector<double> nClustersInRange; // we need to store doubles because of the signature of TMath::Median
8640 nClustersInRange.reserve(clusterSizesPerRange.size());
8641
8642 auto clusterRangeStart = 0ll;
8643 for (int i = 0; i < fNClusterRange; ++i) {
8644 const auto size = fClusterSize[i];
8645 R__ASSERT(size >= 0);
8646 if (fClusterSize[i] == 0)
8647 continue;
8648 const auto nClusters = (1 + fClusterRangeEnd[i] - clusterRangeStart) / fClusterSize[i];
8649 nClustersInRange.emplace_back(nClusters);
8651 }
8652
8654 const auto medianClusterSize =
8656 return medianClusterSize;
8657}
8658
8659////////////////////////////////////////////////////////////////////////////////
8660/// In case of a program crash, it will be possible to recover the data in the
8661/// tree up to the last AutoSave point.
8662/// This function may be called before filling a TTree to specify when the
8663/// branch buffers and TTree header are flushed to disk as part of
8664/// TTree::Fill().
8665/// The default is -300000000, ie the TTree will write data to disk once it
8666/// exceeds 300 MBytes.
8667/// CASE 1: If fAutoSave is positive the watermark is reached when a multiple of
8668/// fAutoSave entries have been filled.
8669/// CASE 2: If fAutoSave is negative the watermark is reached when -fAutoSave
8670/// bytes can be written to the file.
8671/// CASE 3: If fAutoSave is 0, AutoSave() will never be called automatically
8672/// as part of TTree::Fill().
8677}
8678
8679////////////////////////////////////////////////////////////////////////////////
8680/// Set a branch's basket size.
8681///
8682/// bname is the name of a branch.
8683///
8684/// - if bname="*", apply to all branches.
8685/// - if bname="xxx*", apply to all branches with name starting with xxx
8686///
8687/// see TRegexp for wildcarding options
8688/// bufsize = branch basket size
8690void TTree::SetBasketSize(const char* bname, Int_t bufsize)
8691{
8693 TRegexp re(bname, true);
8694 Int_t nb = 0;
8695 for (Int_t i = 0; i < nleaves; i++) {
8697 TBranch* branch = (TBranch*) leaf->GetBranch();
8698 TString s = branch->GetName();
8699 if (strcmp(bname, branch->GetName()) && (s.Index(re) == kNPOS)) {
8700 continue;
8701 }
8702 nb++;
8703 branch->SetBasketSize(bufsize);
8704 }
8705 if (!nb) {
8706 Error("SetBasketSize", "unknown branch -> '%s'", bname);
8707 }
8708}
8709
8710////////////////////////////////////////////////////////////////////////////////
8711/// Change branch address, dealing with clone trees properly.
8712/// See TTree::CheckBranchAddressType for the semantic of the return value.
8713///
8714/// Note: See the comments in TBranchElement::SetAddress() for the
8715/// meaning of the addr parameter and the object ownership policy.
8717Int_t TTree::SetBranchAddress(const char* bname, void* addr, TBranch** ptr)
8718{
8719 TBranch* branch = GetBranch(bname);
8720 if (!branch) {
8721 if (ptr) *ptr = nullptr;
8722 Error("SetBranchAddress", "unknown branch -> %s", bname);
8723 return kMissingBranch;
8724 }
8725 return SetBranchAddressImp(branch,addr,ptr);
8726}
8727
8728////////////////////////////////////////////////////////////////////////////////
8729/// Verify the validity of the type of addr before calling SetBranchAddress.
8730/// See TTree::CheckBranchAddressType for the semantic of the return value.
8731///
8732/// Note: See the comments in TBranchElement::SetAddress() for the
8733/// meaning of the addr parameter and the object ownership policy.
8735Int_t TTree::SetBranchAddress(const char* bname, void* addr, TClass* ptrClass, EDataType datatype, bool isptr)
8736{
8737 return SetBranchAddress(bname, addr, nullptr, ptrClass, datatype, isptr);
8738}
8741 bool isptr)
8742{
8743 if (auto *branchFromSelf = GetBranchFromSelf(bname)) {
8745
8746 // This will set the value of *ptr to branch.
8747 if (res >= 0) {
8748 // The check succeeded.
8749 if ((res & kNeedEnableDecomposedObj) && !branchFromSelf->GetMakeClass())
8750 branchFromSelf->SetMakeClass(true);
8752 } else {
8753 if (ptr)
8754 *ptr = nullptr;
8755 }
8756 return res;
8757 }
8758
8759 // Check friends
8760 // The next code section is going to look for the branch name "bname" in the friends. This could in principle be
8761 // achieved by simply calling GetBranchFromFriends, or collapse this whole function to just searching for the branch
8762 // with GetBranch. This may sometimes not be enough, for example when dealing with friendships with TChain, where
8763 // a certain amount of information may not be propagated correctly by simply calling GetBranch.
8764 if (fFriends) {
8765 int status{kMissingBranch};
8767 if (auto *tree = fe->GetTree()) {
8768 status = tree->SetBranchAddress(bname, addr, ptr, ptrClass, datatype, isptr, true);
8769 if (status != kMatch) {
8770 // Try again, the branch name may be prefixed by the tree name
8771 std::string_view bnameView{bname};
8772 if (ROOT::StartsWith(bnameView, fe->GetName())) {
8773 bnameView.remove_prefix(strlen(fe->GetName()));
8774 if (!bnameView.empty() && bnameView.front() == '.') {
8775 bnameView.remove_prefix(1);
8776 status = tree->SetBranchAddress(bnameView.data(), addr, ptr, ptrClass, datatype, isptr, true);
8777 }
8778 }
8779 }
8780 // We exit early from visiting all friends only if a perfect match was found
8781 if (status == kMatch)
8782 return status;
8783 }
8784 }
8785 // This allows for the valid case of friend TChain(s) which might hold
8786 // the requested branch, but might not know it yet since they haven't loaded
8787 // the tree. This is encoded in the kNoCheck == 5 value.
8788 if (status != kMissingBranch)
8789 return status;
8790 }
8791
8792 // Branch not found
8793 if (ptr)
8794 *ptr = nullptr;
8795
8796 return kMissingBranch;
8797}
8798
8799////////////////////////////////////////////////////////////////////////////////
8800/// Verify the validity of the type of addr before calling SetBranchAddress.
8801/// See TTree::CheckBranchAddressType for the semantic of the return value.
8802///
8803/// Note: See the comments in TBranchElement::SetAddress() for the
8804/// meaning of the addr parameter and the object ownership policy.
8806Int_t TTree::SetBranchAddress(const char *bname, void *addr, TBranch **ptr, TClass *ptrClass, EDataType datatype,
8807 bool isptr)
8808{
8809 auto res = SetBranchAddressImp(bname, addr, ptr, ptrClass, datatype, isptr);
8810 if (res == kMissingBranch)
8811 Error("SetBranchAddress", "unknown branch -> %s", bname);
8812 return res;
8813}
8815Int_t TTree::SetBranchAddress(const char *bname, void *addr, TBranch **ptr, TClass *ptrClass, EDataType datatype,
8816 bool isptr, bool)
8817{
8818 // This has been called while setting the branch address of friends of a TTree. We can't know a priori
8819 // which friend actually has the branch bname, so we avoid printing an error in case of missing branch
8820 return SetBranchAddressImp(bname, addr, ptr, ptrClass, datatype, isptr);
8821}
8822
8823////////////////////////////////////////////////////////////////////////////////
8824/// Change branch address, dealing with clone trees properly.
8825/// See TTree::CheckBranchAddressType for the semantic of the return value.
8826///
8827/// Note: See the comments in TBranchElement::SetAddress() for the
8828/// meaning of the addr parameter and the object ownership policy.
8831{
8832 if (ptr) {
8833 *ptr = branch;
8834 }
8835 if (fClones) {
8836 void* oldAddr = branch->GetAddress();
8837 TIter next(fClones);
8838 TTree* clone = nullptr;
8839 const char *bname = branch->GetName();
8840 while ((clone = (TTree*) next())) {
8841 TBranch* cloneBr = clone->GetBranch(bname);
8842 if (cloneBr && (cloneBr->GetAddress() == oldAddr)) {
8843 cloneBr->SetAddress(addr);
8844 }
8845 }
8846 }
8847 branch->SetAddress(addr);
8848 return kVoidPtr;
8849}
8850
8851////////////////////////////////////////////////////////////////////////////////
8852/// Set branch status to Process or DoNotProcess.
8853///
8854/// When reading a Tree, by default, all branches are read.
8855/// One can speed up considerably the analysis phase by activating
8856/// only the branches that hold variables involved in a query.
8857///
8858/// bname is the name of a branch.
8859///
8860/// - if bname="*", apply to all branches.
8861/// - if bname="xxx*", apply to all branches with name starting with xxx
8862///
8863/// see TRegexp for wildcarding options
8864///
8865/// - status = 1 branch will be processed
8866/// - = 0 branch will not be processed
8867///
8868/// Example:
8869///
8870/// Assume a tree T with sub-branches a,b,c,d,e,f,g,etc..
8871/// when doing T.GetEntry(i) all branches are read for entry i.
8872/// to read only the branches c and e, one can do
8873/// ~~~ {.cpp}
8874/// T.SetBranchStatus("*",0); //disable all branches
8875/// T.SetBranchStatus("c",1);
8876/// T.setBranchStatus("e",1);
8877/// T.GetEntry(i);
8878/// ~~~
8879/// bname is interpreted as a wild-carded TRegexp (see TRegexp::MakeWildcard).
8880/// Thus, "a*b" or "a.*b" matches branches starting with "a" and ending with
8881/// "b", but not any other branch with an "a" followed at some point by a
8882/// "b". For this second behavior, use "*a*b*". Note that TRegExp does not
8883/// support '|', and so you cannot select, e.g. track and shower branches
8884/// with "track|shower".
8885///
8886/// __WARNING! WARNING! WARNING!__
8887///
8888/// SetBranchStatus is matching the branch based on match of the branch
8889/// 'name' and not on the branch hierarchy! In order to be able to
8890/// selectively enable a top level object that is 'split' you need to make
8891/// sure the name of the top level branch is prefixed to the sub-branches'
8892/// name (by adding a dot ('.') at the end of the Branch creation and use the
8893/// corresponding bname.
8894///
8895/// I.e If your Tree has been created in split mode with a parent branch "parent."
8896/// (note the trailing dot).
8897/// ~~~ {.cpp}
8898/// T.SetBranchStatus("parent",1);
8899/// ~~~
8900/// will not activate the sub-branches of "parent". You should do:
8901/// ~~~ {.cpp}
8902/// T.SetBranchStatus("parent*",1);
8903/// ~~~
8904/// Without the trailing dot in the branch creation you have no choice but to
8905/// call SetBranchStatus explicitly for each of the sub branches.
8906///
8907/// An alternative to this function is to read directly and only
8908/// the interesting branches. Example:
8909/// ~~~ {.cpp}
8910/// TBranch *brc = T.GetBranch("c");
8911/// TBranch *bre = T.GetBranch("e");
8912/// brc->GetEntry(i);
8913/// bre->GetEntry(i);
8914/// ~~~
8915/// If found is not 0, the number of branch(es) found matching the regular
8916/// expression is returned in *found AND the error message 'unknown branch'
8917/// is suppressed.
8919void TTree::SetBranchStatus(const char* bname, bool status, UInt_t* found)
8920{
8921 // We already have been visited while recursively looking
8922 // through the friends tree, let return
8924 return;
8925 }
8926
8927 if (!bname || !*bname) {
8928 Error("SetBranchStatus", "Input regexp is an empty string: no match against branch names will be attempted.");
8929 return;
8930 }
8931
8933 TLeaf *leaf, *leafcount;
8934
8935 Int_t i,j;
8937 TRegexp re(bname,true);
8938 Int_t nb = 0;
8939
8940 // first pass, loop on all branches
8941 // for leafcount branches activate/deactivate in function of status
8942 for (i=0;i<nleaves;i++) {
8944 branch = (TBranch*)leaf->GetBranch();
8945 TString s = branch->GetName();
8946 if (strcmp(bname,"*")) { //Regexp gives wrong result for [] in name
8948 longname.Form("%s.%s",GetName(),branch->GetName());
8949 if (strcmp(bname,branch->GetName())
8950 && longname != bname
8951 && s.Index(re) == kNPOS) continue;
8952 }
8953 nb++;
8954 if (status) branch->ResetBit(kDoNotProcess);
8955 else branch->SetBit(kDoNotProcess);
8956 leafcount = leaf->GetLeafCount();
8957 if (leafcount) {
8958 bcount = leafcount->GetBranch();
8959 if (status) bcount->ResetBit(kDoNotProcess);
8960 else bcount->SetBit(kDoNotProcess);
8961 }
8962 }
8963 if (nb==0 && !strchr(bname,'*')) {
8964 branch = GetBranch(bname);
8965 if (branch) {
8966 if (status) branch->ResetBit(kDoNotProcess);
8967 else branch->SetBit(kDoNotProcess);
8968 ++nb;
8969 }
8970 }
8971
8972 //search in list of friends
8974 if (fFriends) {
8975 TFriendLock lock(this,kSetBranchStatus);
8978 TString name;
8979 while ((fe = (TFriendElement*)nextf())) {
8980 TTree *t = fe->GetTree();
8981 if (!t) continue;
8982
8983 // If the alias is present replace it with the real name.
8984 const char *subbranch = strstr(bname,fe->GetName());
8985 if (subbranch!=bname) subbranch = nullptr;
8986 if (subbranch) {
8987 subbranch += strlen(fe->GetName());
8988 if ( *subbranch != '.' ) subbranch = nullptr;
8989 else subbranch ++;
8990 }
8991 if (subbranch) {
8992 name.Form("%s.%s",t->GetName(),subbranch);
8993 } else {
8994 name = bname;
8995 }
8996 t->SetBranchStatus(name,status, &foundInFriend);
8997 }
8998 }
8999 if (!nb && !foundInFriend) {
9000 if (!found) {
9001 if (status) {
9002 if (strchr(bname,'*') != nullptr)
9003 Error("SetBranchStatus", "No branch name is matching wildcard -> %s", bname);
9004 else
9005 Error("SetBranchStatus", "unknown branch -> %s", bname);
9006 } else {
9007 if (strchr(bname,'*') != nullptr)
9008 Warning("SetBranchStatus", "No branch name is matching wildcard -> %s", bname);
9009 else
9010 Warning("SetBranchStatus", "unknown branch -> %s", bname);
9011 }
9012 }
9013 return;
9014 }
9015 if (found) *found = nb + foundInFriend;
9016
9017 // second pass, loop again on all branches
9018 // activate leafcount branches for active branches only
9019 for (i = 0; i < nleaves; i++) {
9021 branch = (TBranch*)leaf->GetBranch();
9022 if (!branch->TestBit(kDoNotProcess)) {
9023 leafcount = leaf->GetLeafCount();
9024 if (leafcount) {
9025 bcount = leafcount->GetBranch();
9026 bcount->ResetBit(kDoNotProcess);
9027 }
9028 } else {
9029 //Int_t nbranches = branch->GetListOfBranches()->GetEntriesFast();
9030 Int_t nbranches = branch->GetListOfBranches()->GetEntries();
9031 for (j=0;j<nbranches;j++) {
9032 bson = (TBranch*)branch->GetListOfBranches()->UncheckedAt(j);
9033 if (!bson) continue;
9034 if (!bson->TestBit(kDoNotProcess)) {
9035 if (bson->GetNleaves() <= 0) continue;
9036 branch->ResetBit(kDoNotProcess);
9037 break;
9038 }
9039 }
9040 }
9041 }
9042}
9043
9044////////////////////////////////////////////////////////////////////////////////
9045/// Set the current branch style. (static function)
9046///
9047/// - style = 0 old Branch
9048/// - style = 1 new Bronch
9053}
9054
9055////////////////////////////////////////////////////////////////////////////////
9056/// Set maximum size of the file cache (TTreeCache) in bytes.
9057//
9058/// - if cachesize = 0 the existing cache (if any) is disabled (deleted if any).
9059/// - if cachesize > 0, the cache is enabled or extended, if necessary
9060/// - if cachesize = -1 (default) it is set to the AutoFlush value when writing
9061/// the Tree (default is 30 MBytes).
9062///
9063/// The cacheSize might be clamped, see TFileCacheRead::SetBufferSize
9064///
9065/// TTreeCache's 'real' job is to actually prefetch (early grab from disk) the compressed data.
9066/// The cachesize controls the size of the read bytes from disk.
9067///
9068/// Returns:
9069/// - 0 size set, cache was created if possible
9070/// - -1 on error
9073{
9074 // remember that the user has requested an explicit cache setup
9075 fCacheUserSet = true;
9076
9077 return SetCacheSizeAux(false, cacheSize);
9078}
9079
9080////////////////////////////////////////////////////////////////////////////////
9081/// Set the maximum size of the file cache (TTreeCache) in bytes and create it if possible.
9082///
9083/// If autocache is true:
9084/// this may be an autocreated cache, possibly enlarging an existing
9085/// autocreated cache. The size is calculated. The value passed in cacheSize:
9086/// - cacheSize = 0 make cache if default cache creation is enabled.
9087/// - cachesize > 0 the cache is enabled or extended, if necessary
9088/// - cacheSize = -1 make a default sized cache in any case
9089///
9090/// If autocache is false:
9091/// this is a user requested cache. cacheSize is used to size the cache.
9092/// This cache should never be automatically adjusted. If cachesize is
9093/// 0, the cache is disabled (deleted if any).
9094///
9095/// The cacheSize might be clamped, see TFileCacheRead::SetBufferSize
9096///
9097/// TTreeCache's 'real' job is to actually prefetch (early grab from disk) the compressed data.
9098/// The cachesize controls the size of the read bytes from disk.
9099///
9100/// Returns:
9101/// - 0 size set, or existing autosized cache almost large enough.
9102/// (cache was created if possible)
9103/// - -1 on error
9105Int_t TTree::SetCacheSizeAux(bool autocache /* = true */, Long64_t cacheSize /* = 0 */ )
9106{
9107 if (autocache) {
9108 // used as a once only control for automatic cache setup
9109 fCacheDoAutoInit = false;
9110 }
9111
9112 if (!autocache) {
9113 // negative size means the user requests the default
9114 if (cacheSize < 0) {
9115 cacheSize = GetCacheAutoSize(true);
9116 }
9117 } else {
9118 if (cacheSize == 0) {
9119 cacheSize = GetCacheAutoSize();
9120 } else if (cacheSize < 0) {
9121 cacheSize = GetCacheAutoSize(true);
9122 }
9123 }
9124
9125 TFile* file = GetCurrentFile();
9126 if (!file || GetTree() != this) {
9127 // if there's no file or we are not a plain tree (e.g. if we're a TChain)
9128 // do not create a cache, only record the size if one was given
9129 if (!autocache) {
9130 fCacheSize = cacheSize;
9131 }
9132 if (GetTree() != this) {
9133 return 0;
9134 }
9135 if (!autocache && cacheSize>0) {
9136 Warning("SetCacheSizeAux", "A TTreeCache could not be created because the TTree has no file");
9137 }
9138 return 0;
9139 }
9140
9141 // Check for an existing cache
9142 TTreeCache* pf = GetReadCache(file);
9143 if (pf) {
9144 if (autocache) {
9145 // reset our cache status tracking in case existing cache was added
9146 // by the user without using one of the TTree methods
9147 fCacheSize = pf->GetBufferSize();
9148 fCacheUserSet = !pf->IsAutoCreated();
9149
9150 if (fCacheUserSet) {
9151 // existing cache was created by the user, don't change it
9152 return 0;
9153 }
9154 } else {
9155 // update the cache to ensure it records the user has explicitly
9156 // requested it
9157 pf->SetAutoCreated(false);
9158 }
9159
9160 // if we're using an automatically calculated size and the existing
9161 // cache is already almost large enough don't resize
9162 if (autocache && Long64_t(0.80*cacheSize) < fCacheSize) {
9163 // already large enough
9164 return 0;
9165 }
9166
9167 if (cacheSize == fCacheSize) {
9168 return 0;
9169 }
9170
9171 if (cacheSize == 0) {
9172 // delete existing cache
9173 pf->WaitFinishPrefetch();
9174 file->SetCacheRead(nullptr,this);
9175 delete pf;
9176 pf = nullptr;
9177 } else {
9178 // resize
9179 Int_t res = pf->SetBufferSize(cacheSize);
9180 if (res < 0) {
9181 return -1;
9182 }
9183 cacheSize = pf->GetBufferSize(); // update after potential clamp
9184 }
9185 } else {
9186 // no existing cache
9187 if (autocache) {
9188 if (fCacheUserSet) {
9189 // value was already set manually.
9190 if (fCacheSize == 0) return 0;
9191 // Expected a cache should exist; perhaps the user moved it
9192 // Do nothing more here.
9193 if (cacheSize) {
9194 Error("SetCacheSizeAux", "Not setting up an automatically sized TTreeCache because of missing cache previously set");
9195 }
9196 return -1;
9197 }
9198 }
9199 }
9200
9201 fCacheSize = cacheSize;
9202 if (cacheSize == 0 || pf) {
9203 return 0;
9204 }
9205
9206#ifdef R__USE_IMT
9208 pf = new TTreeCacheUnzip(this, cacheSize);
9209 else
9210#endif
9211 pf = new TTreeCache(this, cacheSize);
9212
9213 pf->SetAutoCreated(autocache);
9214
9215 return 0;
9216}
9217
9218////////////////////////////////////////////////////////////////////////////////
9219///interface to TTreeCache to set the cache entry range
9220///
9221/// Returns:
9222/// - 0 entry range set
9223/// - -1 on error
9226{
9227 if (!GetTree()) {
9228 if (LoadTree(0)<0) {
9229 Error("SetCacheEntryRange","Could not load a tree");
9230 return -1;
9231 }
9232 }
9233 if (GetTree()) {
9234 if (GetTree() != this) {
9235 return GetTree()->SetCacheEntryRange(first, last);
9236 }
9237 } else {
9238 Error("SetCacheEntryRange", "No tree is available. Could not set cache entry range");
9239 return -1;
9240 }
9241
9242 TFile *f = GetCurrentFile();
9243 if (!f) {
9244 Error("SetCacheEntryRange", "No file is available. Could not set cache entry range");
9245 return -1;
9246 }
9247 TTreeCache *tc = GetReadCache(f,true);
9248 if (!tc) {
9249 Error("SetCacheEntryRange", "No cache is available. Could not set entry range");
9250 return -1;
9251 }
9252 tc->SetEntryRange(first,last);
9253 return 0;
9254}
9255
9256////////////////////////////////////////////////////////////////////////////////
9257/// Interface to TTreeCache to set the number of entries for the learning phase
9262}
9263
9264////////////////////////////////////////////////////////////////////////////////
9265/// Enable/Disable circularity for this tree.
9266///
9267/// if maxEntries > 0 a maximum of maxEntries is kept in one buffer/basket
9268/// per branch in memory.
9269/// Note that when this function is called (maxEntries>0) the Tree
9270/// must be empty or having only one basket per branch.
9271/// if maxEntries <= 0 the tree circularity is disabled.
9272///
9273/// #### NOTE 1:
9274/// Circular Trees are interesting in online real time environments
9275/// to store the results of the last maxEntries events.
9276/// #### NOTE 2:
9277/// Calling SetCircular with maxEntries <= 0 is necessary before
9278/// merging circular Trees that have been saved on files.
9279/// #### NOTE 3:
9280/// SetCircular with maxEntries <= 0 is automatically called
9281/// by TChain::Merge
9282/// #### NOTE 4:
9283/// A circular Tree can still be saved in a file. When read back,
9284/// it is still a circular Tree and can be filled again.
9287{
9288 if (maxEntries <= 0) {
9289 // Disable circularity.
9290 fMaxEntries = 1000000000;
9291 fMaxEntries *= 1000;
9293 //in case the Tree was originally created in gROOT, the branch
9294 //compression level was set to -1. If the Tree is now associated to
9295 //a file, reset the compression level to the file compression level
9296 if (fDirectory) {
9299 if (bfile) {
9300 compress = bfile->GetCompressionSettings();
9301 }
9303 for (Int_t i = 0; i < nb; i++) {
9305 branch->SetCompressionSettings(compress);
9306 }
9307 }
9308 } else {
9309 // Enable circularity.
9312 }
9313}
9314
9315////////////////////////////////////////////////////////////////////////////////
9316/// Set the debug level and the debug range.
9317///
9318/// For entries in the debug range, the functions TBranchElement::Fill
9319/// and TBranchElement::GetEntry will print the number of bytes filled
9320/// or read for each branch.
9322void TTree::SetDebug(Int_t level, Long64_t min, Long64_t max)
9323{
9324 fDebug = level;
9325 fDebugMin = min;
9326 fDebugMax = max;
9327}
9328
9329////////////////////////////////////////////////////////////////////////////////
9330/// Update the default value for the branch's fEntryOffsetLen.
9331/// If updateExisting is true, also update all the existing branches.
9332/// If newdefault is less than 10, the new default value will be 10.
9335{
9336 if (newdefault < 10) {
9337 newdefault = 10;
9338 }
9340 if (updateExisting) {
9341 TIter next( GetListOfBranches() );
9342 TBranch *b;
9343 while ( ( b = (TBranch*)next() ) ) {
9344 b->SetEntryOffsetLen( newdefault, true );
9345 }
9346 if (fBranchRef) {
9348 }
9349 }
9350}
9351
9352////////////////////////////////////////////////////////////////////////////////
9353/// Change the tree's directory.
9354///
9355/// Remove reference to this tree from current directory and
9356/// add reference to new directory dir. The dir parameter can
9357/// be 0 in which case the tree does not belong to any directory.
9358///
9361{
9362 if (fDirectory == dir) {
9363 return;
9364 }
9365 if (fDirectory) {
9366 fDirectory->Remove(this);
9367
9368 // Delete or move the file cache if it points to this Tree
9369 TFile *file = fDirectory->GetFile();
9370 MoveReadCache(file,dir);
9371 }
9372 fDirectory = dir;
9373 if (fDirectory) {
9374 fDirectory->Append(this);
9375 }
9376 TFile* file = nullptr;
9377 if (fDirectory) {
9378 file = fDirectory->GetFile();
9379 }
9380 if (fBranchRef) {
9381 fBranchRef->SetFile(file);
9382 }
9383 TBranch* b = nullptr;
9384 TIter next(GetListOfBranches());
9385 while((b = (TBranch*) next())) {
9386 b->SetFile(file);
9387 }
9388}
9389
9390////////////////////////////////////////////////////////////////////////////////
9391/// Change number of entries in the tree.
9392///
9393/// If n >= 0, set number of entries in the tree = n.
9394///
9395/// If n < 0, set number of entries in the tree to match the
9396/// number of entries in each branch. (default for n is -1)
9397///
9398/// This function should be called only when one fills each branch
9399/// independently via TBranch::Fill without calling TTree::Fill.
9400/// Calling TTree::SetEntries() make sense only if the number of entries
9401/// in each branch is identical, a warning is issued otherwise.
9402/// The function returns the number of entries.
9403///
9406{
9407 // case 1 : force number of entries to n
9408 if (n >= 0) {
9409 fEntries = n;
9410 return n;
9411 }
9412
9413 // case 2; compute the number of entries from the number of entries in the branches
9414 TBranch* b(nullptr), *bMin(nullptr), *bMax(nullptr);
9416 Long64_t nMax = 0;
9417 TIter next(GetListOfBranches());
9418 while((b = (TBranch*) next())){
9419 Long64_t n2 = b->GetEntries();
9420 if (!bMin || n2 < nMin) {
9421 nMin = n2;
9422 bMin = b;
9423 }
9424 if (!bMax || n2 > nMax) {
9425 nMax = n2;
9426 bMax = b;
9427 }
9428 }
9429 if (bMin && nMin != nMax) {
9430 Warning("SetEntries", "Tree branches have different numbers of entries, eg %s has %lld entries while %s has %lld entries.",
9431 bMin->GetName(), nMin, bMax->GetName(), nMax);
9432 }
9433 fEntries = nMax;
9434 return fEntries;
9435}
9436
9437////////////////////////////////////////////////////////////////////////////////
9438/// Set an EntryList
9441{
9442 if (fEntryList) {
9443 //check if the previous entry list is owned by the tree
9445 delete fEntryList;
9446 }
9447 }
9448 fEventList = nullptr;
9449 if (!enlist) {
9450 fEntryList = nullptr;
9451 return;
9452 }
9454 fEntryList->SetTree(this);
9455
9456}
9457
9458////////////////////////////////////////////////////////////////////////////////
9459/// This function transfroms the given TEventList into a TEntryList
9460/// The new TEntryList is owned by the TTree and gets deleted when the tree
9461/// is deleted. This TEntryList can be returned by GetEntryList() function.
9464{
9466 if (fEntryList){
9469 fEntryList = nullptr; // Avoid problem with RecursiveRemove.
9470 delete tmp;
9471 } else {
9472 fEntryList = nullptr;
9473 }
9474 }
9475
9476 if (!evlist) {
9477 fEntryList = nullptr;
9478 fEventList = nullptr;
9479 return;
9480 }
9481
9483 char enlistname[100];
9484 snprintf(enlistname,100, "%s_%s", evlist->GetName(), "entrylist");
9485 fEntryList = new TEntryList(enlistname, evlist->GetTitle());
9486 fEntryList->SetDirectory(nullptr); // We own this.
9487 Int_t nsel = evlist->GetN();
9488 fEntryList->SetTree(this);
9490 for (Int_t i=0; i<nsel; i++){
9491 entry = evlist->GetEntry(i);
9493 }
9494 fEntryList->SetReapplyCut(evlist->GetReapplyCut());
9496}
9497
9498////////////////////////////////////////////////////////////////////////////////
9499/// Set number of entries to estimate variable limits.
9500/// If n is -1, the estimate is set to be the current maximum
9501/// for the tree (i.e. GetEntries() + 1)
9502/// If n is less than -1, the behavior is undefined.
9504void TTree::SetEstimate(Long64_t n /* = 1000000 */)
9505{
9506 if (n == 0) {
9507 n = 10000;
9508 } else if (n < 0) {
9509 n = fEntries - n;
9510 }
9511 fEstimate = n;
9512 GetPlayer();
9513 if (fPlayer) {
9515 }
9516}
9517
9518////////////////////////////////////////////////////////////////////////////////
9519/// Provide the end-user with the ability to enable/disable various experimental
9520/// IO features for this TTree.
9521///
9522/// Returns all the newly-set IO settings.
9525{
9526 // Purposely ignore all unsupported bits; TIOFeatures implementation already warned the user about the
9527 // error of their ways; this is just a safety check.
9529
9534
9536 return newSettings;
9537}
9538
9539////////////////////////////////////////////////////////////////////////////////
9540/// Set fFileNumber to number.
9541/// fFileNumber is used by TTree::Fill to set the file name
9542/// for a new file to be created when the current file exceeds fgTreeMaxSize.
9543/// (see TTree::ChangeFile)
9544/// if fFileNumber=10, the new file name will have a suffix "_11",
9545/// ie, fFileNumber is incremented before setting the file name
9547void TTree::SetFileNumber(Int_t number)
9548{
9549 if (fFileNumber < 0) {
9550 Warning("SetFileNumber", "file number must be positive. Set to 0");
9551 fFileNumber = 0;
9552 return;
9553 }
9554 fFileNumber = number;
9555}
9556
9557////////////////////////////////////////////////////////////////////////////////
9558/// Set all the branches in this TTree to be in decomposed object mode
9559/// (also known as MakeClass mode).
9560///
9561/// For MakeClass mode 0, the TTree expects the address where the data is stored
9562/// to be set by either the user or the TTree to the address of a full object
9563/// through the top level branch.
9564/// For MakeClass mode 1, this address is expected to point to a numerical type
9565/// or C-style array (variable or not) of numerical type, representing the
9566/// primitive data members.
9567/// The function's primary purpose is to allow the user to access the data
9568/// directly with numerical type variable rather than having to have the original
9569/// set of classes (or a reproduction thereof).
9570/// In other words, SetMakeClass sets the branch(es) into a
9571/// mode that allow its reading via a set of independent variables
9572/// (see the result of running TTree::MakeClass on your TTree) by changing the
9573/// interpretation of the address passed to SetAddress from being the beginning
9574/// of the object containing the data to being the exact location where the data
9575/// should be loaded. If you have the shared library corresponding to your object,
9576/// it is better if you do
9577/// `MyClass *objp = 0; tree->SetBranchAddress("toplevel",&objp);`, whereas
9578/// if you do not have the shared library but know your branch data type, e.g.
9579/// `Int_t* ptr = new Int_t[10];`, then:
9580/// `tree->SetMakeClass(1); tree->GetBranch("x")->SetAddress(ptr)` is the way to go.
9582void TTree::SetMakeClass(Int_t make)
9583{
9584 fMakeClass = make;
9585
9587 for (Int_t i = 0; i < nb; ++i) {
9589 branch->SetMakeClass(make);
9590 }
9591}
9592
9593////////////////////////////////////////////////////////////////////////////////
9594/// Set the maximum size in bytes of a Tree file (static function).
9595/// The default size is 100000000000LL, ie 100 Gigabytes.
9596///
9597/// In TTree::Fill, when the file has a size > fgMaxTreeSize,
9598/// the function closes the current file and starts writing into
9599/// a new file with a name of the style "file_1.root" if the original
9600/// requested file name was "file.root".
9605}
9606
9607////////////////////////////////////////////////////////////////////////////////
9608/// Change the name of this tree.
9610void TTree::SetName(const char* name)
9611{
9612 if (gPad) {
9613 gPad->Modified();
9614 }
9615 // Trees are named objects in a THashList.
9616 // We must update hashlists if we change the name.
9617 TFile *file = nullptr;
9618 TTreeCache *pf = nullptr;
9619 if (fDirectory) {
9620 fDirectory->Remove(this);
9621 if ((file = GetCurrentFile())) {
9622 pf = GetReadCache(file);
9623 file->SetCacheRead(nullptr,this,TFile::kDoNotDisconnect);
9624 }
9625 }
9626 // This changes our hash value.
9627 fName = name;
9628 if (fDirectory) {
9629 fDirectory->Append(this);
9630 if (pf) {
9632 }
9633 }
9634}
9636void TTree::SetNotify(TObject *obj)
9637{
9638 if (obj && fNotify && dynamic_cast<TNotifyLinkBase *>(fNotify)) {
9639 auto *oldLink = static_cast<TNotifyLinkBase *>(fNotify);
9640 auto *newLink = dynamic_cast<TNotifyLinkBase *>(obj);
9641 if (!newLink) {
9642 Warning("TTree::SetNotify",
9643 "The tree or chain already has a fNotify registered and it is a TNotifyLink, while the new object is "
9644 "not a TNotifyLink. Setting fNotify to the new value will lead to an orphan linked list of "
9645 "TNotifyLinks and it is most likely not intended. If this is the intended goal, please call "
9646 "SetNotify(nullptr) first to silence this warning.");
9647 } else if (newLink->GetNext() != oldLink && oldLink->GetNext() != newLink) {
9648 // If newLink->GetNext() == oldLink then we are prepending the new head, as in TNotifyLink::PrependLink
9649 // If oldLink->GetNext() == newLink then we are removing the head of the list, as in TNotifyLink::RemoveLink
9650 // Otherwise newLink and oldLink are unrelated:
9651 Warning("TTree::SetNotify",
9652 "The tree or chain already has a TNotifyLink registered, and the new TNotifyLink `obj` does not link "
9653 "to it. Setting fNotify to the new value will lead to an orphan linked list of TNotifyLinks and it is "
9654 "most likely not intended. If this is the intended goal, please call SetNotify(nullptr) first to "
9655 "silence this warning.");
9656 }
9657 }
9658
9659 fNotify = obj;
9660}
9661
9662////////////////////////////////////////////////////////////////////////////////
9663/// Change the name and title of this tree.
9665void TTree::SetObject(const char* name, const char* title)
9666{
9667 if (gPad) {
9668 gPad->Modified();
9669 }
9670
9671 // Trees are named objects in a THashList.
9672 // We must update hashlists if we change the name
9673 TFile *file = nullptr;
9674 TTreeCache *pf = nullptr;
9675 if (fDirectory) {
9676 fDirectory->Remove(this);
9677 if ((file = GetCurrentFile())) {
9678 pf = GetReadCache(file);
9679 file->SetCacheRead(nullptr,this,TFile::kDoNotDisconnect);
9680 }
9681 }
9682 // This changes our hash value.
9683 fName = name;
9684 fTitle = title;
9685 if (fDirectory) {
9686 fDirectory->Append(this);
9687 if (pf) {
9689 }
9690 }
9691}
9692
9693////////////////////////////////////////////////////////////////////////////////
9694/// Enable or disable parallel unzipping of Tree buffers.
9697{
9698#ifdef R__USE_IMT
9699 if (GetTree() == nullptr) {
9701 if (!GetTree())
9702 return;
9703 }
9704 if (GetTree() != this) {
9705 GetTree()->SetParallelUnzip(opt, RelSize);
9706 return;
9707 }
9708 TFile* file = GetCurrentFile();
9709 if (!file)
9710 return;
9711
9712 TTreeCache* pf = GetReadCache(file);
9713 if (pf && !( opt ^ (nullptr != dynamic_cast<TTreeCacheUnzip*>(pf)))) {
9714 // done with opt and type are in agreement.
9715 return;
9716 }
9717 delete pf;
9718 auto cacheSize = GetCacheAutoSize(true);
9719 if (opt) {
9720 auto unzip = new TTreeCacheUnzip(this, cacheSize);
9721 unzip->SetUnzipBufferSize( Long64_t(cacheSize * RelSize) );
9722 } else {
9723 pf = new TTreeCache(this, cacheSize);
9724 }
9725#else
9726 (void)opt;
9727 (void)RelSize;
9728#endif
9729}
9730
9731////////////////////////////////////////////////////////////////////////////////
9732/// Set perf stats
9737}
9738
9739////////////////////////////////////////////////////////////////////////////////
9740/// The current TreeIndex is replaced by the new index.
9741/// Note that this function does not delete the previous index.
9742/// This gives the possibility to play with more than one index, e.g.,
9743/// ~~~ {.cpp}
9744/// TVirtualIndex* oldIndex = tree.GetTreeIndex();
9745/// tree.SetTreeIndex(newIndex);
9746/// tree.Draw();
9747/// tree.SetTreeIndex(oldIndex);
9748/// tree.Draw(); etc
9749/// ~~~
9752{
9753 if (fTreeIndex) {
9754 fTreeIndex->SetTree(nullptr);
9755 }
9756 fTreeIndex = index;
9757}
9758
9759////////////////////////////////////////////////////////////////////////////////
9760/// Set tree weight.
9761///
9762/// The weight is used by TTree::Draw to automatically weight each
9763/// selected entry in the resulting histogram.
9764///
9765/// For example the equivalent of:
9766/// ~~~ {.cpp}
9767/// T.Draw("x", "w")
9768/// ~~~
9769/// is:
9770/// ~~~ {.cpp}
9771/// T.SetWeight(w);
9772/// T.Draw("x");
9773/// ~~~
9774/// This function is redefined by TChain::SetWeight. In case of a
9775/// TChain, an option "global" may be specified to set the same weight
9776/// for all trees in the TChain instead of the default behaviour
9777/// using the weights of each tree in the chain (see TChain::SetWeight).
9780{
9781 fWeight = w;
9782}
9783
9784////////////////////////////////////////////////////////////////////////////////
9785/// Print values of all active leaves for entry.
9786///
9787/// - if entry==-1, print current entry (default)
9788/// - if a leaf is an array, a maximum of lenmax elements is printed.
9791{
9792 if (entry != -1) {
9794 if (ret == -2) {
9795 Error("Show()", "Cannot read entry %lld (entry does not exist)", entry);
9796 return;
9797 } else if (ret == -1) {
9798 Error("Show()", "Cannot read entry %lld (I/O error)", entry);
9799 return;
9800 }
9801 ret = GetEntry(entry);
9802 if (ret == -1) {
9803 Error("Show()", "Cannot read entry %lld (I/O error)", entry);
9804 return;
9805 } else if (ret == 0) {
9806 Error("Show()", "Cannot read entry %lld (no data read)", entry);
9807 return;
9808 }
9809 }
9810 printf("======> EVENT:%lld\n", fReadEntry);
9812 Int_t nleaves = leaves->GetEntriesFast();
9813 Int_t ltype;
9814 for (Int_t i = 0; i < nleaves; i++) {
9815 TLeaf* leaf = (TLeaf*) leaves->UncheckedAt(i);
9816 TBranch* branch = leaf->GetBranch();
9817 if (branch->TestBit(kDoNotProcess)) {
9818 continue;
9819 }
9820 Int_t len = leaf->GetLen();
9821 if (len <= 0) {
9822 continue;
9823 }
9825 if (leaf->IsA() == TLeafElement::Class()) {
9826 leaf->PrintValue(lenmax);
9827 continue;
9828 }
9829 if (branch->GetListOfBranches()->GetEntriesFast() > 0) {
9830 continue;
9831 }
9832 ltype = 10;
9833 if (leaf->IsA() == TLeafF::Class()) {
9834 ltype = 5;
9835 }
9836 if (leaf->IsA() == TLeafD::Class()) {
9837 ltype = 5;
9838 }
9839 if (leaf->IsA() == TLeafC::Class()) {
9840 len = 1;
9841 ltype = 5;
9842 };
9843 printf(" %-15s = ", leaf->GetName());
9844 for (Int_t l = 0; l < len; l++) {
9845 leaf->PrintValue(l);
9846 if (l == (len - 1)) {
9847 printf("\n");
9848 continue;
9849 }
9850 printf(", ");
9851 if ((l % ltype) == 0) {
9852 printf("\n ");
9853 }
9854 }
9855 }
9856}
9857
9858////////////////////////////////////////////////////////////////////////////////
9859/// Start the TTreeViewer on this tree.
9860///
9861/// - ww is the width of the canvas in pixels
9862/// - wh is the height of the canvas in pixels
9864void TTree::StartViewer()
9865{
9866 GetPlayer();
9867 if (fPlayer) {
9868 fPlayer->StartViewer(600, 400);
9869 }
9870}
9871
9872////////////////////////////////////////////////////////////////////////////////
9873/// Stop the cache learning phase
9874///
9875/// Returns:
9876/// - 0 learning phase stopped or not active
9877/// - -1 on error
9880{
9881 if (!GetTree()) {
9882 if (LoadTree(0)<0) {
9883 Error("StopCacheLearningPhase","Could not load a tree");
9884 return -1;
9885 }
9886 }
9887 if (GetTree()) {
9888 if (GetTree() != this) {
9889 return GetTree()->StopCacheLearningPhase();
9890 }
9891 } else {
9892 Error("StopCacheLearningPhase", "No tree is available. Could not stop cache learning phase");
9893 return -1;
9894 }
9895
9896 TFile *f = GetCurrentFile();
9897 if (!f) {
9898 Error("StopCacheLearningPhase", "No file is available. Could not stop cache learning phase");
9899 return -1;
9900 }
9901 TTreeCache *tc = GetReadCache(f,true);
9902 if (!tc) {
9903 Error("StopCacheLearningPhase", "No cache is available. Could not stop learning phase");
9904 return -1;
9905 }
9906 tc->StopLearningPhase();
9907 return 0;
9908}
9909
9910////////////////////////////////////////////////////////////////////////////////
9911/// Set the fTree member for all branches and sub branches.
9914{
9915 Int_t nb = branches.GetEntriesFast();
9916 for (Int_t i = 0; i < nb; ++i) {
9917 TBranch* br = (TBranch*) branches.UncheckedAt(i);
9918 br->SetTree(tree);
9919
9920 Int_t writeBasket = br->GetWriteBasket();
9921 for (Int_t j = writeBasket; j >= 0; --j) {
9922 TBasket *bk = (TBasket*)br->GetListOfBaskets()->UncheckedAt(j);
9923 if (bk) {
9924 tree->IncrementTotalBuffers(bk->GetBufferSize());
9925 }
9926 }
9927
9928 tree->RegisterBranchFullName({std::string{br->GetFullName()}, br});
9929
9930 ROOT::Internal::TreeUtils::TBranch__SetTree(tree, *br->GetListOfBranches());
9931 }
9932}
9933
9934////////////////////////////////////////////////////////////////////////////////
9935/// Set the fTree member for all friend elements.
9938{
9939 if (frlist) {
9940 TObjLink *lnk = frlist->FirstLink();
9941 while (lnk) {
9942 TFriendElement *elem = (TFriendElement*)lnk->GetObject();
9943 elem->fParentTree = tree;
9944 lnk = lnk->Next();
9945 }
9946 }
9947}
9948
9949////////////////////////////////////////////////////////////////////////////////
9950/// Stream a class object.
9953{
9954 if (b.IsReading()) {
9955 UInt_t R__s, R__c;
9956 if (fDirectory) {
9957 fDirectory->Remove(this);
9958 //delete the file cache if it points to this Tree
9959 TFile *file = fDirectory->GetFile();
9960 MoveReadCache(file,nullptr);
9961 }
9962 fDirectory = nullptr;
9963 fCacheDoAutoInit = true;
9964 fCacheUserSet = false;
9965 fNamesToBranches.clear();
9966 Version_t R__v = b.ReadVersion(&R__s, &R__c);
9967 if (R__v > 4) {
9968 b.ReadClassBuffer(TTree::Class(), this, R__v, R__s, R__c);
9969
9970 fBranches.SetOwner(true); // True needed only for R__v < 19 and most R__v == 19
9971
9972 if (fBranchRef) fBranchRef->SetTree(this);
9975
9976 if (fTreeIndex) {
9977 fTreeIndex->SetTree(this);
9978 }
9979 if (fIndex.fN) {
9980 Warning("Streamer", "Old style index in this tree is deleted. Rebuild the index via TTree::BuildIndex");
9981 fIndex.Set(0);
9982 fIndexValues.Set(0);
9983 }
9984 if (fEstimate <= 10000) {
9985 fEstimate = 1000000;
9986 }
9987
9988 if (fNClusterRange) {
9989 // The I/O allocated just enough memory to hold the
9990 // current set of ranges.
9992 }
9993
9994 // Throughs calls to `GetCacheAutoSize` or `EnableCache` (for example
9995 // by TTreePlayer::Process, the cache size will be automatically
9996 // determined unless the user explicitly call `SetCacheSize`
9997 fCacheSize = 0;
9998 fCacheUserSet = false;
9999
10001 return;
10002 }
10003 //====process old versions before automatic schema evolution
10004 Stat_t djunk;
10005 Int_t ijunk;
10010 b >> fScanField;
10013 b >> djunk; fEntries = (Long64_t)djunk;
10018 if (fEstimate <= 10000) fEstimate = 1000000;
10020 if (fBranchRef) fBranchRef->SetTree(this);
10024 if (R__v > 1) fIndexValues.Streamer(b);
10025 if (R__v > 2) fIndex.Streamer(b);
10026 if (R__v > 3) {
10028 OldInfoList.Streamer(b);
10029 OldInfoList.Delete();
10030 }
10031 fNClusterRange = 0;
10034 b.CheckByteCount(R__s, R__c, TTree::IsA());
10035 //====end of old versions
10036 } else {
10037 if (fBranchRef) {
10038 fBranchRef->Clear();
10039 }
10041 if (table) TRefTable::SetRefTable(nullptr);
10042
10043 b.WriteClassBuffer(TTree::Class(), this);
10044
10045 if (table) TRefTable::SetRefTable(table);
10046 }
10047}
10048
10049////////////////////////////////////////////////////////////////////////////////
10050/// Unbinned fit of one or more variable(s) from a tree.
10051///
10052/// funcname is a TF1 function.
10053///
10054/// \note see TTree::Draw for explanations of the other parameters.
10055///
10056/// Fit the variable varexp using the function funcname using the
10057/// selection cuts given by selection.
10058///
10059/// The list of fit options is given in parameter option.
10060///
10061/// - option = "Q" Quiet mode (minimum printing)
10062/// - option = "V" Verbose mode (default is between Q and V)
10063/// - option = "E" Perform better Errors estimation using Minos technique
10064/// - option = "M" More. Improve fit results
10065///
10066/// You can specify boundary limits for some or all parameters via
10067/// ~~~ {.cpp}
10068/// func->SetParLimits(p_number, parmin, parmax);
10069/// ~~~
10070/// if parmin>=parmax, the parameter is fixed
10071///
10072/// Note that you are not forced to fix the limits for all parameters.
10073/// For example, if you fit a function with 6 parameters, you can do:
10074/// ~~~ {.cpp}
10075/// func->SetParameters(0,3.1,1.e-6,0.1,-8,100);
10076/// func->SetParLimits(4,-10,-4);
10077/// func->SetParLimits(5, 1,1);
10078/// ~~~
10079/// With this setup:
10080///
10081/// - Parameters 0->3 can vary freely
10082/// - Parameter 4 has boundaries [-10,-4] with initial value -8
10083/// - Parameter 5 is fixed to 100.
10084///
10085/// For the fit to be meaningful, the function must be self-normalized.
10086///
10087/// i.e. It must have the same integral regardless of the parameter
10088/// settings. Otherwise the fit will effectively just maximize the
10089/// area.
10090///
10091/// It is mandatory to have a normalization variable
10092/// which is fixed for the fit. e.g.
10093/// ~~~ {.cpp}
10094/// TF1* f1 = new TF1("f1", "gaus(0)/sqrt(2*3.14159)/[2]", 0, 5);
10095/// f1->SetParameters(1, 3.1, 0.01);
10096/// f1->SetParLimits(0, 1, 1); // fix the normalization parameter to 1
10097/// data->UnbinnedFit("f1", "jpsimass", "jpsipt>3.0");
10098/// ~~~
10099/// 1, 2 and 3 Dimensional fits are supported. See also TTree::Fit
10100///
10101/// Return status:
10102///
10103/// - The function return the status of the fit in the following form
10104/// fitResult = migradResult + 10*minosResult + 100*hesseResult + 1000*improveResult
10105/// - The fitResult is 0 is the fit is OK.
10106/// - The fitResult is negative in case of an error not connected with the fit.
10107/// - The number of entries used in the fit can be obtained via mytree.GetSelectedRows();
10108/// - If the number of selected entries is null the function returns -1
10111{
10112 GetPlayer();
10113 if (fPlayer) {
10115 }
10116 return -1;
10117}
10118
10119////////////////////////////////////////////////////////////////////////////////
10120/// Replace current attributes by current style.
10143}
10144
10145////////////////////////////////////////////////////////////////////////////////
10146/// Write this object to the current directory. For more see TObject::Write
10147/// If option & kFlushBasket, call FlushBasket before writing the tree.
10149Int_t TTree::Write(const char *name, Int_t option, Int_t bufsize) const
10150{
10153 return 0;
10155}
10156
10157////////////////////////////////////////////////////////////////////////////////
10158/// Write this object to the current directory. For more see TObject::Write
10159/// If option & kFlushBasket, call FlushBasket before writing the tree.
10162{
10163 return ((const TTree*)this)->Write(name, option, bufsize);
10164}
10165
10166////////////////////////////////////////////////////////////////////////////////
10167/// \class TTreeFriendLeafIter
10168///
10169/// Iterator on all the leaves in a TTree and its friend
10170
10171
10172////////////////////////////////////////////////////////////////////////////////
10173/// Create a new iterator. By default the iteration direction
10174/// is kIterForward. To go backward use kIterBackward.
10177: fTree(const_cast<TTree*>(tree))
10178, fLeafIter(nullptr)
10179, fTreeIter(nullptr)
10180, fDirection(dir)
10181{
10182}
10183
10184////////////////////////////////////////////////////////////////////////////////
10185/// Copy constructor. Does NOT copy the 'cursor' location!
10188: TIterator(iter)
10189, fTree(iter.fTree)
10190, fLeafIter(nullptr)
10191, fTreeIter(nullptr)
10192, fDirection(iter.fDirection)
10193{
10194}
10195
10196////////////////////////////////////////////////////////////////////////////////
10197/// Overridden assignment operator. Does NOT copy the 'cursor' location!
10200{
10201 if (this != &rhs && rhs.IsA() == TTreeFriendLeafIter::Class()) {
10203 fDirection = rhs1.fDirection;
10204 }
10205 return *this;
10206}
10207
10208////////////////////////////////////////////////////////////////////////////////
10209/// Overridden assignment operator. Does NOT copy the 'cursor' location!
10212{
10213 if (this != &rhs) {
10214 fDirection = rhs.fDirection;
10215 }
10216 return *this;
10217}
10218
10219////////////////////////////////////////////////////////////////////////////////
10220/// Go the next friend element
10223{
10224 if (!fTree) return nullptr;
10225
10226 TObject * next;
10227 TTree * nextTree;
10228
10229 if (!fLeafIter) {
10230 TObjArray *list = fTree->GetListOfLeaves();
10231 if (!list) return nullptr; // Can happen with an empty chain.
10232 fLeafIter = list->MakeIterator(fDirection);
10233 if (!fLeafIter) return nullptr;
10234 }
10235
10236 next = fLeafIter->Next();
10237 if (!next) {
10238 if (!fTreeIter) {
10240 if (!list) return next;
10241 fTreeIter = list->MakeIterator(fDirection);
10242 if (!fTreeIter) return nullptr;
10243 }
10245 ///nextTree = (TTree*)fTreeIter->Next();
10246 if (nextFriend) {
10247 nextTree = const_cast<TTree*>(nextFriend->GetTree());
10248 if (!nextTree) return Next();
10250 fLeafIter = nextTree->GetListOfLeaves()->MakeIterator(fDirection);
10251 if (!fLeafIter) return nullptr;
10252 next = fLeafIter->Next();
10253 }
10254 }
10255 return next;
10256}
10257
10258////////////////////////////////////////////////////////////////////////////////
10259/// Returns the object option stored in the list.
10262{
10263 if (fLeafIter) return fLeafIter->GetOption();
10264 return "";
10265}
10271}
10277}
#define R__unlikely(expr)
Definition RConfig.hxx:592
#define SafeDelete(p)
Definition RConfig.hxx:531
#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
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:77
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
short Version_t
Class version identifier (short)
Definition RtypesCore.h:79
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:68
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:60
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:71
double Double_t
Double 8 bytes.
Definition RtypesCore.h:73
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
Definition RtypesCore.h:131
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
unsigned long long ULong64_t
Portable unsigned long integer 8 bytes.
Definition RtypesCore.h:84
const char Option_t
Option string (const char)
Definition RtypesCore.h:80
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:125
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:145
int nentries
R__EXTERN TInterpreter * gCling
Binding & operator=(OUT(*fun)(void))
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:783
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:426
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2510
R__EXTERN TStyle * gStyle
Definition TStyle.h:442
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
constexpr Int_t kNEntriesResort
Definition TTree.cxx:476
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:4843
static char DataTypeToChar(EDataType datatype)
Definition TTree.cxx:487
void TFriendElement__SetTree(TTree *tree, TList *frlist)
Set the fTree member for all friend elements.
Definition TTree.cxx:9936
bool CheckReshuffling(TTree &mainTree, TTree &friendTree)
Definition TTree.cxx:1269
constexpr Float_t kNEntriesResortInv
Definition TTree.cxx:477
#define R__LOCKGUARD(mutex)
#define gPad
#define snprintf
Definition civetweb.c:1579
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:21
virtual Style_t GetMarkerStyle() const
Return the marker style.
Definition TAttMarker.h:34
virtual void SetMarkerColor(Color_t mcolor=1)
Set the marker color.
Definition TAttMarker.h:41
virtual Color_t GetMarkerColor() const
Return the marker color.
Definition TAttMarker.h:33
virtual Size_t GetMarkerSize() const
Return the marker size.
Definition TAttMarker.h:35
virtual void SetMarkerStyle(Style_t mstyle=1)
Set the marker style.
Definition TAttMarker.h:43
virtual void Streamer(TBuffer &)
virtual void SetMarkerSize(Size_t msize=1)
Set the marker size.
Definition TAttMarker.h:48
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:2326
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition TClass.cxx:2907
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition TClass.cxx:5048
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:5470
void BuildRealData(void *pointer=nullptr, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition TClass.cxx:2038
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:3694
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:6043
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:4657
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4932
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2918
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:2994
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:2417
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:3490
@ kDoNotDisconnect
Definition TFile.h:148
virtual void Flush()
Synchronize a file's in-memory and on-disk states.
Definition TFile.cxx:1152
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:3787
virtual void WriteHeader()
Write File Header.
Definition TFile.cxx:2667
@ kCancelTTreeChangeRequest
Definition TFile.h:275
TFileCacheRead * GetCacheRead(const TObject *tree=nullptr) const
Return a pointer to the current read cache.
Definition TFile.cxx:1273
<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:615
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:459
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:204
@ kBitMask
Definition TObject.h:95
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:224
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1081
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:986
@ kOnlyPrepStep
Used to request that the class specific implementation of TObject::Write just prepare the objects to ...
Definition TObject.h:115
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:885
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:546
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1095
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1123
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:1069
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:425
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:2060
const char * Data() const
Definition TString.h:384
Bool_t EqualTo(const char *cs, ECaseCompare cmp=kExact) const
Definition TString.h:654
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:713
@ 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:2385
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2363
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:641
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:660
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:10198
TObject * Next() override
Go the next friend element.
Definition TTree.cxx:10221
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:10260
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:640
Long64_t Previous()
Move on to the previous cluster and return the starting entry of this previous cluster.
Definition TTree.cxx:723
Long64_t Next()
Move on to the next cluster and return the starting entry of this next cluster.
Definition TTree.cxx:679
Long64_t GetNextEntry()
Definition TTree.h:359
TClusterIterator(TTree *tree, Long64_t firstEntry)
Regular constructor.
Definition TTree.cxx:589
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:555
TFriendLock(const TFriendLock &)
Copy constructor.
Definition TTree.cxx:545
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:568
A TTree represents a columnar dataset.
Definition TTree.h:89
virtual Int_t Fill()
Fill all branches.
Definition TTree.cxx:4655
virtual TFriendElement * AddFriend(const char *treename, const char *filename="")
Add a TFriendElement to the list of friends.
Definition TTree.cxx:1361
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:6437
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:2684
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:5386
virtual Int_t SetBranchAddress(const char *bname, void *add, TBranch **ptr, TClass *realClass, EDataType datatype, bool isptr, bool suppressMissingBranchError)
Definition TTree.cxx:8814
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:4950
virtual void SetBranchStatus(const char *bname, bool status=true, UInt_t *found=nullptr)
Set branch status to Process or DoNotProcess.
Definition TTree.cxx:8918
bool EnableCache()
Enable the TTreeCache unless explicitly disabled for this TTree by a prior call to SetCacheSize(0).
Definition TTree.cxx:2717
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition TTree.cxx:5438
static Int_t GetBranchStyle()
Static function returning the current branch style.
Definition TTree.cxx:5479
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:5464
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:5186
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:9789
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:9878
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:5726
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:9285
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:1088
Long64_t GetMedianClusterSize()
Estimate the median cluster size for the TTree.
Definition TTree.cxx:8628
virtual TClusterIterator GetClusterIterator(Long64_t firstentry)
Return an iterator over the cluster of baskets starting at firstentry.
Definition TTree.cxx:5551
virtual void ResetBranchAddress(TBranch *)
Tell a branch to set its address to zero.
Definition TTree.cxx:8382
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:7905
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:5998
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:9404
virtual TObjArray * GetListOfLeaves()
Definition TTree.h:584
TLeaf * SearchLeafInListOfLeaves(const char *branchName, const char *leafName)
Definition TTree.cxx:6206
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:2106
virtual Int_t GetEntryWithIndex(Long64_t major, Long64_t minor=0)
Read entry corresponding to major and minor number.
Definition TTree.cxx:6016
Long64_t GetCacheAutoSize(bool withDefault=false)
Used for automatic sizing of the cache.
Definition TTree.cxx:5491
virtual TBranch * BranchRef()
Build the optional branch supporting the TRefTable.
Definition TTree.cxx:2360
TFile * GetCurrentFile() const
Return pointer to the current file.
Definition TTree.cxx:5563
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:3761
virtual Int_t DropBranchFromCache(const char *bname, bool subbranches=false)
Remove the branch with name 'bname' from the Tree cache.
Definition TTree.cxx:1171
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:5136
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:9951
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:8198
TVirtualTreePlayer * GetPlayer()
Load the TTreePlayer (if not already done).
Definition TTree.cxx:6540
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:7011
virtual Long64_t ReadStream(std::istream &inputStream, const char *branchDescriptor="", char delimiter=' ')
Create or simply read branches from an input stream.
Definition TTree.cxx:7932
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:9321
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:6064
virtual void SetNotify(TObject *obj)
Sets the address of the object to be notified when the tree is loaded.
Definition TTree.cxx:9635
virtual Double_t GetMaximum(const char *columname)
Return maximum of column with name columname.
Definition TTree.cxx:6514
virtual Long64_t GetEntryNumberWithBestIndex(Long64_t major, Long64_t minor=0) const
Return entry number corresponding to major and minor number.
Definition TTree.cxx:5978
static void SetMaxTreeSize(Long64_t maxsize=100000000000LL)
Set the maximum size in bytes of a Tree file (static function).
Definition TTree.cxx:9601
void Print(Option_t *option="") const override
Print a summary of the tree contents.
Definition TTree.cxx:7538
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:10109
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:7690
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:6201
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:9581
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:7331
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:6553
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:2781
@ kSplitCollectionOfPointers
Definition TTree.h:318
virtual TEntryList * GetEntryList()
Returns the entry list assigned to this tree.
Definition TTree.cxx:5942
virtual void SetWeight(Double_t w=1, Option_t *option="")
Set tree weight.
Definition TTree.cxx:9778
void InitializeBranchLists(bool checkLeafCount)
Divides the top-level branches into two vectors: (i) branches to be processed sequentially and (ii) b...
Definition TTree.cxx:5869
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:9733
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:9258
TEntryList * fEntryList
! Pointer to event selection list (if one)
Definition TTree.h:136
TBranch * FindBranchFromFriends(const char *branchName)
Definition TTree.cxx:4906
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:7145
virtual void SetMaxVirtualSize(Long64_t size=0)
Definition TTree.h:725
virtual void DropBaskets()
Remove some baskets from memory.
Definition TTree.cxx:4570
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:8673
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:9695
virtual void SetDirectory(TDirectory *dir)
Change the tree's directory.
Definition TTree.cxx:9359
void SortBranchesByTime()
Sorts top-level branches by the last average task time recorded per branch.
Definition TTree.cxx:5922
void Delete(Option_t *option="") override
Delete this tree from memory or/and disk.
Definition TTree.cxx:3789
virtual TBranchRef * GetBranchRef() const
Definition TTree.h:505
TLeaf * SearchLeafInListOfFriends(const char *branchName, const char *leafName)
Definition TTree.cxx:6255
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:7768
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:1664
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:9462
void MoveReadCache(TFile *src, TDirectory *dir)
Move a cache from a file to the current file in dir.
Definition TTree.cxx:7302
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:8351
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:9503
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:9104
virtual Long64_t AutoSave(Option_t *option="")
AutoSave tree header every fAutoSave bytes.
Definition TTree.cxx:1529
virtual Long64_t GetEntryNumber(Long64_t entry) const
Return entry number corresponding to entry.
Definition TTree.cxx:5953
virtual TTree * CloneTree(Long64_t nentries=-1, Option_t *option="")
Create a clone of this tree and copy nentries.
Definition TTree.cxx:3175
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:6306
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:8320
virtual void KeepCircular()
Keep a maximum of fMaxEntries in memory.
Definition TTree.cxx:6650
virtual void SetDefaultEntryOffsetLen(Int_t newdefault, bool updateExisting=false)
Update the default value for the branch's fEntryOffsetLen.
Definition TTree.cxx:9333
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:3861
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:7065
virtual void SetObject(const char *name, const char *title)
Change the name and title of this tree.
Definition TTree.cxx:9664
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:5350
TTree()
Default constructor and I/O constructor.
Definition TTree.cxx:766
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:7096
bool MemoryFull(Int_t nbytes)
Check if adding nbytes to memory we are still below MaxVirtualsize.
Definition TTree.cxx:7080
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:9439
bool Notify() override
Function called when loading a new class library.
Definition TTree.cxx:7352
virtual void AddZipBytes(Int_t zip)
Definition TTree.h:384
virtual Long64_t LoadTree(Long64_t entry)
Set current entry.
Definition TTree.cxx:6708
virtual Long64_t ReadFile(const char *filename, const char *branchDescriptor="", char delimiter=' ')
Create or simply read branches from filename.
Definition TTree.cxx:7881
virtual const char * GetAlias(const char *aliasName) const
Returns the expanded value of the alias. Search in the friends if any.
Definition TTree.cxx:5283
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:9523
virtual TBasket * CreateBasket(TBranch *)
Create a basket for this tree and given branch.
Definition TTree.cxx:3773
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:6532
virtual void RemoveFriend(TTree *)
Remove a friend from the list of friends.
Definition TTree.cxx:8294
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:2641
virtual TList * GetUserInfo()
Return a pointer to the list containing user objects associated to this tree.
Definition TTree.cxx:6591
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:5598
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:7829
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:2436
virtual void SetBasketSize(const char *bname, Int_t buffsize=16000)
Set a branch's basket size.
Definition TTree.cxx:8689
static void SetBranchStyle(Int_t style=1)
Set the current branch style.
Definition TTree.cxx:9049
~TTree() override
Destructor.
Definition TTree.cxx:949
void ImportClusterRanges(TTree *fromtree)
Appends the cluster range information stored in 'fromtree' to this tree, including the value of fAuto...
Definition TTree.cxx:6607
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:5203
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:6800
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:10160
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:10121
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:1583
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:9750
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:7376
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:7814
virtual Int_t SetCacheEntryRange(Long64_t first, Long64_t last)
interface to TTreeCache to set the cache entry range
Definition TTree.cxx:9224
static Long64_t GetMaxTreeSize()
Static function which returns the tree file size limit in bytes.
Definition TTree.cxx:6522
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:8472
virtual void CopyAddresses(TTree *, bool undo=false)
Set branch addresses of passed tree equal to ours.
Definition TTree.cxx:3341
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:2669
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:4583
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:8233
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:8527
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:8589
TBranch * FindBranchFromSelf(const char *branchName)
Definition TTree.cxx:4886
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:9546
virtual TLeaf * FindLeaf(const char *name)
Find first leaf containing searchname.
Definition TTree.cxx:4973
virtual void StartViewer()
Start the TTreeViewer on this tree.
Definition TTree.cxx:9863
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:6883
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:8392
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:9609
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:8274
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:8739
virtual Int_t SetCacheSize(Long64_t cachesize=-1)
Set maximum size of the file cache (TTreeCache) in bytes.
Definition TTree.cxx:9071
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:1248
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:2903
TBuffer * GetTransientBuffer(Int_t size)
Returns the transient buffer currently used by this TTree for reading/writing baskets.
Definition TTree.cxx:1066
ROOT::TIOFeatures GetIOFeatures() const
Returns the current set of IO settings.
Definition TTree.cxx:6193
virtual Int_t MakeClass(const char *classname=nullptr, Option_t *option="")
Generate a skeleton analysis class for this tree.
Definition TTree.cxx:6850
virtual const char * GetFriendAlias(TTree *) const
If the 'tree' is a friend, this method returns its alias name.
Definition TTree.cxx:6121
virtual void RemoveExternalFriend(TFriendElement *)
Removes external friend.
Definition TTree.cxx:8285
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:1760
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:8430
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:2444
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:3576
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:6686
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:7519
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:10272
TBranch * CallBranchImpRef(TTree &tree, const char *branchname, TClass *ptrClass, EDataType datatype, void *addobj, Int_t bufsize=32000, Int_t splitlevel=99)
Definition TTree.cxx:10266
void TBranch__SetTree(TTree *tree, TObjArray &branches)
Set the fTree member for all branches and sub branches.
Definition TTree.cxx:9912
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
Definition TROOT.cxx:675
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:415
bool StartsWith(std::string_view string, std::string_view prefix)
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)
Same as RMS.
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