Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TTree.cxx
Go to the documentation of this file.
1// @(#)root/tree:$Id$
2// Author: Rene Brun 12/01/96
3
4/*************************************************************************
5 * Copyright (C) 1995-2024, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11/**
12 \defgroup tree TTree
13
14 RNTuple is the modern way of storing columnar datasets: please consider to use it
15 before starting new projects based on TTree and related classes.
16
17 In order to store columnar datasets, ROOT historically provides the TTree, TChain,
18 TNtuple and TNtupleD classes.
19 The TTree class represents a columnar dataset. Any C++ type can be stored in the
20 columns. The TTree has allowed to store about **1 EB** of data coming from the LHC alone:
21 it is demonstrated to scale and it's battle tested. It has been optimized during the years
22 to reduce dataset sizes on disk and to deliver excellent runtime performance.
23 It allows to access only part of the columns of the datasets, too.
24 The TNtuple and TNtupleD classes are specialisations of the TTree class which can
25 only hold single precision and double precision floating-point numbers respectively;
26 The TChain is a collection of TTrees, which can be located also in different files.
27
28*/
29
30/** \class TTree
31\ingroup tree
32
33A TTree represents a columnar dataset. Any C++ type can be stored in its columns. The modern
34version of TTree is RNTuple: please consider using it before opting for TTree.
35
36A TTree, often called in jargon *tree*, consists of a list of independent columns or *branches*,
37represented by the TBranch class.
38Behind each branch, buffers are allocated automatically by ROOT.
39Such buffers are automatically written to disk or kept in memory until the size stored in the
40attribute fMaxVirtualSize is reached.
41Variables of one branch are written to the same buffer. A branch buffer is
42automatically compressed if the file compression attribute is set (default).
43Branches may be written to different files (see TBranch::SetFile).
44
45The ROOT user can decide to make one single branch and serialize one object into
46one single I/O buffer or to make several branches.
47Making several branches is particularly interesting in the data analysis phase,
48when it is desirable to have a high reading rate and not all columns are equally interesting
49
50\anchor creatingattreetoc
51## Create a TTree to store columnar data
52- [Construct a TTree](\ref creatingattree)
53- [Add a column of Fundamental Types and Arrays thereof](\ref addcolumnoffundamentaltypes)
54- [Add a column of a STL Collection instances](\ref addingacolumnofstl)
55- [Add a column holding an object](\ref addingacolumnofobjs)
56- [Add a column holding a TClonesArray](\ref addingacolumnoftclonesarray)
57- [Fill the tree](\ref fillthetree)
58- [Add a column to an already existing Tree](\ref addcoltoexistingtree)
59- [An Example](\ref fullexample)
60
61\anchor creatingattree
62## Construct a TTree
63
64~~~ {.cpp}
65 TTree tree(name, title)
66~~~
67Creates a Tree with name and title.
68
69Various kinds of branches can be added to a tree:
70- Variables representing fundamental types, simple classes/structures or list of variables: for example for C or Fortran
71structures.
72- Any C++ object or collection, provided by the STL or ROOT.
73
74In the following, the details about the creation of different types of branches are given.
75
76\anchor addcolumnoffundamentaltypes
77## Add a column ("branch") holding fundamental types and arrays thereof
78This strategy works also for lists of variables, e.g. to describe simple structures.
79It is strongly recommended to persistify those as objects rather than lists of leaves.
80
81~~~ {.cpp}
82 auto branch = tree.Branch(branchname, address, leaflist, bufsize)
83~~~
84- `address` is the address of the first item of a structure
85- `leaflist` is the concatenation of all the variable names and types
86 separated by a colon character :
87 The variable name and the variable type are separated by a
88 slash (/). The variable type must be 1 character. (Characters
89 after the first are legal and will be appended to the visible
90 name of the leaf, but have no effect.) If no type is given, the
91 type of the variable is assumed to be the same as the previous
92 variable. If the first variable does not have a type, it is
93 assumed of type `F` by default. The list of currently supported
94 types is given below:
95 - `C` : a character string terminated by the 0 character
96 - `B` : an 8 bit integer (`Char_t`); Mostly signed, might be unsigned in special platforms or depending on compiler flags, thus do not use std::int8_t as underlying variable since they are not equivalent; Treated as a character when in an array.
97 - `b` : an 8 bit unsigned integer (`UChar_t`)
98 - `S` : a 16 bit signed integer (`Short_t`)
99 - `s` : a 16 bit unsigned integer (`UShort_t`)
100 - `I` : a 32 bit signed integer (`Int_t`)
101 - `i` : a 32 bit unsigned integer (`UInt_t`)
102 - `F` : a 32 bit floating point (`Float_t`)
103 - `f` : a 24 bit (or 32) floating point with truncated mantissa (`Float16_t`, stored as 3 bytes by default or as fixed-point arithmetic 4 bytes Int_t if range is customized; occupies 4 bytes in memory): By default, in disk, only 21 bits are used: 1 for the sign, 8 for the exponent and 12 for the mantissa. Can be customized with suffix `[min,max(,nbits)] `where `nbits` is for the mantissa.
104 - `D` : a 64 bit floating point (`Double_t`)
105 - `d` : a 32 (or 24) bit floating point with truncated mantissa (`Double32_t`, stored as a 4 bytes Float_t by default or as 3 bytes if range is customized; occupies 8 bytes in memory): By default, in disk, 1 bit is used for the sign, 8 for the exponent and 23 for the mantissa. Can be customized to 3 bytes (24 bits) with suffix `[min,max(,nbits)]` where `nbits` is for the mantissa.
106 - `L` : a 64 bit signed integer (`Long64_t`)
107 - `l` : a 64 bit unsigned integer (`ULong64_t`)
108 - `G` : a long signed integer, stored as 64 bit (`Long_t`)
109 - `g` : a long unsigned integer, stored as 64 bit (`ULong_t`)
110 - `O` : [the letter `o`, not a zero] a boolean (`bool`)
111
112 Examples:
113 - A int: "myVar/I"
114 - A float array with fixed size: "myArrfloat[42]/F"
115 - An double array with variable size, held by the `myvar` column: "myArrdouble[myvar]/D"
116 - An Double32_t array with variable size, held by the `myvar` column , with values between 0 and 16: "myArr[myvar]/d[0,10]"
117 - The `myvar` column, which holds the variable size, **MUST** be an `Int_t` (/I).
118
119- If the address points to a single numerical variable, the leaflist is optional:
120~~~ {.cpp}
121 int value;
122 tree->Branch(branchname, &value);
123~~~
124- If the address points to more than one numerical variable, we strongly recommend
125 that the variable be sorted in decreasing order of size. Any other order will
126 result in a non-portable TTree (i.e. you will not be able to read it back on a
127 platform with a different padding strategy).
128 We recommend to persistify objects rather than composite leaflists.
129- In case of the truncated floating point types (`Float16_t` and `Double32_t`) you can
130 also specify the range in the style `[xmin,xmax]` or `[xmin,xmax,nbits]` after
131 the type character. For example, for storing a variable size array `myArr` of
132 `Double32_t` with values within a range of `[0, 2*pi]` and the size of which is stored
133 in an `Int_t` (/I) branch called `myArrSize`, the syntax for the `leaflist` string would
134 be: `myArr[myArrSize]/d[0,twopi]`. Of course the number of bits could be specified,
135 the standard rules of opaque typedefs annotation are valid. For example, if only
136 18 bits were sufficient, the syntax would become: `myArr[myArrSize]/d[0,twopi,18]`.
137 See TStreamerElement::GetRange for further details.
138
139 Examples of writing/reading plain C arrays with fixed or variable length into/from TTrees:
140
141~~~ {.cpp}
142 TTree *t = new TTree("t", "t");
143 int n;
144 Double32_t arr[64];
145 // Double32_t* arr = new Double32_t[64]; // equivalent, later just remember delete[]
146 t->Branch("n", &n);
147 t->Branch("arr", arr, "arr[n]/d[0,1,32]");
148 t->Branch("arr_def", arr, "arr_def[n]/d");
149 t->Branch("arr_fix", arr, "arr_fix[64]/d[0,1,32]");
150 t->Branch("arr_fix_def", arr, "arr_fix_def[64]/d");
151 t->Branch("single", arr, "single/d[0,1,32]");
152 t->Branch("single_def", arr, "single_def/d");
153 for (int j = 0; j < 64; ++j) {
154 arr[j] = 0.01 * j;
155 }
156 n = 3;
157 t->Fill();
158 // Reading now:
159 const auto nEntries = t->GetEntries();
160 t->Scan();
161 for (auto name : {"arr", "arr_def", "arr_fix", "arr_fix_def", "single", "single_def"}) {
162 t->ResetBranchAddresses();
163 t->SetBranchAddress("n", &n);
164 t->SetBranchAddress(name, arr);
165 for (Long64_t i = 0; i < nEntries; ++i) {
166 t->GetEntry(i);
167 // Work with arr
168 }
169 }
170~~~
171
172\anchor addingacolumnofstl
173## Adding a column holding STL collection instances (e.g. std::vector or std::list)
174
175~~~ {.cpp}
176 auto branch = tree.Branch( branchname, STLcollection, bufsize, splitlevel);
177~~~
178`STLcollection` is the address of a pointer to a container of the standard
179library such as `std::vector`, `std::list`, containing pointers, fundamental types
180or objects.
181If the splitlevel is a value bigger than 100 (`TTree::kSplitCollectionOfPointers`)
182then the collection will be written in split mode, i.e. transparently storing
183individual data members as arrays, therewith potentially increasing compression ratio.
184
185### Note
186In case of dynamic structures changing with each entry, see e.g.
187~~~ {.cpp}
188 branch->SetAddress(void *address)
189~~~
190one must redefine the branch address before filling the branch
191again. This is done via the `TBranch::SetAddress` member function.
192
193\anchor addingacolumnofobjs
194## Add a column holding objects (or a TObjArray)
195
196~~~ {.cpp}
197 MyClass object;
198 auto branch = tree.Branch(branchname, &object, bufsize, splitlevel)
199~~~
200Note: The 2nd parameter must be the address of a valid object.
201 The object must not be destroyed (i.e. be deleted) until the TTree
202 is deleted or TTree::ResetBranchAddress is called.
203
204- if splitlevel=0, the object is serialized in the branch buffer.
205- if splitlevel=1 (default), this branch will automatically be split
206 into subbranches, with one subbranch for each data member or object
207 of the object itself. In case the object member is a TClonesArray,
208 the mechanism described in case C is applied to this array.
209- if splitlevel=2 ,this branch will automatically be split
210 into subbranches, with one subbranch for each data member or object
211 of the object itself. In case the object member is a TClonesArray,
212 it is processed as a TObject*, only one branch.
213
214Another available syntax is the following:
215
216~~~ {.cpp}
217 auto branch_a = tree.Branch(branchname, &p_object, bufsize, splitlevel)
218 auto branch_b = tree.Branch(branchname, className, &p_object, bufsize, splitlevel)
219~~~
220- `p_object` is a pointer to an object.
221- If `className` is not specified, the `Branch` method uses the type of `p_object`
222 to determine the type of the object.
223- If `className` is used to specify explicitly the object type, the `className`
224 must be of a type related to the one pointed to by the pointer. It should be
225 either a parent or derived class.
226
227Note: The pointer whose address is passed to `TTree::Branch` must not
228 be destroyed (i.e. go out of scope) until the TTree is deleted or
229 TTree::ResetBranchAddress is called.
230
231Note: The pointer `p_object` can be initialized before calling `TTree::Branch`
232~~~ {.cpp}
233 auto p_object = new MyDataClass;
234 tree.Branch(branchname, &p_object);
235~~~
236or not
237~~~ {.cpp}
238 MyDataClass* p_object = nullptr;
239 tree.Branch(branchname, &p_object);
240~~~
241In either case, the ownership of the object is not taken over by the `TTree`.
242Even though in the first case an object is be allocated by `TTree::Branch`,
243the object will <b>not</b> be deleted when the `TTree` is deleted.
244
245\anchor addingacolumnoftclonesarray
246## Add a column holding TClonesArray instances
247
248*The usage of `TClonesArray` should be abandoned in favour of `std::vector`,
249for which `TTree` has been heavily optimised, as well as `RNTuple`.*
250
251~~~ {.cpp}
252 // clonesarray is the address of a pointer to a TClonesArray.
253 auto branch = tree.Branch(branchname, clonesarray, bufsize, splitlevel)
254~~~
255The TClonesArray is a direct access list of objects of the same class.
256For example, if the TClonesArray is an array of TTrack objects,
257this function will create one subbranch for each data member of
258the object TTrack.
259
260\anchor fillthetree
261## Fill the Tree
262
263A TTree instance is filled with the invocation of the TTree::Fill method:
264~~~ {.cpp}
265 tree.Fill()
266~~~
267Upon its invocation, a loop on all defined branches takes place that for each branch invokes
268the TBranch::Fill method.
269
270\anchor addcoltoexistingtree
271## Add a column to an already existing Tree
272
273You may want to add a branch to an existing tree. For example,
274if one variable in the tree was computed with a certain algorithm,
275you may want to try another algorithm and compare the results.
276One solution is to add a new branch, fill it, and save the tree.
277The code below adds a simple branch to an existing tree.
278Note the `kOverwrite` option in the `Write` method: it overwrites the
279existing tree. If it is not specified, two copies of the tree headers
280are saved.
281~~~ {.cpp}
282 void addBranchToTree() {
283 TFile f("tree.root", "update");
284
285 Float_t new_v;
286 auto mytree = f->Get<TTree>("mytree");
287 auto newBranch = mytree->Branch("new_v", &new_v, "new_v/F");
288
289 auto nentries = mytree->GetEntries(); // read the number of entries in the mytree
290
291 for (Long64_t i = 0; i < nentries; i++) {
292 new_v = gRandom->Gaus(0, 1);
293 newBranch->Fill();
294 }
295
296 mytree->Write("", TObject::kOverwrite); // save only the new version of the tree
297 }
298~~~
299It is not always possible to add branches to existing datasets stored in TFiles: for example,
300these files might not be writeable, just readable. In addition, modifying in place a TTree
301causes a new TTree instance to be written and the previous one to be deleted.
302For this reasons, ROOT offers the concept of friends for TTree and TChain.
303
304\anchor fullexample
305## A Complete Example
306
307~~~ {.cpp}
308// A simple example creating a tree
309// Compile it with: `g++ myTreeExample.cpp -o myTreeExample `root-config --cflags --libs`
310
311#include "TFile.h"
312#include "TH1D.h"
313#include "TRandom3.h"
314#include "TTree.h"
315
316int main()
317{
318 // Create a new ROOT binary machine independent file.
319 // Note that this file may contain any kind of ROOT objects, histograms,trees
320 // pictures, graphics objects, detector geometries, tracks, events, etc..
321 TFile hfile("htree.root", "RECREATE", "Demo ROOT file with trees");
322
323 // Define a histogram and some simple structures
324 TH1D hpx("hpx", "This is the px distribution", 100, -4, 4);
325
326 typedef struct {
327 Float_t x, y, z;
328 } Point;
329
330 typedef struct {
331 Int_t ntrack, nseg, nvertex;
332 UInt_t flag;
333 Float_t temperature;
334 } Event;
335 Point point;
336 Event event;
337
338 // Create a ROOT Tree
339 TTree tree("T", "An example of ROOT tree with a few branches");
340 tree.Branch("point", &point, "x:y:z");
341 tree.Branch("event", &event, "ntrack/I:nseg:nvertex:flag/i:temperature/F");
342 tree.Branch("hpx", &hpx);
343
344 float px, py;
345
346 TRandom3 myGenerator;
347
348 // Here we start a loop on 1000 events
349 for (Int_t i = 0; i < 1000; i++) {
350 myGenerator.Rannor(px, py);
351 const auto random = myGenerator.Rndm(1);
352
353 // Fill histogram
354 hpx.Fill(px);
355
356 // Fill structures
357 point.x = 10 * (random - 1);
358 point.y = 5 * random;
359 point.z = 20 * random;
360 event.ntrack = int(100 * random);
361 event.nseg = int(2 * event.ntrack);
362 event.nvertex = 1;
363 event.flag = int(random + 0.5);
364 event.temperature = 20 + random;
365
366 // Fill the tree. For each event, save the 2 structures and object.
367 // In this simple example, the objects hpx, hprof and hpxpy are only slightly
368 // different from event to event. We expect a big compression factor!
369 tree.Fill();
370 }
371
372 // Save all objects in this file
373 hfile.Write();
374
375 // Close the file. Note that this is automatically done when you leave
376 // the application upon file destruction.
377 hfile.Close();
378
379 return 0;
380}
381~~~
382## TTree Diagram
383
384The following diagram shows the organisation of the federation of classes related to TTree.
385
386Begin_Macro
387../../../tutorials/legacy/tree/tree.C
388End_Macro
389*/
390
391#include <ROOT/RConfig.hxx>
392#include "TTree.h"
393
394#include "ROOT/TIOFeatures.hxx"
395#include "TArrayC.h"
396#include "TBufferFile.h"
397#include "TBaseClass.h"
398#include "TBasket.h"
399#include "TBranchClones.h"
400#include "TBranchElement.h"
401#include "TBranchObject.h"
402#include "TBranchRef.h"
403#include "TBrowser.h"
404#include "TClass.h"
405#include "TClassEdit.h"
406#include "TClonesArray.h"
407#include "TCut.h"
408#include "TDataMember.h"
409#include "TDataType.h"
410#include "TDirectory.h"
411#include "TError.h"
412#include "TEntryList.h"
413#include "TEnv.h"
414#include "TEventList.h"
415#include "TFile.h"
416#include "TFolder.h"
417#include "TFriendElement.h"
418#include "TInterpreter.h"
419#include "TLeaf.h"
420#include "TLeafB.h"
421#include "TLeafC.h"
422#include "TLeafD.h"
423#include "TLeafElement.h"
424#include "TLeafF.h"
425#include "TLeafI.h"
426#include "TLeafL.h"
427#include "TLeafObject.h"
428#include "TLeafS.h"
429#include "TList.h"
430#include "TMath.h"
431#include "TMemFile.h"
432#include "TROOT.h"
433#include "TRealData.h"
434#include "TRegexp.h"
435#include "TRefTable.h"
436#include "TStreamerElement.h"
437#include "TStreamerInfo.h"
438#include "TStyle.h"
439#include "TSystem.h"
440#include "TTreeCloner.h"
441#include "TTreeCache.h"
442#include "TTreeCacheUnzip.h"
445#include "TVirtualIndex.h"
446#include "TVirtualPerfStats.h"
447#include "TVirtualPad.h"
448#include "TBranchSTL.h"
449#include "TSchemaRuleSet.h"
450#include "TFileMergeInfo.h"
451#include "ROOT/StringConv.hxx"
452#include "TVirtualMutex.h"
453#include "strlcpy.h"
454
455#include "TBranchIMTHelper.h"
456#include "TNotifyLink.h"
457
458#include <ROOT/StringUtils.hxx>
459
460#include <chrono>
461#include <cstddef>
462#include <iostream>
463#include <fstream>
464#include <sstream>
465#include <string>
466#include <cstdio>
467#include <climits>
468#include <algorithm>
469#include <set>
470
471#ifdef R__USE_IMT
473#include <thread>
474#endif
476constexpr Int_t kNEntriesResort = 100;
478
479Int_t TTree::fgBranchStyle = 1; // Use new TBranch style with TBranchElement.
480Long64_t TTree::fgMaxTreeSize = 100000000000LL;
481
482
483////////////////////////////////////////////////////////////////////////////////
484////////////////////////////////////////////////////////////////////////////////
485////////////////////////////////////////////////////////////////////////////////
487static char DataTypeToChar(EDataType datatype)
488{
489 // Return the leaflist 'char' for a given datatype.
490
491 switch(datatype) {
492 case kChar_t: return 'B';
493 case kUChar_t: return 'b';
494 case kBool_t: return 'O';
495 case kShort_t: return 'S';
496 case kUShort_t: return 's';
497 case kCounter:
498 case kInt_t: return 'I';
499 case kUInt_t: return 'i';
500 case kDouble_t: return 'D';
501 case kDouble32_t: return 'd';
502 case kFloat_t: return 'F';
503 case kFloat16_t: return 'f';
504 case kLong_t: return 'G';
505 case kULong_t: return 'g';
506 case kchar: return 0; // unsupported
507 case kLong64_t: return 'L';
508 case kULong64_t: return 'l';
509
510 case kCharStar: return 'C';
511 case kBits: return 0; //unsupported
512
513 case kOther_t:
514 case kNoType_t:
515 default:
516 return 0;
517 }
518 return 0;
519}
520
521////////////////////////////////////////////////////////////////////////////////
522/// \class TTree::TFriendLock
523/// Helper class to prevent infinite recursion in the usage of TTree Friends.
524
525////////////////////////////////////////////////////////////////////////////////
526/// Record in tree that it has been used while recursively looks through the friends.
529: fTree(tree)
530{
531 // We could also add some code to acquire an actual
532 // lock to prevent multi-thread issues
533 fMethodBit = methodbit;
534 if (fTree) {
537 } else {
538 fPrevious = false;
539 }
540}
541
542////////////////////////////////////////////////////////////////////////////////
543/// Copy constructor.
546 fTree(tfl.fTree),
547 fMethodBit(tfl.fMethodBit),
548 fPrevious(tfl.fPrevious)
549{
550}
551
552////////////////////////////////////////////////////////////////////////////////
553/// Assignment operator.
556{
557 if(this!=&tfl) {
558 fTree=tfl.fTree;
559 fMethodBit=tfl.fMethodBit;
560 fPrevious=tfl.fPrevious;
561 }
562 return *this;
563}
564
565////////////////////////////////////////////////////////////////////////////////
566/// Restore the state of tree the same as before we set the lock.
569{
570 if (fTree) {
571 if (!fPrevious) {
572 fTree->fFriendLockStatus &= ~(fMethodBit & kBitMask);
573 }
574 }
575}
576
577////////////////////////////////////////////////////////////////////////////////
578/// \class TTree::TClusterIterator
579/// Helper class to iterate over cluster of baskets.
580/// \note In contrast to class TListIter, looping here must NOT be done using
581/// `while (iter())` or `while (iter.Next())` that would lead to an infinite loop, but rather using
582/// `while( (auto clusterStart = iter()) < tree->GetEntries() )`.
583/// \see TTree::GetClusterIterator
584
585////////////////////////////////////////////////////////////////////////////////
586/// Regular constructor.
587/// TTree is not set as const, since we might modify if it is a TChain.
589TTree::TClusterIterator::TClusterIterator(TTree *tree, Long64_t firstEntry) : fTree(tree), fClusterRange(0), fStartEntry(0), fNextEntry(0), fEstimatedSize(-1)
590{
591 if (fTree->fNClusterRange) {
592 // Find the correct cluster range.
593 //
594 // Since fClusterRangeEnd contains the inclusive upper end of the range, we need to search for the
595 // range that was containing the previous entry and add 1 (because BinarySearch consider the values
596 // to be the inclusive start of the bucket).
598
599 Long64_t entryInRange;
600 Long64_t pedestal;
601 if (fClusterRange == 0) {
602 pedestal = 0;
603 entryInRange = firstEntry;
604 } else {
605 pedestal = fTree->fClusterRangeEnd[fClusterRange-1] + 1;
606 entryInRange = firstEntry - pedestal;
607 }
608 Long64_t autoflush;
610 autoflush = fTree->fAutoFlush;
611 } else {
612 autoflush = fTree->fClusterSize[fClusterRange];
613 }
614 if (autoflush <= 0) {
615 autoflush = GetEstimatedClusterSize();
616 }
617 fStartEntry = pedestal + entryInRange - entryInRange%autoflush;
618 } else if ( fTree->GetAutoFlush() <= 0 ) {
619 // Case of old files before November 9 2009 *or* small tree where AutoFlush was never set.
620 fStartEntry = firstEntry;
621 } else {
622 fStartEntry = firstEntry - firstEntry%fTree->GetAutoFlush();
623 }
624 fNextEntry = fStartEntry; // Position correctly for the first call to Next()
625}
626
627////////////////////////////////////////////////////////////////////////////////
628/// Estimate the cluster size.
629///
630/// In almost all cases, this quickly returns the size of the auto-flush
631/// in the TTree.
632///
633/// However, in the case where the cluster size was not fixed (old files and
634/// case where autoflush was explicitly set to zero), we need estimate
635/// a cluster size in relation to the size of the cache.
636///
637/// After this value is calculated once for the TClusterIterator, it is
638/// cached and reused in future calls.
641{
642 auto autoFlush = fTree->GetAutoFlush();
643 if (autoFlush > 0) return autoFlush;
644 if (fEstimatedSize > 0) return fEstimatedSize;
645
646 Long64_t zipBytes = fTree->GetZipBytes();
647 if (zipBytes == 0) {
648 fEstimatedSize = fTree->GetEntries() - 1;
649 if (fEstimatedSize <= 0)
650 fEstimatedSize = 1;
651 } else {
652 Long64_t clusterEstimate = 1;
653 Long64_t cacheSize = fTree->GetCacheSize();
654 if (cacheSize == 0) {
655 // Humm ... let's double check on the file.
656 TFile *file = fTree->GetCurrentFile();
657 if (file) {
658 TFileCacheRead *cache = fTree->GetReadCache(file);
659 if (cache) {
660 cacheSize = cache->GetBufferSize();
661 }
662 }
663 }
664 // If neither file nor tree has a cache, use the current default.
665 if (cacheSize <= 0) {
666 cacheSize = 30000000;
667 }
668 clusterEstimate = fTree->GetEntries() * cacheSize / zipBytes;
669 // If there are no entries, then just default to 1.
670 fEstimatedSize = clusterEstimate ? clusterEstimate : 1;
671 }
672 return fEstimatedSize;
673}
674
675////////////////////////////////////////////////////////////////////////////////
676/// Move on to the next cluster and return the starting entry
677/// of this next cluster
680{
681 fStartEntry = fNextEntry;
682 if (fTree->fNClusterRange || fTree->GetAutoFlush() > 0) {
683 if (fClusterRange == fTree->fNClusterRange) {
684 // We are looking at a range which size
685 // is defined by AutoFlush itself and goes to the GetEntries.
686 fNextEntry += GetEstimatedClusterSize();
687 } else {
688 if (fStartEntry > fTree->fClusterRangeEnd[fClusterRange]) {
689 ++fClusterRange;
690 }
691 if (fClusterRange == fTree->fNClusterRange) {
692 // We are looking at the last range which size
693 // is defined by AutoFlush itself and goes to the GetEntries.
694 fNextEntry += GetEstimatedClusterSize();
695 } else {
696 Long64_t clusterSize = fTree->fClusterSize[fClusterRange];
697 if (clusterSize == 0) {
698 clusterSize = GetEstimatedClusterSize();
699 }
700 fNextEntry += clusterSize;
701 if (fNextEntry > fTree->fClusterRangeEnd[fClusterRange]) {
702 // The last cluster of the range was a partial cluster,
703 // so the next cluster starts at the beginning of the
704 // next range.
705 fNextEntry = fTree->fClusterRangeEnd[fClusterRange] + 1;
706 }
707 }
708 }
709 } else {
710 // Case of old files before November 9 2009
711 fNextEntry = fStartEntry + GetEstimatedClusterSize();
712 }
713 if (fNextEntry > fTree->GetEntries()) {
714 fNextEntry = fTree->GetEntries();
715 }
716 return fStartEntry;
717}
718
719////////////////////////////////////////////////////////////////////////////////
720/// Move on to the previous cluster and return the starting entry
721/// of this previous cluster
724{
725 fNextEntry = fStartEntry;
726 if (fTree->fNClusterRange || fTree->GetAutoFlush() > 0) {
727 if (fClusterRange == 0 || fTree->fNClusterRange == 0) {
728 // We are looking at a range which size
729 // is defined by AutoFlush itself.
730 fStartEntry -= GetEstimatedClusterSize();
731 } else {
732 if (fNextEntry <= fTree->fClusterRangeEnd[fClusterRange]) {
733 --fClusterRange;
734 }
735 if (fClusterRange == 0) {
736 // We are looking at the first range.
737 fStartEntry = 0;
738 } else {
739 Long64_t clusterSize = fTree->fClusterSize[fClusterRange];
740 if (clusterSize == 0) {
741 clusterSize = GetEstimatedClusterSize();
742 }
743 fStartEntry -= clusterSize;
744 }
745 }
746 } else {
747 // Case of old files before November 9 2009 or trees that never auto-flushed.
748 fStartEntry = fNextEntry - GetEstimatedClusterSize();
749 }
750 if (fStartEntry < 0) {
751 fStartEntry = 0;
752 }
753 return fStartEntry;
754}
755
756////////////////////////////////////////////////////////////////////////////////
757////////////////////////////////////////////////////////////////////////////////
758////////////////////////////////////////////////////////////////////////////////
759
760////////////////////////////////////////////////////////////////////////////////
761/// Default constructor and I/O constructor.
762///
763/// Note: We do *not* insert ourself into the current directory.
764///
767: TNamed()
768, TAttLine()
769, TAttFill()
770, TAttMarker()
771, fEntries(0)
772, fTotBytes(0)
773, fZipBytes(0)
774, fSavedBytes(0)
775, fFlushedBytes(0)
776, fWeight(1)
778, fScanField(25)
779, fUpdate(0)
783, fMaxEntries(0)
784, fMaxEntryLoop(0)
786, fAutoSave( -300000000)
787, fAutoFlush(-30000000)
788, fEstimate(1000000)
789, fClusterRangeEnd(nullptr)
790, fClusterSize(nullptr)
791, fCacheSize(0)
792, fChainOffset(0)
793, fReadEntry(-1)
794, fTotalBuffers(0)
795, fPacketSize(100)
796, fNfill(0)
797, fDebug(0)
798, fDebugMin(0)
799, fDebugMax(9999999)
800, fMakeClass(0)
801, fFileNumber(0)
802, fNotify(nullptr)
803, fDirectory(nullptr)
804, fBranches()
805, fLeaves()
806, fAliases(nullptr)
807, fEventList(nullptr)
808, fEntryList(nullptr)
809, fIndexValues()
810, fIndex()
811, fTreeIndex(nullptr)
812, fFriends(nullptr)
813, fExternalFriends(nullptr)
814, fPerfStats(nullptr)
815, fUserInfo(nullptr)
816, fPlayer(nullptr)
817, fClones(nullptr)
818, fBranchRef(nullptr)
820, fTransientBuffer(nullptr)
821, fCacheDoAutoInit(true)
823, fCacheUserSet(false)
824, fIMTEnabled(ROOT::IsImplicitMTEnabled())
826{
827 fMaxEntries = 1000000000;
828 fMaxEntries *= 1000;
829
830 fMaxEntryLoop = 1000000000;
831 fMaxEntryLoop *= 1000;
832
833 fBranches.SetOwner(true);
834}
835
836////////////////////////////////////////////////////////////////////////////////
837/// Normal tree constructor.
838///
839/// The tree is created in the current directory.
840/// Use the various functions Branch below to add branches to this tree.
841///
842/// If the first character of title is a "/", the function assumes a folder name.
843/// In this case, it creates automatically branches following the folder hierarchy.
844/// splitlevel may be used in this case to control the split level.
846TTree::TTree(const char* name, const char* title, Int_t splitlevel /* = 99 */,
847 TDirectory* dir /* = gDirectory*/)
848: TNamed(name, title)
849, TAttLine()
850, TAttFill()
851, TAttMarker()
852, fEntries(0)
853, fTotBytes(0)
854, fZipBytes(0)
855, fSavedBytes(0)
856, fFlushedBytes(0)
857, fWeight(1)
858, fTimerInterval(0)
859, fScanField(25)
860, fUpdate(0)
861, fDefaultEntryOffsetLen(1000)
862, fNClusterRange(0)
863, fMaxClusterRange(0)
864, fMaxEntries(0)
865, fMaxEntryLoop(0)
866, fMaxVirtualSize(0)
867, fAutoSave( -300000000)
868, fAutoFlush(-30000000)
869, fEstimate(1000000)
870, fClusterRangeEnd(nullptr)
871, fClusterSize(nullptr)
872, fCacheSize(0)
873, fChainOffset(0)
874, fReadEntry(-1)
875, fTotalBuffers(0)
876, fPacketSize(100)
877, fNfill(0)
878, fDebug(0)
879, fDebugMin(0)
880, fDebugMax(9999999)
881, fMakeClass(0)
882, fFileNumber(0)
883, fNotify(nullptr)
884, fDirectory(dir)
885, fBranches()
886, fLeaves()
887, fAliases(nullptr)
888, fEventList(nullptr)
889, fEntryList(nullptr)
890, fIndexValues()
891, fIndex()
892, fTreeIndex(nullptr)
893, fFriends(nullptr)
894, fExternalFriends(nullptr)
895, fPerfStats(nullptr)
896, fUserInfo(nullptr)
897, fPlayer(nullptr)
898, fClones(nullptr)
899, fBranchRef(nullptr)
900, fFriendLockStatus(0)
901, fTransientBuffer(nullptr)
902, fCacheDoAutoInit(true)
903, fCacheDoClusterPrefetch(false)
904, fCacheUserSet(false)
905, fIMTEnabled(ROOT::IsImplicitMTEnabled())
906, fNEntriesSinceSorting(0)
907{
908 // TAttLine state.
912
913 // TAttFill state.
916
917 // TAttMarkerState.
921
922 fMaxEntries = 1000000000;
923 fMaxEntries *= 1000;
924
925 fMaxEntryLoop = 1000000000;
926 fMaxEntryLoop *= 1000;
927
928 // Insert ourself into the current directory.
929 // FIXME: This is very annoying behaviour, we should
930 // be able to choose to not do this like we
931 // can with a histogram.
932 if (fDirectory) fDirectory->Append(this);
933
934 fBranches.SetOwner(true);
935
936 // If title starts with "/" and is a valid folder name, a superbranch
937 // is created.
938 // FIXME: Why?
939 if (strlen(title) > 2) {
940 if (title[0] == '/') {
941 Branch(title+1,32000,splitlevel);
942 }
943 }
944}
945
946////////////////////////////////////////////////////////////////////////////////
947/// Destructor.
950{
951 if (auto link = dynamic_cast<TNotifyLinkBase*>(fNotify)) {
952 link->Clear();
953 }
954 if (fAllocationCount && (gDebug > 0)) {
955 Info("TTree::~TTree", "For tree %s, allocation count is %u.", GetName(), fAllocationCount.load());
956#ifdef R__TRACK_BASKET_ALLOC_TIME
957 Info("TTree::~TTree", "For tree %s, allocation time is %lluus.", GetName(), fAllocationTime.load());
958#endif
959 }
960
961 if (fDirectory) {
962 // We are in a directory, which may possibly be a file.
963 if (fDirectory->GetList()) {
964 // Remove us from the directory listing.
965 fDirectory->Remove(this);
966 }
967 //delete the file cache if it points to this Tree
968 TFile *file = fDirectory->GetFile();
969 MoveReadCache(file,nullptr);
970 }
971
972 // Remove the TTree from any list (linked to to the list of Cleanups) to avoid the unnecessary call to
973 // this RecursiveRemove while we delete our content.
975 ResetBit(kMustCleanup); // Don't redo it.
976
977 // We don't own the leaves in fLeaves, the branches do.
978 fLeaves.Clear();
979 // I'm ready to destroy any objects allocated by
980 // SetAddress() by my branches. If I have clones,
981 // tell them to zero their pointers to this shared
982 // memory.
983 if (fClones && fClones->GetEntries()) {
984 // I have clones.
985 // I am about to delete the objects created by
986 // SetAddress() which we are sharing, so tell
987 // the clones to release their pointers to them.
988 for (TObjLink* lnk = fClones->FirstLink(); lnk; lnk = lnk->Next()) {
989 TTree* clone = (TTree*) lnk->GetObject();
990 // clone->ResetBranchAddresses();
991
992 // Reset only the branch we have set the address of.
993 CopyAddresses(clone,true);
994 }
995 }
996 // Get rid of our branches, note that this will also release
997 // any memory allocated by TBranchElement::SetAddress().
999
1000 // The TBranch destructor is using fDirectory to detect whether it
1001 // owns the TFile that contains its data (See TBranch::~TBranch)
1002 fDirectory = nullptr;
1003
1004 // FIXME: We must consider what to do with the reset of these if we are a clone.
1005 delete fPlayer;
1006 fPlayer = nullptr;
1007 if (fExternalFriends) {
1008 using namespace ROOT::Detail;
1010 fetree->Reset();
1011 fExternalFriends->Clear("nodelete");
1013 }
1014 if (fFriends) {
1015 fFriends->Delete();
1016 delete fFriends;
1017 fFriends = nullptr;
1018 }
1019 if (fAliases) {
1020 fAliases->Delete();
1021 delete fAliases;
1022 fAliases = nullptr;
1023 }
1024 if (fUserInfo) {
1025 fUserInfo->Delete();
1026 delete fUserInfo;
1027 fUserInfo = nullptr;
1028 }
1029 if (fClones) {
1030 // Clone trees should no longer be removed from fClones when they are deleted.
1031 {
1033 gROOT->GetListOfCleanups()->Remove(fClones);
1034 }
1035 // Note: fClones does not own its content.
1036 delete fClones;
1037 fClones = nullptr;
1038 }
1039 if (fEntryList) {
1040 if (fEntryList->TestBit(kCanDelete) && fEntryList->GetDirectory()==nullptr) {
1041 // Delete the entry list if it is marked to be deleted and it is not also
1042 // owned by a directory. (Otherwise we would need to make sure that a
1043 // TDirectoryFile that has a TTree in it does a 'slow' TList::Delete.
1044 delete fEntryList;
1045 fEntryList=nullptr;
1046 }
1047 }
1048 delete fTreeIndex;
1049 fTreeIndex = nullptr;
1050 delete fBranchRef;
1051 fBranchRef = nullptr;
1052 delete [] fClusterRangeEnd;
1053 fClusterRangeEnd = nullptr;
1054 delete [] fClusterSize;
1055 fClusterSize = nullptr;
1056
1057 if (fTransientBuffer) {
1058 delete fTransientBuffer;
1059 fTransientBuffer = nullptr;
1060 }
1061}
1062
1063////////////////////////////////////////////////////////////////////////////////
1064/// Returns the transient buffer currently used by this TTree for reading/writing baskets.
1076}
1077
1078////////////////////////////////////////////////////////////////////////////////
1079/// Add branch with name bname to the Tree cache.
1080/// If bname="*" all branches are added to the cache.
1081/// if subbranches is true all the branches of the subbranches are
1082/// also put to the cache.
1083///
1084/// Returns:
1085/// - 0 branch added or already included
1086/// - -1 on error
1088Int_t TTree::AddBranchToCache(const char*bname, bool subbranches)
1089{
1090 if (!GetTree()) {
1091 if (LoadTree(0)<0) {
1092 Error("AddBranchToCache","Could not load a tree");
1093 return -1;
1094 }
1095 }
1096 if (GetTree()) {
1097 if (GetTree() != this) {
1098 return GetTree()->AddBranchToCache(bname, subbranches);
1099 }
1100 } else {
1101 Error("AddBranchToCache", "No tree is available. Branch was not added to the cache");
1102 return -1;
1103 }
1104
1105 TFile *f = GetCurrentFile();
1106 if (!f) {
1107 Error("AddBranchToCache", "No file is available. Branch was not added to the cache");
1108 return -1;
1109 }
1110 TTreeCache *tc = GetReadCache(f,true);
1111 if (!tc) {
1112 Error("AddBranchToCache", "No cache is available, branch not added");
1113 return -1;
1114 }
1115 return tc->AddBranch(bname,subbranches);
1116}
1117
1118////////////////////////////////////////////////////////////////////////////////
1119/// Add branch b to the Tree cache.
1120/// if subbranches is true all the branches of the subbranches are
1121/// also put to the cache.
1122///
1123/// Returns:
1124/// - 0 branch added or already included
1125/// - -1 on error
1127Int_t TTree::AddBranchToCache(TBranch *b, bool subbranches)
1128{
1129 if (!GetTree()) {
1130 if (LoadTree(0)<0) {
1131 Error("AddBranchToCache","Could not load a tree");
1132 return -1;
1133 }
1134 }
1135 if (GetTree()) {
1136 if (GetTree() != this) {
1137 Int_t res = GetTree()->AddBranchToCache(b, subbranches);
1138 if (res<0) {
1139 Error("AddBranchToCache", "Error adding branch");
1140 }
1141 return res;
1142 }
1143 } else {
1144 Error("AddBranchToCache", "No tree is available. Branch was not added to the cache");
1145 return -1;
1146 }
1147
1148 TFile *f = GetCurrentFile();
1149 if (!f) {
1150 Error("AddBranchToCache", "No file is available. Branch was not added to the cache");
1151 return -1;
1152 }
1153 TTreeCache *tc = GetReadCache(f,true);
1154 if (!tc) {
1155 Error("AddBranchToCache", "No cache is available, branch not added");
1156 return -1;
1157 }
1158 return tc->AddBranch(b,subbranches);
1159}
1160
1161////////////////////////////////////////////////////////////////////////////////
1162/// Remove the branch with name 'bname' from the Tree cache.
1163/// If bname="*" all branches are removed from the cache.
1164/// if subbranches is true all the branches of the subbranches are
1165/// also removed from the cache.
1166///
1167/// Returns:
1168/// - 0 branch dropped or not in cache
1169/// - -1 on error
1171Int_t TTree::DropBranchFromCache(const char*bname, bool subbranches)
1172{
1173 if (!GetTree()) {
1174 if (LoadTree(0)<0) {
1175 Error("DropBranchFromCache","Could not load a tree");
1176 return -1;
1177 }
1178 }
1179 if (GetTree()) {
1180 if (GetTree() != this) {
1181 return GetTree()->DropBranchFromCache(bname, subbranches);
1182 }
1183 } else {
1184 Error("DropBranchFromCache", "No tree is available. Branch was not dropped from the cache");
1185 return -1;
1186 }
1187
1188 TFile *f = GetCurrentFile();
1189 if (!f) {
1190 Error("DropBranchFromCache", "No file is available. Branch was not dropped from the cache");
1191 return -1;
1192 }
1193 TTreeCache *tc = GetReadCache(f,true);
1194 if (!tc) {
1195 Error("DropBranchFromCache", "No cache is available, branch not dropped");
1196 return -1;
1197 }
1198 return tc->DropBranch(bname,subbranches);
1199}
1200
1201////////////////////////////////////////////////////////////////////////////////
1202/// Remove the branch b from the Tree cache.
1203/// if subbranches is true all the branches of the subbranches are
1204/// also removed from the cache.
1205///
1206/// Returns:
1207/// - 0 branch dropped or not in cache
1208/// - -1 on error
1210Int_t TTree::DropBranchFromCache(TBranch *b, bool subbranches)
1211{
1212 if (!GetTree()) {
1213 if (LoadTree(0)<0) {
1214 Error("DropBranchFromCache","Could not load a tree");
1215 return -1;
1216 }
1217 }
1218 if (GetTree()) {
1219 if (GetTree() != this) {
1220 Int_t res = GetTree()->DropBranchFromCache(b, subbranches);
1221 if (res<0) {
1222 Error("DropBranchFromCache", "Error dropping branch");
1223 }
1224 return res;
1225 }
1226 } else {
1227 Error("DropBranchFromCache", "No tree is available. Branch was not dropped from the cache");
1228 return -1;
1229 }
1230
1231 TFile *f = GetCurrentFile();
1232 if (!f) {
1233 Error("DropBranchFromCache", "No file is available. Branch was not dropped from the cache");
1234 return -1;
1235 }
1236 TTreeCache *tc = GetReadCache(f,true);
1237 if (!tc) {
1238 Error("DropBranchFromCache", "No cache is available, branch not dropped");
1239 return -1;
1240 }
1241 return tc->DropBranch(b,subbranches);
1242}
1243
1244////////////////////////////////////////////////////////////////////////////////
1245/// Add a cloned tree to our list of trees to be notified whenever we change
1246/// our branch addresses or when we are deleted.
1248void TTree::AddClone(TTree* clone)
1249{
1250 if (!fClones) {
1251 fClones = new TList();
1252 fClones->SetOwner(false);
1253 // So that the clones are automatically removed from the list when
1254 // they are deleted.
1255 {
1257 gROOT->GetListOfCleanups()->Add(fClones);
1258 }
1259 }
1260 if (!fClones->FindObject(clone)) {
1261 fClones->Add(clone);
1262 }
1263}
1264
1265// Check whether mainTree and friendTree can be friends w.r.t. the kEntriesReshuffled bit.
1266// In particular, if any has the bit set, then friendTree must have a TTreeIndex and the
1267// branches used for indexing must be present in mainTree.
1268// Return true if the trees can be friends, false otherwise.
1269bool CheckReshuffling(TTree &mainTree, TTree &friendTree)
1270{
1271 const auto isMainReshuffled = mainTree.TestBit(TTree::kEntriesReshuffled);
1272 const auto isFriendReshuffled = friendTree.TestBit(TTree::kEntriesReshuffled);
1273 const auto friendHasValidIndex = [&] {
1274 auto idx = friendTree.GetTreeIndex();
1275 return idx ? idx->IsValidFor(&mainTree) : false;
1276 }();
1277
1278 if ((isMainReshuffled || isFriendReshuffled) && !friendHasValidIndex) {
1279 const auto reshuffledTreeName = isMainReshuffled ? mainTree.GetName() : friendTree.GetName();
1280 const auto msg =
1281 "Tree '%s' has the kEntriesReshuffled bit set and cannot have friends nor can be added as a friend unless the "
1282 "main tree has a TTreeIndex on the friend tree '%s'. You can also unset the bit manually if you know what you "
1283 "are doing; note that you risk associating wrong TTree entries of the friend with those of the main TTree!";
1284 Error("AddFriend", msg, reshuffledTreeName, friendTree.GetName());
1285 return false;
1286 }
1287 return true;
1288}
1289
1290////////////////////////////////////////////////////////////////////////////////
1291/// Add a TFriendElement to the list of friends.
1292///
1293/// This function:
1294/// - opens a file if filename is specified
1295/// - reads a Tree with name treename from the file (current directory)
1296/// - adds the Tree to the list of friends
1297/// see other AddFriend functions
1298///
1299/// A TFriendElement TF describes a TTree object TF in a file.
1300/// When a TFriendElement TF is added to the list of friends of an
1301/// existing TTree T, any variable from TF can be referenced in a query
1302/// to T.
1303///
1304/// A tree keeps a list of friends. In the context of a tree (or a chain),
1305/// friendship means unrestricted access to the friends data. In this way
1306/// it is much like adding another branch to the tree without taking the risk
1307/// of damaging it. To add a friend to the list, you can use the TTree::AddFriend
1308/// method. The tree in the diagram below has two friends (friend_tree1 and
1309/// friend_tree2) and now has access to the variables a,b,c,i,j,k,l and m.
1310///
1311/// \image html ttree_friend1.png
1312///
1313/// The AddFriend method has two parameters, the first is the tree name and the
1314/// second is the name of the ROOT file where the friend tree is saved.
1315/// AddFriend automatically opens the friend file. If no file name is given,
1316/// the tree called ft1 is assumed to be in the same file as the original tree.
1317///
1318/// tree.AddFriend("ft1","friendfile1.root");
1319/// If the friend tree has the same name as the original tree, you can give it
1320/// an alias in the context of the friendship:
1321///
1322/// tree.AddFriend("tree1 = tree","friendfile1.root");
1323/// Once the tree has friends, we can use TTree::Draw as if the friend's
1324/// variables were in the original tree. To specify which tree to use in
1325/// the Draw method, use the syntax:
1326/// ~~~ {.cpp}
1327/// <treeName>.<branchname>.<varname>
1328/// ~~~
1329/// If the variablename is enough to uniquely identify the variable, you can
1330/// leave out the tree and/or branch name.
1331/// For example, these commands generate a 3-d scatter plot of variable "var"
1332/// in the TTree tree versus variable v1 in TTree ft1 versus variable v2 in
1333/// TTree ft2.
1334/// ~~~ {.cpp}
1335/// tree.AddFriend("ft1","friendfile1.root");
1336/// tree.AddFriend("ft2","friendfile2.root");
1337/// tree.Draw("var:ft1.v1:ft2.v2");
1338/// ~~~
1339/// \image html ttree_friend2.png
1340///
1341/// The picture illustrates the access of the tree and its friends with a
1342/// Draw command.
1343/// When AddFriend is called, the ROOT file is automatically opened and the
1344/// friend tree (ft1) is read into memory. The new friend (ft1) is added to
1345/// the list of friends of tree.
1346/// The number of entries in the friend must be equal or greater to the number
1347/// of entries of the original tree. If the friend tree has fewer entries a
1348/// warning is given and the missing entries are not included in the histogram.
1349/// To retrieve the list of friends from a tree use TTree::GetListOfFriends.
1350/// When the tree is written to file (TTree::Write), the friends list is saved
1351/// with it. And when the tree is retrieved, the trees on the friends list are
1352/// also retrieved and the friendship restored.
1353/// When a tree is deleted, the elements of the friend list are also deleted.
1354/// It is possible to declare a friend tree that has the same internal
1355/// structure (same branches and leaves) as the original tree, and compare the
1356/// same values by specifying the tree.
1357/// ~~~ {.cpp}
1358/// tree.Draw("var:ft1.var:ft2.var")
1359/// ~~~
1361TFriendElement *TTree::AddFriend(const char *treename, const char *filename)
1362{
1363 if (!fFriends) {
1364 fFriends = new TList();
1365 }
1366 TFriendElement *fe = new TFriendElement(this, treename, filename);
1367
1368 TTree *t = fe->GetTree();
1369 bool canAddFriend = true;
1370 if (t) {
1371 canAddFriend = CheckReshuffling(*this, *t);
1372 if (!t->GetTreeIndex() && (t->GetEntries() < fEntries)) {
1373 Warning("AddFriend", "FriendElement %s in file %s has less entries %lld than its parent Tree: %lld", treename,
1375 }
1376 } else {
1377 Error("AddFriend", "Cannot find tree '%s' in file '%s', friend not added", treename, filename);
1378 canAddFriend = false;
1379 }
1380
1381 if (canAddFriend)
1382 fFriends->Add(fe);
1383 return fe;
1384}
1385
1386////////////////////////////////////////////////////////////////////////////////
1387/// Add a TFriendElement to the list of friends.
1388///
1389/// The TFile is managed by the user (e.g. the user must delete the file).
1390/// For complete description see AddFriend(const char *, const char *).
1391/// This function:
1392/// - reads a Tree with name treename from the file
1393/// - adds the Tree to the list of friends
1395TFriendElement *TTree::AddFriend(const char *treename, TFile *file)
1396{
1397 if (!fFriends) {
1398 fFriends = new TList();
1399 }
1400 TFriendElement *fe = new TFriendElement(this, treename, file);
1401 R__ASSERT(fe);
1402 TTree *t = fe->GetTree();
1403 bool canAddFriend = true;
1404 if (t) {
1405 canAddFriend = CheckReshuffling(*this, *t);
1406 if (!t->GetTreeIndex() && (t->GetEntries() < fEntries)) {
1407 Warning("AddFriend", "FriendElement %s in file %s has less entries %lld than its parent tree: %lld", treename,
1408 file->GetName(), t->GetEntries(), fEntries);
1409 }
1410 } else {
1411 Error("AddFriend", "Cannot find tree '%s' in file '%s', friend not added", treename, file->GetName());
1412 canAddFriend = false;
1413 }
1414
1415 if (canAddFriend)
1416 fFriends->Add(fe);
1417 return fe;
1418}
1419
1420////////////////////////////////////////////////////////////////////////////////
1421/// Add a TFriendElement to the list of friends.
1422///
1423/// The TTree is managed by the user (e.g., the user must delete the file).
1424/// For a complete description see AddFriend(const char *, const char *).
1426TFriendElement *TTree::AddFriend(TTree *tree, const char *alias, bool warn)
1427{
1428 if (!tree) {
1429 return nullptr;
1430 }
1431 if (!fFriends) {
1432 fFriends = new TList();
1433 }
1434 TFriendElement *fe = new TFriendElement(this, tree, alias);
1435 R__ASSERT(fe); // this assert is for historical reasons. Don't remove it unless you understand all the consequences.
1436 TTree *t = fe->GetTree();
1437 if (warn && (t->GetEntries() < fEntries)) {
1438 Warning("AddFriend", "FriendElement '%s' in file '%s' has less entries %lld than its parent tree: %lld",
1439 tree->GetName(), fe->GetFile() ? fe->GetFile()->GetName() : "(memory resident)", t->GetEntries(),
1440 fEntries);
1441 }
1442 if (CheckReshuffling(*this, *t))
1443 fFriends->Add(fe);
1444 else
1445 tree->RemoveExternalFriend(fe);
1446 return fe;
1447}
1448
1449////////////////////////////////////////////////////////////////////////////////
1450/// AutoSave tree header every fAutoSave bytes.
1451///
1452/// When large Trees are produced, it is safe to activate the AutoSave
1453/// procedure. Some branches may have buffers holding many entries.
1454/// If fAutoSave is negative, AutoSave is automatically called by
1455/// TTree::Fill when the number of bytes generated since the previous
1456/// AutoSave is greater than -fAutoSave bytes.
1457/// If fAutoSave is positive, AutoSave is automatically called by
1458/// TTree::Fill every N entries.
1459/// This function may also be invoked by the user.
1460/// Each AutoSave generates a new key on the file.
1461/// Once the key with the tree header has been written, the previous cycle
1462/// (if any) is deleted.
1463///
1464/// Note that calling TTree::AutoSave too frequently (or similarly calling
1465/// TTree::SetAutoSave with a small value) is an expensive operation.
1466/// You should make tests for your own application to find a compromise
1467/// between speed and the quantity of information you may loose in case of
1468/// a job crash.
1469///
1470/// In case your program crashes before closing the file holding this tree,
1471/// the file will be automatically recovered when you will connect the file
1472/// in UPDATE mode.
1473/// The Tree will be recovered at the status corresponding to the last AutoSave.
1474///
1475/// if option contains "SaveSelf", gDirectory->SaveSelf() is called.
1476/// This allows another process to analyze the Tree while the Tree is being filled.
1477///
1478/// if option contains "FlushBaskets", TTree::FlushBaskets is called and all
1479/// the current basket are closed-out and written to disk individually.
1480///
1481/// By default the previous header is deleted after having written the new header.
1482/// if option contains "Overwrite", the previous Tree header is deleted
1483/// before written the new header. This option is slightly faster, but
1484/// the default option is safer in case of a problem (disk quota exceeded)
1485/// when writing the new header.
1486///
1487/// The function returns the number of bytes written to the file.
1488/// if the number of bytes is null, an error has occurred while writing
1489/// the header to the file.
1490///
1491/// ## How to write a Tree in one process and view it from another process
1492///
1493/// The following two scripts illustrate how to do this.
1494/// The script treew.C is executed by process1, treer.C by process2
1495///
1496/// script treew.C:
1497/// ~~~ {.cpp}
1498/// void treew() {
1499/// TFile f("test.root","recreate");
1500/// TNtuple *ntuple = new TNtuple("ntuple","Demo","px:py:pz:random:i");
1501/// Float_t px, py, pz;
1502/// for ( Int_t i=0; i<10000000; i++) {
1503/// gRandom->Rannor(px,py);
1504/// pz = px*px + py*py;
1505/// Float_t random = gRandom->Rndm(1);
1506/// ntuple->Fill(px,py,pz,random,i);
1507/// if (i%1000 == 1) ntuple->AutoSave("SaveSelf");
1508/// }
1509/// }
1510/// ~~~
1511/// script treer.C:
1512/// ~~~ {.cpp}
1513/// void treer() {
1514/// TFile f("test.root");
1515/// TTree *ntuple = (TTree*)f.Get("ntuple");
1516/// TCanvas c1;
1517/// Int_t first = 0;
1518/// while(1) {
1519/// if (first == 0) ntuple->Draw("px>>hpx", "","",10000000,first);
1520/// else ntuple->Draw("px>>+hpx","","",10000000,first);
1521/// first = (Int_t)ntuple->GetEntries();
1522/// c1.Update();
1523/// gSystem->Sleep(1000); //sleep 1 second
1524/// ntuple->Refresh();
1525/// }
1526/// }
1527/// ~~~
1530{
1531 if (!fDirectory || fDirectory == gROOT || !fDirectory->IsWritable()) return 0;
1532 if (gDebug > 0) {
1533 Info("AutoSave", "Tree:%s after %lld bytes written\n",GetName(),GetTotBytes());
1534 }
1535 TString opt = option;
1536 opt.ToLower();
1537
1538 if (opt.Contains("flushbaskets")) {
1539 if (gDebug > 0) Info("AutoSave", "calling FlushBaskets \n");
1541 }
1542
1544
1546 Long64_t nbytes;
1547 if (opt.Contains("overwrite")) {
1548 nbytes = fDirectory->WriteTObject(this,"","overwrite");
1549 } else {
1550 nbytes = fDirectory->WriteTObject(this); //nbytes will be 0 if Write failed (disk space exceeded)
1551 if (nbytes && key && strcmp(ClassName(), key->GetClassName()) == 0) {
1552 key->Delete();
1553 delete key;
1554 }
1555 }
1556 // save StreamerInfo
1557 TFile *file = fDirectory->GetFile();
1558 if (file) file->WriteStreamerInfo();
1559
1560 if (opt.Contains("saveself")) {
1562 //the following line is required in case GetUserInfo contains a user class
1563 //for which the StreamerInfo must be written. One could probably be a bit faster (Rene)
1564 if (file) file->WriteHeader();
1565 }
1566
1567 return nbytes;
1568}
1569
1570namespace {
1571 // This error message is repeated several times in the code. We write it once.
1572 const char* writeStlWithoutProxyMsg = "The class requested (%s) for the branch \"%s\""
1573 " is an instance of an stl collection and does not have a compiled CollectionProxy."
1574 " Please generate the dictionary for this collection (%s) to avoid to write corrupted data.";
1575}
1576
1577////////////////////////////////////////////////////////////////////////////////
1578/// Same as TTree::Branch() with added check that addobj matches className.
1579///
1580/// \see TTree::Branch()
1581///
1583TBranch* TTree::BranchImp(const char* branchname, const char* classname, TClass* ptrClass, void* addobj, Int_t bufsize, Int_t splitlevel)
1584{
1585 TClass* claim = TClass::GetClass(classname);
1586 if (!ptrClass) {
1587 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1588 Error("Branch", writeStlWithoutProxyMsg,
1589 claim->GetName(), branchname, claim->GetName());
1590 return nullptr;
1591 }
1592 return Branch(branchname, classname, (void*) addobj, bufsize, splitlevel);
1593 }
1594 TClass* actualClass = nullptr;
1595 void** addr = (void**) addobj;
1596 if (addr) {
1597 actualClass = ptrClass->GetActualClass(*addr);
1598 }
1599 if (ptrClass && claim) {
1600 if (!(claim->InheritsFrom(ptrClass) || ptrClass->InheritsFrom(claim))) {
1601 // Note we currently do not warn in case of splicing or over-expectation).
1602 if (claim->IsLoaded() && ptrClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), ptrClass->GetTypeInfo()->name() ) == 0) {
1603 // The type is the same according to the C++ type_info, we must be in the case of
1604 // a template of Double32_t. This is actually a correct case.
1605 } else {
1606 Error("Branch", "The class requested (%s) for \"%s\" is different from the type of the pointer passed (%s)",
1607 claim->GetName(), branchname, ptrClass->GetName());
1608 }
1609 } else if (actualClass && (claim != actualClass) && !actualClass->InheritsFrom(claim)) {
1610 if (claim->IsLoaded() && actualClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), actualClass->GetTypeInfo()->name() ) == 0) {
1611 // The type is the same according to the C++ type_info, we must be in the case of
1612 // a template of Double32_t. This is actually a correct case.
1613 } else {
1614 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s",
1615 actualClass->GetName(), branchname, claim->GetName());
1616 }
1617 }
1618 }
1619 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1620 Error("Branch", writeStlWithoutProxyMsg,
1621 claim->GetName(), branchname, claim->GetName());
1622 return nullptr;
1623 }
1624 return Branch(branchname, classname, (void*) addobj, bufsize, splitlevel);
1625}
1626
1627////////////////////////////////////////////////////////////////////////////////
1628/// Same as TTree::Branch but automatic detection of the class name.
1629/// \see TTree::Branch
1631TBranch* TTree::BranchImp(const char* branchname, TClass* ptrClass, void* addobj, Int_t bufsize, Int_t splitlevel)
1632{
1633 if (!ptrClass) {
1634 Error("Branch", "The pointer specified for %s is not of a class known to ROOT", branchname);
1635 return nullptr;
1636 }
1637 TClass* actualClass = nullptr;
1638 void** addr = (void**) addobj;
1639 if (addr && *addr) {
1640 actualClass = ptrClass->GetActualClass(*addr);
1641 if (!actualClass) {
1642 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",
1643 branchname, ptrClass->GetName());
1644 actualClass = ptrClass;
1645 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1646 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());
1647 return nullptr;
1648 }
1649 } else {
1650 actualClass = ptrClass;
1651 }
1652 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1653 Error("Branch", writeStlWithoutProxyMsg,
1654 actualClass->GetName(), branchname, actualClass->GetName());
1655 return nullptr;
1656 }
1657 return Branch(branchname, actualClass->GetName(), (void*) addobj, bufsize, splitlevel);
1658}
1659
1660////////////////////////////////////////////////////////////////////////////////
1661/// Same as TTree::Branch but automatic detection of the class name.
1662/// \see TTree::Branch
1664TBranch* TTree::BranchImpRef(const char* branchname, const char *classname, TClass* ptrClass, void *addobj, Int_t bufsize, Int_t splitlevel)
1665{
1666 TClass* claim = TClass::GetClass(classname);
1667 if (!ptrClass) {
1668 if (claim && claim->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(claim->GetCollectionProxy())) {
1669 Error("Branch", writeStlWithoutProxyMsg,
1670 claim->GetName(), branchname, claim->GetName());
1671 return nullptr;
1672 } else if (claim == nullptr) {
1673 Error("Branch", "The pointer specified for %s is not of a class known to ROOT and %s is not a known class", branchname, classname);
1674 return nullptr;
1675 }
1676 ptrClass = claim;
1677 }
1678 TClass* actualClass = nullptr;
1679 if (!addobj) {
1680 Error("Branch", "Reference interface requires a valid object (for branch: %s)!", branchname);
1681 return nullptr;
1682 }
1683 actualClass = ptrClass->GetActualClass(addobj);
1684 if (ptrClass && claim) {
1685 if (!(claim->InheritsFrom(ptrClass) || ptrClass->InheritsFrom(claim))) {
1686 // Note we currently do not warn in case of splicing or over-expectation).
1687 if (claim->IsLoaded() && ptrClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), ptrClass->GetTypeInfo()->name() ) == 0) {
1688 // The type is the same according to the C++ type_info, we must be in the case of
1689 // a template of Double32_t. This is actually a correct case.
1690 } else {
1691 Error("Branch", "The class requested (%s) for \"%s\" is different from the type of the object passed (%s)",
1692 claim->GetName(), branchname, ptrClass->GetName());
1693 }
1694 } else if (actualClass && (claim != actualClass) && !actualClass->InheritsFrom(claim)) {
1695 if (claim->IsLoaded() && actualClass->IsLoaded() && strcmp( claim->GetTypeInfo()->name(), actualClass->GetTypeInfo()->name() ) == 0) {
1696 // The type is the same according to the C++ type_info, we must be in the case of
1697 // a template of Double32_t. This is actually a correct case.
1698 } else {
1699 Error("Branch", "The actual class (%s) of the object provided for the definition of the branch \"%s\" does not inherit from %s",
1700 actualClass->GetName(), branchname, claim->GetName());
1701 }
1702 }
1703 }
1704 if (!actualClass) {
1705 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",
1706 branchname, ptrClass->GetName());
1707 actualClass = ptrClass;
1708 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1709 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());
1710 return nullptr;
1711 }
1712 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1713 Error("Branch", writeStlWithoutProxyMsg,
1714 actualClass->GetName(), branchname, actualClass->GetName());
1715 return nullptr;
1716 }
1717 return BronchExec(branchname, actualClass->GetName(), (void*) addobj, false, bufsize, splitlevel);
1718}
1719
1720////////////////////////////////////////////////////////////////////////////////
1721/// Same as TTree::Branch but automatic detection of the class name.
1722/// \see TTree::Branch
1724TBranch* TTree::BranchImpRef(const char* branchname, TClass* ptrClass, EDataType datatype, void* addobj, Int_t bufsize, Int_t splitlevel)
1725{
1726 if (!ptrClass) {
1727 if (datatype == kOther_t || datatype == kNoType_t) {
1728 Error("Branch", "The pointer specified for %s is not of a class or type known to ROOT", branchname);
1729 } else {
1730 TString varname; varname.Form("%s/%c",branchname,DataTypeToChar(datatype));
1731 return Branch(branchname,addobj,varname.Data(),bufsize);
1732 }
1733 return nullptr;
1734 }
1735 TClass* actualClass = nullptr;
1736 if (!addobj) {
1737 Error("Branch", "Reference interface requires a valid object (for branch: %s)!", branchname);
1738 return nullptr;
1739 }
1740 actualClass = ptrClass->GetActualClass(addobj);
1741 if (!actualClass) {
1742 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",
1743 branchname, ptrClass->GetName());
1744 actualClass = ptrClass;
1745 } else if ((ptrClass != actualClass) && !actualClass->InheritsFrom(ptrClass)) {
1746 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());
1747 return nullptr;
1748 }
1749 if (actualClass && actualClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(actualClass->GetCollectionProxy())) {
1750 Error("Branch", writeStlWithoutProxyMsg,
1751 actualClass->GetName(), branchname, actualClass->GetName());
1752 return nullptr;
1753 }
1754 return BronchExec(branchname, actualClass->GetName(), (void*) addobj, false, bufsize, splitlevel);
1755}
1756
1757////////////////////////////////////////////////////////////////////////////////
1758// Wrapper to turn Branch call with an std::array into the relevant leaf list
1759// call
1760TBranch *TTree::BranchImpArr(const char *branchname, EDataType datatype, std::size_t N, void *addobj, Int_t bufsize,
1761 Int_t /* splitlevel */)
1762{
1763 if (datatype == kOther_t || datatype == kNoType_t) {
1764 Error("Branch",
1765 "The inner type of the std::array passed specified for %s is not of a class or type known to ROOT",
1766 branchname);
1767 } else {
1768 TString varname;
1769 varname.Form("%s[%d]/%c", branchname, (int)N, DataTypeToChar(datatype));
1770 return Branch(branchname, addobj, varname.Data(), bufsize);
1771 }
1772 return nullptr;
1773}
1774
1775////////////////////////////////////////////////////////////////////////////////
1776/// Deprecated function. Use next function instead.
1778Int_t TTree::Branch(TList* li, Int_t bufsize /* = 32000 */ , Int_t splitlevel /* = 99 */)
1779{
1780 return Branch((TCollection*) li, bufsize, splitlevel);
1781}
1782
1783////////////////////////////////////////////////////////////////////////////////
1784/// Create one branch for each element in the collection.
1785///
1786/// Each entry in the collection becomes a top level branch if the
1787/// corresponding class is not a collection. If it is a collection, the entry
1788/// in the collection becomes in turn top level branches, etc.
1789/// The splitlevel is decreased by 1 every time a new collection is found.
1790/// For example if list is a TObjArray*
1791/// - if splitlevel = 1, one top level branch is created for each element
1792/// of the TObjArray.
1793/// - if splitlevel = 2, one top level branch is created for each array element.
1794/// if, in turn, one of the array elements is a TCollection, one top level
1795/// branch will be created for each element of this collection.
1796///
1797/// In case a collection element is a TClonesArray, the special Tree constructor
1798/// for TClonesArray is called.
1799/// The collection itself cannot be a TClonesArray.
1800///
1801/// The function returns the total number of branches created.
1802///
1803/// If name is given, all branch names will be prefixed with name_.
1804///
1805/// IMPORTANT NOTE1: This function should not be called with splitlevel < 1.
1806///
1807/// IMPORTANT NOTE2: The branches created by this function will have names
1808/// corresponding to the collection or object names. It is important
1809/// to give names to collections to avoid misleading branch names or
1810/// identical branch names. By default collections have a name equal to
1811/// the corresponding class name, e.g. the default name for a TList is "TList".
1812///
1813/// And in general, in case two or more master branches contain subbranches
1814/// with identical names, one must add a "." (dot) character at the end
1815/// of the master branch name. This will force the name of the subbranches
1816/// to be of the form `master.subbranch` instead of simply `subbranch`.
1817/// This situation happens when the top level object
1818/// has two or more members referencing the same class.
1819/// Without the dot, the prefix will not be there and that might cause ambiguities.
1820/// For example, if a Tree has two branches B1 and B2 corresponding
1821/// to objects of the same class MyClass, one can do:
1822/// ~~~ {.cpp}
1823/// tree.Branch("B1.","MyClass",&b1,8000,1);
1824/// tree.Branch("B2.","MyClass",&b2,8000,1);
1825/// ~~~
1826/// if MyClass has 3 members a,b,c, the two instructions above will generate
1827/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
1828/// In other words, the trailing dot of the branch name is semantically relevant
1829/// and recommended.
1830///
1831/// Example:
1832/// ~~~ {.cpp}
1833/// {
1834/// TTree T("T","test list");
1835/// TList *list = new TList();
1836///
1837/// TObjArray *a1 = new TObjArray();
1838/// a1->SetName("a1");
1839/// list->Add(a1);
1840/// TH1F *ha1a = new TH1F("ha1a","ha1",100,0,1);
1841/// TH1F *ha1b = new TH1F("ha1b","ha1",100,0,1);
1842/// a1->Add(ha1a);
1843/// a1->Add(ha1b);
1844/// TObjArray *b1 = new TObjArray();
1845/// b1->SetName("b1");
1846/// list->Add(b1);
1847/// TH1F *hb1a = new TH1F("hb1a","hb1",100,0,1);
1848/// TH1F *hb1b = new TH1F("hb1b","hb1",100,0,1);
1849/// b1->Add(hb1a);
1850/// b1->Add(hb1b);
1851///
1852/// TObjArray *a2 = new TObjArray();
1853/// a2->SetName("a2");
1854/// list->Add(a2);
1855/// TH1S *ha2a = new TH1S("ha2a","ha2",100,0,1);
1856/// TH1S *ha2b = new TH1S("ha2b","ha2",100,0,1);
1857/// a2->Add(ha2a);
1858/// a2->Add(ha2b);
1859///
1860/// T.Branch(list,16000,2);
1861/// T.Print();
1862/// }
1863/// ~~~
1865Int_t TTree::Branch(TCollection* li, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */, const char* name /* = "" */)
1866{
1867
1868 if (!li) {
1869 return 0;
1870 }
1871 TObject* obj = nullptr;
1872 Int_t nbranches = GetListOfBranches()->GetEntries();
1873 if (li->InheritsFrom(TClonesArray::Class())) {
1874 Error("Branch", "Cannot call this constructor for a TClonesArray");
1875 return 0;
1876 }
1877 Int_t nch = strlen(name);
1878 TString branchname;
1879 TIter next(li);
1880 while ((obj = next())) {
1881 if ((splitlevel > 1) && obj->InheritsFrom(TCollection::Class()) && !obj->InheritsFrom(TClonesArray::Class())) {
1882 TCollection* col = (TCollection*) obj;
1883 if (nch) {
1884 branchname.Form("%s_%s_", name, col->GetName());
1885 } else {
1886 branchname.Form("%s_", col->GetName());
1887 }
1888 Branch(col, bufsize, splitlevel - 1, branchname);
1889 } else {
1890 if (nch && (name[nch-1] == '_')) {
1891 branchname.Form("%s%s", name, obj->GetName());
1892 } else {
1893 if (nch) {
1894 branchname.Form("%s_%s", name, obj->GetName());
1895 } else {
1896 branchname.Form("%s", obj->GetName());
1897 }
1898 }
1899 if (splitlevel > 99) {
1900 branchname += ".";
1901 }
1902 Bronch(branchname, obj->ClassName(), li->GetObjectRef(obj), bufsize, splitlevel - 1);
1903 }
1904 }
1905 return GetListOfBranches()->GetEntries() - nbranches;
1906}
1907
1908////////////////////////////////////////////////////////////////////////////////
1909/// Create one branch for each element in the folder.
1910/// Returns the total number of branches created.
1912Int_t TTree::Branch(const char* foldername, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
1913{
1914 TObject* ob = gROOT->FindObjectAny(foldername);
1915 if (!ob) {
1916 return 0;
1917 }
1918 if (ob->IsA() != TFolder::Class()) {
1919 return 0;
1920 }
1921 Int_t nbranches = GetListOfBranches()->GetEntries();
1922 TFolder* folder = (TFolder*) ob;
1923 TIter next(folder->GetListOfFolders());
1924 TObject* obj = nullptr;
1925 char* curname = new char[1000];
1926 char occur[20];
1927 while ((obj = next())) {
1928 snprintf(curname,1000, "%s/%s", foldername, obj->GetName());
1929 if (obj->IsA() == TFolder::Class()) {
1930 Branch(curname, bufsize, splitlevel - 1);
1931 } else {
1932 void* add = (void*) folder->GetListOfFolders()->GetObjectRef(obj);
1933 for (Int_t i = 0; i < 1000; ++i) {
1934 if (curname[i] == 0) {
1935 break;
1936 }
1937 if (curname[i] == '/') {
1938 curname[i] = '.';
1939 }
1940 }
1941 Int_t noccur = folder->Occurence(obj);
1942 if (noccur > 0) {
1943 snprintf(occur,20, "_%d", noccur);
1944 strlcat(curname, occur,1000);
1945 }
1946 TBranchElement* br = (TBranchElement*) Bronch(curname, obj->ClassName(), add, bufsize, splitlevel - 1);
1947 if (br) br->SetBranchFolder();
1948 }
1949 }
1950 delete[] curname;
1951 return GetListOfBranches()->GetEntries() - nbranches;
1952}
1953
1954////////////////////////////////////////////////////////////////////////////////
1955/// Create a new TTree Branch.
1956///
1957/// This Branch constructor is provided to support non-objects in
1958/// a Tree. The variables described in leaflist may be simple
1959/// variables or structures. // See the two following
1960/// constructors for writing objects in a Tree.
1961///
1962/// By default the branch buffers are stored in the same file as the Tree.
1963/// use TBranch::SetFile to specify a different file
1964///
1965/// * address is the address of the first item of a structure.
1966/// * leaflist is the concatenation of all the variable names and types
1967/// separated by a colon character :
1968/// The variable name and the variable type are separated by a slash (/).
1969/// The variable type may be 0,1 or 2 characters. If no type is given,
1970/// the type of the variable is assumed to be the same as the previous
1971/// variable. If the first variable does not have a type, it is assumed
1972/// of type `F` by default. The list of currently supported types is given below:
1973/// - `C` : a character string terminated by the 0 character
1974/// - `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.
1975/// - `b` : an 8 bit unsigned integer (`UChar_t`)
1976/// - `S` : a 16 bit signed integer (`Short_t`)
1977/// - `s` : a 16 bit unsigned integer (`UShort_t`)
1978/// - `I` : a 32 bit signed integer (`Int_t`)
1979/// - `i` : a 32 bit unsigned integer (`UInt_t`)
1980/// - `F` : a 32 bit floating point (`Float_t`)
1981/// - `f` : a 24 bit floating point with truncated mantissa (`Float16_t`)
1982/// - `D` : a 64 bit floating point (`Double_t`)
1983/// - `d` : a 24 bit truncated floating point (`Double32_t`)
1984/// - `L` : a 64 bit signed integer (`Long64_t`)
1985/// - `l` : a 64 bit unsigned integer (`ULong64_t`)
1986/// - `G` : a long signed integer, stored as 64 bit (`Long_t`)
1987/// - `g` : a long unsigned integer, stored as 64 bit (`ULong_t`)
1988/// - `O` : [the letter `o`, not a zero] a boolean (`bool`)
1989///
1990/// Arrays of values are supported with the following syntax:
1991/// - If leaf name has the form var[nelem], where nelem is alphanumeric, then
1992/// if nelem is a leaf name, it is used as the variable size of the array,
1993/// otherwise return 0.
1994/// The leaf referred to by nelem **MUST** be an int (/I),
1995/// - If leaf name has the form var[nelem], where nelem is a non-negative integer, then
1996/// it is used as the fixed size of the array.
1997/// - If leaf name has the form of a multi-dimensional array (e.g. var[nelem][nelem2])
1998/// where nelem and nelem2 are non-negative integer) then
1999/// it is used as a 2 dimensional array of fixed size.
2000/// - In case of the truncated floating point types (Float16_t and Double32_t) you can
2001/// furthermore specify the range in the style [xmin,xmax] or [xmin,xmax,nbits] after
2002/// the type character. See `TStreamerElement::GetRange()` for further information.
2003///
2004/// Any of other form is not supported.
2005///
2006/// Note that the TTree will assume that all the item are contiguous in memory.
2007/// On some platform, this is not always true of the member of a struct or a class,
2008/// due to padding and alignment. Sorting your data member in order of decreasing
2009/// sizeof usually leads to their being contiguous in memory.
2010///
2011/// * bufsize is the buffer size in bytes for this branch
2012/// The default value is 32000 bytes and should be ok for most cases.
2013/// You can specify a larger value (e.g. 256000) if your Tree is not split
2014/// and each entry is large (Megabytes)
2015/// A small value for bufsize is optimum if you intend to access
2016/// the entries in the Tree randomly and your Tree is in split mode.
2018TBranch* TTree::Branch(const char* name, void* address, const char* leaflist, Int_t bufsize /* = 32000 */)
2019{
2020 TBranch* branch = new TBranch(this, name, address, leaflist, bufsize);
2021 if (branch->IsZombie()) {
2022 delete branch;
2023 branch = nullptr;
2024 return nullptr;
2025 }
2026 fBranches.Add(branch);
2027 return branch;
2028}
2029
2030////////////////////////////////////////////////////////////////////////////////
2031/// Create a new branch with the object of class classname at address addobj.
2032///
2033/// WARNING:
2034///
2035/// Starting with Root version 3.01, the Branch function uses the new style
2036/// branches (TBranchElement). To get the old behaviour, you can:
2037/// - call BranchOld or
2038/// - call TTree::SetBranchStyle(0)
2039///
2040/// Note that with the new style, classname does not need to derive from TObject.
2041/// It must derived from TObject if the branch style has been set to 0 (old)
2042///
2043/// Note: See the comments in TBranchElement::SetAddress() for a more
2044/// detailed discussion of the meaning of the addobj parameter in
2045/// the case of new-style branches.
2046///
2047/// Use splitlevel < 0 instead of splitlevel=0 when the class
2048/// has a custom Streamer
2049///
2050/// Note: if the split level is set to the default (99), TTree::Branch will
2051/// not issue a warning if the class can not be split.
2053TBranch* TTree::Branch(const char* name, const char* classname, void* addobj, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2054{
2055 if (fgBranchStyle == 1) {
2056 return Bronch(name, classname, addobj, bufsize, splitlevel);
2057 } else {
2058 if (splitlevel < 0) {
2059 splitlevel = 0;
2060 }
2061 return BranchOld(name, classname, addobj, bufsize, splitlevel);
2062 }
2063}
2064
2065////////////////////////////////////////////////////////////////////////////////
2066/// Create a new TTree BranchObject.
2067///
2068/// Build a TBranchObject for an object of class classname.
2069/// addobj is the address of a pointer to an object of class classname.
2070/// IMPORTANT: classname must derive from TObject.
2071/// The class dictionary must be available (ClassDef in class header).
2072///
2073/// This option requires access to the library where the corresponding class
2074/// is defined. Accessing one single data member in the object implies
2075/// reading the full object.
2076/// See the next Branch constructor for a more efficient storage
2077/// in case the entry consists of arrays of identical objects.
2078///
2079/// By default the branch buffers are stored in the same file as the Tree.
2080/// use TBranch::SetFile to specify a different file
2081///
2082/// IMPORTANT NOTE about branch names:
2083///
2084/// And in general, in case two or more master branches contain subbranches
2085/// with identical names, one must add a "." (dot) character at the end
2086/// of the master branch name. This will force the name of the subbranches
2087/// to be of the form `master.subbranch` instead of simply `subbranch`.
2088/// This situation happens when the top level object
2089/// has two or more members referencing the same class.
2090/// For example, if a Tree has two branches B1 and B2 corresponding
2091/// to objects of the same class MyClass, one can do:
2092/// ~~~ {.cpp}
2093/// tree.Branch("B1.","MyClass",&b1,8000,1);
2094/// tree.Branch("B2.","MyClass",&b2,8000,1);
2095/// ~~~
2096/// if MyClass has 3 members a,b,c, the two instructions above will generate
2097/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
2098///
2099/// bufsize is the buffer size in bytes for this branch
2100/// The default value is 32000 bytes and should be ok for most cases.
2101/// You can specify a larger value (e.g. 256000) if your Tree is not split
2102/// and each entry is large (Megabytes)
2103/// A small value for bufsize is optimum if you intend to access
2104/// the entries in the Tree randomly and your Tree is in split mode.
2106TBranch* TTree::BranchOld(const char* name, const char* classname, void* addobj, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 1 */)
2107{
2108 TClass* cl = TClass::GetClass(classname);
2109 if (!cl) {
2110 Error("BranchOld", "Cannot find class: '%s'", classname);
2111 return nullptr;
2112 }
2113 if (!cl->IsTObject()) {
2114 if (fgBranchStyle == 0) {
2115 Fatal("BranchOld", "The requested class ('%s') does not inherit from TObject.\n"
2116 "\tfgBranchStyle is set to zero requesting by default to use BranchOld.\n"
2117 "\tIf this is intentional use Bronch instead of Branch or BranchOld.", classname);
2118 } else {
2119 Fatal("BranchOld", "The requested class ('%s') does not inherit from TObject.\n"
2120 "\tYou can not use BranchOld to store objects of this type.",classname);
2121 }
2122 return nullptr;
2123 }
2124 TBranch* branch = new TBranchObject(this, name, classname, addobj, bufsize, splitlevel);
2125 fBranches.Add(branch);
2126 if (!splitlevel) {
2127 return branch;
2128 }
2129 // We are going to fully split the class now.
2130 TObjArray* blist = branch->GetListOfBranches();
2131 const char* rdname = nullptr;
2132 const char* dname = nullptr;
2133 TString branchname;
2134 char** apointer = (char**) addobj;
2135 TObject* obj = (TObject*) *apointer;
2136 bool delobj = false;
2137 if (!obj) {
2138 obj = (TObject*) cl->New();
2139 delobj = true;
2140 }
2141 // Build the StreamerInfo if first time for the class.
2142 BuildStreamerInfo(cl, obj);
2143 // Loop on all public data members of the class and its base classes.
2144 Int_t lenName = strlen(name);
2145 Int_t isDot = 0;
2146 if (name[lenName-1] == '.') {
2147 isDot = 1;
2148 }
2149 TBranch* branch1 = nullptr;
2150 TRealData* rd = nullptr;
2151 TRealData* rdi = nullptr;
2152 TIter nexti(cl->GetListOfRealData());
2153 TIter next(cl->GetListOfRealData());
2154 // Note: This loop results in a full split because the
2155 // real data list includes all data members of
2156 // data members.
2157 while ((rd = (TRealData*) next())) {
2158 if (rd->TestBit(TRealData::kTransient)) continue;
2159
2160 // Loop over all data members creating branches for each one.
2161 TDataMember* dm = rd->GetDataMember();
2162 if (!dm->IsPersistent()) {
2163 // Do not process members with an "!" as the first character in the comment field.
2164 continue;
2165 }
2166 if (rd->IsObject()) {
2167 // We skip data members of class type.
2168 // But we do build their real data, their
2169 // streamer info, and write their streamer
2170 // info to the current directory's file.
2171 // Oh yes, and we also do this for all of
2172 // their base classes.
2174 if (clm) {
2175 BuildStreamerInfo(clm, (char*) obj + rd->GetThisOffset());
2176 }
2177 continue;
2178 }
2179 rdname = rd->GetName();
2180 dname = dm->GetName();
2181 if (cl->CanIgnoreTObjectStreamer()) {
2182 // Skip the TObject base class data members.
2183 // FIXME: This prevents a user from ever
2184 // using these names themself!
2185 if (!strcmp(dname, "fBits")) {
2186 continue;
2187 }
2188 if (!strcmp(dname, "fUniqueID")) {
2189 continue;
2190 }
2191 }
2192 TDataType* dtype = dm->GetDataType();
2193 Int_t code = 0;
2194 if (dtype) {
2195 code = dm->GetDataType()->GetType();
2196 }
2197 // Encode branch name. Use real data member name
2198 branchname = rdname;
2199 if (isDot) {
2200 if (dm->IsaPointer()) {
2201 // FIXME: This is wrong! The asterisk is not usually in the front!
2202 branchname.Form("%s%s", name, &rdname[1]);
2203 } else {
2204 branchname.Form("%s%s", name, &rdname[0]);
2205 }
2206 }
2207 // FIXME: Change this to a string stream.
2208 TString leaflist;
2209 Int_t offset = rd->GetThisOffset();
2210 char* pointer = ((char*) obj) + offset;
2211 if (dm->IsaPointer()) {
2212 // We have a pointer to an object or a pointer to an array of basic types.
2213 TClass* clobj = nullptr;
2214 if (!dm->IsBasic()) {
2215 clobj = TClass::GetClass(dm->GetTypeName());
2216 }
2217 if (clobj && clobj->InheritsFrom(TClonesArray::Class())) {
2218 // We have a pointer to a clones array.
2219 char* cpointer = (char*) pointer;
2220 char** ppointer = (char**) cpointer;
2221 TClonesArray* li = (TClonesArray*) *ppointer;
2222 if (splitlevel != 2) {
2223 if (isDot) {
2224 branch1 = new TBranchClones(branch,branchname, pointer, bufsize);
2225 } else {
2226 // FIXME: This is wrong! The asterisk is not usually in the front!
2227 branch1 = new TBranchClones(branch,&branchname.Data()[1], pointer, bufsize);
2228 }
2229 blist->Add(branch1);
2230 } else {
2231 if (isDot) {
2232 branch1 = new TBranchObject(branch, branchname, li->ClassName(), pointer, bufsize);
2233 } else {
2234 // FIXME: This is wrong! The asterisk is not usually in the front!
2235 branch1 = new TBranchObject(branch, &branchname.Data()[1], li->ClassName(), pointer, bufsize);
2236 }
2237 blist->Add(branch1);
2238 }
2239 } else if (clobj) {
2240 // We have a pointer to an object.
2241 //
2242 // It must be a TObject object.
2243 if (!clobj->IsTObject()) {
2244 continue;
2245 }
2246 branch1 = new TBranchObject(branch, dname, clobj->GetName(), pointer, bufsize, 0);
2247 if (isDot) {
2248 branch1->SetName(branchname);
2249 } else {
2250 // FIXME: This is wrong! The asterisk is not usually in the front!
2251 // Do not use the first character (*).
2252 branch1->SetName(&branchname.Data()[1]);
2253 }
2254 blist->Add(branch1);
2255 } else {
2256 // We have a pointer to an array of basic types.
2257 //
2258 // Check the comments in the text of the code for an index specification.
2259 const char* index = dm->GetArrayIndex();
2260 if (index[0]) {
2261 // We are a pointer to a varying length array of basic types.
2262 //check that index is a valid data member name
2263 //if member is part of an object (e.g. fA and index=fN)
2264 //index must be changed from fN to fA.fN
2265 TString aindex (rd->GetName());
2266 Ssiz_t rdot = aindex.Last('.');
2267 if (rdot>=0) {
2268 aindex.Remove(rdot+1);
2269 aindex.Append(index);
2270 }
2271 nexti.Reset();
2272 while ((rdi = (TRealData*) nexti())) {
2273 if (rdi->TestBit(TRealData::kTransient)) continue;
2274
2275 if (!strcmp(rdi->GetName(), index)) {
2276 break;
2277 }
2278 if (!strcmp(rdi->GetName(), aindex)) {
2279 index = rdi->GetName();
2280 break;
2281 }
2282 }
2283
2284 char vcode = DataTypeToChar((EDataType)code);
2285 // Note that we differentiate between strings and
2286 // char array by the fact that there is NO specified
2287 // size for a string (see next if (code == 1)
2288
2289 if (vcode) {
2290 leaflist.Form("%s[%s]/%c", &rdname[0], index, vcode);
2291 } else {
2292 Error("BranchOld", "Cannot create branch for rdname: %s code: %d", branchname.Data(), code);
2293 leaflist = "";
2294 }
2295 } else {
2296 // We are possibly a character string.
2297 if (code == 1) {
2298 // We are a character string.
2299 leaflist.Form("%s/%s", dname, "C");
2300 } else {
2301 // Invalid array specification.
2302 // FIXME: We need an error message here.
2303 continue;
2304 }
2305 }
2306 // There are '*' in both the branchname and leaflist, remove them.
2307 TString bname( branchname );
2308 bname.ReplaceAll("*","");
2309 leaflist.ReplaceAll("*","");
2310 // Add the branch to the tree and indicate that the address
2311 // is that of a pointer to be dereferenced before using.
2312 branch1 = new TBranch(branch, bname, *((void**) pointer), leaflist, bufsize);
2313 TLeaf* leaf = (TLeaf*) branch1->GetListOfLeaves()->At(0);
2315 leaf->SetAddress((void**) pointer);
2316 blist->Add(branch1);
2317 }
2318 } else if (dm->IsBasic()) {
2319 // We have a basic type.
2320
2321 char vcode = DataTypeToChar((EDataType)code);
2322 if (vcode) {
2323 leaflist.Form("%s/%c", rdname, vcode);
2324 } else {
2325 Error("BranchOld", "Cannot create branch for rdname: %s code: %d", branchname.Data(), code);
2326 leaflist = "";
2327 }
2328 branch1 = new TBranch(branch, branchname, pointer, leaflist, bufsize);
2329 branch1->SetTitle(rdname);
2330 blist->Add(branch1);
2331 } else {
2332 // We have a class type.
2333 // Note: This cannot happen due to the rd->IsObject() test above.
2334 // FIXME: Put an error message here just in case.
2335 }
2336 if (branch1) {
2337 branch1->SetOffset(offset);
2338 } else {
2339 Warning("BranchOld", "Cannot process member: '%s'", rdname);
2340 }
2341 }
2342 if (delobj) {
2343 delete obj;
2344 obj = nullptr;
2345 }
2346 return branch;
2347}
2348
2349////////////////////////////////////////////////////////////////////////////////
2350/// Build the optional branch supporting the TRefTable.
2351/// This branch will keep all the information to find the branches
2352/// containing referenced objects.
2353///
2354/// At each Tree::Fill, the branch numbers containing the
2355/// referenced objects are saved to the TBranchRef basket.
2356/// When the Tree header is saved (via TTree::Write), the branch
2357/// is saved keeping the information with the pointers to the branches
2358/// having referenced objects.
2361{
2362 if (!fBranchRef) {
2363 fBranchRef = new TBranchRef(this);
2364 }
2365 return fBranchRef;
2366}
2367
2368////////////////////////////////////////////////////////////////////////////////
2369/// Create a new TTree BranchElement.
2370///
2371/// ## WARNING about this new function
2372///
2373/// This function is designed to replace the internal
2374/// implementation of the old TTree::Branch (whose implementation
2375/// has been moved to BranchOld).
2376///
2377/// NOTE: The 'Bronch' method supports only one possible calls
2378/// signature (where the object type has to be specified
2379/// explicitly and the address must be the address of a pointer).
2380/// For more flexibility use 'Branch'. Use Bronch only in (rare)
2381/// cases (likely to be legacy cases) where both the new and old
2382/// implementation of Branch needs to be used at the same time.
2383///
2384/// This function is far more powerful than the old Branch
2385/// function. It supports the full C++, including STL and has
2386/// the same behaviour in split or non-split mode. classname does
2387/// not have to derive from TObject. The function is based on
2388/// the new TStreamerInfo.
2389///
2390/// Build a TBranchElement for an object of class classname.
2391///
2392/// addr is the address of a pointer to an object of class
2393/// classname. The class dictionary must be available (ClassDef
2394/// in class header).
2395///
2396/// Note: See the comments in TBranchElement::SetAddress() for a more
2397/// detailed discussion of the meaning of the addr parameter.
2398///
2399/// This option requires access to the library where the
2400/// corresponding class is defined. Accessing one single data
2401/// member in the object implies reading the full object.
2402///
2403/// By default the branch buffers are stored in the same file as the Tree.
2404/// use TBranch::SetFile to specify a different file
2405///
2406/// IMPORTANT NOTE about branch names:
2407///
2408/// And in general, in case two or more master branches contain subbranches
2409/// with identical names, one must add a "." (dot) character at the end
2410/// of the master branch name. This will force the name of the subbranches
2411/// to be of the form `master.subbranch` instead of simply `subbranch`.
2412/// This situation happens when the top level object
2413/// has two or more members referencing the same class.
2414/// For example, if a Tree has two branches B1 and B2 corresponding
2415/// to objects of the same class MyClass, one can do:
2416/// ~~~ {.cpp}
2417/// tree.Branch("B1.","MyClass",&b1,8000,1);
2418/// tree.Branch("B2.","MyClass",&b2,8000,1);
2419/// ~~~
2420/// if MyClass has 3 members a,b,c, the two instructions above will generate
2421/// subbranches called B1.a, B1.b ,B1.c, B2.a, B2.b, B2.c
2422///
2423/// bufsize is the buffer size in bytes for this branch
2424/// The default value is 32000 bytes and should be ok for most cases.
2425/// You can specify a larger value (e.g. 256000) if your Tree is not split
2426/// and each entry is large (Megabytes)
2427/// A small value for bufsize is optimum if you intend to access
2428/// the entries in the Tree randomly and your Tree is in split mode.
2429///
2430/// Use splitlevel < 0 instead of splitlevel=0 when the class
2431/// has a custom Streamer
2432///
2433/// Note: if the split level is set to the default (99), TTree::Branch will
2434/// not issue a warning if the class can not be split.
2436TBranch* TTree::Bronch(const char* name, const char* classname, void* addr, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2437{
2438 return BronchExec(name, classname, addr, true, bufsize, splitlevel);
2439}
2440
2441////////////////////////////////////////////////////////////////////////////////
2442/// Helper function implementing TTree::Bronch and TTree::Branch(const char *name, T &obj);
2444TBranch* TTree::BronchExec(const char* name, const char* classname, void* addr, bool isptrptr, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */)
2445{
2446 TClass* cl = TClass::GetClass(classname);
2447 if (!cl) {
2448 Error("Bronch", "Cannot find class:%s", classname);
2449 return nullptr;
2450 }
2451
2452 //if splitlevel <= 0 and class has a custom Streamer, we must create
2453 //a TBranchObject. We cannot assume that TClass::ReadBuffer is consistent
2454 //with the custom Streamer. The penalty is that one cannot process
2455 //this Tree without the class library containing the class.
2456
2457 char* objptr = nullptr;
2458 if (!isptrptr) {
2459 objptr = (char*)addr;
2460 } else if (addr) {
2461 objptr = *((char**) addr);
2462 }
2463
2464 if (cl == TClonesArray::Class()) {
2465 TClonesArray* clones = (TClonesArray*) objptr;
2466 if (!clones) {
2467 Error("Bronch", "Pointer to TClonesArray is null");
2468 return nullptr;
2469 }
2470 if (!clones->GetClass()) {
2471 Error("Bronch", "TClonesArray with no class defined in branch: %s", name);
2472 return nullptr;
2473 }
2474 if (!clones->GetClass()->HasDataMemberInfo()) {
2475 Error("Bronch", "TClonesArray with no dictionary defined in branch: %s", name);
2476 return nullptr;
2477 }
2478 bool hasCustomStreamer = clones->GetClass()->HasCustomStreamerMember();
2479 if (splitlevel > 0) {
2480 if (hasCustomStreamer)
2481 Warning("Bronch", "Using split mode on a class: %s with a custom Streamer", clones->GetClass()->GetName());
2482 } else {
2483 if (hasCustomStreamer) clones->BypassStreamer(false);
2484 TBranchObject *branch = new TBranchObject(this,name,classname,addr,bufsize,0,/*compress=*/ -1,isptrptr);
2485 fBranches.Add(branch);
2486 return branch;
2487 }
2488 }
2489
2490 if (cl->GetCollectionProxy()) {
2492 //if (!collProxy) {
2493 // Error("Bronch", "%s is missing its CollectionProxy (for branch %s)", classname, name);
2494 //}
2495 TClass* inklass = collProxy->GetValueClass();
2496 if (!inklass && (collProxy->GetType() == 0)) {
2497 Error("Bronch", "%s with no class defined in branch: %s", classname, name);
2498 return nullptr;
2499 }
2500 if ((splitlevel > 0) && inklass && (inklass->GetCollectionProxy() == nullptr)) {
2502 if ((stl != ROOT::kSTLmap) && (stl != ROOT::kSTLmultimap)) {
2503 if (!inklass->HasDataMemberInfo()) {
2504 Error("Bronch", "Container with no dictionary defined in branch: %s", name);
2505 return nullptr;
2506 }
2507 if (inklass->HasCustomStreamerMember()) {
2508 Warning("Bronch", "Using split mode on a class: %s with a custom Streamer", inklass->GetName());
2509 }
2510 }
2511 }
2512 //-------------------------------------------------------------------------
2513 // If the splitting switch is enabled, the split level is big enough and
2514 // the collection contains pointers we can split it
2515 //////////////////////////////////////////////////////////////////////////
2516
2517 TBranch *branch;
2518 if( splitlevel > kSplitCollectionOfPointers && collProxy->HasPointers() )
2519 branch = new TBranchSTL( this, name, collProxy, bufsize, splitlevel );
2520 else
2521 branch = new TBranchElement(this, name, collProxy, bufsize, splitlevel);
2522 fBranches.Add(branch);
2523 if (isptrptr) {
2524 branch->SetAddress(addr);
2525 } else {
2526 branch->SetObject(addr);
2527 }
2528 return branch;
2529 }
2530
2531 bool hasCustomStreamer = false;
2532 if (!cl->HasDataMemberInfo() && !cl->GetCollectionProxy()) {
2533 Error("Bronch", "Cannot find dictionary for class: %s", classname);
2534 return nullptr;
2535 }
2536
2537 if (!cl->GetCollectionProxy() && cl->HasCustomStreamerMember()) {
2538 // Not an STL container and the linkdef file had a "-" after the class name.
2539 hasCustomStreamer = true;
2540 }
2541
2542 if (splitlevel < 0 || ((splitlevel == 0) && hasCustomStreamer && cl->IsTObject())) {
2543 TBranchObject* branch = new TBranchObject(this, name, classname, addr, bufsize, 0, /*compress=*/ ROOT::RCompressionSetting::EAlgorithm::kInherit, isptrptr);
2544 fBranches.Add(branch);
2545 return branch;
2546 }
2547
2548 if (cl == TClonesArray::Class()) {
2549 // Special case of TClonesArray.
2550 // No dummy object is created.
2551 // The streamer info is not rebuilt unoptimized.
2552 // No dummy top-level branch is created.
2553 // No splitting is attempted.
2554 TBranchElement* branch = new TBranchElement(this, name, (TClonesArray*) objptr, bufsize, splitlevel%kSplitCollectionOfPointers);
2555 fBranches.Add(branch);
2556 if (isptrptr) {
2557 branch->SetAddress(addr);
2558 } else {
2559 branch->SetObject(addr);
2560 }
2561 return branch;
2562 }
2563
2564 //
2565 // If we are not given an object to use as an i/o buffer
2566 // then create a temporary one which we will delete just
2567 // before returning.
2568 //
2569
2570 bool delobj = false;
2571
2572 if (!objptr) {
2573 objptr = (char*) cl->New();
2574 delobj = true;
2575 }
2576
2577 //
2578 // Avoid splitting unsplittable classes.
2579 //
2580
2581 if ((splitlevel > 0) && !cl->CanSplit()) {
2582 if (splitlevel != 99) {
2583 Warning("Bronch", "%s cannot be split, resetting splitlevel to 0", cl->GetName());
2584 }
2585 splitlevel = 0;
2586 }
2587
2588 //
2589 // Make sure the streamer info is built and fetch it.
2590 //
2591 // If we are splitting, then make sure the streamer info
2592 // is built unoptimized (data members are not combined).
2593 //
2594
2595 TStreamerInfo* sinfo = BuildStreamerInfo(cl, objptr, splitlevel==0);
2596 if (!sinfo) {
2597 Error("Bronch", "Cannot build the StreamerInfo for class: %s", cl->GetName());
2598 return nullptr;
2599 }
2600
2601 //
2602 // Create a dummy top level branch object.
2603 //
2604
2605 Int_t id = -1;
2606 if (splitlevel > 0) {
2607 id = -2;
2608 }
2609 TBranchElement* branch = new TBranchElement(this, name, sinfo, id, objptr, bufsize, splitlevel);
2610 fBranches.Add(branch);
2611
2612 //
2613 // Do splitting, if requested.
2614 //
2615
2616 if (splitlevel%kSplitCollectionOfPointers > 0) {
2617 branch->Unroll(name, cl, sinfo, objptr, bufsize, splitlevel);
2618 }
2619
2620 //
2621 // Setup our offsets into the user's i/o buffer.
2622 //
2623
2624 if (isptrptr) {
2625 branch->SetAddress(addr);
2626 } else {
2627 branch->SetObject(addr);
2628 }
2629
2630 if (delobj) {
2631 cl->Destructor(objptr);
2632 objptr = nullptr;
2633 }
2634
2635 return branch;
2636}
2637
2638////////////////////////////////////////////////////////////////////////////////
2639/// Browse content of the TTree.
2642{
2644 if (fUserInfo) {
2645 if (strcmp("TList",fUserInfo->GetName())==0) {
2646 fUserInfo->SetName("UserInfo");
2647 b->Add(fUserInfo);
2648 fUserInfo->SetName("TList");
2649 } else {
2650 b->Add(fUserInfo);
2651 }
2652 }
2653}
2654
2655////////////////////////////////////////////////////////////////////////////////
2656/// Build a Tree Index (default is TTreeIndex).
2657/// See a description of the parameters and functionality in
2658/// TTreeIndex::TTreeIndex().
2659///
2660/// The return value is the number of entries in the Index (< 0 indicates failure).
2661///
2662/// A TTreeIndex object pointed by fTreeIndex is created.
2663/// This object will be automatically deleted by the TTree destructor.
2664/// If an index is already existing, this is replaced by the new one without being
2665/// deleted. This behaviour prevents the deletion of a previously external index
2666/// assigned to the TTree via the TTree::SetTreeIndex() method.
2667/// \see TTree::SetTreeIndex()
2669Int_t TTree::BuildIndex(const char* majorname, const char* minorname /* = "0" */, bool long64major, bool long64minor)
2670{
2671 fTreeIndex = GetPlayer()->BuildIndex(this, majorname, minorname, long64major, long64minor);
2672 if (fTreeIndex->IsZombie()) {
2673 delete fTreeIndex;
2674 fTreeIndex = nullptr;
2675 return 0;
2676 }
2677 return fTreeIndex->GetN();
2678}
2679
2680////////////////////////////////////////////////////////////////////////////////
2681/// Build StreamerInfo for class cl.
2682/// pointer is an optional argument that may contain a pointer to an object of cl.
2684TStreamerInfo* TTree::BuildStreamerInfo(TClass* cl, void* pointer /* = 0 */, bool canOptimize /* = true */ )
2685{
2686 if (!cl) {
2687 return nullptr;
2688 }
2689 cl->BuildRealData(pointer);
2691
2692 // Create StreamerInfo for all base classes.
2693 TBaseClass* base = nullptr;
2694 TIter nextb(cl->GetListOfBases());
2695 while((base = (TBaseClass*) nextb())) {
2696 if (base->IsSTLContainer()) {
2697 continue;
2698 }
2699 TClass* clm = TClass::GetClass(base->GetName());
2700 BuildStreamerInfo(clm, pointer, canOptimize);
2701 }
2702 if (sinfo && fDirectory) {
2704 }
2705 return sinfo;
2706}
2707
2708////////////////////////////////////////////////////////////////////////////////
2709/// Enable the TTreeCache unless explicitly disabled for this TTree by
2710/// a prior call to `SetCacheSize(0)`.
2711/// If the environment variable `ROOT_TTREECACHE_SIZE` or the rootrc config
2712/// `TTreeCache.Size` has been set to zero, this call will over-ride them with
2713/// a value of 1.0 (i.e. use a cache size to hold 1 cluster)
2714///
2715/// Return true if there is a cache attached to the `TTree` (either pre-exisiting
2716/// or created as part of this call)
2717bool TTree::EnableCache()
2718{
2719 TFile* file = GetCurrentFile();
2720 if (!file)
2721 return false;
2722 // Check for an existing cache
2723 TTreeCache* pf = GetReadCache(file);
2724 if (pf)
2725 return true;
2726 if (fCacheUserSet && fCacheSize == 0)
2727 return false;
2728 return (0 == SetCacheSizeAux(true, -1));
2729}
2730
2731////////////////////////////////////////////////////////////////////////////////
2732/// Called by TTree::Fill() when file has reached its maximum fgMaxTreeSize.
2733/// Create a new file. If the original file is named "myfile.root",
2734/// subsequent files are named "myfile_1.root", "myfile_2.root", etc.
2735///
2736/// Returns a pointer to the new file.
2737///
2738/// Currently, the automatic change of file is restricted
2739/// to the case where the tree is in the top level directory.
2740/// The file should not contain sub-directories.
2741///
2742/// Before switching to a new file, the tree header is written
2743/// to the current file, then the current file is closed.
2744///
2745/// To process the multiple files created by ChangeFile, one must use
2746/// a TChain.
2747///
2748/// The new file name has a suffix "_N" where N is equal to fFileNumber+1.
2749/// By default a Root session starts with fFileNumber=0. One can set
2750/// fFileNumber to a different value via TTree::SetFileNumber.
2751/// In case a file named "_N" already exists, the function will try
2752/// a file named "__N", then "___N", etc.
2753///
2754/// fgMaxTreeSize can be set via the static function TTree::SetMaxTreeSize.
2755/// The default value of fgMaxTreeSize is 100 Gigabytes.
2756///
2757/// If the current file contains other objects like TH1 and TTree,
2758/// these objects are automatically moved to the new file.
2759///
2760/// \warning Be careful when writing the final Tree header to the file!
2761/// Don't do:
2762/// ~~~ {.cpp}
2763/// TFile *file = new TFile("myfile.root","recreate");
2764/// TTree *T = new TTree("T","title");
2765/// T->Fill(); // Loop
2766/// file->Write();
2767/// file->Close();
2768/// ~~~
2769/// \warning but do the following:
2770/// ~~~ {.cpp}
2771/// TFile *file = new TFile("myfile.root","recreate");
2772/// TTree *T = new TTree("T","title");
2773/// T->Fill(); // Loop
2774/// file = T->GetCurrentFile(); // To get the pointer to the current file
2775/// file->Write();
2776/// file->Close();
2777/// ~~~
2778///
2779/// \note This method is never called if the input file is a `TMemFile` or derivate.
2782{
2783 // Changing file clashes with the design of TMemFile and derivates, see #6523,
2784 // as well as with TFileMerger operations, see #6640.
2785 if ((dynamic_cast<TMemFile *>(file)) || file->TestBit(TFile::kCancelTTreeChangeRequest))
2786 return file;
2787 file->cd();
2788 Write();
2789 Reset();
2790 constexpr auto kBufSize = 2000;
2791 char* fname = new char[kBufSize];
2792 ++fFileNumber;
2793 char uscore[10];
2794 for (Int_t i = 0; i < 10; ++i) {
2795 uscore[i] = 0;
2796 }
2797 Int_t nus = 0;
2798 // Try to find a suitable file name that does not already exist.
2799 while (nus < 10) {
2800 uscore[nus] = '_';
2801 fname[0] = 0;
2802 strlcpy(fname, file->GetName(), kBufSize);
2803
2804 if (fFileNumber > 1) {
2805 char* cunder = strrchr(fname, '_');
2806 if (cunder) {
2807 snprintf(cunder, kBufSize - Int_t(cunder - fname), "%s%d", uscore, fFileNumber);
2808 const char* cdot = strrchr(file->GetName(), '.');
2809 if (cdot) {
2810 strlcat(fname, cdot, kBufSize);
2811 }
2812 } else {
2813 char fcount[21];
2814 snprintf(fcount,21, "%s%d", uscore, fFileNumber);
2815 strlcat(fname, fcount, kBufSize);
2816 }
2817 } else {
2818 char* cdot = strrchr(fname, '.');
2819 if (cdot) {
2820 snprintf(cdot, kBufSize - Int_t(fname-cdot), "%s%d", uscore, fFileNumber);
2821 strlcat(fname, strrchr(file->GetName(), '.'), kBufSize);
2822 } else {
2823 char fcount[21];
2824 snprintf(fcount,21, "%s%d", uscore, fFileNumber);
2825 strlcat(fname, fcount, kBufSize);
2826 }
2827 }
2828 if (gSystem->AccessPathName(fname)) {
2829 break;
2830 }
2831 ++nus;
2832 Warning("ChangeFile", "file %s already exists, trying with %d underscores", fname, nus + 1);
2833 }
2834 Int_t compress = file->GetCompressionSettings();
2835 TFile* newfile = TFile::Open(fname, "recreate", "chain files", compress);
2836 if (newfile == nullptr) {
2837 Error("Fill","Failed to open new file %s, continuing as a memory tree.",fname);
2838 } else {
2839 Printf("Fill: Switching to new file: %s", fname);
2840 }
2841 // The current directory may contain histograms and trees.
2842 // These objects must be moved to the new file.
2843 TBranch* branch = nullptr;
2844 TObject* obj = nullptr;
2845 while ((obj = file->GetList()->First())) {
2846 file->Remove(obj);
2847 // Histogram: just change the directory.
2848 if (obj->InheritsFrom("TH1")) {
2849 gROOT->ProcessLine(TString::Format("((%s*)0x%zx)->SetDirectory((TDirectory*)0x%zx);", obj->ClassName(), (size_t) obj, (size_t) newfile));
2850 continue;
2851 }
2852 // Tree: must save all trees in the old file, reset them.
2853 if (obj->InheritsFrom(TTree::Class())) {
2854 TTree* t = (TTree*) obj;
2855 if (t != this) {
2856 t->AutoSave();
2857 t->Reset();
2859 }
2860 t->SetDirectory(newfile);
2861 TIter nextb(t->GetListOfBranches());
2862 while ((branch = (TBranch*)nextb())) {
2863 branch->SetFile(newfile);
2864 }
2865 if (t->GetBranchRef()) {
2866 t->GetBranchRef()->SetFile(newfile);
2867 }
2868 continue;
2869 }
2870 // Not a TH1 or a TTree, move object to new file.
2871 if (newfile) newfile->Append(obj);
2872 file->Remove(obj);
2873 }
2874 file->TObject::Delete();
2875 file = nullptr;
2876 delete[] fname;
2877 fname = nullptr;
2878 return newfile;
2879}
2880
2881////////////////////////////////////////////////////////////////////////////////
2882/// Check whether or not the address described by the last 3 parameters
2883/// matches the content of the branch. If a Data Model Evolution conversion
2884/// is involved, reset the fInfo of the branch.
2885/// The return values are:
2886//
2887/// - kMissingBranch (-5) : Missing branch
2888/// - kInternalError (-4) : Internal error (could not find the type corresponding to a data type number)
2889/// - kMissingCompiledCollectionProxy (-3) : Missing compiled collection proxy for a compiled collection
2890/// - kMismatch (-2) : Non-Class Pointer type given does not match the type expected by the branch
2891/// - kClassMismatch (-1) : Class Pointer type given does not match the type expected by the branch
2892/// - kMatch (0) : perfect match
2893/// - kMatchConversion (1) : match with (I/O) conversion
2894/// - kMatchConversionCollection (2) : match with (I/O) conversion of the content of a collection
2895/// - kMakeClass (3) : MakeClass mode so we can not check.
2896/// - kVoidPtr (4) : void* passed so no check was made.
2897/// - kNoCheck (5) : Underlying TBranch not yet available so no check was made.
2898/// In addition this can be multiplexed with the two bits:
2899/// - kNeedEnableDecomposedObj : in order for the address (type) to be 'usable' the branch needs to be in Decomposed Object (aka MakeClass) mode.
2900/// - kNeedDisableDecomposedObj : in order for the address (type) to be 'usable' the branch needs to not be in Decomposed Object (aka MakeClass) mode.
2901/// This bits can be masked out by using kDecomposedObjMask
2903Int_t TTree::CheckBranchAddressType(TBranch* branch, TClass* ptrClass, EDataType datatype, bool isptr)
2904{
2905 if (GetMakeClass()) {
2906 // If we are in MakeClass mode so we do not really use classes.
2907 return kMakeClass;
2908 }
2909
2910 // Let's determine what we need!
2911 TClass* expectedClass = nullptr;
2912 EDataType expectedType = kOther_t;
2913 if (0 != branch->GetExpectedType(expectedClass,expectedType) ) {
2914 // Something went wrong, the warning message has already been issued.
2915 return kInternalError;
2916 }
2917 bool isBranchElement = branch->InheritsFrom( TBranchElement::Class() );
2918 if (expectedClass && datatype == kOther_t && ptrClass == nullptr) {
2919 if (isBranchElement) {
2920 TBranchElement* bEl = (TBranchElement*)branch;
2921 bEl->SetTargetClass( expectedClass->GetName() );
2922 }
2923 if (expectedClass && expectedClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(expectedClass->GetCollectionProxy())) {
2924 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2925 "The class expected (%s) refers to an stl collection and do not have a compiled CollectionProxy. "
2926 "Please generate the dictionary for this class (%s)",
2927 branch->GetName(), expectedClass->GetName(), expectedClass->GetName());
2929 }
2930 if (!expectedClass->IsLoaded()) {
2931 // The originally expected class does not have a dictionary, it is then plausible that the pointer being passed is the right type
2932 // (we really don't know). So let's express that.
2933 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2934 "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."
2935 "Please generate the dictionary for this class (%s)",
2936 branch->GetName(), expectedClass->GetName(), expectedClass->GetName());
2937 } else {
2938 Error("SetBranchAddress", "Unable to determine the type given for the address for \"%s\". "
2939 "This is probably due to a missing dictionary, the original data class for this branch is %s.", branch->GetName(), expectedClass->GetName());
2940 }
2941 return kClassMismatch;
2942 }
2943 if (expectedClass && ptrClass && (branch->GetMother() == branch)) {
2944 // Top Level branch
2945 if (!isptr) {
2946 Error("SetBranchAddress", "The address for \"%s\" should be the address of a pointer!", branch->GetName());
2947 }
2948 }
2949 if (expectedType == kFloat16_t) {
2950 expectedType = kFloat_t;
2951 }
2952 if (expectedType == kDouble32_t) {
2953 expectedType = kDouble_t;
2954 }
2955 if (datatype == kFloat16_t) {
2956 datatype = kFloat_t;
2957 }
2958 if (datatype == kDouble32_t) {
2959 datatype = kDouble_t;
2960 }
2961
2962 /////////////////////////////////////////////////////////////////////////////
2963 // Deal with the class renaming
2964 /////////////////////////////////////////////////////////////////////////////
2965
2966 if( expectedClass && ptrClass &&
2967 expectedClass != ptrClass &&
2968 isBranchElement &&
2969 ptrClass->GetSchemaRules() &&
2970 ptrClass->GetSchemaRules()->HasRuleWithSourceClass( expectedClass->GetName() ) ) {
2971 TBranchElement* bEl = (TBranchElement*)branch;
2972
2973 if ( ptrClass->GetCollectionProxy() && expectedClass->GetCollectionProxy() ) {
2974 if (gDebug > 7)
2975 Info("SetBranchAddress", "Matching STL collection (at least according to the SchemaRuleSet when "
2976 "reading a %s into a %s",expectedClass->GetName(),ptrClass->GetName());
2977
2978 bEl->SetTargetClass( ptrClass->GetName() );
2979 return kMatchConversion;
2980
2981 } else if ( !ptrClass->GetConversionStreamerInfo( expectedClass, bEl->GetClassVersion() ) &&
2982 !ptrClass->FindConversionStreamerInfo( expectedClass, bEl->GetCheckSum() ) ) {
2983 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());
2984
2985 bEl->SetTargetClass( expectedClass->GetName() );
2986 return kClassMismatch;
2987 }
2988 else {
2989
2990 bEl->SetTargetClass( ptrClass->GetName() );
2991 return kMatchConversion;
2992 }
2993
2994 } else if (expectedClass && ptrClass && !expectedClass->InheritsFrom(ptrClass)) {
2995
2996 if (expectedClass->GetCollectionProxy() && ptrClass->GetCollectionProxy() &&
2997 isBranchElement &&
2998 expectedClass->GetCollectionProxy()->GetValueClass() &&
2999 ptrClass->GetCollectionProxy()->GetValueClass() )
3000 {
3001 // In case of collection, we know how to convert them, if we know how to convert their content.
3002 // NOTE: we need to extend this to std::pair ...
3003
3004 TClass *onfileValueClass = expectedClass->GetCollectionProxy()->GetValueClass();
3005 TClass *inmemValueClass = ptrClass->GetCollectionProxy()->GetValueClass();
3006
3007 if (inmemValueClass->GetSchemaRules() &&
3008 inmemValueClass->GetSchemaRules()->HasRuleWithSourceClass(onfileValueClass->GetName() ) )
3009 {
3010 TBranchElement* bEl = (TBranchElement*)branch;
3011 bEl->SetTargetClass( ptrClass->GetName() );
3013 }
3014 }
3015
3016 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());
3017 if (isBranchElement) {
3018 TBranchElement* bEl = (TBranchElement*)branch;
3019 bEl->SetTargetClass( expectedClass->GetName() );
3020 }
3021 return kClassMismatch;
3022
3023 } else if ((expectedType != kOther_t) && (datatype != kOther_t) && (expectedType != kNoType_t) && (datatype != kNoType_t) && (expectedType != datatype)) {
3024 if (datatype != kChar_t) {
3025 // For backward compatibility we assume that (char*) was just a cast and/or a generic address
3026 Error("SetBranchAddress", "The pointer type given \"%s\" (%d) does not correspond to the type needed \"%s\" (%d) by the branch: %s",
3027 TDataType::GetTypeName(datatype), datatype, TDataType::GetTypeName(expectedType), expectedType, branch->GetName());
3028 return kMismatch;
3029 }
3030 } else if ((expectedClass && (datatype != kOther_t && datatype != kNoType_t && datatype != kInt_t)) ||
3031 (ptrClass && (expectedType != kOther_t && expectedType != kNoType_t && datatype != kInt_t)) ) {
3032 // Sometime a null pointer can look an int, avoid complaining in that case.
3033 if (expectedClass) {
3034 Error("SetBranchAddress", "The pointer type given \"%s\" (%d) does not correspond to the type needed \"%s\" by the branch: %s",
3035 TDataType::GetTypeName(datatype), datatype, expectedClass->GetName(), branch->GetName());
3036 if (isBranchElement) {
3037 TBranchElement* bEl = (TBranchElement*)branch;
3038 bEl->SetTargetClass( expectedClass->GetName() );
3039 }
3040 } else {
3041 // 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
3042 // a struct).
3043 bool found = false;
3044 if (ptrClass->IsLoaded()) {
3045 TIter next(ptrClass->GetListOfRealData());
3046 TRealData *rdm;
3047 while ((rdm = (TRealData*)next())) {
3048 if (rdm->GetThisOffset() == 0) {
3049 TDataType *dmtype = rdm->GetDataMember()->GetDataType();
3050 if (dmtype) {
3051 EDataType etype = (EDataType)dmtype->GetType();
3052 if (etype == expectedType) {
3053 found = true;
3054 }
3055 }
3056 break;
3057 }
3058 }
3059 } else {
3060 TIter next(ptrClass->GetListOfDataMembers());
3061 TDataMember *dm;
3062 while ((dm = (TDataMember*)next())) {
3063 if (dm->GetOffset() == 0) {
3064 TDataType *dmtype = dm->GetDataType();
3065 if (dmtype) {
3066 EDataType etype = (EDataType)dmtype->GetType();
3067 if (etype == expectedType) {
3068 found = true;
3069 }
3070 }
3071 break;
3072 }
3073 }
3074 }
3075 if (found) {
3076 // let's check the size.
3077 TLeaf *last = (TLeaf*)branch->GetListOfLeaves()->Last();
3078 long len = last->GetOffset() + last->GetLenType() * last->GetLen();
3079 if (len <= ptrClass->Size()) {
3080 return kMatch;
3081 }
3082 }
3083 Error("SetBranchAddress", "The pointer type given \"%s\" does not correspond to the type needed \"%s\" (%d) by the branch: %s",
3084 ptrClass->GetName(), TDataType::GetTypeName(expectedType), expectedType, branch->GetName());
3085 }
3086 return kMismatch;
3087 }
3088 if (expectedClass && expectedClass->GetCollectionProxy() && dynamic_cast<TEmulatedCollectionProxy*>(expectedClass->GetCollectionProxy())) {
3089 Error("SetBranchAddress", writeStlWithoutProxyMsg,
3090 expectedClass->GetName(), branch->GetName(), expectedClass->GetName());
3091 if (isBranchElement) {
3092 TBranchElement* bEl = (TBranchElement*)branch;
3093 bEl->SetTargetClass( expectedClass->GetName() );
3094 }
3096 }
3097 if (isBranchElement) {
3098 if (expectedClass) {
3099 TBranchElement* bEl = (TBranchElement*)branch;
3100 bEl->SetTargetClass( expectedClass->GetName() );
3101 } else if (expectedType != kNoType_t && expectedType != kOther_t) {
3103 }
3104 }
3105 return kMatch;
3106}
3107
3108////////////////////////////////////////////////////////////////////////////////
3109/// Create a clone of this tree and copy nentries.
3110///
3111/// By default copy all entries.
3112/// The compression level of the cloned tree is set to the destination
3113/// file's compression level.
3114///
3115/// NOTE: Only active branches are copied. See TTree::SetBranchStatus for more
3116/// information and usage regarding the (de)activation of branches. More
3117/// examples are provided in the tutorials listed below.
3118///
3119/// NOTE: If the TTree is a TChain, the structure of the first TTree
3120/// is used for the copy.
3121///
3122/// IMPORTANT: The cloned tree stays connected with this tree until
3123/// this tree is deleted. In particular, any changes in
3124/// branch addresses in this tree are forwarded to the
3125/// clone trees, unless a branch in a clone tree has had
3126/// its address changed, in which case that change stays in
3127/// effect. When this tree is deleted, all the addresses of
3128/// the cloned tree are reset to their default values.
3129///
3130/// If 'option' contains the word 'fast' and nentries is -1, the
3131/// cloning will be done without unzipping or unstreaming the baskets
3132/// (i.e., a direct copy of the raw bytes on disk).
3133///
3134/// When 'fast' is specified, 'option' can also contain a sorting
3135/// order for the baskets in the output file.
3136///
3137/// There are currently 3 supported sorting order:
3138///
3139/// - SortBasketsByOffset (the default)
3140/// - SortBasketsByBranch
3141/// - SortBasketsByEntry
3142///
3143/// When using SortBasketsByOffset the baskets are written in the
3144/// output file in the same order as in the original file (i.e. the
3145/// baskets are sorted by their offset in the original file; Usually
3146/// this also means that the baskets are sorted by the index/number of
3147/// the _last_ entry they contain)
3148///
3149/// When using SortBasketsByBranch all the baskets of each individual
3150/// branches are stored contiguously. This tends to optimize reading
3151/// speed when reading a small number (1->5) of branches, since all
3152/// their baskets will be clustered together instead of being spread
3153/// across the file. However it might decrease the performance when
3154/// reading more branches (or the full entry).
3155///
3156/// When using SortBasketsByEntry the baskets with the lowest starting
3157/// entry are written first. (i.e. the baskets are sorted by the
3158/// index/number of the first entry they contain). This means that on
3159/// the file the baskets will be in the order in which they will be
3160/// needed when reading the whole tree sequentially.
3161///
3162/// For examples of CloneTree, see tutorials:
3163///
3164/// - copytree.C:
3165/// A macro to copy a subset of a TTree to a new TTree.
3166/// The input file has been generated by the program in
3167/// $ROOTSYS/test/Event with: Event 1000 1 1 1
3168///
3169/// - copytree2.C:
3170/// A macro to copy a subset of a TTree to a new TTree.
3171/// One branch of the new Tree is written to a separate file.
3172/// The input file has been generated by the program in
3173/// $ROOTSYS/test/Event with: Event 1000 1 1 1
3175TTree* TTree::CloneTree(Long64_t nentries /* = -1 */, Option_t* option /* = "" */)
3176{
3177 // Options
3178 bool fastClone = false;
3179
3180 TString opt = option;
3181 opt.ToLower();
3182 if (opt.Contains("fast")) {
3183 fastClone = true;
3184 }
3185
3186 // If we are a chain, switch to the first tree.
3187 if (fEntries > 0) {
3188 const auto res = LoadTree(0);
3189 if (res < -2 || res == -1) {
3190 // -1 is not accepted, it happens when no trees were defined
3191 // -2 is the only acceptable error, when the chain has zero entries, but tree(s) were defined
3192 // Other errors (-3, ...) are not accepted
3193 Error("CloneTree", "returning nullptr since LoadTree failed with code %lld.", res);
3194 return nullptr;
3195 }
3196 }
3197
3198 // Note: For a tree we get the this pointer, for
3199 // a chain we get the chain's current tree.
3200 TTree* thistree = GetTree();
3201
3202 // We will use this to override the IO features on the cloned branches.
3203 ROOT::TIOFeatures features = this->GetIOFeatures();
3204 ;
3205
3206 // Note: For a chain, the returned clone will be
3207 // a clone of the chain's first tree.
3208 TTree* newtree = (TTree*) thistree->Clone();
3209 if (!newtree) {
3210 return nullptr;
3211 }
3212
3213 // The clone should not delete any objects allocated by SetAddress().
3214 TObjArray* branches = newtree->GetListOfBranches();
3215 Int_t nb = branches->GetEntriesFast();
3216 for (Int_t i = 0; i < nb; ++i) {
3217 TBranch* br = (TBranch*) branches->UncheckedAt(i);
3219 ((TBranchElement*) br)->ResetDeleteObject();
3220 }
3221 }
3222
3223 // Add the new tree to the list of clones so that
3224 // we can later inform it of changes to branch addresses.
3225 thistree->AddClone(newtree);
3226 if (thistree != this) {
3227 // In case this object is a TChain, add the clone
3228 // also to the TChain's list of clones.
3229 AddClone(newtree);
3230 }
3231
3232 newtree->Reset();
3233
3234 TDirectory* ndir = newtree->GetDirectory();
3235 TFile* nfile = nullptr;
3236 if (ndir) {
3237 nfile = ndir->GetFile();
3238 }
3239 Int_t newcomp = -1;
3240 if (nfile) {
3241 newcomp = nfile->GetCompressionSettings();
3242 }
3243
3244 //
3245 // Delete non-active branches from the clone.
3246 //
3247 // Note: If we are a chain, this does nothing
3248 // since chains have no leaves.
3249 TObjArray* leaves = newtree->GetListOfLeaves();
3250 Int_t nleaves = leaves->GetEntriesFast();
3251 for (Int_t lndx = 0; lndx < nleaves; ++lndx) {
3252 TLeaf* leaf = (TLeaf*) leaves->UncheckedAt(lndx);
3253 if (!leaf) {
3254 continue;
3255 }
3256 TBranch* branch = leaf->GetBranch();
3257 if (branch && (newcomp > -1)) {
3258 branch->SetCompressionSettings(newcomp);
3259 }
3260 if (branch) branch->SetIOFeatures(features);
3261 if (!branch || !branch->TestBit(kDoNotProcess)) {
3262 continue;
3263 }
3264 // size might change at each iteration of the loop over the leaves.
3265 nb = branches->GetEntriesFast();
3266 for (Long64_t i = 0; i < nb; ++i) {
3267 TBranch* br = (TBranch*) branches->UncheckedAt(i);
3268 if (br == branch) {
3269 branches->RemoveAt(i);
3270 delete br;
3271 br = nullptr;
3272 branches->Compress();
3273 break;
3274 }
3275 TObjArray* lb = br->GetListOfBranches();
3276 Int_t nb1 = lb->GetEntriesFast();
3277 for (Int_t j = 0; j < nb1; ++j) {
3278 TBranch* b1 = (TBranch*) lb->UncheckedAt(j);
3279 if (!b1) {
3280 continue;
3281 }
3282 if (b1 == branch) {
3283 lb->RemoveAt(j);
3284 delete b1;
3285 b1 = nullptr;
3286 lb->Compress();
3287 break;
3288 }
3289 TObjArray* lb1 = b1->GetListOfBranches();
3290 Int_t nb2 = lb1->GetEntriesFast();
3291 for (Int_t k = 0; k < nb2; ++k) {
3292 TBranch* b2 = (TBranch*) lb1->UncheckedAt(k);
3293 if (!b2) {
3294 continue;
3295 }
3296 if (b2 == branch) {
3297 lb1->RemoveAt(k);
3298 delete b2;
3299 b2 = nullptr;
3300 lb1->Compress();
3301 break;
3302 }
3303 }
3304 }
3305 }
3306 }
3307 leaves->Compress();
3308
3309 // Copy MakeClass status.
3310 newtree->SetMakeClass(fMakeClass);
3311
3312 // Copy branch addresses.
3313 CopyAddresses(newtree);
3314
3315 //
3316 // Copy entries if requested.
3317 //
3318
3319 if (nentries != 0) {
3320 if (fastClone && (nentries < 0)) {
3321 if ( newtree->CopyEntries( this, -1, option, false ) < 0 ) {
3322 // There was a problem!
3323 Error("CloneTTree", "TTree has not been cloned\n");
3324 delete newtree;
3325 newtree = nullptr;
3326 return nullptr;
3327 }
3328 } else {
3329 newtree->CopyEntries( this, nentries, option, false );
3330 }
3331 }
3332
3333 return newtree;
3334}
3335
3336////////////////////////////////////////////////////////////////////////////////
3337/// Set branch addresses of passed tree equal to ours.
3338/// If undo is true, reset the branch addresses instead of copying them.
3339/// This ensures 'separation' of a cloned tree from its original.
3341void TTree::CopyAddresses(TTree* tree, bool undo)
3342{
3343 // Copy branch addresses starting from branches.
3344 TObjArray* branches = GetListOfBranches();
3345 Int_t nbranches = branches->GetEntriesFast();
3346 for (Int_t i = 0; i < nbranches; ++i) {
3347 TBranch* branch = (TBranch*) branches->UncheckedAt(i);
3348 if (branch->TestBit(kDoNotProcess)) {
3349 continue;
3350 }
3351 if (undo) {
3352 TBranch* br = tree->GetBranch(branch->GetName());
3353 tree->ResetBranchAddress(br);
3354 } else {
3355 char* addr = branch->GetAddress();
3356 if (!addr) {
3357 if (branch->IsA() == TBranch::Class()) {
3358 // If the branch was created using a leaflist, the branch itself may not have
3359 // an address but the leaf might already.
3360 TLeaf *firstleaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
3361 if (!firstleaf || firstleaf->GetValuePointer()) {
3362 // Either there is no leaf (and thus no point in copying the address)
3363 // or the leaf has an address but we can not copy it via the branche
3364 // this will be copied via the next loop (over the leaf).
3365 continue;
3366 }
3367 }
3368 // Note: This may cause an object to be allocated.
3369 branch->SetAddress(nullptr);
3370 addr = branch->GetAddress();
3371 }
3372 TBranch* br = tree->GetBranch(branch->GetFullName());
3373 if (br) {
3374 if (br->GetMakeClass() != branch->GetMakeClass())
3375 br->SetMakeClass(branch->GetMakeClass());
3376 br->SetAddress(addr);
3377 // The copy does not own any object allocated by SetAddress().
3379 ((TBranchElement*) br)->ResetDeleteObject();
3380 }
3381 } else {
3382 Warning("CopyAddresses", "Could not find branch named '%s' in tree named '%s'", branch->GetName(), tree->GetName());
3383 }
3384 }
3385 }
3386
3387 // Copy branch addresses starting from leaves.
3388 TObjArray* tleaves = tree->GetListOfLeaves();
3389 Int_t ntleaves = tleaves->GetEntriesFast();
3390 std::set<TLeaf*> updatedLeafCount;
3391 for (Int_t i = 0; i < ntleaves; ++i) {
3392 TLeaf* tleaf = (TLeaf*) tleaves->UncheckedAt(i);
3393 TBranch* tbranch = tleaf->GetBranch();
3394 TBranch* branch = GetBranch(tbranch->GetName());
3395 if (!branch) {
3396 continue;
3397 }
3398 TLeaf* leaf = branch->GetLeaf(tleaf->GetName());
3399 if (!leaf) {
3400 continue;
3401 }
3402 if (branch->TestBit(kDoNotProcess)) {
3403 continue;
3404 }
3405 if (undo) {
3406 // Now we know whether the address has been transferred
3407 tree->ResetBranchAddress(tbranch);
3408 } else {
3409 TBranchElement *mother = dynamic_cast<TBranchElement*>(leaf->GetBranch()->GetMother());
3410 bool needAddressReset = false;
3411 if (leaf->GetLeafCount() && (leaf->TestBit(TLeaf::kNewValue) || !leaf->GetValuePointer() || (mother && mother->IsObjectOwner())) && tleaf->GetLeafCount())
3412 {
3413 // If it is an array and it was allocated by the leaf itself,
3414 // let's make sure it is large enough for the incoming data.
3415 if (leaf->GetLeafCount()->GetMaximum() < tleaf->GetLeafCount()->GetMaximum()) {
3416 leaf->GetLeafCount()->IncludeRange( tleaf->GetLeafCount() );
3417 updatedLeafCount.insert(leaf->GetLeafCount());
3418 needAddressReset = true;
3419 } else {
3420 needAddressReset = (updatedLeafCount.find(leaf->GetLeafCount()) != updatedLeafCount.end());
3421 }
3422 }
3423 if (needAddressReset && leaf->GetValuePointer()) {
3424 if (leaf->IsA() == TLeafElement::Class() && mother)
3425 mother->ResetAddress();
3426 else
3427 leaf->SetAddress(nullptr);
3428 }
3429 if (!branch->GetAddress() && !leaf->GetValuePointer()) {
3430 // We should attempts to set the address of the branch.
3431 // something like:
3432 //(TBranchElement*)branch->GetMother()->SetAddress(0)
3433 //plus a few more subtleties (see TBranchElement::GetEntry).
3434 //but for now we go the simplest route:
3435 //
3436 // Note: This may result in the allocation of an object.
3437 branch->SetupAddresses();
3438 }
3439 if (branch->GetAddress()) {
3440 tree->SetBranchAddress(branch->GetName(), (void*) branch->GetAddress());
3441 TBranch* br = tree->GetBranch(branch->GetName());
3442 if (br) {
3443 if (br->IsA() != branch->IsA()) {
3444 Error(
3445 "CopyAddresses",
3446 "Branch kind mismatch between input tree '%s' and output tree '%s' for branch '%s': '%s' vs '%s'",
3447 tree->GetName(), br->GetTree()->GetName(), br->GetName(), branch->IsA()->GetName(),
3448 br->IsA()->GetName());
3449 }
3450 // The copy does not own any object allocated by SetAddress().
3451 // FIXME: We do too much here, br may not be a top-level branch.
3453 ((TBranchElement*) br)->ResetDeleteObject();
3454 }
3455 } else {
3456 Warning("CopyAddresses", "Could not find branch named '%s' in tree named '%s'", branch->GetName(), tree->GetName());
3457 }
3458 } else {
3459 tleaf->SetAddress(leaf->GetValuePointer());
3460 }
3461 }
3462 }
3463
3464 if (undo &&
3465 ( tree->IsA()->InheritsFrom("TNtuple") || tree->IsA()->InheritsFrom("TNtupleD") )
3466 ) {
3467 tree->ResetBranchAddresses();
3468 }
3469}
3470
3471namespace {
3472
3473 enum EOnIndexError { kDrop, kKeep, kBuild };
3474
3475 bool R__HandleIndex(EOnIndexError onIndexError, TTree *newtree, TTree *oldtree)
3476 {
3477 // Return true if we should continue to handle indices, false otherwise.
3478
3479 bool withIndex = true;
3480
3481 if ( newtree->GetTreeIndex() ) {
3482 if ( oldtree->GetTree()->GetTreeIndex() == nullptr ) {
3483 switch (onIndexError) {
3484 case kDrop:
3485 delete newtree->GetTreeIndex();
3486 newtree->SetTreeIndex(nullptr);
3487 withIndex = false;
3488 break;
3489 case kKeep:
3490 // Nothing to do really.
3491 break;
3492 case kBuild:
3493 // Build the index then copy it
3494 if (oldtree->GetTree()->BuildIndex(newtree->GetTreeIndex()->GetMajorName(), newtree->GetTreeIndex()->GetMinorName())) {
3495 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3496 // Clean up
3497 delete oldtree->GetTree()->GetTreeIndex();
3498 oldtree->GetTree()->SetTreeIndex(nullptr);
3499 }
3500 break;
3501 }
3502 } else {
3503 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3504 }
3505 } else if ( oldtree->GetTree()->GetTreeIndex() != nullptr ) {
3506 // We discover the first index in the middle of the chain.
3507 switch (onIndexError) {
3508 case kDrop:
3509 // Nothing to do really.
3510 break;
3511 case kKeep: {
3513 index->SetTree(newtree);
3514 newtree->SetTreeIndex(index);
3515 break;
3516 }
3517 case kBuild:
3518 if (newtree->GetEntries() == 0) {
3519 // Start an index.
3521 index->SetTree(newtree);
3522 newtree->SetTreeIndex(index);
3523 } else {
3524 // Build the index so far.
3525 if (newtree->BuildIndex(oldtree->GetTree()->GetTreeIndex()->GetMajorName(), oldtree->GetTree()->GetTreeIndex()->GetMinorName())) {
3526 newtree->GetTreeIndex()->Append(oldtree->GetTree()->GetTreeIndex(), true);
3527 }
3528 }
3529 break;
3530 }
3531 } else if ( onIndexError == kDrop ) {
3532 // There is no index on this or on tree->GetTree(), we know we have to ignore any further
3533 // index
3534 withIndex = false;
3535 }
3536 return withIndex;
3537 }
3538}
3539
3540////////////////////////////////////////////////////////////////////////////////
3541/// Copy nentries from given tree to this tree.
3542/// This routines assumes that the branches that intended to be copied are
3543/// already connected. The typical case is that this tree was created using
3544/// tree->CloneTree(0).
3545///
3546/// By default copy all entries.
3547///
3548/// Returns number of bytes copied to this tree.
3549///
3550/// If 'option' contains the word 'fast' and nentries is -1, the cloning will be
3551/// done without unzipping or unstreaming the baskets (i.e., a direct copy of the
3552/// raw bytes on disk).
3553///
3554/// When 'fast' is specified, 'option' can also contains a sorting order for the
3555/// baskets in the output file.
3556///
3557/// There are currently 3 supported sorting order:
3558///
3559/// - SortBasketsByOffset (the default)
3560/// - SortBasketsByBranch
3561/// - SortBasketsByEntry
3562///
3563/// See TTree::CloneTree for a detailed explanation of the semantics of these 3 options.
3564///
3565/// If the tree or any of the underlying tree of the chain has an index, that index and any
3566/// index in the subsequent underlying TTree objects will be merged.
3567///
3568/// There are currently three 'options' to control this merging:
3569/// - NoIndex : all the TTreeIndex object are dropped.
3570/// - DropIndexOnError : if any of the underlying TTree object do no have a TTreeIndex,
3571/// they are all dropped.
3572/// - AsIsIndexOnError [default]: In case of missing TTreeIndex, the resulting TTree index has gaps.
3573/// - BuildIndexOnError : If any of the underlying TTree objects do not have a TTreeIndex,
3574/// all TTreeIndex are 'ignored' and the missing piece are rebuilt.
3576Long64_t TTree::CopyEntries(TTree* tree, Long64_t nentries /* = -1 */, Option_t* option /* = "" */, bool needCopyAddresses /* = false */)
3577{
3578 if (!tree) {
3579 return 0;
3580 }
3581 // Options
3582 TString opt = option;
3583 opt.ToLower();
3584 bool fastClone = opt.Contains("fast");
3585 bool withIndex = !opt.Contains("noindex");
3586 EOnIndexError onIndexError;
3587 if (opt.Contains("asisindex")) {
3588 onIndexError = kKeep;
3589 } else if (opt.Contains("buildindex")) {
3590 onIndexError = kBuild;
3591 } else if (opt.Contains("dropindex")) {
3592 onIndexError = kDrop;
3593 } else {
3594 onIndexError = kBuild;
3595 }
3596 Ssiz_t cacheSizeLoc = opt.Index("cachesize=");
3597 Long64_t cacheSize = -1;
3598 if (cacheSizeLoc != TString::kNPOS) {
3599 // If the parse faile, cacheSize stays at -1.
3600 Ssiz_t cacheSizeEnd = opt.Index(" ",cacheSizeLoc+10) - (cacheSizeLoc+10);
3601 TSubString cacheSizeStr( opt(cacheSizeLoc+10,cacheSizeEnd) );
3602 auto parseResult = ROOT::FromHumanReadableSize(cacheSizeStr,cacheSize);
3603 if (parseResult == ROOT::EFromHumanReadableSize::kParseFail) {
3604 Warning("CopyEntries","The cachesize option can not be parsed: %s. The default size will be used.",cacheSizeStr.String().Data());
3605 } else if (parseResult == ROOT::EFromHumanReadableSize::kOverflow) {
3606 double m;
3607 const char *munit = nullptr;
3608 ROOT::ToHumanReadableSize(std::numeric_limits<decltype(cacheSize)>::max(),false,&m,&munit);
3609
3610 Warning("CopyEntries","The cachesize option is too large: %s (%g%s max). The default size will be used.",cacheSizeStr.String().Data(),m,munit);
3611 }
3612 }
3613 if (gDebug > 0 && cacheSize != -1) Info("CopyEntries","Using Cache size: %lld\n",cacheSize);
3614
3615 Long64_t nbytes = 0;
3616 Long64_t treeEntries = tree->GetEntriesFast();
3617 if (nentries < 0) {
3618 nentries = treeEntries;
3619 } else if (nentries > treeEntries) {
3620 nentries = treeEntries;
3621 }
3622
3623 if (fastClone && (nentries < 0 || nentries == tree->GetEntriesFast())) {
3624 // Quickly copy the basket without decompression and streaming.
3625 Long64_t totbytes = GetTotBytes();
3626 for (Long64_t i = 0; i < nentries; i += tree->GetTree()->GetEntries()) {
3627 if (tree->LoadTree(i) < 0) {
3628 break;
3629 }
3630 if ( withIndex ) {
3631 withIndex = R__HandleIndex( onIndexError, this, tree );
3632 }
3633 if (this->GetDirectory()) {
3634 TFile* file2 = this->GetDirectory()->GetFile();
3635 if (file2 && (file2->GetEND() > TTree::GetMaxTreeSize())) {
3636 if (this->GetDirectory() == (TDirectory*) file2) {
3637 this->ChangeFile(file2);
3638 }
3639 }
3640 }
3641 TTreeCloner cloner(tree->GetTree(), this, option, TTreeCloner::kNoWarnings);
3642 if (cloner.IsValid()) {
3643 this->SetEntries(this->GetEntries() + tree->GetTree()->GetEntries());
3644 if (cacheSize != -1) cloner.SetCacheSize(cacheSize);
3645 cloner.Exec();
3646 } else {
3647 if (i == 0) {
3648 Warning("CopyEntries","%s",cloner.GetWarning());
3649 // If the first cloning does not work, something is really wrong
3650 // (since apriori the source and target are exactly the same structure!)
3651 return -1;
3652 } else {
3653 if (cloner.NeedConversion()) {
3654 TTree *localtree = tree->GetTree();
3655 Long64_t tentries = localtree->GetEntries();
3656 if (needCopyAddresses) {
3657 // Copy MakeClass status.
3658 tree->SetMakeClass(fMakeClass);
3659 // Copy branch addresses.
3660 CopyAddresses(tree);
3661 }
3662 for (Long64_t ii = 0; ii < tentries; ii++) {
3663 if (localtree->GetEntry(ii) <= 0) {
3664 break;
3665 }
3666 this->Fill();
3667 }
3668 if (needCopyAddresses)
3669 tree->ResetBranchAddresses();
3670 if (this->GetTreeIndex()) {
3671 this->GetTreeIndex()->Append(tree->GetTree()->GetTreeIndex(), true);
3672 }
3673 } else {
3674 Warning("CopyEntries","%s",cloner.GetWarning());
3675 if (tree->GetDirectory() && tree->GetDirectory()->GetFile()) {
3676 Warning("CopyEntries", "Skipped file %s\n", tree->GetDirectory()->GetFile()->GetName());
3677 } else {
3678 Warning("CopyEntries", "Skipped file number %d\n", tree->GetTreeNumber());
3679 }
3680 }
3681 }
3682 }
3683
3684 }
3685 if (this->GetTreeIndex()) {
3686 this->GetTreeIndex()->Append(nullptr,false); // Force the sorting
3687 }
3688 nbytes = GetTotBytes() - totbytes;
3689 } else {
3690 if (nentries < 0) {
3691 nentries = treeEntries;
3692 } else if (nentries > treeEntries) {
3693 nentries = treeEntries;
3694 }
3695 if (needCopyAddresses) {
3696 // Copy MakeClass status.
3697 tree->SetMakeClass(fMakeClass);
3698 // Copy branch addresses.
3699 CopyAddresses(tree);
3700 }
3701 Int_t treenumber = -1;
3702 for (Long64_t i = 0; i < nentries; i++) {
3703 if (tree->LoadTree(i) < 0) {
3704 break;
3705 }
3706 if (treenumber != tree->GetTreeNumber()) {
3707 if ( withIndex ) {
3708 withIndex = R__HandleIndex( onIndexError, this, tree );
3709 }
3710 treenumber = tree->GetTreeNumber();
3711 }
3712 if (tree->GetEntry(i) <= 0) {
3713 break;
3714 }
3715 nbytes += this->Fill();
3716 }
3717 if (needCopyAddresses)
3718 tree->ResetBranchAddresses();
3719 if (this->GetTreeIndex()) {
3720 this->GetTreeIndex()->Append(nullptr,false); // Force the sorting
3721 }
3722 }
3723 return nbytes;
3724}
3725
3726////////////////////////////////////////////////////////////////////////////////
3727/// Copy a tree with selection.
3728///
3729/// ### Important:
3730///
3731/// The returned copied tree stays connected with the original tree
3732/// until the original tree is deleted. In particular, any changes
3733/// to the branch addresses in the original tree are also made to
3734/// the copied tree. Any changes made to the branch addresses of the
3735/// copied tree are overridden anytime the original tree changes its
3736/// branch addresses. When the original tree is deleted, all the
3737/// branch addresses of the copied tree are set to zero.
3738///
3739/// For examples of CopyTree, see the tutorials:
3740///
3741/// - copytree.C:
3742/// Example macro to copy a subset of a tree to a new tree.
3743/// The input file was generated by running the program in
3744/// $ROOTSYS/test/Event in this way:
3745/// ~~~ {.cpp}
3746/// ./Event 1000 1 1 1
3747/// ~~~
3748/// - copytree2.C
3749/// Example macro to copy a subset of a tree to a new tree.
3750/// One branch of the new tree is written to a separate file.
3751/// The input file was generated by running the program in
3752/// $ROOTSYS/test/Event in this way:
3753/// ~~~ {.cpp}
3754/// ./Event 1000 1 1 1
3755/// ~~~
3756/// - copytree3.C
3757/// Example macro to copy a subset of a tree to a new tree.
3758/// Only selected entries are copied to the new tree.
3759/// NOTE that only the active branches are copied.
3761TTree* TTree::CopyTree(const char* selection, Option_t* option /* = 0 */, Long64_t nentries /* = TTree::kMaxEntries */, Long64_t firstentry /* = 0 */)
3762{
3763 GetPlayer();
3764 if (fPlayer) {
3765 return fPlayer->CopyTree(selection, option, nentries, firstentry);
3766 }
3767 return nullptr;
3768}
3769
3770////////////////////////////////////////////////////////////////////////////////
3771/// Create a basket for this tree and given branch.
3774{
3775 if (!branch) {
3776 return nullptr;
3777 }
3778 return new TBasket(branch->GetName(), GetName(), branch);
3779}
3780
3781////////////////////////////////////////////////////////////////////////////////
3782/// Delete this tree from memory or/and disk.
3783///
3784/// - if option == "all" delete Tree object from memory AND from disk
3785/// all baskets on disk are deleted. All keys with same name
3786/// are deleted.
3787/// - if option =="" only Tree object in memory is deleted.
3789void TTree::Delete(Option_t* option /* = "" */)
3790{
3791 TFile *file = GetCurrentFile();
3792
3793 // delete all baskets and header from file
3794 if (file && option && !strcmp(option,"all")) {
3795 if (!file->IsWritable()) {
3796 Error("Delete","File : %s is not writable, cannot delete Tree:%s", file->GetName(),GetName());
3797 return;
3798 }
3799
3800 //find key and import Tree header in memory
3801 TKey *key = fDirectory->GetKey(GetName());
3802 if (!key) return;
3803
3804 TDirectory *dirsav = gDirectory;
3805 file->cd();
3806
3807 //get list of leaves and loop on all the branches baskets
3808 TIter next(GetListOfLeaves());
3809 TLeaf *leaf;
3810 char header[16];
3811 Int_t ntot = 0;
3812 Int_t nbask = 0;
3813 Int_t nbytes,objlen,keylen;
3814 while ((leaf = (TLeaf*)next())) {
3815 TBranch *branch = leaf->GetBranch();
3816 Int_t nbaskets = branch->GetMaxBaskets();
3817 for (Int_t i=0;i<nbaskets;i++) {
3818 Long64_t pos = branch->GetBasketSeek(i);
3819 if (!pos) continue;
3820 TFile *branchFile = branch->GetFile();
3821 if (!branchFile) continue;
3822 branchFile->GetRecordHeader(header,pos,16,nbytes,objlen,keylen);
3823 if (nbytes <= 0) continue;
3824 branchFile->MakeFree(pos,pos+nbytes-1);
3825 ntot += nbytes;
3826 nbask++;
3827 }
3828 }
3829
3830 // delete Tree header key and all keys with the same name
3831 // A Tree may have been saved many times. Previous cycles are invalid.
3832 while (key) {
3833 ntot += key->GetNbytes();
3834 key->Delete();
3835 delete key;
3836 key = fDirectory->GetKey(GetName());
3837 }
3838 if (dirsav) dirsav->cd();
3839 if (gDebug) Info("TTree::Delete", "Deleting Tree: %s: %d baskets deleted. Total space freed = %d bytes\n",GetName(),nbask,ntot);
3840 }
3841
3842 if (fDirectory) {
3843 fDirectory->Remove(this);
3844 //delete the file cache if it points to this Tree
3845 MoveReadCache(file,nullptr);
3846 fDirectory = nullptr;
3848 }
3849
3850 // Delete object from Cling symbol table so it can not be used anymore.
3851 gCling->DeleteGlobal(this);
3852
3853 // Warning: We have intentional invalidated this object while inside a member function!
3854 delete this;
3855}
3856
3857 ///////////////////////////////////////////////////////////////////////////////
3858 /// Called by TKey and TObject::Clone to automatically add us to a directory
3859 /// when we are read from a file.
3862{
3863 if (fDirectory == dir) return;
3864 if (fDirectory) {
3865 fDirectory->Remove(this);
3866 // Delete or move the file cache if it points to this Tree
3867 TFile *file = fDirectory->GetFile();
3868 MoveReadCache(file,dir);
3869 }
3870 fDirectory = dir;
3871 TBranch* b = nullptr;
3872 TIter next(GetListOfBranches());
3873 while((b = (TBranch*) next())) {
3874 b->UpdateFile();
3875 }
3876 if (fBranchRef) {
3878 }
3879 if (fDirectory) fDirectory->Append(this);
3880}
3881
3882////////////////////////////////////////////////////////////////////////////////
3883/// Draw expression varexp for specified entries.
3884///
3885/// \return -1 in case of error or number of selected events in case of success.
3886/// If `selection` involves an array variable `x[n]`, for example `x[] > 0` or
3887/// `x > 0`, then we return the number of selected instances rather than number of events.
3888/// In the output of `tree.Scan()`, instances are shown in individual printed rows, thus
3889/// each event (tree entry) is split across the various instances (lines) of the array.
3890/// In contrast, the function `GetEntries(selection)` always returns the number of entries selected.
3891///
3892/// This function accepts TCut objects as arguments.
3893/// Useful to use the string operator +
3894///
3895/// Example:
3896///
3897/// ~~~ {.cpp}
3898/// ntuple.Draw("x",cut1+cut2+cut3);
3899/// ~~~
3900
3902Long64_t TTree::Draw(const char* varexp, const TCut& selection, Option_t* option, Long64_t nentries, Long64_t firstentry)
3903{
3904 return TTree::Draw(varexp, selection.GetTitle(), option, nentries, firstentry);
3905}
3906
3907/////////////////////////////////////////////////////////////////////////////////////////
3908/// \brief Draw expression varexp for entries and objects that pass a (optional) selection.
3909///
3910/// \return -1 in case of error or number of selected events in case of success.
3911/// If `selection` involves an array variable `x[n]`, for example `x[] > 0` or
3912/// `x > 0`, then we return the number of selected instances rather than number of events.
3913/// In the output of `tree.Scan()`, instances are shown in individual printed rows, thus
3914/// each event (tree entry) is split across the various instances (lines) of the array.
3915/// In contrast, the function `GetEntries(selection)` always returns the number of entries selected.
3916///
3917/// \param [in] varexp
3918/// \parblock
3919/// A string that takes one of these general forms:
3920/// - "e1" produces a 1-d histogram (TH1F) of expression "e1"
3921/// - "e1:e2" produces an unbinned 2-d scatter-plot (TGraph) of "e1"
3922/// on the y-axis versus "e2" on the x-axis
3923/// - "e1:e2:e3" produces an unbinned 3-d scatter-plot (TPolyMarker3D) of "e1"
3924/// vs "e2" vs "e3" on the z-, y-, x-axis, respectively
3925/// - "e1:e2:e3:e4" produces an unbinned 3-d scatter-plot (TPolyMarker3D) of "e1"
3926/// vs "e2" vs "e3" and "e4" mapped on the current color palette.
3927/// (to create histograms in the 2, 3, and 4 dimensional case,
3928/// see section "Saving the result of Draw to an histogram")
3929/// - "e1:e2:e3:e4:e5" with option "GL5D" produces a 5D plot using OpenGL. `gStyle->SetCanvasPreferGL(true)` is
3930/// 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
3970/// example, for each event here we perform a simple object selection:
3971/// ~~~{.cpp}
3972/// // Muon_pt is an array: fill a histogram with the array elements > 100 in each event
3973/// tree->Draw('Muon_pt', 'Muon_pt > 100')
3974/// ~~~
3975/// \endparblock
3976/// \param [in] option
3977/// \parblock
3978/// The drawing option.
3979/// - When an histogram is produced it can be any histogram drawing option
3980/// listed in THistPainter.
3981/// - when no option is specified:
3982/// - the default histogram drawing option is used
3983/// if the expression is of the form "e1".
3984/// - if the expression is of the form "e1:e2"or "e1:e2:e3" a cloud of
3985/// unbinned 2D or 3D points is drawn respectively.
3986/// - if the expression has four fields "e1:e2:e3:e4" a cloud of unbinned 3D
3987/// points is produced with e1 vs e2 vs e3, and e4 is mapped on the current color
3988/// palette.
3989/// - If option COL is specified when varexp has three fields:
3990/// ~~~ {.cpp}
3991/// tree.Draw("e1:e2:e3","","col");
3992/// ~~~
3993/// a 2D scatter is produced with e1 vs e2, and e3 is mapped on the current
3994/// color palette. The colors for e3 are evaluated once in linear scale before
3995/// painting. Therefore changing the pad to log scale along Z as no effect
3996/// on the colors.
3997/// - if expression has more than four fields the option "PARA"or "CANDLE"
3998/// can be used.
3999/// - If option contains the string "goff", no graphics is generated.
4000/// \endparblock
4001/// \param [in] nentries The number of entries to process (default is all)
4002/// \param [in] firstentry The first entry to process (default is 0)
4003///
4004/// ### Drawing expressions using arrays and array elements
4005///
4006/// Let assumes, a leaf fMatrix, on the branch fEvent, which is a 3 by 3 array,
4007/// or a TClonesArray.
4008/// In a TTree::Draw expression you can now access fMatrix using the following
4009/// syntaxes:
4010///
4011/// | String passed | What is used for each entry of the tree
4012/// |-----------------|--------------------------------------------------------|
4013/// | `fMatrix` | the 9 elements of fMatrix |
4014/// | `fMatrix[][]` | the 9 elements of fMatrix |
4015/// | `fMatrix[2][2]` | only the elements fMatrix[2][2] |
4016/// | `fMatrix[1]` | the 3 elements fMatrix[1][0], fMatrix[1][1] and fMatrix[1][2] |
4017/// | `fMatrix[1][]` | the 3 elements fMatrix[1][0], fMatrix[1][1] and fMatrix[1][2] |
4018/// | `fMatrix[][0]` | the 3 elements fMatrix[0][0], fMatrix[1][0] and fMatrix[2][0] |
4019///
4020/// "fEvent.fMatrix...." same as "fMatrix..." (unless there is more than one leaf named fMatrix!).
4021///
4022/// In summary, if a specific index is not specified for a dimension, TTree::Draw
4023/// will loop through all the indices along this dimension. Leaving off the
4024/// last (right most) dimension of specifying then with the two characters '[]'
4025/// is equivalent. For variable size arrays (and TClonesArray) the range
4026/// of the first dimension is recalculated for each entry of the tree.
4027/// You can also specify the index as an expression of any other variables from the
4028/// tree.
4029///
4030/// TTree::Draw also now properly handling operations involving 2 or more arrays.
4031///
4032/// Let assume a second matrix fResults[5][2], here are a sample of some
4033/// of the possible combinations, the number of elements they produce and
4034/// the loop used:
4035///
4036/// | expression | element(s) | Loop |
4037/// |----------------------------------|------------|--------------------------|
4038/// | `fMatrix[2][1] - fResults[5][2]` | one | no loop |
4039/// | `fMatrix[2][] - fResults[5][2]` | three | on 2nd dim fMatrix |
4040/// | `fMatrix[2][] - fResults[5][]` | two | on both 2nd dimensions |
4041/// | `fMatrix[][2] - fResults[][1]` | three | on both 1st dimensions |
4042/// | `fMatrix[][2] - fResults[][]` | six | on both 1st and 2nd dimensions of fResults |
4043/// | `fMatrix[][2] - fResults[3][]` | two | on 1st dim of fMatrix and 2nd of fResults (at the same time) |
4044/// | `fMatrix[][] - fResults[][]` | six | on 1st dim then on 2nd dim |
4045/// | `fMatrix[][fResult[][]]` | 30 | on 1st dim of fMatrix then on both dimensions of fResults. The
4046/// value if fResults[j][k] is used as the second index of fMatrix.|
4047///
4048///
4049/// In summary, TTree::Draw loops through all unspecified dimensions. To
4050/// figure out the range of each loop, we match each unspecified dimension
4051/// from left to right (ignoring ALL dimensions for which an index has been
4052/// specified), in the equivalent loop matched dimensions use the same index
4053/// and are restricted to the smallest range (of only the matched dimensions).
4054/// When involving variable arrays, the range can of course be different
4055/// for each entry of the tree.
4056///
4057/// So the loop equivalent to "fMatrix[][2] - fResults[3][]" is:
4058/// ~~~ {.cpp}
4059/// for (Int_t i0; i < min(3,2); i++) {
4060/// use the value of (fMatrix[i0][2] - fMatrix[3][i0])
4061/// }
4062/// ~~~
4063/// So the loop equivalent to "fMatrix[][2] - fResults[][]" is:
4064/// ~~~ {.cpp}
4065/// for (Int_t i0; i < min(3,5); i++) {
4066/// for (Int_t i1; i1 < 2; i1++) {
4067/// use the value of (fMatrix[i0][2] - fMatrix[i0][i1])
4068/// }
4069/// }
4070/// ~~~
4071/// So the loop equivalent to "fMatrix[][] - fResults[][]" is:
4072/// ~~~ {.cpp}
4073/// for (Int_t i0; i < min(3,5); i++) {
4074/// for (Int_t i1; i1 < min(3,2); i1++) {
4075/// use the value of (fMatrix[i0][i1] - fMatrix[i0][i1])
4076/// }
4077/// }
4078/// ~~~
4079/// So the loop equivalent to "fMatrix[][fResults[][]]" is:
4080/// ~~~ {.cpp}
4081/// for (Int_t i0; i0 < 3; i0++) {
4082/// for (Int_t j2; j2 < 5; j2++) {
4083/// for (Int_t j3; j3 < 2; j3++) {
4084/// i1 = fResults[j2][j3];
4085/// use the value of fMatrix[i0][i1]
4086/// }
4087/// }
4088/// ~~~
4089/// ### Retrieving the result of Draw
4090///
4091/// By default a temporary histogram called `htemp` is created. It will be:
4092///
4093/// - A TH1F* in case of a mono-dimensional distribution: `Draw("e1")`,
4094/// - A TH2F* in case of a bi-dimensional distribution: `Draw("e1:e2")`,
4095/// - A TH3F* in case of a three-dimensional distribution: `Draw("e1:e2:e3")`.
4096///
4097/// In the one dimensional case the `htemp` is filled and drawn whatever the drawing
4098/// option is.
4099///
4100/// In the two and three dimensional cases, with the default drawing option (`""`),
4101/// a cloud of points is drawn and the histogram `htemp` is not filled. For all the other
4102/// drawing options `htemp` will be filled.
4103///
4104/// In all cases `htemp` can be retrieved by calling:
4105///
4106/// ~~~ {.cpp}
4107/// auto htemp = (TH1F*)gPad->GetPrimitive("htemp"); // 1D
4108/// auto htemp = (TH2F*)gPad->GetPrimitive("htemp"); // 2D
4109/// auto htemp = (TH3F*)gPad->GetPrimitive("htemp"); // 3D
4110/// ~~~
4111///
4112/// In the two dimensional case (`Draw("e1;e2")`), with the default drawing option, the
4113/// data is filled into a TGraph named `Graph`. This TGraph can be retrieved by
4114/// calling
4115///
4116/// ~~~ {.cpp}
4117/// auto graph = (TGraph*)gPad->GetPrimitive("Graph");
4118/// ~~~
4119///
4120/// For the three and four dimensional cases, with the default drawing option, an unnamed
4121/// TPolyMarker3D is produced, and therefore cannot be retrieved.
4122///
4123/// In all cases `htemp` can be used to access the axes. For instance in the 2D case:
4124///
4125/// ~~~ {.cpp}
4126/// auto htemp = (TH2F*)gPad->GetPrimitive("htemp");
4127/// auto xaxis = htemp->GetXaxis();
4128/// ~~~
4129///
4130/// When the option `"A"` is used (with TGraph painting option) to draw a 2D
4131/// distribution:
4132/// ~~~ {.cpp}
4133/// tree.Draw("e1:e2","","A*");
4134/// ~~~
4135/// a scatter plot is produced (with stars in that case) but the axis creation is
4136/// delegated to TGraph and `htemp` is not created.
4137///
4138/// ### Saving the result of Draw to a histogram
4139///
4140/// If `varexp` contains `>>hnew` (following the variable(s) name(s)),
4141/// the new histogram called `hnew` is created and it is kept in the current
4142/// directory (and also the current pad). This works for all dimensions.
4143///
4144/// Example:
4145/// ~~~ {.cpp}
4146/// tree.Draw("sqrt(x)>>hsqrt","y>0")
4147/// ~~~
4148/// will draw `sqrt(x)` and save the histogram as "hsqrt" in the current
4149/// directory. To retrieve it do:
4150/// ~~~ {.cpp}
4151/// TH1F *hsqrt = (TH1F*)gDirectory->Get("hsqrt");
4152/// ~~~
4153/// The binning information is taken from the environment variables
4154/// ~~~ {.cpp}
4155/// Hist.Binning.?D.?
4156/// ~~~
4157/// In addition, the name of the histogram can be followed by up to 9
4158/// numbers between '(' and ')', where the numbers describe the
4159/// following:
4160///
4161/// - 1 - bins in x-direction
4162/// - 2 - lower limit in x-direction
4163/// - 3 - upper limit in x-direction
4164/// - 4-6 same for y-direction
4165/// - 7-9 same for z-direction
4166///
4167/// When a new binning is used the new value will become the default.
4168/// Values can be skipped.
4169///
4170/// Example:
4171/// ~~~ {.cpp}
4172/// tree.Draw("sqrt(x)>>hsqrt(500,10,20)")
4173/// // plot sqrt(x) between 10 and 20 using 500 bins
4174/// tree.Draw("sqrt(x):sin(y)>>hsqrt(100,10,60,50,.1,.5)")
4175/// // plot sqrt(x) against sin(y)
4176/// // 100 bins in x-direction; lower limit on x-axis is 10; upper limit is 60
4177/// // 50 bins in y-direction; lower limit on y-axis is .1; upper limit is .5
4178/// ~~~
4179/// By default, if a histogram with the same name is already registered to the current
4180/// ROOT directory, the specified histogram is reset. To continue to append data to an
4181/// existing histogram, use "+" in front of the histogram name.
4182///
4183/// A '+' in front of the histogram name is ignored, when the name is followed by
4184/// binning information as described in the previous paragraph.
4185/// ~~~ {.cpp}
4186/// tree.Draw("sqrt(x)>>+hsqrt","y>0")
4187/// ~~~
4188/// will not reset `hsqrt`, but will continue filling. This works for 1-D, 2-D
4189/// and 3-D histograms.
4190///
4191/// Note that when the automatic registration of histograms is off (see \ref DisableObjectAutoRegistration() ),
4192/// external histogram are not visible to TTree::Draw unless they are registered to the current directory explicitly.
4193/// ~~~ {.cpp}
4194/// auto histo = new TH1D("histo", ...);
4195/// histo->SetDirectory(gDirectory);
4196/// tree.Draw("sqrt(x)>>histo","y>0")
4197/// ~~~
4198/// When auto-registration is off, histograms created by TTree::Draw will still be registered to the current directory.
4199///
4200/// ### Accessing collection objects
4201///
4202/// TTree::Draw default's handling of collections is to assume that any
4203/// request on a collection pertain to it content. For example, if fTracks
4204/// is a collection of Track objects, the following:
4205/// ~~~ {.cpp}
4206/// tree->Draw("event.fTracks.fPx");
4207/// ~~~
4208/// will plot the value of fPx for each Track objects inside the collection.
4209/// Also
4210/// ~~~ {.cpp}
4211/// tree->Draw("event.fTracks.size()");
4212/// ~~~
4213/// would plot the result of the member function Track::size() for each
4214/// Track object inside the collection.
4215/// To access information about the collection itself, TTree::Draw support
4216/// the '@' notation. If a variable which points to a collection is prefixed
4217/// or postfixed with '@', the next part of the expression will pertain to
4218/// the collection object. For example:
4219/// ~~~ {.cpp}
4220/// tree->Draw("event.@fTracks.size()");
4221/// ~~~
4222/// will plot the size of the collection referred to by `fTracks` (i.e the number
4223/// of Track objects).
4224///
4225/// ### Drawing 'objects'
4226///
4227/// When a class has a member function named AsDouble or AsString, requesting
4228/// to directly draw the object will imply a call to one of the 2 functions.
4229/// If both AsDouble and AsString are present, AsDouble will be used.
4230/// AsString can return either a char*, a std::string or a TString.s
4231/// For example, the following
4232/// ~~~ {.cpp}
4233/// tree->Draw("event.myTTimeStamp");
4234/// ~~~
4235/// will draw the same histogram as
4236/// ~~~ {.cpp}
4237/// tree->Draw("event.myTTimeStamp.AsDouble()");
4238/// ~~~
4239/// In addition, when the object is a type TString or std::string, TTree::Draw
4240/// will call respectively `TString::Data` and `std::string::c_str()`
4241///
4242/// If the object is a TBits, the histogram will contain the index of the bit
4243/// that are turned on.
4244///
4245/// ### Retrieving information about the tree itself.
4246///
4247/// You can refer to the tree (or chain) containing the data by using the
4248/// string 'This'.
4249/// You can then could any TTree methods. For example:
4250/// ~~~ {.cpp}
4251/// tree->Draw("This->GetReadEntry()");
4252/// ~~~
4253/// will display the local entry numbers be read.
4254/// ~~~ {.cpp}
4255/// tree->Draw("This->GetUserInfo()->At(0)->GetName()");
4256/// ~~~
4257/// will display the name of the first 'user info' object.
4258///
4259/// ### Special functions and variables
4260///
4261/// `Entry$`: A TTree::Draw formula can use the special variable `Entry$`
4262/// to access the entry number being read. For example to draw every
4263/// other entry use:
4264/// ~~~ {.cpp}
4265/// tree.Draw("myvar","Entry$%2==0");
4266/// ~~~
4267/// - `Entry$` : return the current entry number (`== TTree::GetReadEntry()`)
4268/// - `LocalEntry$` : return the current entry number in the current tree of a
4269/// chain (`== GetTree()->GetReadEntry()`)
4270/// - `Entries$` : return the total number of entries (== TTree::GetEntries())
4271/// - `LocalEntries$` : return the total number of entries in the current tree
4272/// of a chain (== GetTree()->TTree::GetEntries())
4273/// - `Length$` : return the total number of element of this formula for this
4274/// entry (`==TTreeFormula::GetNdata()`)
4275/// - `Iteration$` : return the current iteration over this formula for this
4276/// entry (i.e. varies from 0 to `Length$ - 1`).
4277/// - `Length$(formula )` : return the total number of element of the formula
4278/// given as a parameter.
4279/// - `Sum$(formula )` : return the sum of the value of the elements of the
4280/// formula given as a parameter. For example the mean for all the elements in
4281/// one entry can be calculated with: `Sum$(formula )/Length$(formula )`
4282/// - `Min$(formula )` : return the minimum (within one TTree entry) of the value of the
4283/// elements of the formula given as a parameter.
4284/// - `Max$(formula )` : return the maximum (within one TTree entry) of the value of the
4285/// elements of the formula given as a parameter.
4286/// - `MinIf$(formula,condition)`
4287/// - `MaxIf$(formula,condition)` : return the minimum (maximum) (within one TTree entry)
4288/// of the value of the elements of the formula given as a parameter
4289/// if they match the condition. If no element matches the condition,
4290/// the result is zero. To avoid the resulting peak at zero, use the
4291/// pattern:
4292/// ~~~ {.cpp}
4293/// tree->Draw("MinIf$(formula,condition)","condition");
4294/// ~~~
4295/// which will avoid calculation `MinIf$` for the entries that have no match
4296/// for the condition.
4297/// - `Alt$(primary,alternate)` : return the value of "primary" if it is available
4298/// for the current iteration otherwise return the value of "alternate".
4299/// For example, with arr1[3] and arr2[2]
4300/// ~~~ {.cpp}
4301/// tree->Draw("arr1+Alt$(arr2,0)");
4302/// ~~~
4303/// will draw arr1[0]+arr2[0] ; arr1[1]+arr2[1] and arr1[2]+0
4304/// Or with a variable size array arr3
4305/// ~~~ {.cpp}
4306/// tree->Draw("Alt$(arr3[0],0)+Alt$(arr3[1],0)+Alt$(arr3[2],0)");
4307/// ~~~
4308/// will draw the sum arr3 for the index 0 to min(2,actual_size_of_arr3-1)
4309/// As a comparison
4310/// ~~~ {.cpp}
4311/// tree->Draw("arr3[0]+arr3[1]+arr3[2]");
4312/// ~~~
4313/// will draw the sum arr3 for the index 0 to 2 only if the
4314/// actual_size_of_arr3 is greater or equal to 3.
4315/// Note that the array in 'primary' is flattened/linearized thus using
4316/// `Alt$` with multi-dimensional arrays of different dimensions is unlikely
4317/// to yield the expected results. To visualize a bit more what elements
4318/// would be matched by TTree::Draw, TTree::Scan can be used:
4319/// ~~~ {.cpp}
4320/// tree->Scan("arr1:Alt$(arr2,0)");
4321/// ~~~
4322/// will print on one line the value of arr1 and (arr2,0) that will be
4323/// matched by
4324/// ~~~ {.cpp}
4325/// tree->Draw("arr1-Alt$(arr2,0)");
4326/// ~~~
4327/// The ternary operator is not directly supported in TTree::Draw however, to plot the
4328/// equivalent of `var2<20 ? -99 : var1`, you can use:
4329/// ~~~ {.cpp}
4330/// tree->Draw("(var2<20)*99+(var2>=20)*var1","");
4331/// ~~~
4332///
4333/// ### Drawing a user function accessing the TTree data directly
4334///
4335/// If the formula contains a file name, TTree::MakeProxy will be used
4336/// to load and execute this file. In particular it will draw the
4337/// result of a function with the same name as the file. The function
4338/// will be executed in a context where the name of the branches can
4339/// be used as a C++ variable.
4340///
4341/// For example draw px using the file hsimple.root (generated by the
4342/// hsimple.C tutorial), we need a file named hsimple.cxx:
4343/// ~~~ {.cpp}
4344/// double hsimple() {
4345/// return px;
4346/// }
4347/// ~~~
4348/// MakeProxy can then be used indirectly via the TTree::Draw interface
4349/// as follow:
4350/// ~~~ {.cpp}
4351/// new TFile("hsimple.root")
4352/// ntuple->Draw("hsimple.cxx");
4353/// ~~~
4354/// A more complete example is available in the tutorials directory:
4355/// `h1analysisProxy.cxx`, `h1analysProxy.h` and `h1analysisProxyCut.C`
4356/// which reimplement the selector found in `h1analysis.C`
4357///
4358/// The main features of this facility are:
4359///
4360/// * on-demand loading of branches
4361/// * ability to use the 'branchname' as if it was a data member
4362/// * protection against array out-of-bound
4363/// * ability to use the branch data as object (when the user code is available)
4364///
4365/// See TTree::MakeProxy for more details.
4366///
4367/// ### Making a Profile histogram
4368///
4369/// In case of a 2-Dim expression, one can generate a TProfile histogram
4370/// instead of a TH2F histogram by specifying option=prof or option=profs
4371/// or option=profi or option=profg ; the trailing letter select the way
4372/// the bin error are computed, See TProfile2D::SetErrorOption for
4373/// details on the differences.
4374/// The option=prof is automatically selected in case of y:x>>pf
4375/// where pf is an existing TProfile histogram.
4376///
4377/// ### Making a 2D Profile histogram
4378///
4379/// In case of a 3-Dim expression, one can generate a TProfile2D histogram
4380/// instead of a TH3F histogram by specifying option=prof or option=profs.
4381/// or option=profi or option=profg ; the trailing letter select the way
4382/// the bin error are computed, See TProfile2D::SetErrorOption for
4383/// details on the differences.
4384/// The option=prof is automatically selected in case of z:y:x>>pf
4385/// where pf is an existing TProfile2D histogram.
4386///
4387/// ### Making a 5D plot using GL
4388///
4389/// If option GL5D is specified together with 5 variables, a 5D plot is drawn
4390/// using OpenGL. See tree502_staff.C as example.
4391///
4392/// ### Making a parallel coordinates plot
4393///
4394/// In case of a 2-Dim or more expression with the option=para, one can generate
4395/// a parallel coordinates plot. With that option, the number of dimensions is
4396/// arbitrary. Giving more than 4 variables without the option=para or
4397/// option=candle or option=goff will produce an error.
4398///
4399/// ### Making a candle sticks chart
4400///
4401/// In case of a 2-Dim or more expression with the option=candle, one can generate
4402/// a candle sticks chart. With that option, the number of dimensions is
4403/// arbitrary. Giving more than 4 variables without the option=para or
4404/// option=candle or option=goff will produce an error.
4405///
4406/// ### Normalizing the output histogram to 1
4407///
4408/// When option contains "norm" the output histogram is normalized to 1.
4409///
4410/// ### Saving the result of Draw to a TEventList, a TEntryList or a TEntryListArray
4411///
4412/// TTree::Draw can be used to fill a TEventList object (list of entry numbers)
4413/// instead of histogramming one variable.
4414/// If varexp0 has the form >>elist , a TEventList object named "elist"
4415/// is created in the current directory. elist will contain the list
4416/// of entry numbers satisfying the current selection.
4417/// If option "entrylist" is used, a TEntryList object is created
4418/// If the selection contains arrays, vectors or any container class and option
4419/// "entrylistarray" is used, a TEntryListArray object is created
4420/// containing also the subentries satisfying the selection, i.e. the indices of
4421/// the branches which hold containers classes.
4422/// Example:
4423/// ~~~ {.cpp}
4424/// tree.Draw(">>yplus","y>0")
4425/// ~~~
4426/// will create a TEventList object named "yplus" in the current directory.
4427/// In an interactive session, one can type (after TTree::Draw)
4428/// ~~~ {.cpp}
4429/// yplus.Print("all")
4430/// ~~~
4431/// to print the list of entry numbers in the list.
4432/// ~~~ {.cpp}
4433/// tree.Draw(">>yplus", "y>0", "entrylist")
4434/// ~~~
4435/// will create a TEntryList object names "yplus" in the current directory
4436/// ~~~ {.cpp}
4437/// tree.Draw(">>yplus", "y>0", "entrylistarray")
4438/// ~~~
4439/// will create a TEntryListArray object names "yplus" in the current directory
4440///
4441/// By default, the specified entry list is reset.
4442/// To continue to append data to an existing list, use "+" in front
4443/// of the list name;
4444/// ~~~ {.cpp}
4445/// tree.Draw(">>+yplus","y>0")
4446/// ~~~
4447/// will not reset yplus, but will enter the selected entries at the end
4448/// of the existing list.
4449///
4450/// Note that when the automatic registration of event lists is off (see \ref DisableObjectAutoRegistration() ),
4451/// they are not visible to TTree::Draw unless they are registered to the current directory explicitly.
4452/// ~~~ {.cpp}
4453/// auto elist = new TEventList("elist", ...);
4454/// elist->SetDirectory(gDirectory);
4455/// tree.Draw(">>+elist","y>0")
4456/// ~~~
4457///
4458/// ### Using a TEventList, TEntryList or TEntryListArray as Input
4459///
4460/// Once a TEventList or a TEntryList object has been generated, it can be used as input
4461/// for TTree::Draw. Use TTree::SetEventList or TTree::SetEntryList to set the
4462/// current event list
4463///
4464/// Example 1:
4465/// ~~~ {.cpp}
4466/// TEventList *elist = (TEventList*)gDirectory->Get("yplus");
4467/// tree->SetEventList(elist);
4468/// tree->Draw("py");
4469/// ~~~
4470/// Example 2:
4471/// ~~~ {.cpp}
4472/// TEntryList *elist = (TEntryList*)gDirectory->Get("yplus");
4473/// tree->SetEntryList(elist);
4474/// tree->Draw("py");
4475/// ~~~
4476/// If a TEventList object is used as input, a new TEntryList object is created
4477/// inside the SetEventList function. In case of a TChain, all tree headers are loaded
4478/// for this transformation. This new object is owned by the chain and is deleted
4479/// with it, unless the user extracts it by calling GetEntryList() function.
4480/// See also comments to SetEventList() function of TTree and TChain.
4481///
4482/// If arrays are used in the selection criteria and TEntryListArray is not used,
4483/// all the entries that have at least one element of the array that satisfy the selection
4484/// are entered in the list.
4485///
4486/// Example:
4487/// ~~~ {.cpp}
4488/// tree.Draw(">>pyplus","fTracks.fPy>0");
4489/// tree->SetEventList(pyplus);
4490/// tree->Draw("fTracks.fPy");
4491/// ~~~
4492/// will draw the fPy of ALL tracks in event with at least one track with
4493/// a positive fPy.
4494///
4495/// To select only the elements that did match the original selection
4496/// use TEventList::SetReapplyCut or TEntryList::SetReapplyCut.
4497///
4498/// Example:
4499/// ~~~ {.cpp}
4500/// tree.Draw(">>pyplus","fTracks.fPy>0");
4501/// pyplus->SetReapplyCut(true);
4502/// tree->SetEventList(pyplus);
4503/// tree->Draw("fTracks.fPy");
4504/// ~~~
4505/// will draw the fPy of only the tracks that have a positive fPy.
4506///
4507/// To draw only the elements that match a selection in case of arrays,
4508/// you can also use TEntryListArray (faster in case of a more general selection).
4509///
4510/// Example:
4511/// ~~~ {.cpp}
4512/// tree.Draw(">>pyplus","fTracks.fPy>0", "entrylistarray");
4513/// tree->SetEntryList(pyplus);
4514/// tree->Draw("fTracks.fPy");
4515/// ~~~
4516/// will draw the fPy of only the tracks that have a positive fPy,
4517/// but without redoing the selection.
4518///
4519/// Note: Use tree->SetEventList(0) if you do not want use the list as input.
4520///
4521/// ### How to obtain more info from TTree::Draw
4522///
4523/// Once TTree::Draw has been called, it is possible to access useful
4524/// information still stored in the TTree object via the following functions:
4525///
4526/// - GetSelectedRows() // return the number of values accepted by the selection expression. In case where no selection
4527/// was specified, returns the number of values processed.
4528/// - GetV1() // returns a pointer to the double array of V1
4529/// - GetV2() // returns a pointer to the double array of V2
4530/// - GetV3() // returns a pointer to the double array of V3
4531/// - GetV4() // returns a pointer to the double array of V4
4532/// - GetW() // returns a pointer to the double array of Weights where weight equal the result of the
4533/// selection expression.
4534///
4535/// where V1,V2,V3 correspond to the expressions in
4536/// ~~~ {.cpp}
4537/// TTree::Draw("V1:V2:V3:V4",selection);
4538/// ~~~
4539/// If the expression has more than 4 component use GetVal(index)
4540///
4541/// Example:
4542/// ~~~ {.cpp}
4543/// Root > ntuple->Draw("py:px","pz>4");
4544/// Root > TGraph *gr = new TGraph(ntuple->GetSelectedRows(),
4545/// ntuple->GetV2(), ntuple->GetV1());
4546/// Root > gr->Draw("ap"); //draw graph in current pad
4547/// ~~~
4548///
4549/// A more complete complete tutorial (treegetval.C) shows how to use the
4550/// GetVal() method.
4551///
4552/// creates a TGraph object with a number of points corresponding to the
4553/// number of entries selected by the expression "pz>4", the x points of the graph
4554/// being the px values of the Tree and the y points the py values.
4555///
4556/// Important note: By default TTree::Draw creates the arrays obtained
4557/// with GetW, GetV1, GetV2, GetV3, GetV4, GetVal with a length corresponding
4558/// to the parameter fEstimate. The content will be the last `GetSelectedRows() % GetEstimate()`
4559/// values calculated.
4560/// By default fEstimate=1000000 and can be modified
4561/// via TTree::SetEstimate. To keep in memory all the results (in case
4562/// where there is only one result per entry), use
4563/// ~~~ {.cpp}
4564/// tree->SetEstimate(tree->GetEntries()+1); // same as tree->SetEstimate(-1);
4565/// ~~~
4566/// You must call SetEstimate if the expected number of selected rows
4567/// you need to look at is greater than 1000000.
4568///
4569/// You can use the option "goff" to turn off the graphics output
4570/// of TTree::Draw in the above example.
4571///
4572/// ### Automatic interface to TTree::Draw via the TTreeViewer
4573///
4574/// A complete graphical interface to this function is implemented
4575/// in the class TTreeViewer.
4576/// To start the TTreeViewer, three possibilities:
4577/// - select TTree context menu item "StartViewer"
4578/// - type the command "TTreeViewer TV(treeName)"
4579/// - execute statement "tree->StartViewer();"
4581Long64_t TTree::Draw(const char* varexp, const char* selection, Option_t* option, Long64_t nentries, Long64_t firstentry)
4582{
4583 GetPlayer();
4584 if (fPlayer)
4585 return fPlayer->DrawSelect(varexp,selection,option,nentries,firstentry);
4586 return -1;
4587}
4588
4589////////////////////////////////////////////////////////////////////////////////
4590/// Remove some baskets from memory.
4592void TTree::DropBaskets()
4593{
4594 TBranch* branch = nullptr;
4596 for (Int_t i = 0; i < nb; ++i) {
4597 branch = (TBranch*) fBranches.UncheckedAt(i);
4598 branch->DropBaskets("all");
4599 }
4600}
4601
4602////////////////////////////////////////////////////////////////////////////////
4603/// Drop branch buffers to accommodate nbytes below MaxVirtualsize.
4606{
4607 // Be careful not to remove current read/write buffers.
4608 Int_t nleaves = fLeaves.GetEntriesFast();
4609 for (Int_t i = 0; i < nleaves; ++i) {
4610 TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
4611 TBranch* branch = (TBranch*) leaf->GetBranch();
4612 Int_t nbaskets = branch->GetListOfBaskets()->GetEntries();
4613 for (Int_t j = 0; j < nbaskets - 1; ++j) {
4614 if ((j == branch->GetReadBasket()) || (j == branch->GetWriteBasket())) {
4615 continue;
4616 }
4617 TBasket* basket = (TBasket*)branch->GetListOfBaskets()->UncheckedAt(j);
4618 if (basket) {
4619 basket->DropBuffers();
4621 return;
4622 }
4623 }
4624 }
4625 }
4626}
4627
4628////////////////////////////////////////////////////////////////////////////////
4629/// Fill all branches.
4630///
4631/// This function loops on all the branches of this tree. For
4632/// each branch, it copies to the branch buffer (basket) the current
4633/// values of the leaves data types. If a leaf is a simple data type,
4634/// a simple conversion to a machine independent format has to be done.
4635///
4636/// This machine independent version of the data is copied into a
4637/// basket (each branch has its own basket). When a basket is full
4638/// (32k worth of data by default), it is then optionally compressed
4639/// and written to disk (this operation is also called committing or
4640/// 'flushing' the basket). The committed baskets are then
4641/// immediately removed from memory.
4642///
4643/// The function returns the number of bytes committed to the
4644/// individual branches.
4645///
4646/// If a write error occurs, the number of bytes returned is -1.
4647///
4648/// If no data are written, because, e.g., the branch is disabled,
4649/// the number of bytes returned is 0.
4650///
4651/// __The baskets are flushed and the Tree header saved at regular intervals__
4652///
4653/// At regular intervals, when the amount of data written so far is
4654/// greater than fAutoFlush (see SetAutoFlush) all the baskets are flushed to disk.
4655/// This makes future reading faster as it guarantees that baskets belonging to nearby
4656/// entries will be on the same disk region.
4657/// When the first call to flush the baskets happen, we also take this opportunity
4658/// to optimize the baskets buffers.
4659/// We also check if the amount of data written is greater than fAutoSave (see SetAutoSave).
4660/// In this case we also write the Tree header. This makes the Tree recoverable up to this point
4661/// in case the program writing the Tree crashes.
4662/// The decisions to FlushBaskets and Auto Save can be made based either on the number
4663/// of bytes written (fAutoFlush and fAutoSave negative) or on the number of entries
4664/// written (fAutoFlush and fAutoSave positive).
4665/// Note that the user can decide to call FlushBaskets and AutoSave in her event loop
4666/// base on the number of events written instead of the number of bytes written.
4667///
4668/// \note Calling `TTree::FlushBaskets` too often increases the IO time.
4669///
4670/// \note Calling `TTree::AutoSave` too often increases the IO time and also the
4671/// file size.
4672///
4673/// \note This method calls `TTree::ChangeFile` when the tree reaches a size
4674/// greater than `TTree::fgMaxTreeSize`. This doesn't happen if the tree is
4675/// attached to a `TMemFile` or derivate.
4678{
4679 Int_t nbytes = 0;
4680 Int_t nwrite = 0;
4681 Int_t nerror = 0;
4682 Int_t nbranches = fBranches.GetEntriesFast();
4683
4684 // Case of one single super branch. Automatically update
4685 // all the branch addresses if a new object was created.
4686 if (nbranches == 1)
4687 ((TBranch *)fBranches.UncheckedAt(0))->UpdateAddress();
4688
4689 if (fBranchRef)
4690 fBranchRef->Clear();
4691
4692#ifdef R__USE_IMT
4693 const auto useIMT = ROOT::IsImplicitMTEnabled() && fIMTEnabled;
4695 if (useIMT) {
4696 fIMTFlush = true;
4697 fIMTZipBytes.store(0);
4698 fIMTTotBytes.store(0);
4699 }
4700#endif
4701
4702 for (Int_t i = 0; i < nbranches; ++i) {
4703 // Loop over all branches, filling and accumulating bytes written and error counts.
4704 TBranch *branch = (TBranch *)fBranches.UncheckedAt(i);
4705
4706 if (branch->TestBit(kDoNotProcess))
4707 continue;
4708
4709#ifndef R__USE_IMT
4710 nwrite = branch->FillImpl(nullptr);
4711#else
4712 nwrite = branch->FillImpl(useIMT ? &imtHelper : nullptr);
4713#endif
4714 if (nwrite < 0) {
4715 if (nerror < 2) {
4716 Error("Fill", "Failed filling branch:%s.%s, nbytes=%d, entry=%lld\n"
4717 " This error is symptomatic of a Tree created as a memory-resident Tree\n"
4718 " Instead of doing:\n"
4719 " TTree *T = new TTree(...)\n"
4720 " TFile *f = new TFile(...)\n"
4721 " you should do:\n"
4722 " TFile *f = new TFile(...)\n"
4723 " TTree *T = new TTree(...)\n\n",
4724 GetName(), branch->GetName(), nwrite, fEntries + 1);
4725 } else {
4726 Error("Fill", "Failed filling branch:%s.%s, nbytes=%d, entry=%lld", GetName(), branch->GetName(), nwrite,
4727 fEntries + 1);
4728 }
4729 ++nerror;
4730 } else {
4731 nbytes += nwrite;
4732 }
4733 }
4734
4735#ifdef R__USE_IMT
4736 if (fIMTFlush) {
4737 imtHelper.Wait();
4738 fIMTFlush = false;
4739 const_cast<TTree *>(this)->AddTotBytes(fIMTTotBytes);
4740 const_cast<TTree *>(this)->AddZipBytes(fIMTZipBytes);
4741 nbytes += imtHelper.GetNbytes();
4742 nerror += imtHelper.GetNerrors();
4743 }
4744#endif
4745
4746 if (fBranchRef)
4747 fBranchRef->Fill();
4748
4749 ++fEntries;
4750
4751 if (fEntries > fMaxEntries)
4752 KeepCircular();
4753
4754 if (gDebug > 0)
4755 Info("TTree::Fill", " - A: %d %lld %lld %lld %lld %lld %lld \n", nbytes, fEntries, fAutoFlush, fAutoSave,
4757
4758 bool autoFlush = false;
4759 bool autoSave = false;
4760
4761 if (fAutoFlush != 0 || fAutoSave != 0) {
4762 // Is it time to flush or autosave baskets?
4763 if (fFlushedBytes == 0) {
4764 // If fFlushedBytes == 0, it means we never flushed or saved, so
4765 // we need to check if it's time to do it and recompute the values
4766 // of fAutoFlush and fAutoSave in terms of the number of entries.
4767 // Decision can be based initially either on the number of bytes
4768 // or the number of entries written.
4769 Long64_t zipBytes = GetZipBytes();
4770
4771 if (fAutoFlush)
4772 autoFlush = fAutoFlush < 0 ? (zipBytes > -fAutoFlush) : fEntries % fAutoFlush == 0;
4773
4774 if (fAutoSave)
4775 autoSave = fAutoSave < 0 ? (zipBytes > -fAutoSave) : fEntries % fAutoSave == 0;
4776
4777 if (autoFlush || autoSave) {
4778 // First call FlushBasket to make sure that fTotBytes is up to date.
4780 autoFlush = false; // avoid auto flushing again later
4781
4782 // When we are in one-basket-per-cluster mode, there is no need to optimize basket:
4783 // they will automatically grow to the size needed for an event cluster (with the basket
4784 // shrinking preventing them from growing too much larger than the actually-used space).
4786 OptimizeBaskets(GetTotBytes(), 1, "");
4787 if (gDebug > 0)
4788 Info("TTree::Fill", "OptimizeBaskets called at entry %lld, fZipBytes=%lld, fFlushedBytes=%lld\n",
4790 }
4792 fAutoFlush = fEntries; // Use test on entries rather than bytes
4793
4794 // subsequently in run
4795 if (fAutoSave < 0) {
4796 // Set fAutoSave to the largest integer multiple of
4797 // fAutoFlush events such that fAutoSave*fFlushedBytes
4798 // < (minus the input value of fAutoSave)
4799 Long64_t totBytes = GetTotBytes();
4800 if (zipBytes != 0) {
4801 fAutoSave = TMath::Max(fAutoFlush, fEntries * ((-fAutoSave / zipBytes) / fEntries));
4802 } else if (totBytes != 0) {
4803 fAutoSave = TMath::Max(fAutoFlush, fEntries * ((-fAutoSave / totBytes) / fEntries));
4804 } else {
4806 TTree::Class()->WriteBuffer(b, (TTree *)this);
4807 Long64_t total = b.Length();
4809 }
4810 } else if (fAutoSave > 0) {
4812 }
4813
4814 if (fAutoSave != 0 && fEntries >= fAutoSave)
4815 autoSave = true;
4816
4817 if (gDebug > 0)
4818 Info("TTree::Fill", "First AutoFlush. fAutoFlush = %lld, fAutoSave = %lld\n", fAutoFlush, fAutoSave);
4819 }
4820 } else {
4821 // Check if we need to auto flush
4822 if (fAutoFlush) {
4823 if (fNClusterRange == 0)
4824 autoFlush = fEntries > 1 && fEntries % fAutoFlush == 0;
4825 else
4826 autoFlush = (fEntries - (fClusterRangeEnd[fNClusterRange - 1] + 1)) % fAutoFlush == 0;
4827 }
4828 // Check if we need to auto save
4829 if (fAutoSave)
4830 autoSave = fEntries % fAutoSave == 0;
4831 }
4832 }
4833
4834 if (autoFlush) {
4836 if (gDebug > 0)
4837 Info("TTree::Fill", "FlushBaskets() called at entry %lld, fZipBytes=%lld, fFlushedBytes=%lld\n", fEntries,
4840 }
4841
4842 if (autoSave) {
4843 AutoSave(); // does not call FlushBasketsImpl() again
4844 if (gDebug > 0)
4845 Info("TTree::Fill", "AutoSave called at entry %lld, fZipBytes=%lld, fSavedBytes=%lld\n", fEntries,
4847 }
4848
4849 // Check that output file is still below the maximum size.
4850 // If above, close the current file and continue on a new file.
4851 // Currently, the automatic change of file is restricted
4852 // to the case where the tree is in the top level directory.
4853 if (fDirectory)
4854 if (TFile *file = fDirectory->GetFile())
4855 if (static_cast<TDirectory *>(file) == fDirectory && (file->GetEND() > fgMaxTreeSize))
4856 ChangeFile(file);
4857
4858 return nerror == 0 ? nbytes : -1;
4859}
4860
4861////////////////////////////////////////////////////////////////////////////////
4862/// Search in the array for a branch matching the branch name,
4863/// with the branch possibly expressed as a 'full' path name (with dots).
4865static TBranch *R__FindBranchHelper(TObjArray *list, const char *branchname) {
4866 if (list==nullptr || branchname == nullptr || branchname[0] == '\0') return nullptr;
4867
4868 Int_t nbranches = list->GetEntries();
4869
4870 UInt_t brlen = strlen(branchname);
4871
4872 for(Int_t index = 0; index < nbranches; ++index) {
4873 TBranch *where = (TBranch*)list->UncheckedAt(index);
4874
4875 const char *name = where->GetName();
4876 UInt_t len = strlen(name);
4877 if (len && name[len - 1] == ']' && (brlen == 0 || branchname[brlen - 1] != ']')) {
4878 const char *dim = strchr(name,'[');
4879 if (dim) {
4880 len = dim - name;
4881 }
4882 }
4883 if (brlen == len && strncmp(branchname,name,len)==0) {
4884 return where;
4885 }
4886 TBranch *next = nullptr;
4887 if ((brlen >= len) && (branchname[len] == '.')
4888 && strncmp(name, branchname, len) == 0) {
4889 // The prefix subbranch name match the branch name.
4890
4891 next = where->FindBranch(branchname);
4892 if (!next) {
4893 next = where->FindBranch(branchname+len+1);
4894 }
4895 if (next) return next;
4896 }
4897 const char *dot = strchr((char*)branchname,'.');
4898 if (dot) {
4899 if (len==(size_t)(dot-branchname) &&
4900 strncmp(branchname,name,dot-branchname)==0 ) {
4901 return R__FindBranchHelper(where->GetListOfBranches(),dot+1);
4902 }
4903 }
4904 }
4905 return nullptr;
4906}
4908TBranch *TTree::FindBranchFromSelf(const char *branchName)
4909{
4910 // If the first part of the name match the TTree name, look for the right part in the
4911 // list of branches. This will allow the branchName to be preceded by the name of this tree.
4912 if (strncmp(fName.Data(), branchName, fName.Length()) == 0 && branchName[fName.Length()] == '.')
4913 if (auto *br = R__FindBranchHelper(GetListOfBranches(), branchName + fName.Length() + 1))
4914 return br;
4915
4916 // If we did not find it, let's try to find the full name in the list of branches.
4917 if (auto *br = R__FindBranchHelper(GetListOfBranches(), branchName))
4918 return br;
4919
4920 // If we still did not find, let's try to find it within each branch assuming it does not contain the branch name.
4922 if (auto *nestedbranch = branch->FindBranch(branchName))
4923 return nestedbranch;
4924
4925 return nullptr;
4926}
4928TBranch *TTree::FindBranchFromFriends(const char *branchName)
4929{
4930 if (!fFriends) {
4931 return nullptr;
4932 }
4933
4934 TFriendLock lock(this, kFindBranch);
4936 TTree *t = frEl->GetTree();
4937 if (!t) {
4938 continue;
4939 }
4940 // If the alias is present replace it with the real name.
4941 const char *subbranch = strstr(branchName, frEl->GetName());
4942 if (subbranch != branchName) {
4943 subbranch = nullptr;
4944 }
4945 if (subbranch) {
4946 subbranch += strlen(frEl->GetName());
4947 if (*subbranch != '.') {
4948 subbranch = nullptr;
4949 } else {
4950 ++subbranch;
4951 }
4952 }
4953 std::ostringstream name;
4954 if (subbranch) {
4955 name << t->GetName() << "." << subbranch;
4956 } else {
4957 name << branchName;
4958 }
4959 if (auto *br = t->FindBranch(name.str().c_str()))
4960 return br;
4961 }
4962
4963 return nullptr;
4964}
4965
4966////////////////////////////////////////////////////////////////////////////////
4967/// Return the branch that correspond to the path 'branchname', which can
4968/// include the name of the tree or the omitted name of the parent branches.
4969/// In case of ambiguity, returns the first match.
4970/// \sa TTree::GetBranch
4972TBranch *TTree::FindBranch(const char *branchname)
4973{
4974 // We already have been visited while recursively looking
4975 // through the friends tree, let return
4977 return nullptr;
4978 }
4979
4980 if (!branchname)
4981 return nullptr;
4982
4983 if (auto *br = FindBranchFromSelf(branchname))
4984 return br;
4985
4986 if (auto *br = FindBranchFromFriends(branchname))
4987 return br;
4988
4989 return nullptr;
4990}
4991
4992////////////////////////////////////////////////////////////////////////////////
4993/// Find first leaf containing searchname.
4995TLeaf* TTree::FindLeaf(const char* searchname)
4996{
4997 if (!searchname)
4998 return nullptr;
4999
5000 // We already have been visited while recursively looking
5001 // through the friends tree, let's return.
5003 return nullptr;
5004 }
5005
5006 // This will allow the branchname to be preceded by
5007 // the name of this tree.
5008 const char* subsearchname = strstr(searchname, GetName());
5009 if (subsearchname != searchname) {
5010 subsearchname = nullptr;
5011 }
5012 if (subsearchname) {
5013 subsearchname += strlen(GetName());
5014 if (*subsearchname != '.') {
5015 subsearchname = nullptr;
5016 } else {
5017 ++subsearchname;
5018 if (subsearchname[0] == 0) {
5019 subsearchname = nullptr;
5020 }
5021 }
5022 }
5023
5024 TString leafname;
5025 TString leaftitle;
5026 TString longname;
5027 TString longtitle;
5028
5029 const bool searchnameHasDot = strchr(searchname, '.') != nullptr;
5030
5031 // For leaves we allow for one level up to be prefixed to the name.
5032 TIter next(GetListOfLeaves());
5033 TLeaf* leaf = nullptr;
5034 while ((leaf = (TLeaf*) next())) {
5035 leafname = leaf->GetName();
5036 Ssiz_t dim = leafname.First('[');
5037 if (dim >= 0) leafname.Remove(dim);
5038
5039 if (leafname == searchname) {
5040 return leaf;
5041 }
5042 if (subsearchname && leafname == subsearchname) {
5043 return leaf;
5044 }
5045 // The TLeafElement contains the branch name
5046 // in its name, let's use the title.
5047 leaftitle = leaf->GetTitle();
5048 dim = leaftitle.First('[');
5049 if (dim >= 0) leaftitle.Remove(dim);
5050
5051 if (leaftitle == searchname) {
5052 return leaf;
5053 }
5054 if (subsearchname && leaftitle == subsearchname) {
5055 return leaf;
5056 }
5057 if (!searchnameHasDot)
5058 continue;
5059 TBranch* branch = leaf->GetBranch();
5060 if (branch) {
5061 longname.Form("%s.%s",branch->GetName(),leafname.Data());
5062 dim = longname.First('[');
5063 if (dim>=0) longname.Remove(dim);
5064 if (longname == searchname) {
5065 return leaf;
5066 }
5067 if (subsearchname && longname == subsearchname) {
5068 return leaf;
5069 }
5070 longtitle.Form("%s.%s",branch->GetName(),leaftitle.Data());
5071 dim = longtitle.First('[');
5072 if (dim>=0) longtitle.Remove(dim);
5073 if (longtitle == searchname) {
5074 return leaf;
5075 }
5076 if (subsearchname && longtitle == subsearchname) {
5077 return leaf;
5078 }
5079 // The following is for the case where the branch is only
5080 // a sub-branch. Since we do not see it through
5081 // TTree::GetListOfBranches, we need to see it indirectly.
5082 // This is the less sturdy part of this search ... it may
5083 // need refining ...
5084 if (strstr(searchname, ".") && !strcmp(searchname, branch->GetName())) {
5085 return leaf;
5086 }
5087 if (subsearchname && strstr(subsearchname, ".") && !strcmp(subsearchname, branch->GetName())) {
5088 return leaf;
5089 }
5090 }
5091 }
5092 // Search in list of friends.
5093 if (!fFriends) {
5094 return nullptr;
5095 }
5096 TFriendLock lock(this, kFindLeaf);
5097 TIter nextf(fFriends);
5098 TFriendElement* fe = nullptr;
5099 while ((fe = (TFriendElement*) nextf())) {
5100 TTree* t = fe->GetTree();
5101 if (!t) {
5102 continue;
5103 }
5104 // If the alias is present replace it with the real name.
5105 subsearchname = strstr(searchname, fe->GetName());
5106 if (subsearchname != searchname) {
5107 subsearchname = nullptr;
5108 }
5109 if (subsearchname) {
5110 subsearchname += strlen(fe->GetName());
5111 if (*subsearchname != '.') {
5112 subsearchname = nullptr;
5113 } else {
5114 ++subsearchname;
5115 }
5116 }
5117 if (subsearchname) {
5118 leafname.Form("%s.%s",t->GetName(),subsearchname);
5119 } else {
5120 leafname = searchname;
5121 }
5122 leaf = t->FindLeaf(leafname);
5123 if (leaf) {
5124 return leaf;
5125 }
5126 }
5127 return nullptr;
5128}
5129
5130////////////////////////////////////////////////////////////////////////////////
5131/// Fit a projected item(s) from a tree.
5132///
5133/// funcname is a TF1 function.
5134///
5135/// See TTree::Draw() for explanations of the other parameters.
5136///
5137/// By default the temporary histogram created is called htemp.
5138/// If varexp contains >>hnew , the new histogram created is called hnew
5139/// and it is kept in the current directory.
5140///
5141/// The function returns the number of selected entries.
5142///
5143/// Example:
5144/// ~~~ {.cpp}
5145/// tree.Fit(pol4,"sqrt(x)>>hsqrt","y>0")
5146/// ~~~
5147/// will fit sqrt(x) and save the histogram as "hsqrt" in the current
5148/// directory.
5149///
5150/// See also TTree::UnbinnedFit
5151///
5152/// ## Return status
5153///
5154/// The function returns the status of the histogram fit (see TH1::Fit)
5155/// If no entries were selected, the function returns -1;
5156/// (i.e. fitResult is null if the fit is OK)
5158Int_t TTree::Fit(const char* funcname, const char* varexp, const char* selection, Option_t* option, Option_t* goption, Long64_t nentries, Long64_t firstentry)
5159{
5160 GetPlayer();
5161 if (fPlayer) {
5162 return fPlayer->Fit(funcname, varexp, selection, option, goption, nentries, firstentry);
5163 }
5164 return -1;
5165}
5166
5167namespace {
5168struct BoolRAIIToggle {
5169 bool &m_val;
5170
5171 BoolRAIIToggle(bool &val) : m_val(val) { m_val = true; }
5172 ~BoolRAIIToggle() { m_val = false; }
5173};
5174}
5175
5176////////////////////////////////////////////////////////////////////////////////
5177/// Write to disk all the basket that have not yet been individually written and
5178/// create an event cluster boundary (by default).
5179///
5180/// If the caller wishes to flush the baskets but not create an event cluster,
5181/// then set create_cluster to false.
5182///
5183/// If ROOT has IMT-mode enabled, this will launch multiple TBB tasks in parallel
5184/// via TThreadExecutor to do this operation; one per basket compression. If the
5185/// caller utilizes TBB also, care must be taken to prevent deadlocks.
5186///
5187/// For example, let's say the caller holds mutex A and calls FlushBaskets; while
5188/// TBB is waiting for the ROOT compression tasks to complete, it may decide to
5189/// run another one of the user's tasks in this thread. If the second user task
5190/// tries to acquire A, then a deadlock will occur. The example call sequence
5191/// looks like this:
5192///
5193/// - User acquires mutex A
5194/// - User calls FlushBaskets.
5195/// - ROOT launches N tasks and calls wait.
5196/// - TBB schedules another user task, T2.
5197/// - T2 tries to acquire mutex A.
5198///
5199/// At this point, the thread will deadlock: the code may function with IMT-mode
5200/// disabled if the user assumed the legacy code never would run their own TBB
5201/// tasks.
5202///
5203/// SO: users of TBB who want to enable IMT-mode should carefully review their
5204/// locking patterns and make sure they hold no coarse-grained application
5205/// locks when they invoke ROOT.
5206///
5207/// Return the number of bytes written or -1 in case of write error.
5208Int_t TTree::FlushBaskets(bool create_cluster) const
5209{
5210 Int_t retval = FlushBasketsImpl();
5211 if (retval == -1) return retval;
5212
5213 if (create_cluster) const_cast<TTree *>(this)->MarkEventCluster();
5214 return retval;
5215}
5216
5217////////////////////////////////////////////////////////////////////////////////
5218/// Internal implementation of the FlushBaskets algorithm.
5219/// Unlike the public interface, this does NOT create an explicit event cluster
5220/// boundary; it is up to the (internal) caller to determine whether that should
5221/// done.
5222///
5223/// Otherwise, the comments for FlushBaskets applies.
5226{
5227 if (!fDirectory) return 0;
5228 Int_t nbytes = 0;
5229 Int_t nerror = 0;
5230 TObjArray *lb = const_cast<TTree*>(this)->GetListOfBranches();
5231 Int_t nb = lb->GetEntriesFast();
5232
5233#ifdef R__USE_IMT
5234 const auto useIMT = ROOT::IsImplicitMTEnabled() && fIMTEnabled;
5235 if (useIMT) {
5236 // ROOT-9668: here we need to check if the size of fSortedBranches is different from the
5237 // size of the list of branches before triggering the initialisation of the fSortedBranches
5238 // container to cover two cases:
5239 // 1. This is the first time we flush. fSortedBranches is empty and we need to fill it.
5240 // 2. We flushed at least once already but a branch has been be added to the tree since then
5241 if (fSortedBranches.size() != unsigned(nb)) { const_cast<TTree*>(this)->InitializeBranchLists(false); }
5242
5243 BoolRAIIToggle sentry(fIMTFlush);
5244 fIMTZipBytes.store(0);
5245 fIMTTotBytes.store(0);
5246 std::atomic<Int_t> nerrpar(0);
5247 std::atomic<Int_t> nbpar(0);
5248 std::atomic<Int_t> pos(0);
5249
5250 auto mapFunction = [&]() {
5251 // The branch to process is obtained when the task starts to run.
5252 // This way, since branches are sorted, we make sure that branches
5253 // leading to big tasks are processed first. If we assigned the
5254 // branch at task creation time, the scheduler would not necessarily
5255 // respect our sorting.
5256 Int_t j = pos.fetch_add(1);
5257
5258 auto branch = fSortedBranches[j].second;
5259 if (R__unlikely(!branch)) { return; }
5260
5261 if (R__unlikely(gDebug > 0)) {
5262 std::stringstream ss;
5263 ss << std::this_thread::get_id();
5264 Info("FlushBaskets", "[IMT] Thread %s", ss.str().c_str());
5265 Info("FlushBaskets", "[IMT] Running task for branch #%d: %s", j, branch->GetName());
5266 }
5267
5268 Int_t nbtask = branch->FlushBaskets();
5269
5270 if (nbtask < 0) { nerrpar++; }
5271 else { nbpar += nbtask; }
5272 };
5273
5275 pool.Foreach(mapFunction, nb);
5276
5277 fIMTFlush = false;
5278 const_cast<TTree*>(this)->AddTotBytes(fIMTTotBytes);
5279 const_cast<TTree*>(this)->AddZipBytes(fIMTZipBytes);
5280
5281 return nerrpar ? -1 : nbpar.load();
5282 }
5283#endif
5284 for (Int_t j = 0; j < nb; j++) {
5285 TBranch* branch = (TBranch*) lb->UncheckedAt(j);
5286 if (branch) {
5287 Int_t nwrite = branch->FlushBaskets();
5288 if (nwrite<0) {
5289 ++nerror;
5290 } else {
5291 nbytes += nwrite;
5292 }
5293 }
5294 }
5295 if (nerror) {
5296 return -1;
5297 } else {
5298 return nbytes;
5299 }
5300}
5301
5302////////////////////////////////////////////////////////////////////////////////
5303/// Returns the expanded value of the alias. Search in the friends if any.
5305const char* TTree::GetAlias(const char* aliasName) const
5306{
5307 // We already have been visited while recursively looking
5308 // through the friends tree, let's return.
5310 return nullptr;
5311 }
5312 if (fAliases) {
5313 TObject* alias = fAliases->FindObject(aliasName);
5314 if (alias) {
5315 return alias->GetTitle();
5316 }
5317 }
5318 if (!fFriends) {
5319 return nullptr;
5320 }
5321 TFriendLock lock(const_cast<TTree*>(this), kGetAlias);
5322 TIter nextf(fFriends);
5323 TFriendElement* fe = nullptr;
5324 while ((fe = (TFriendElement*) nextf())) {
5325 TTree* t = fe->GetTree();
5326 if (t) {
5327 const char* alias = t->GetAlias(aliasName);
5328 if (alias) {
5329 return alias;
5330 }
5331 const char* subAliasName = strstr(aliasName, fe->GetName());
5332 if (subAliasName && (subAliasName[strlen(fe->GetName())] == '.')) {
5333 alias = t->GetAlias(aliasName + strlen(fe->GetName()) + 1);
5334 if (alias) {
5335 return alias;
5336 }
5337 }
5338 }
5339 }
5340 return nullptr;
5341}
5342
5343namespace {
5344/// Do a breadth first search through the implied hierarchy
5345/// of branches.
5346/// To avoid scanning through the list multiple time
5347/// we also remember the 'depth-first' match.
5348TBranch *R__GetBranch(const TObjArray &branches, const char *name)
5349{
5350 TBranch *result = nullptr;
5351 Int_t nb = branches.GetEntriesFast();
5352 for (Int_t i = 0; i < nb; i++) {
5353 TBranch* b = (TBranch*)branches.UncheckedAt(i);
5354 if (!b)
5355 continue;
5356 if (!strcmp(b->GetName(), name)) {
5357 return b;
5358 }
5359 if (!strcmp(b->GetFullName(), name)) {
5360 return b;
5361 }
5362 if (!result)
5363 result = R__GetBranch(*(b->GetListOfBranches()), name);
5364 }
5365 return result;
5366}
5367}
5368
5369////////////////////////////////////////////////////////////////////////////////
5370/// Returns a pointer to the branch with the given name, if it can be found in
5371/// this tree. Otherwise, returns nullptr.
5372TBranch *TTree::GetBranchFromSelf(const char *branchName)
5373{
5374 // Look for an exact match in the list of top level
5375 // branches.
5376 if (auto *br = static_cast<TBranch *>(fBranches.FindObject(branchName)))
5377 return br;
5378
5379 // Look for an exact match in the mapping from branch name to TBranch *
5380 // gathered when first reading the TTree from disk.
5381 if (auto it = fNamesToBranches.find(branchName); it != fNamesToBranches.end())
5382 return it->second;
5383
5384 // Search using branches, breadth first.
5385 if (auto *br = R__GetBranch(fBranches, branchName))
5386 return br;
5387
5388 // Search using leaves.
5389 TObjArray *leaves = GetListOfLeaves();
5390 Int_t nleaves = leaves->GetEntriesFast();
5391 for (Int_t i = 0; i < nleaves; i++) {
5392 TLeaf *leaf = (TLeaf *)leaves->UncheckedAt(i);
5393 TBranch *branch = leaf->GetBranch();
5394 if (!strcmp(branch->GetName(), branchName)) {
5395 return branch;
5396 }
5397 if (!strcmp(branch->GetFullName(), branchName)) {
5398 return branch;
5399 }
5400 }
5401
5402 return nullptr;
5403}
5404
5405////////////////////////////////////////////////////////////////////////////////
5406/// Returns a pointer to the branch with the given name, if it can be found in
5407/// the list of friends of this tree. Otherwise, returns nullptr.
5408TBranch *TTree::GetBranchFromFriends(const char *branchName)
5409{
5410 if (!fFriends) {
5411 return nullptr;
5412 }
5413
5414 // Search in list of friends.
5415 TFriendLock lock(this, kGetBranch);
5416 TIter next(fFriends);
5417 TFriendElement *fe = nullptr;
5418 while ((fe = (TFriendElement *)next())) {
5419 TTree *t = fe->GetTree();
5420 if (t) {
5421 TBranch *branch = t->GetBranch(branchName);
5422 if (branch) {
5423 return branch;
5424 }
5425 }
5426 }
5427
5428 // Second pass in the list of friends when
5429 // the branch name is prefixed by the tree name.
5430 next.Reset();
5431 while ((fe = (TFriendElement *)next())) {
5432 TTree *t = fe->GetTree();
5433 if (!t) {
5434 continue;
5435 }
5436 const char *subname = strstr(branchName, fe->GetName());
5437 if (subname != branchName) {
5438 continue;
5439 }
5440 Int_t l = strlen(fe->GetName());
5441 subname += l;
5442 if (*subname != '.') {
5443 continue;
5444 }
5445 subname++;
5446 TBranch *branch = t->GetBranch(subname);
5447 if (branch) {
5448 return branch;
5449 }
5450 }
5451
5452 return nullptr;
5453}
5454
5455////////////////////////////////////////////////////////////////////////////////
5456/// Return pointer to the branch with the given name in this tree or its friends.
5457/// The search is done breadth first.
5458/// \sa TTree::FindBranch
5460TBranch *TTree::GetBranch(const char *name)
5461{
5462 // We already have been visited while recursively
5463 // looking through the friends tree, let's return.
5465 return nullptr;
5466 }
5467
5468 if (!name)
5469 return nullptr;
5470
5471 if (auto *br = GetBranchFromSelf(name))
5472 return br;
5473
5474 if (auto *br = GetBranchFromFriends(name))
5475 return br;
5476
5477 return nullptr;
5478}
5479
5480////////////////////////////////////////////////////////////////////////////////
5481/// Return status of branch with name branchname.
5482///
5483/// - 0 if branch is not activated
5484/// - 1 if branch is activated
5486bool TTree::GetBranchStatus(const char* branchname) const
5487{
5488 TBranch* br = const_cast<TTree*>(this)->GetBranch(branchname);
5489 if (br) {
5490 return br->TestBit(kDoNotProcess) == 0;
5491 }
5492 return false;
5493}
5494
5495////////////////////////////////////////////////////////////////////////////////
5496/// Static function returning the current branch style.
5497///
5498/// - style = 0 old Branch
5499/// - style = 1 new Bronch
5504}
5505
5506////////////////////////////////////////////////////////////////////////////////
5507/// Used for automatic sizing of the cache.
5508///
5509/// Estimates a suitable size in bytes for the tree cache based on AutoFlush.
5510/// A cache sizing factor is taken from the configuration. If this yields zero
5511/// and withDefault is true the historical algorithm for default size is used.
5513Long64_t TTree::GetCacheAutoSize(bool withDefault /* = false */ )
5514{
5515 auto calculateCacheSize = [this](Double_t cacheFactor)
5516 {
5517 Long64_t cacheSize = 0;
5518 if (fAutoFlush < 0) {
5519 cacheSize = Long64_t(-cacheFactor * fAutoFlush);
5520 } else if (fAutoFlush == 0) {
5521 const auto medianClusterSize = GetMedianClusterSize();
5522 if (medianClusterSize > 0)
5523 cacheSize = Long64_t(cacheFactor * 1.5 * medianClusterSize * GetZipBytes() / (fEntries + 1));
5524 else
5525 cacheSize = Long64_t(cacheFactor * 1.5 * 30000000); // use the default value of fAutoFlush
5526 } else {
5527 cacheSize = Long64_t(cacheFactor * 1.5 * fAutoFlush * GetZipBytes() / (fEntries + 1));
5528 }
5529 if (cacheSize >= (INT_MAX / 4)) {
5530 cacheSize = INT_MAX / 4;
5531 }
5532 return cacheSize;
5533 };
5534
5535 const char *stcs;
5536 Double_t cacheFactor = 0.0;
5537 if (!(stcs = gSystem->Getenv("ROOT_TTREECACHE_SIZE")) || !*stcs) {
5538 cacheFactor = gEnv->GetValue("TTreeCache.Size", 1.0);
5539 } else {
5540 cacheFactor = TString(stcs).Atof();
5541 }
5542
5543 if (cacheFactor < 0.0) {
5544 // ignore negative factors
5545 cacheFactor = 0.0;
5546 }
5547
5548 Long64_t cacheSize = calculateCacheSize(cacheFactor);
5549
5550 if (cacheSize < 0) {
5551 cacheSize = 0;
5552 }
5553
5554 if (cacheSize == 0 && withDefault) {
5555 cacheSize = calculateCacheSize(1.0);
5556 }
5557
5558 return cacheSize;
5559}
5560
5561////////////////////////////////////////////////////////////////////////////////
5562/// Return an iterator over the cluster of baskets starting at firstentry.
5563///
5564/// This iterator is not yet supported for TChain object.
5565/// ~~~ {.cpp}
5566/// TTree::TClusterIterator clusterIter = tree->GetClusterIterator(entry);
5567/// Long64_t clusterStart;
5568/// while( (clusterStart = clusterIter()) < tree->GetEntries() ) {
5569/// printf("The cluster starts at %lld and ends at %lld (inclusive)\n",clusterStart,clusterIter.GetNextEntry()-1);
5570/// }
5571/// ~~~
5574{
5575 // create cache if wanted
5576 if (fCacheDoAutoInit)
5578
5579 return TClusterIterator(this,firstentry);
5580}
5581
5582////////////////////////////////////////////////////////////////////////////////
5583/// Return pointer to the current file.
5586{
5587 if (!fDirectory || fDirectory==gROOT) {
5588 return nullptr;
5589 }
5590 return fDirectory->GetFile();
5591}
5592
5593////////////////////////////////////////////////////////////////////////////////
5594/// Return the number of entries matching the selection.
5595/// Return -1 in case of errors.
5596///
5597/// If the selection uses any arrays or containers, we return the number
5598/// of entries where at least one element match the selection.
5599/// GetEntries is implemented using the selector class TSelectorEntries,
5600/// which can be used directly (see code in TTreePlayer::GetEntries) for
5601/// additional option.
5602/// If SetEventList was used on the TTree or TChain, only that subset
5603/// of entries will be considered.
5605Long64_t TTree::GetEntries(const char *selection)
5606{
5607 GetPlayer();
5608 if (fPlayer) {
5609 return fPlayer->GetEntries(selection);
5610 }
5611 return -1;
5612}
5613
5614////////////////////////////////////////////////////////////////////////////////
5615/// Returns a number corresponding to:
5616/// - The number of entries in this tree, if greater than zero
5617/// - The number of entries in the first friend tree, if there are any friends
5618/// - 0 otherwise
5621{
5622 if (fEntries) return fEntries;
5623 if (!fFriends) return 0;
5625 if (!fr) return 0;
5626 TTree *t = fr->GetTree();
5627 if (t==nullptr) return 0;
5628 return t->GetEntriesFriend();
5629}
5630
5631////////////////////////////////////////////////////////////////////////////////
5632/// Read all branches of entry and return total number of bytes read.
5633///
5634/// - `getall = 0` : get only active branches
5635/// - `getall = 1` : get all branches
5636///
5637/// The function returns the number of bytes read from the input buffer.
5638/// If entry does not exist the function returns 0.
5639/// If an I/O error occurs, the function returns -1.
5640/// If all branches are disabled and getall == 0, it also returns 0
5641/// even if the specified entry exists in the tree, since zero bytes were read.
5642///
5643/// If the Tree has friends, also read the friends entry.
5644///
5645/// To activate/deactivate one or more branches, use TBranch::SetBranchStatus
5646/// For example, if you have a Tree with several hundred branches, and you
5647/// are interested only by branches named "a" and "b", do
5648/// ~~~ {.cpp}
5649/// mytree.SetBranchStatus("*",0); //disable all branches
5650/// mytree.SetBranchStatus("a",1);
5651/// mytree.SetBranchStatus("b",1);
5652/// ~~~
5653/// when calling mytree.GetEntry(i); only branches "a" and "b" will be read.
5654///
5655/// __WARNING!!__
5656/// If your Tree has been created in split mode with a parent branch "parent.",
5657/// ~~~ {.cpp}
5658/// mytree.SetBranchStatus("parent",1);
5659/// ~~~
5660/// will not activate the sub-branches of "parent". You should do:
5661/// ~~~ {.cpp}
5662/// mytree.SetBranchStatus("parent*",1);
5663/// ~~~
5664/// Without the trailing dot in the branch creation you have no choice but to
5665/// call SetBranchStatus explicitly for each of the sub branches.
5666///
5667/// An alternative is to call directly
5668/// ~~~ {.cpp}
5669/// brancha.GetEntry(i)
5670/// branchb.GetEntry(i);
5671/// ~~~
5672/// ## IMPORTANT NOTE
5673///
5674/// By default, GetEntry reuses the space allocated by the previous object
5675/// for each branch. You can force the previous object to be automatically
5676/// deleted if you call mybranch.SetAutoDelete(true) (default is false).
5677///
5678/// Example:
5679///
5680/// Consider the example in $ROOTSYS/test/Event.h
5681/// The top level branch in the tree T is declared with:
5682/// ~~~ {.cpp}
5683/// Event *event = 0; //event must be null or point to a valid object
5684/// //it must be initialized
5685/// T.SetBranchAddress("event",&event);
5686/// ~~~
5687/// When reading the Tree, one can choose one of these 3 options:
5688///
5689/// ## OPTION 1
5690///
5691/// ~~~ {.cpp}
5692/// for (Long64_t i=0;i<nentries;i++) {
5693/// T.GetEntry(i);
5694/// // the object event has been filled at this point
5695/// }
5696/// ~~~
5697/// The default (recommended). At the first entry an object of the class
5698/// Event will be created and pointed by event. At the following entries,
5699/// event will be overwritten by the new data. All internal members that are
5700/// TObject* are automatically deleted. It is important that these members
5701/// be in a valid state when GetEntry is called. Pointers must be correctly
5702/// initialized. However these internal members will not be deleted if the
5703/// characters "->" are specified as the first characters in the comment
5704/// field of the data member declaration.
5705///
5706/// If "->" is specified, the pointer member is read via pointer->Streamer(buf).
5707/// In this case, it is assumed that the pointer is never null (case of
5708/// pointer TClonesArray *fTracks in the Event example). If "->" is not
5709/// specified, the pointer member is read via buf >> pointer. In this case
5710/// the pointer may be null. Note that the option with "->" is faster to
5711/// read or write and it also consumes less space in the file.
5712///
5713/// ## OPTION 2
5714///
5715/// The option AutoDelete is set
5716/// ~~~ {.cpp}
5717/// TBranch *branch = T.GetBranch("event");
5718/// branch->SetAddress(&event);
5719/// branch->SetAutoDelete(true);
5720/// for (Long64_t i=0;i<nentries;i++) {
5721/// T.GetEntry(i);
5722/// // the object event has been filled at this point
5723/// }
5724/// ~~~
5725/// In this case, at each iteration, the object event is deleted by GetEntry
5726/// and a new instance of Event is created and filled.
5727///
5728/// ## OPTION 3
5729///
5730/// ~~~ {.cpp}
5731/// Same as option 1, but you delete yourself the event.
5732///
5733/// for (Long64_t i=0;i<nentries;i++) {
5734/// delete event;
5735/// event = 0; // EXTREMELY IMPORTANT
5736/// T.GetEntry(i);
5737/// // the object event has been filled at this point
5738/// }
5739/// ~~~
5740/// It is strongly recommended to use the default option 1. It has the
5741/// additional advantage that functions like TTree::Draw (internally calling
5742/// TTree::GetEntry) will be functional even when the classes in the file are
5743/// not available.
5744///
5745/// Note: See the comments in TBranchElement::SetAddress() for the
5746/// object ownership policy of the underlying (user) data.
5748Int_t TTree::GetEntry(Long64_t entry, Int_t getall)
5749{
5750 // We already have been visited while recursively looking
5751 // through the friends tree, let return
5752 if (kGetEntry & fFriendLockStatus) return 0;
5753
5754 if (entry < 0 || entry >= fEntries) return 0;
5755 Int_t i;
5756 Int_t nbytes = 0;
5757 fReadEntry = entry;
5758
5759 // create cache if wanted
5760 if (fCacheDoAutoInit)
5762
5763 Int_t nbranches = fBranches.GetEntriesUnsafe();
5764 Int_t nb=0;
5765
5766 auto seqprocessing = [&]() {
5767 TBranch *branch;
5768 for (i=0;i<nbranches;i++) {
5769 branch = (TBranch*)fBranches.UncheckedAt(i);
5770 nb = branch->GetEntry(entry, getall);
5771 if (nb < 0) break;
5772 nbytes += nb;
5773 }
5774 };
5775
5776#ifdef R__USE_IMT
5778 if (fSortedBranches.empty())
5780
5781 // Count branches are processed first and sequentially
5782 for (auto branch : fSeqBranches) {
5783 nb = branch->GetEntry(entry, getall);
5784 if (nb < 0) break;
5785 nbytes += nb;
5786 }
5787 if (nb < 0) return nb;
5788
5789 // Enable this IMT use case (activate its locks)
5791
5792 Int_t errnb = 0;
5793 std::atomic<Int_t> pos(0);
5794 std::atomic<Int_t> nbpar(0);
5795
5796 auto mapFunction = [&]() {
5797 // The branch to process is obtained when the task starts to run.
5798 // This way, since branches are sorted, we make sure that branches
5799 // leading to big tasks are processed first. If we assigned the
5800 // branch at task creation time, the scheduler would not necessarily
5801 // respect our sorting.
5802 Int_t j = pos.fetch_add(1);
5803
5804 Int_t nbtask = 0;
5805 auto branch = fSortedBranches[j].second;
5806
5807 if (gDebug > 0) {
5808 std::stringstream ss;
5809 ss << std::this_thread::get_id();
5810 Info("GetEntry", "[IMT] Thread %s", ss.str().c_str());
5811 Info("GetEntry", "[IMT] Running task for branch #%d: %s", j, branch->GetName());
5812 }
5813
5814 std::chrono::time_point<std::chrono::system_clock> start, end;
5815
5816 start = std::chrono::system_clock::now();
5817 nbtask = branch->GetEntry(entry, getall);
5818 end = std::chrono::system_clock::now();
5819
5820 Long64_t tasktime = (Long64_t)std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
5821 fSortedBranches[j].first += tasktime;
5822
5823 if (nbtask < 0) errnb = nbtask;
5824 else nbpar += nbtask;
5825 };
5826
5828 pool.Foreach(mapFunction, fSortedBranches.size());
5829
5830 if (errnb < 0) {
5831 nb = errnb;
5832 }
5833 else {
5834 // Save the number of bytes read by the tasks
5835 nbytes += nbpar;
5836
5837 // Re-sort branches if necessary
5841 }
5842 }
5843 }
5844 else {
5845 seqprocessing();
5846 }
5847#else
5848 seqprocessing();
5849#endif
5850 if (nb < 0) return nb;
5851
5852 // GetEntry in list of friends
5853 if (!fFriends) return nbytes;
5854 TFriendLock lock(this,kGetEntry);
5855 TIter nextf(fFriends);
5856 TFriendElement *fe;
5857 while ((fe = (TFriendElement*)nextf())) {
5858 TTree *t = fe->GetTree();
5859 if (t) {
5861 nb = t->GetEntry(t->GetReadEntry(),getall);
5862 } else {
5863 if ( t->LoadTreeFriend(entry,this) >= 0 ) {
5864 nb = t->GetEntry(t->GetReadEntry(),getall);
5865 } else nb = 0;
5866 }
5867 if (nb < 0) return nb;
5868 nbytes += nb;
5869 }
5870 }
5871 return nbytes;
5872}
5873
5874
5875////////////////////////////////////////////////////////////////////////////////
5876/// Divides the top-level branches into two vectors: (i) branches to be
5877/// processed sequentially and (ii) branches to be processed in parallel.
5878/// Even if IMT is on, some branches might need to be processed first and in a
5879/// sequential fashion: in the parallelization of GetEntry, those are the
5880/// branches that store the size of another branch for every entry
5881/// (e.g. the size of an array branch). If such branches were processed
5882/// in parallel with the rest, there could be two threads invoking
5883/// TBranch::GetEntry on one of them at the same time, since a branch that
5884/// depends on a size (or count) branch will also invoke GetEntry on the latter.
5885/// This method can be invoked several times during the event loop if the TTree
5886/// is being written, for example when adding new branches. In these cases, the
5887/// `checkLeafCount` parameter is false.
5888/// \param[in] checkLeafCount True if we need to check whether some branches are
5889/// count leaves.
5891void TTree::InitializeBranchLists(bool checkLeafCount)
5892{
5893 Int_t nbranches = fBranches.GetEntriesFast();
5894
5895 // The special branch fBranchRef needs to be processed sequentially:
5896 // we add it once only.
5897 if (fBranchRef && fBranchRef != fSeqBranches[0]) {
5898 fSeqBranches.push_back(fBranchRef);
5899 }
5900
5901 // The branches to be processed sequentially are those that are the leaf count of another branch
5902 if (checkLeafCount) {
5903 for (Int_t i = 0; i < nbranches; i++) {
5904 TBranch* branch = (TBranch*)fBranches.UncheckedAt(i);
5905 auto leafCount = ((TLeaf*)branch->GetListOfLeaves()->At(0))->GetLeafCount();
5906 if (leafCount) {
5907 auto countBranch = leafCount->GetBranch();
5908 if (std::find(fSeqBranches.begin(), fSeqBranches.end(), countBranch) == fSeqBranches.end()) {
5909 fSeqBranches.push_back(countBranch);
5910 }
5911 }
5912 }
5913 }
5914
5915 // Any branch that is not a leaf count can be safely processed in parallel when reading
5916 // We need to reset the vector to make sure we do not re-add several times the same branch.
5917 if (!checkLeafCount) {
5918 fSortedBranches.clear();
5919 }
5920 for (Int_t i = 0; i < nbranches; i++) {
5921 Long64_t bbytes = 0;
5922 TBranch* branch = (TBranch*)fBranches.UncheckedAt(i);
5923 if (std::find(fSeqBranches.begin(), fSeqBranches.end(), branch) == fSeqBranches.end()) {
5924 bbytes = branch->GetTotBytes("*");
5925 fSortedBranches.emplace_back(bbytes, branch);
5926 }
5927 }
5928
5929 // Initially sort parallel branches by size
5930 std::sort(fSortedBranches.begin(),
5931 fSortedBranches.end(),
5932 [](std::pair<Long64_t,TBranch*> a, std::pair<Long64_t,TBranch*> b) {
5933 return a.first > b.first;
5934 });
5935
5936 for (size_t i = 0; i < fSortedBranches.size(); i++) {
5937 fSortedBranches[i].first = 0LL;
5938 }
5939}
5940
5941////////////////////////////////////////////////////////////////////////////////
5942/// Sorts top-level branches by the last average task time recorded per branch.
5945{
5946 for (size_t i = 0; i < fSortedBranches.size(); i++) {
5948 }
5949
5950 std::sort(fSortedBranches.begin(),
5951 fSortedBranches.end(),
5952 [](std::pair<Long64_t,TBranch*> a, std::pair<Long64_t,TBranch*> b) {
5953 return a.first > b.first;
5954 });
5955
5956 for (size_t i = 0; i < fSortedBranches.size(); i++) {
5957 fSortedBranches[i].first = 0LL;
5958 }
5959}
5960
5961////////////////////////////////////////////////////////////////////////////////
5962///Returns the entry list assigned to this tree
5965{
5966 return fEntryList;
5967}
5968
5969////////////////////////////////////////////////////////////////////////////////
5970/// Return entry number corresponding to entry.
5971///
5972/// if no TEntryList set returns entry
5973/// else returns the entry number corresponding to the list index=entry
5976{
5977 if (!fEntryList) {
5978 return entry;
5979 }
5980
5981 return fEntryList->GetEntry(entry);
5982}
5983
5984////////////////////////////////////////////////////////////////////////////////
5985/// Return entry number corresponding to major and minor number.
5986/// Note that this function returns only the entry number, not the data
5987/// To read the data corresponding to an entry number, use TTree::GetEntryWithIndex
5988/// the BuildIndex function has created a table of Long64_t* of sorted values
5989/// corresponding to val = major<<31 + minor;
5990/// The function performs binary search in this sorted table.
5991/// If it finds a pair that matches val, it returns directly the
5992/// index in the table.
5993/// If an entry corresponding to major and minor is not found, the function
5994/// returns the index of the major,minor pair immediately lower than the
5995/// requested value, ie it will return -1 if the pair is lower than
5996/// the first entry in the index.
5997///
5998/// See also GetEntryNumberWithIndex
6001{
6002 if (!fTreeIndex) {
6003 return -1;
6004 }
6005 return fTreeIndex->GetEntryNumberWithBestIndex(major, minor);
6006}
6007
6008////////////////////////////////////////////////////////////////////////////////
6009/// Return entry number corresponding to major and minor number.
6010/// Note that this function returns only the entry number, not the data
6011/// To read the data corresponding to an entry number, use TTree::GetEntryWithIndex
6012/// the BuildIndex function has created a table of Long64_t* of sorted values
6013/// corresponding to val = major<<31 + minor;
6014/// The function performs binary search in this sorted table.
6015/// If it finds a pair that matches val, it returns directly the
6016/// index in the table, otherwise it returns -1.
6017///
6018/// See also GetEntryNumberWithBestIndex
6021{
6022 if (!fTreeIndex) {
6023 return -1;
6024 }
6025 return fTreeIndex->GetEntryNumberWithIndex(major, minor);
6026}
6027
6028////////////////////////////////////////////////////////////////////////////////
6029/// Read entry corresponding to major and minor number.
6030///
6031/// The function returns the total number of bytes read; -1 if entry not found.
6032/// If the Tree has friend trees, the corresponding entry with
6033/// the index values (major,minor) is read. Note that the master Tree
6034/// and its friend may have different entry serial numbers corresponding
6035/// to (major,minor).
6036/// \note See TTreeIndex::GetEntryNumberWithIndex for information about the maximum values accepted for major and minor
6039{
6040 // We already have been visited while recursively looking
6041 // through the friends tree, let's return.
6043 return 0;
6044 }
6045 Long64_t serial = GetEntryNumberWithIndex(major, minor);
6046 if (serial < 0) {
6047 return -1;
6048 }
6049 // create cache if wanted
6050 if (fCacheDoAutoInit)
6052
6053 Int_t i;
6054 Int_t nbytes = 0;
6055 fReadEntry = serial;
6056 TBranch *branch;
6057 Int_t nbranches = fBranches.GetEntriesFast();
6058 Int_t nb;
6059 for (i = 0; i < nbranches; ++i) {
6060 branch = (TBranch*)fBranches.UncheckedAt(i);
6061 nb = branch->GetEntry(serial);
6062 if (nb < 0) return nb;
6063 nbytes += nb;
6064 }
6065 // GetEntry in list of friends
6066 if (!fFriends) return nbytes;
6068 TIter nextf(fFriends);
6069 TFriendElement* fe = nullptr;
6070 while ((fe = (TFriendElement*) nextf())) {
6071 TTree *t = fe->GetTree();
6072 if (t) {
6073 serial = t->GetEntryNumberWithIndex(major,minor);
6074 if (serial <0) return -nbytes;
6075 nb = t->GetEntry(serial);
6076 if (nb < 0) return nb;
6077 nbytes += nb;
6078 }
6079 }
6080 return nbytes;
6081}
6082
6083////////////////////////////////////////////////////////////////////////////////
6084/// Return a pointer to the TTree friend whose name or alias is `friendname`.
6086TTree* TTree::GetFriend(const char *friendname) const
6087{
6088
6089 // We already have been visited while recursively
6090 // looking through the friends tree, let's return.
6092 return nullptr;
6093 }
6094 if (!fFriends) {
6095 return nullptr;
6096 }
6097 TFriendLock lock(const_cast<TTree*>(this), kGetFriend);
6098 TIter nextf(fFriends);
6099 TFriendElement* fe = nullptr;
6100 while ((fe = (TFriendElement*) nextf())) {
6101 if (strcmp(friendname,fe->GetName())==0
6102 || strcmp(friendname,fe->GetTreeName())==0) {
6103 return fe->GetTree();
6104 }
6105 }
6106 // After looking at the first level,
6107 // let's see if it is a friend of friends.
6108 nextf.Reset();
6109 fe = nullptr;
6110 while ((fe = (TFriendElement*) nextf())) {
6111 TTree *res = fe->GetTree()->GetFriend(friendname);
6112 if (res) {
6113 return res;
6114 }
6115 }
6116 return nullptr;
6117}
6118
6119////////////////////////////////////////////////////////////////////////////////
6120/// If the 'tree' is a friend, this method returns its alias name.
6121///
6122/// This alias is an alternate name for the tree.
6123///
6124/// It can be used in conjunction with a branch or leaf name in a TTreeFormula,
6125/// to specify in which particular tree the branch or leaf can be found if
6126/// the friend trees have branches or leaves with the same name as the master
6127/// tree.
6128///
6129/// It can also be used in conjunction with an alias created using
6130/// TTree::SetAlias in a TTreeFormula, e.g.:
6131/// ~~~ {.cpp}
6132/// maintree->Draw("treealias.fPx - treealias.myAlias");
6133/// ~~~
6134/// where fPx is a branch of the friend tree aliased as 'treealias' and 'myAlias'
6135/// was created using TTree::SetAlias on the friend tree.
6136///
6137/// However, note that 'treealias.myAlias' will be expanded literally,
6138/// without remembering that it comes from the aliased friend and thus
6139/// the branch name might not be disambiguated properly, which means
6140/// that you may not be able to take advantage of this feature.
6141///
6143const char *TTree::GetFriendAlias(TTree *tree) const
6144{
6145 if ((tree == this) || (tree == GetTree())) {
6146 return nullptr;
6147 }
6148
6149 // We already have been visited while recursively
6150 // looking through the friends tree, let's return.
6152 return nullptr;
6153 }
6154
6155 // This is a TTree and it does not have any friends, we can return early
6156 if (GetTree() == this && !fFriends)
6157 return nullptr;
6158
6159 TFriendLock lock(const_cast<TTree *>(this), kGetFriendAlias);
6160
6161 auto lookForFriendNameInListOfFriends = [tree](const TList &friends) -> const char * {
6162 for (auto *frEl : ROOT::Detail::TRangeStaticCast<TFriendElement>(friends)) {
6163 auto *frElTree = frEl->GetTree();
6164 // Simplest case: we found a friend which tree is the same as the input tree
6165 if (frElTree == tree)
6166 return frEl->GetName();
6167 // Try again: the friend tree might be actually a TChain
6168 if (frElTree && frElTree->GetTree() == tree)
6169 return frEl->GetName();
6170 }
6171 return nullptr;
6172 };
6173
6174 // First, look for the immediate friends of this tree
6175 if (fFriends) {
6176 const char *friendAlias = lookForFriendNameInListOfFriends(*fFriends);
6177 if (friendAlias)
6178 return friendAlias;
6179 }
6180
6181 // Then, check if this is a TChain and the current tree has friends
6182 // The non-redundant scenario here is that the currently-available
6183 // inner TTree of this TChain has a list of friends which the TChain
6184 // itself doesn't know anything about.
6185 if (const auto *innerListOfFriends = GetTree()->GetListOfFriends();
6186 innerListOfFriends && innerListOfFriends != fFriends) {
6187 const char *friendAlias = lookForFriendNameInListOfFriends(*innerListOfFriends);
6188 if (friendAlias)
6189 return friendAlias;
6190 }
6191
6192 // Recursively look into the list of friends of this tree
6193 if (fFriends) {
6195 const char *friendAlias = frEl->GetTree()->GetFriendAlias(tree);
6196 if (friendAlias)
6197 return friendAlias;
6198 }
6199 }
6200
6201 // Recursively look into the list of friends of the inner tree
6202 if (const auto *innerListOfFriends = GetTree()->GetListOfFriends();
6203 innerListOfFriends && innerListOfFriends != fFriends) {
6204 for (auto *frEl : ROOT::Detail::TRangeStaticCast<TFriendElement>(*innerListOfFriends)) {
6205 const char *friendAlias = frEl->GetTree()->GetFriendAlias(tree);
6206 if (friendAlias)
6207 return friendAlias;
6208 }
6209 }
6210 return nullptr;
6211}
6212
6213////////////////////////////////////////////////////////////////////////////////
6214/// Returns the current set of IO settings
6216{
6217 return fIOFeatures;
6218}
6219
6220////////////////////////////////////////////////////////////////////////////////
6221/// Creates a new iterator that will go through all the leaves on the tree itself and its friend.
6224{
6225 return new TTreeFriendLeafIter(this, dir);
6226}
6228TLeaf *TTree::SearchLeafInListOfLeaves(const char *branchName, const char *leafName)
6229{
6231 if (strcmp(leaf->GetFullName(), leafName) != 0 && strcmp(leaf->GetName(), leafName) != 0)
6232 continue; // leafName does not match GetName() nor GetFullName(), this is not the right leaf
6233 if (branchName) {
6234 // check the branchName is also a match
6235 TBranch *br = leaf->GetBranch();
6236 // if a quick comparison with the branch full name is a match, we are done
6237 if (!strcmp(br->GetFullName(), branchName))
6238 return leaf;
6239 UInt_t nbch = strlen(branchName);
6240 const char* brname = br->GetName();
6241 TBranch *mother = br->GetMother();
6242 if (strncmp(brname, branchName, nbch)) {
6243 if (mother != br) {
6244 const char *mothername = mother->GetName();
6245 UInt_t motherlen = strlen(mothername);
6246 if (!strcmp(mothername, branchName)) {
6247 return leaf;
6248 } else if (nbch > motherlen && strncmp(mothername, branchName, motherlen) == 0 &&
6249 (mothername[motherlen - 1] == '.' || branchName[motherlen] == '.')) {
6250 // 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.
6251 if (strncmp(brname, branchName + motherlen + 1, nbch - motherlen - 1)) {
6252 // No it does not
6253 continue;
6254 } // else we have match so we can proceed.
6255 } else {
6256 // no match
6257 continue;
6258 }
6259 } else {
6260 continue;
6261 }
6262 }
6263 // The start of the branch name is identical to the content
6264 // of 'aname' before the first '/'.
6265 // Let's make sure that it is not longer (we are trying
6266 // to avoid having jet2/value match the branch jet23
6267 if ((strlen(brname) > nbch) && (brname[nbch] != '.') && (brname[nbch] != '[')) {
6268 continue;
6269 }
6270 }
6271 return leaf;
6272 }
6273
6274 return nullptr;
6275}
6277TLeaf *TTree::SearchLeafInListOfFriends(const char *branchName, const char *leafName)
6278{
6279 if (!fFriends) return nullptr;
6280 // The corresponding check is in GetLeaf
6281 TFriendLock lock(this, kGetLeaf);
6282
6284 if (auto *t = frEl->GetTree())
6285 if (auto *leaf = t->GetLeaf(branchName, leafName))
6286 return leaf;
6287
6288 // Second pass in the list of friends when the leaf name is prefixed by the tree name
6289 TString strippedArg;
6291 TTree *t = frEl->GetTree();
6292 if (!t) continue;
6293 const char *subLeafName = strstr(leafName, frEl->GetName());
6294 if (subLeafName != leafName)
6295 continue;
6296 Int_t l = strlen(frEl->GetName());
6297 subLeafName += l;
6298 if (*subLeafName != '.')
6299 continue;
6300 subLeafName++;
6301 strippedArg += subLeafName;
6302 if (auto *leaf = t->GetLeaf(branchName, subLeafName))
6303 return leaf;
6304 }
6305
6306 return nullptr;
6307}
6308
6309////////////////////////////////////////////////////////////////////////////////
6310/// Searches in this tree and any of its friends for a leaf named \p leafname in branch \p branchname , returns first
6311/// match or nullptr if no match.
6312///
6313/// Search order:
6314///
6315/// 1. Look for a \p branchname match (via FindBranch(branchname)):
6316/// a. In the list of branches of this tree
6317/// b. Recursively in nested branches of each branch of this tree
6318/// c. In the friends of this tree
6319/// 2. Look for matching \p branchname and \p leafname in list of leaves of this tree
6320/// 3. Look for matching \p branchname and \p leafname in friends of this tree (eventually calling GetLeaf on each
6321/// friend)
6322///
6323/// \note \p branchname can be an empty string, in which case the function will return the first leaf with matching
6324/// \p leafname in any branch of this tree or any of its friends following the search order above.
6325///
6326/// \note \p leafname can contain the name of a friend tree with the syntax: `friend_dir_and_tree.full_leaf_name`. In
6327/// particular, `friend_dir_and_tree` can be of the form `TDirectoryName/TreeName`.
6328TLeaf* TTree::GetLeaf(const char* branchname, const char *leafname)
6329{
6330 if (leafname == nullptr) return nullptr;
6331
6332 // We already have been visited while recursively looking
6333 // through the friends tree, let return
6335 return nullptr;
6336 }
6337
6338 if (auto *br = FindBranch(branchname))
6339 if (auto leaf = br->GetLeaf(leafname))
6340 return leaf;
6341
6342 if (auto *leaf = SearchLeafInListOfLeaves(branchname, leafname))
6343 return leaf;
6344
6345 if (auto *leaf = SearchLeafInListOfFriends(branchname, leafname))
6346 return leaf;
6347
6348 return nullptr;
6349}
6350
6351////////////////////////////////////////////////////////////////////////////////
6352/// Searches in this tree and any of its friends for a leaf named \p leafname , returns first leaf matching in any
6353/// branch.
6354///
6355/// See TTree::GetLeaf(const char* branchname, const char *leafname) for a description of the search order.
6356///
6357/// \note \p name may be in the form `branch/leaf`
6359TLeaf* TTree::GetLeaf(const char *name)
6360{
6361 // Return nullptr if name is invalid or if we have
6362 // already been visited while searching friend trees
6363 if (!name || (kGetLeaf & fFriendLockStatus))
6364 return nullptr;
6365
6366 std::string path(name);
6367 const auto sep = path.find_last_of('/');
6368 if (sep != std::string::npos)
6369 return GetLeaf(path.substr(0, sep).c_str(), name + sep + 1);
6370
6371 return GetLeaf(nullptr, name);
6372}
6373
6374namespace {
6375
6376////////////////////////////////////////////////////////////////////////////////
6377/// \brief Helper detecting *any* file transition of a tree dataset
6378///
6379/// This is a generic helper, works if the dataset is a TTree or a TChain, and
6380/// transitively detects transitions in friends.
6381///
6382/// Comparing `TChain::GetTreeNumber()` before and after a call to
6383/// `TChain::LoadTree` only detects that the chain itself switched to another of
6384/// its own sub-trees. It does *not* detect that one of the (possibly indirect)
6385/// friends of the chain switched to a new file: in that case the cached
6386/// TLeaf/TBranch pointers become dangling even though the tree number of the
6387/// chain is unchanged.
6388///
6389/// `TChain::LoadTree` (both when the chain itself moves to a new tree and, via
6390/// `TChain::RefreshFriendAddresses`, when only a friend was updated) calls
6391/// `fNotify->Notify()`. Subscribing to that notification is therefore the
6392/// reliable way to know that anything in the friend graph moved.
6393///
6394/// This derives directly from TNotifyLinkBase rather than using TNotifyLink<T>
6395/// because the latter would require a dictionary for the instantiation.
6396///
6397/// We could also use
6398/// ```
6399/// struct TLeafRefresher {
6400/// bool fDirty = true;
6401/// bool Notify() { fDirty = true; return true; }
6402/// };
6403/// ```
6404/// declared in TChain.h or InternalTreeUtils.hxx and genereate a dictionary for
6405/// TNotifyLink<TLeafRefresher>.
6406class FileTransitionDetector final : public TNotifyLinkBase {
6407 /// Set to true initially so that the very first iteration performs the lookup.
6408 bool fChanged = true;
6409 TTree &fChain;
6410
6411public:
6412 FileTransitionDetector(TTree &chain) : fChain(chain) { PrependLink(fChain); }
6413
6414 ~FileTransitionDetector() override { RemoveLink(fChain); }
6415 FileTransitionDetector(const FileTransitionDetector &) = delete;
6416 FileTransitionDetector &operator=(const FileTransitionDetector &) = delete;
6417 FileTransitionDetector(FileTransitionDetector &&) = delete;
6418 FileTransitionDetector &operator=(FileTransitionDetector &&) = delete;
6419
6420 /// Must return true: returning false would make TChain::LoadTree fail with -6.
6421 Bool_t Notify() override
6422 {
6423 fChanged = true;
6424 // Propagate to the rest of the list of subscribers, as TNotifyLink does.
6425 if (fNext)
6426 return fNext->Notify();
6427 return true;
6428 }
6429
6430 /// Returns true (once) if the chain or any of its direct or indirect friends
6431 /// switched to a new tree since the last call.
6432 bool CheckAndReset()
6433 {
6434 bool changed = fChanged;
6435 fChanged = false;
6436 return changed;
6437 }
6438};
6439} // anonymous namespace
6440
6441////////////////////////////////////////////////////////////////////////////////
6442/// Computes the extremum (minimum or maximum) for the input column name
6443///
6444/// It takes into account the following situations:
6445///
6446/// * The dataset is a TTree and contains the input column
6447/// * The dataset is a TChain and contains the input column, in which case the methods detect file switching and update
6448/// the leaf pointer correctly.
6449/// * The dataset is a TChain, contains the input column, but some files miss it, in which case the methods skip the
6450/// entries from those files.
6451/// * The dataset has a friend TTree which contains the input column
6452/// * The dataset is a TChain and has a friend TChain which contains the input column, in which case the methods detect
6453/// file switching on the friend and update the leaf pointer correctly.
6454/// * The dataset is a TChain and has a friend TChain. The input column is partially available in either the main or the
6455/// friend chain. This can happen for example if the main chain has some files missing the input column and the user
6456/// knowingly injects the input column in the files of the friend chain. In this case, the methods detect file switching
6457/// at the boundary between files of the main chain, but also detect if there are file switches in the friend chain.
6458/// Notably, the entries must still be overall aligned between the main chain and the friend one.
6459double TTree::ComputeExtremum(const char *columname, double errVal, bool (*cmp)(double, double))
6460{
6461 // Ensure the TTree cursor is brought back to the current entry after computing the value
6462 struct CurrentEntryRAII {
6463
6464 Long64_t fCurrentEntry;
6465 TTree &fTree;
6466
6467 CurrentEntryRAII(TTree &tree) : fCurrentEntry(tree.GetReadEntry()), fTree(tree) {}
6468
6469 ~CurrentEntryRAII() { fTree.LoadTree(fCurrentEntry); }
6470 } raii{*this};
6471
6472 // Initial lookup of the leaf name, this will find it whether it's in the
6473 // current tree or in any of its friends
6474 TLeaf *leaf = GetLeaf(columname);
6475 if (!leaf) {
6476 return 0;
6477 }
6478 TBranch *branch = leaf->GetBranch();
6479 assert(branch); // leaf without a branch is not allowed by construction
6480
6481 // create cache if wanted
6482 if (fCacheDoAutoInit)
6484
6485 FileTransitionDetector fileTransition{*this};
6486 double extremum{errVal};
6487 for (Long64_t i = 0; i < fEntries; ++i) {
6488 const auto entryNumber = GetEntryNumber(i);
6489 if (entryNumber < 0) break;
6490 const auto localEntryNumber = LoadTree(entryNumber);
6491 if (localEntryNumber < 0)
6492 break;
6493
6494 // At every entry, we check if the processing has triggered a switch to
6495 // a new file. We detect both a switch of the current tree in the chain
6496 // (if this tree is a TChain) as well as a switch in any of its direct
6497 // and indirect friends (if they are also a TChain)
6498 if (fileTransition.CheckAndReset()) {
6499 branch = nullptr;
6500 leaf = GetLeaf(columname);
6501 if (leaf) {
6502 branch = leaf->GetBranch();
6503 assert(branch); // leaf without a branch is not allowed by construction
6504 }
6505 }
6506
6507 // We accept that the leaf may not be present in one or more files in case
6508 // it was found in a chain, we just continue processing the next entry
6509 if (!leaf)
6510 continue;
6511
6512 // If the branch belongs to a friend, the local entry number of the friend
6513 // may differ from the one of the chain (e.g. when the friend is indexed).
6514 // The owning TTree has already been positioned by TChain::LoadTree, so
6515 // its read entry is the correct one to use.
6516 auto *owningTree = branch->GetTree();
6517 branch->GetEntry(owningTree->GetReadEntry());
6518
6519 auto leafLen{leaf->GetLen()};
6520 for (decltype(leafLen) j = 0; j < leafLen; ++j) {
6521 auto val = leaf->GetValue(j);
6522 if (cmp(val, extremum)) {
6523 extremum = val;
6524 }
6525 }
6526 }
6527
6528 return extremum;
6529}
6530
6531////////////////////////////////////////////////////////////////////////////////
6532/// Return maximum of column with name columname.
6533/// if the Tree has an associated TEventList or TEntryList, the maximum
6534/// is computed for the entries in this list.
6536Double_t TTree::GetMaximum(const char *columname)
6537{
6538 return ComputeExtremum(columname, std::numeric_limits<double>::lowest(), [](double a, double b) { return a > b; });
6539}
6540
6541////////////////////////////////////////////////////////////////////////////////
6542/// Static function which returns the tree file size limit in bytes.
6547}
6548
6549////////////////////////////////////////////////////////////////////////////////
6550/// Return minimum of column with name columname.
6551/// if the Tree has an associated TEventList or TEntryList, the minimum
6552/// is computed for the entries in this list.
6554Double_t TTree::GetMinimum(const char* columname)
6555{
6556 return ComputeExtremum(columname, std::numeric_limits<double>::max(), [](double a, double b) { return a < b; });
6557}
6558
6559////////////////////////////////////////////////////////////////////////////////
6560/// Load the TTreePlayer (if not already done).
6563{
6564 if (fPlayer) {
6565 return fPlayer;
6566 }
6568 return fPlayer;
6569}
6570
6571////////////////////////////////////////////////////////////////////////////////
6572/// Find and return the TTreeCache registered with the file and which may
6573/// contain branches for us.
6576{
6577 TTreeCache *pe = dynamic_cast<TTreeCache*>(file->GetCacheRead(GetTree()));
6578 if (pe && pe->GetTree() != GetTree())
6579 pe = nullptr;
6580 return pe;
6581}
6582
6583////////////////////////////////////////////////////////////////////////////////
6584/// Find and return the TTreeCache registered with the file and which may
6585/// contain branches for us. If create is true and there is no cache
6586/// a new cache is created with default size.
6588TTreeCache *TTree::GetReadCache(TFile *file, bool create)
6589{
6590 TTreeCache *pe = GetReadCache(file);
6591 if (create && !pe) {
6592 if (fCacheDoAutoInit)
6593 SetCacheSizeAux(true, -1);
6594 pe = dynamic_cast<TTreeCache*>(file->GetCacheRead(GetTree()));
6595 if (pe && pe->GetTree() != GetTree()) pe = nullptr;
6596 }
6597 return pe;
6598}
6599
6600////////////////////////////////////////////////////////////////////////////////
6601/// Return a pointer to the list containing user objects associated to this tree.
6602///
6603/// The list is automatically created if it does not exist.
6604///
6605/// WARNING: By default the TTree destructor will delete all objects added
6606/// to this list. If you do not want these objects to be deleted,
6607/// call:
6608///
6609/// mytree->GetUserInfo()->Clear();
6610///
6611/// before deleting the tree.
6614{
6615 if (!fUserInfo) {
6616 fUserInfo = new TList();
6617 fUserInfo->SetName("UserInfo");
6618 }
6619 return fUserInfo;
6620}
6621
6622////////////////////////////////////////////////////////////////////////////////
6623/// Appends the cluster range information stored in 'fromtree' to this tree,
6624/// including the value of fAutoFlush.
6625///
6626/// This is used when doing a fast cloning (by TTreeCloner).
6627/// See also fAutoFlush and fAutoSave if needed.
6629void TTree::ImportClusterRanges(TTree *fromtree)
6630{
6631 Long64_t autoflush = fromtree->GetAutoFlush();
6632 if (fromtree->fNClusterRange == 0 && fromtree->fAutoFlush == fAutoFlush) {
6633 // nothing to do
6634 } else if (fNClusterRange || fromtree->fNClusterRange) {
6635 Int_t newsize = fNClusterRange + 1 + fromtree->fNClusterRange;
6636 if (newsize > fMaxClusterRange) {
6637 if (fMaxClusterRange) {
6639 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
6641 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
6642 fMaxClusterRange = newsize;
6643 } else {
6644 fMaxClusterRange = newsize;
6647 }
6648 }
6649 if (fEntries) {
6653 }
6654 for (Int_t i = 0 ; i < fromtree->fNClusterRange; ++i) {
6658 }
6659 fAutoFlush = autoflush;
6660 } else {
6661 SetAutoFlush( autoflush );
6662 }
6663 Long64_t autosave = GetAutoSave();
6664 if (autoflush > 0 && autosave > 0) {
6665 SetAutoSave( autoflush*(autosave/autoflush) );
6666 }
6667}
6668
6669////////////////////////////////////////////////////////////////////////////////
6670/// Keep a maximum of fMaxEntries in memory.
6673{
6675 Long64_t maxEntries = fMaxEntries - (fMaxEntries / 10);
6676 for (Int_t i = 0; i < nb; ++i) {
6677 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
6678 branch->KeepCircular(maxEntries);
6679 }
6680 if (fNClusterRange) {
6681 Long64_t entriesOffset = fEntries - maxEntries;
6682 Int_t oldsize = fNClusterRange;
6683 for(Int_t i = 0, j = 0; j < oldsize; ++j) {
6684 if (fClusterRangeEnd[j] > entriesOffset) {
6685 fClusterRangeEnd[i] = fClusterRangeEnd[j] - entriesOffset;
6686 ++i;
6687 } else {
6689 }
6690 }
6691 }
6692 fEntries = maxEntries;
6693 fReadEntry = -1;
6694}
6695
6696////////////////////////////////////////////////////////////////////////////////
6697/// Read in memory all baskets from all branches up to the limit of maxmemory bytes.
6698///
6699/// If maxmemory is non null and positive SetMaxVirtualSize is called
6700/// with this value. Default for maxmemory is 2000000000 (2 Gigabytes).
6701/// The function returns the total number of baskets read into memory
6702/// if negative an error occurred while loading the branches.
6703/// This method may be called to force branch baskets in memory
6704/// when random access to branch entries is required.
6705/// If random access to only a few branches is required, you should
6706/// call directly TBranch::LoadBaskets.
6709{
6710 if (maxmemory > 0) SetMaxVirtualSize(maxmemory);
6711
6712 TIter next(GetListOfLeaves());
6713 TLeaf *leaf;
6714 Int_t nimported = 0;
6715 while ((leaf=(TLeaf*)next())) {
6716 nimported += leaf->GetBranch()->LoadBaskets();//break;
6717 }
6718 return nimported;
6719}
6720
6721////////////////////////////////////////////////////////////////////////////////
6722/// Set current entry.
6723///
6724/// Returns -2 if entry does not exist (just as TChain::LoadTree()).
6725/// Returns -6 if an error occurs in the notification callback (just as TChain::LoadTree()).
6726///
6727/// Calls fNotify->Notify() (if fNotify is not null) when starting the processing of a new tree.
6728///
6729/// \note This function is overloaded in TChain.
6731{
6732 // We have already been visited while recursively looking
6733 // through the friend trees, let's return
6735 // We need to return a negative value to avoid a circular list of friends
6736 // to think that there is always an entry somewhere in the list.
6737 return -1;
6738 }
6739
6740 // create cache if wanted
6741 if (fCacheDoAutoInit && entry >=0)
6743
6744 if (fNotify) {
6745 if (fReadEntry < 0) {
6746 fNotify->Notify();
6747 }
6748 }
6749 fReadEntry = entry;
6750
6751 bool friendHasEntry = false;
6752 if (fFriends) {
6753 // Set current entry in friends as well.
6754 //
6755 // An alternative would move this code to each of the
6756 // functions calling LoadTree (and to overload a few more).
6757 bool needUpdate = false;
6758 {
6759 // This scope is need to insure the lock is released at the right time
6760 TIter nextf(fFriends);
6761 TFriendLock lock(this, kLoadTree);
6762 TFriendElement* fe = nullptr;
6763 while ((fe = (TFriendElement*) nextf())) {
6765 // This friend element was added by the chain that owns this
6766 // tree, the chain will deal with loading the correct entry.
6767 continue;
6768 }
6769 TTree* friendTree = fe->GetTree();
6770 if (friendTree) {
6771 if (friendTree->LoadTreeFriend(entry, this) >= 0) {
6772 friendHasEntry = true;
6773 }
6774 }
6775 if (fe->IsUpdated()) {
6776 needUpdate = true;
6777 fe->ResetUpdated();
6778 }
6779 } // for each friend
6780 }
6781 if (needUpdate) {
6782 //update list of leaves in all TTreeFormula of the TTreePlayer (if any)
6783 if (fPlayer) {
6785 }
6786 //Notify user if requested
6787 if (fNotify) {
6788 if(!fNotify->Notify()) return -6;
6789 }
6790 // We cannot know a priori if the branch(es) of the friend TChain(s) that were just
6791 // updated were supposed to be connected to possibly a TChainElement of another chain
6792 // that has befriended this TTree (i.e., one of the "external friends"). Thus, we
6793 // forward the notification that one or more friend trees were updated to the friends
6794 // of this TTree.
6795 if (fExternalFriends)
6797 external_fe->MarkUpdated();
6798 }
6799 }
6800
6801 if ((fReadEntry >= fEntries) && !friendHasEntry) {
6802 fReadEntry = -1;
6803 return -2;
6804 }
6805 return fReadEntry;
6806}
6807
6808////////////////////////////////////////////////////////////////////////////////
6809/// Load entry on behalf of our master tree, we may use an index.
6810///
6811/// Called by LoadTree() when the masterTree looks for the entry
6812/// number in a friend tree (us) corresponding to the passed entry
6813/// number in the masterTree.
6814///
6815/// If we have no index, our entry number and the masterTree entry
6816/// number are the same.
6817///
6818/// If we *do* have an index, we must find the (major, minor) value pair
6819/// in masterTree to locate our corresponding entry.
6820///
6822Long64_t TTree::LoadTreeFriend(Long64_t entry, TTree* masterTree)
6823{
6824 if (!fTreeIndex) {
6825 return LoadTree(entry);
6826 }
6827 return LoadTree(fTreeIndex->GetEntryNumberFriend(masterTree));
6828}
6829
6830////////////////////////////////////////////////////////////////////////////////
6831/// Generate a skeleton analysis class for this tree.
6832///
6833/// The following files are produced: classname.h and classname.C.
6834/// If classname is 0, classname will be called "nameoftree".
6835///
6836/// The generated code in classname.h includes the following:
6837///
6838/// - Identification of the original tree and the input file name.
6839/// - Definition of an analysis class (data members and member functions).
6840/// - The following member functions:
6841/// - constructor (by default opening the tree file),
6842/// - GetEntry(Long64_t entry),
6843/// - Init(TTree* tree) to initialize a new TTree,
6844/// - Show(Long64_t entry) to read and dump entry.
6845///
6846/// The generated code in classname.C includes only the main
6847/// analysis function Loop.
6848///
6849/// To use this function:
6850///
6851/// - Open your tree file (eg: TFile f("myfile.root");)
6852/// - T->MakeClass("MyClass");
6853///
6854/// where T is the name of the TTree in file myfile.root,
6855/// and MyClass.h, MyClass.C the name of the files created by this function.
6856/// In a ROOT session, you can do:
6857/// ~~~ {.cpp}
6858/// root > .L MyClass.C
6859/// root > MyClass* t = new MyClass;
6860/// root > t->GetEntry(12); // Fill data members of t with entry number 12.
6861/// root > t->Show(); // Show values of entry 12.
6862/// root > t->Show(16); // Read and show values of entry 16.
6863/// root > t->Loop(); // Loop on all entries.
6864/// ~~~
6865/// NOTE: Do not use the code generated for a single TTree which is part
6866/// of a TChain to process that entire TChain. The maximum dimensions
6867/// calculated for arrays on the basis of a single TTree from the TChain
6868/// might be (will be!) too small when processing all of the TTrees in
6869/// the TChain. You must use myChain.MakeClass() to generate the code,
6870/// not myTree.MakeClass(...).
6872Int_t TTree::MakeClass(const char* classname, Option_t* option)
6873{
6874 GetPlayer();
6875 if (!fPlayer) {
6876 return 0;
6877 }
6878 return fPlayer->MakeClass(classname, option);
6879}
6880
6881////////////////////////////////////////////////////////////////////////////////
6882/// Generate a skeleton function for this tree.
6883///
6884/// The function code is written on filename.
6885/// If filename is 0, filename will be called nameoftree.C
6886///
6887/// The generated code includes the following:
6888/// - Identification of the original Tree and Input file name,
6889/// - Opening the Tree file,
6890/// - Declaration of Tree variables,
6891/// - Setting of branches addresses,
6892/// - A skeleton for the entry loop.
6893///
6894/// To use this function:
6895///
6896/// - Open your Tree file (eg: TFile f("myfile.root");)
6897/// - T->MakeCode("MyAnalysis.C");
6898///
6899/// where T is the name of the TTree in file myfile.root
6900/// and MyAnalysis.C the name of the file created by this function.
6901///
6902/// NOTE: Since the implementation of this function, a new and better
6903/// function TTree::MakeClass() has been developed.
6905Int_t TTree::MakeCode(const char* filename)
6906{
6907 Warning("MakeCode", "MakeCode is obsolete. Use MakeClass or MakeSelector instead");
6908
6909 GetPlayer();
6910 if (!fPlayer) return 0;
6911 return fPlayer->MakeCode(filename);
6912}
6913
6914////////////////////////////////////////////////////////////////////////////////
6915/// Generate a skeleton analysis class for this Tree using TBranchProxy.
6916///
6917/// TBranchProxy is the base of a class hierarchy implementing an
6918/// indirect access to the content of the branches of a TTree.
6919///
6920/// "proxyClassname" is expected to be of the form:
6921/// ~~~ {.cpp}
6922/// [path/]fileprefix
6923/// ~~~
6924/// The skeleton will then be generated in the file:
6925/// ~~~ {.cpp}
6926/// fileprefix.h
6927/// ~~~
6928/// located in the current directory or in 'path/' if it is specified.
6929/// The class generated will be named 'fileprefix'
6930///
6931/// "macrofilename" and optionally "cutfilename" are expected to point
6932/// to source files which will be included by the generated skeleton.
6933/// Method of the same name as the file(minus the extension and path)
6934/// will be called by the generated skeleton's Process method as follow:
6935/// ~~~ {.cpp}
6936/// [if (cutfilename())] htemp->Fill(macrofilename());
6937/// ~~~
6938/// "option" can be used select some of the optional features during
6939/// the code generation. The possible options are:
6940///
6941/// - nohist : indicates that the generated ProcessFill should not fill the histogram.
6942///
6943/// 'maxUnrolling' controls how deep in the class hierarchy does the
6944/// system 'unroll' classes that are not split. Unrolling a class
6945/// allows direct access to its data members (this emulates the behavior
6946/// of TTreeFormula).
6947///
6948/// The main features of this skeleton are:
6949///
6950/// * on-demand loading of branches
6951/// * ability to use the 'branchname' as if it was a data member
6952/// * protection against array out-of-bounds errors
6953/// * ability to use the branch data as an object (when the user code is available)
6954///
6955/// For example with Event.root, if
6956/// ~~~ {.cpp}
6957/// Double_t somePx = fTracks.fPx[2];
6958/// ~~~
6959/// is executed by one of the method of the skeleton,
6960/// somePx will updated with the current value of fPx of the 3rd track.
6961///
6962/// Both macrofilename and the optional cutfilename are expected to be
6963/// the name of source files which contain at least a free standing
6964/// function with the signature:
6965/// ~~~ {.cpp}
6966/// x_t macrofilename(); // i.e function with the same name as the file
6967/// ~~~
6968/// and
6969/// ~~~ {.cpp}
6970/// y_t cutfilename(); // i.e function with the same name as the file
6971/// ~~~
6972/// x_t and y_t needs to be types that can convert respectively to a double
6973/// and a bool (because the skeleton uses:
6974///
6975/// if (cutfilename()) htemp->Fill(macrofilename());
6976///
6977/// These two functions are run in a context such that the branch names are
6978/// available as local variables of the correct (read-only) type.
6979///
6980/// Note that if you use the same 'variable' twice, it is more efficient
6981/// to 'cache' the value. For example:
6982/// ~~~ {.cpp}
6983/// Int_t n = fEventNumber; // Read fEventNumber
6984/// if (n<10 || n>10) { ... }
6985/// ~~~
6986/// is more efficient than
6987/// ~~~ {.cpp}
6988/// if (fEventNumber<10 || fEventNumber>10)
6989/// ~~~
6990/// Also, optionally, the generated selector will also call methods named
6991/// macrofilename_methodname in each of 6 main selector methods if the method
6992/// macrofilename_methodname exist (Where macrofilename is stripped of its
6993/// extension).
6994///
6995/// Concretely, with the script named h1analysisProxy.C,
6996///
6997/// - The method calls the method (if it exist)
6998/// - Begin -> void h1analysisProxy_Begin(TTree*);
6999/// - SlaveBegin -> void h1analysisProxy_SlaveBegin(TTree*);
7000/// - Notify -> bool h1analysisProxy_Notify();
7001/// - Process -> bool h1analysisProxy_Process(Long64_t);
7002/// - SlaveTerminate -> void h1analysisProxy_SlaveTerminate();
7003/// - Terminate -> void h1analysisProxy_Terminate();
7004///
7005/// If a file name macrofilename.h (or .hh, .hpp, .hxx, .hPP, .hXX) exist
7006/// it is included before the declaration of the proxy class. This can
7007/// be used in particular to insure that the include files needed by
7008/// the macro file are properly loaded.
7009///
7010/// The default histogram is accessible via the variable named 'htemp'.
7011///
7012/// If the library of the classes describing the data in the branch is
7013/// loaded, the skeleton will add the needed `include` statements and
7014/// give the ability to access the object stored in the branches.
7015///
7016/// To draw px using the file hsimple.root (generated by the
7017/// hsimple.C tutorial), we need a file named hsimple.cxx:
7018/// ~~~ {.cpp}
7019/// double hsimple() {
7020/// return px;
7021/// }
7022/// ~~~
7023/// MakeProxy can then be used indirectly via the TTree::Draw interface
7024/// as follow:
7025/// ~~~ {.cpp}
7026/// new TFile("hsimple.root")
7027/// ntuple->Draw("hsimple.cxx");
7028/// ~~~
7029/// A more complete example is available in the tutorials directory:
7030/// h1analysisProxy.cxx , h1analysProxy.h and h1analysisProxyCut.C
7031/// which reimplement the selector found in h1analysis.C
7033Int_t TTree::MakeProxy(const char* proxyClassname, const char* macrofilename, const char* cutfilename, const char* option, Int_t maxUnrolling)
7034{
7035 GetPlayer();
7036 if (!fPlayer) return 0;
7037 return fPlayer->MakeProxy(proxyClassname,macrofilename,cutfilename,option,maxUnrolling);
7038}
7039
7040////////////////////////////////////////////////////////////////////////////////
7041/// Generate skeleton selector class for this tree.
7042///
7043/// The following files are produced: selector.h and selector.C.
7044/// If selector is 0, the selector will be called "nameoftree".
7045/// The option can be used to specify the branches that will have a data member.
7046/// - If option is "=legacy", a pre-ROOT6 selector will be generated (data
7047/// members and branch pointers instead of TTreeReaders).
7048/// - If option is empty, readers will be generated for each leaf.
7049/// - If option is "@", readers will be generated for the topmost branches.
7050/// - Individual branches can also be picked by their name:
7051/// - "X" generates readers for leaves of X.
7052/// - "@X" generates a reader for X as a whole.
7053/// - "@X;Y" generates a reader for X as a whole and also readers for the
7054/// leaves of Y.
7055/// - For further examples see the figure below.
7056///
7057/// \image html ttree_makeselector_option_examples.png
7058///
7059/// The generated code in selector.h includes the following:
7060/// - Identification of the original Tree and Input file name
7061/// - Definition of selector class (data and functions)
7062/// - The following class functions:
7063/// - constructor and destructor
7064/// - void Begin(TTree *tree)
7065/// - void SlaveBegin(TTree *tree)
7066/// - void Init(TTree *tree)
7067/// - bool Notify()
7068/// - bool Process(Long64_t entry)
7069/// - void Terminate()
7070/// - void SlaveTerminate()
7071///
7072/// The class selector derives from TSelector.
7073/// The generated code in selector.C includes empty functions defined above.
7074///
7075/// To use this function:
7076///
7077/// - connect your Tree file (eg: `TFile f("myfile.root");`)
7078/// - `T->MakeSelector("myselect");`
7079///
7080/// where T is the name of the Tree in file myfile.root
7081/// and myselect.h, myselect.C the name of the files created by this function.
7082/// In a ROOT session, you can do:
7083/// ~~~ {.cpp}
7084/// root > T->Process("myselect.C")
7085/// ~~~
7087Int_t TTree::MakeSelector(const char* selector, Option_t* option)
7088{
7089 TString opt(option);
7090 if(opt.EqualTo("=legacy", TString::ECaseCompare::kIgnoreCase)) {
7091 return MakeClass(selector, "selector");
7092 } else {
7093 GetPlayer();
7094 if (!fPlayer) return 0;
7095 return fPlayer->MakeReader(selector, option);
7096 }
7097}
7098
7099////////////////////////////////////////////////////////////////////////////////
7100/// Check if adding nbytes to memory we are still below MaxVirtualsize.
7102bool TTree::MemoryFull(Int_t nbytes)
7103{
7104 if ((fTotalBuffers + nbytes) < fMaxVirtualSize) {
7105 return false;
7106 }
7107 return true;
7108}
7109
7110////////////////////////////////////////////////////////////////////////////////
7111/// Static function merging the trees in the TList into a new tree.
7112///
7113/// Trees in the list can be memory or disk-resident trees.
7114/// The new tree is created in the current directory (memory if gROOT).
7115/// Trees with no branches will be skipped, the branch structure
7116/// will be taken from the first non-zero-branch Tree of {li}
7118TTree* TTree::MergeTrees(TList* li, Option_t* options)
7119{
7120 if (!li) return nullptr;
7121 TIter next(li);
7122 TTree *newtree = nullptr;
7123 TObject *obj;
7124
7125 while ((obj=next())) {
7126 if (!obj->InheritsFrom(TTree::Class())) continue;
7127 TTree *tree = (TTree*)obj;
7128 if (tree->GetListOfBranches()->IsEmpty()) {
7129 if (gDebug > 2) {
7130 tree->Warning("MergeTrees","TTree %s has no branches, skipping.", tree->GetName());
7131 }
7132 continue; // Completely ignore the empty trees.
7133 }
7134 Long64_t nentries = tree->GetEntries();
7135 if (newtree && nentries == 0)
7136 continue; // If we already have the structure and we have no entry, save time and skip
7137 if (!newtree) {
7138 newtree = (TTree*)tree->CloneTree(-1, options);
7139 if (!newtree) continue;
7140
7141 // Once the cloning is done, separate the trees,
7142 // to avoid as many side-effects as possible
7143 // The list of clones is guaranteed to exist since we
7144 // just cloned the tree.
7145 tree->GetListOfClones()->Remove(newtree);
7146 tree->ResetBranchAddresses();
7147 newtree->ResetBranchAddresses();
7148 continue;
7149 }
7150 if (nentries == 0)
7151 continue;
7152 newtree->CopyEntries(tree, -1, options, true);
7153 }
7154 if (newtree && newtree->GetTreeIndex()) {
7155 newtree->GetTreeIndex()->Append(nullptr,false); // Force the sorting
7156 }
7157 return newtree;
7158}
7159
7160////////////////////////////////////////////////////////////////////////////////
7161/// Merge the trees in the TList into this tree.
7162///
7163/// Returns the total number of entries in the merged tree.
7164/// Trees with no branches will be skipped, the branch structure
7165/// will be taken from the first non-zero-branch Tree of {this+li}
7168{
7169 if (fBranches.IsEmpty()) {
7170 if (!li || li->IsEmpty())
7171 return 0; // Nothing to do ....
7172 // Let's find the first non-empty
7173 TIter next(li);
7174 TTree *tree;
7175 while ((tree = (TTree *)next())) {
7176 if (tree == this || tree->GetListOfBranches()->IsEmpty()) {
7177 if (gDebug > 2) {
7178 Warning("Merge","TTree %s has no branches, skipping.", tree->GetName());
7179 }
7180 continue;
7181 }
7182 // We could come from a list made up of different names, the first one still wins
7183 tree->SetName(this->GetName());
7184 auto prevEntries = tree->GetEntries();
7185 auto result = tree->Merge(li, options);
7186 if (result != prevEntries) {
7187 // If there is no additional entries, the first write was enough.
7188 tree->Write();
7189 }
7190 // Make sure things are really written out to disk before attempting any reading.
7191 if (tree->GetCurrentFile()) {
7192 tree->GetCurrentFile()->Flush();
7193 // Read back the complete info in this TTree, so that caller does not
7194 // inadvertently write the empty tree.
7195 tree->GetDirectory()->ReadTObject(this, this->GetName());
7196 }
7197 return result;
7198 }
7199 return 0; // All trees have empty branches
7200 }
7201 if (!li) return 0;
7202 Long64_t storeAutoSave = fAutoSave;
7203 // Disable the autosave as the TFileMerge keeps a list of key and deleting the underlying
7204 // key would invalidate its iteration (or require costly measure to not use the deleted keys).
7205 // Also since this is part of a merging operation, the output file is not as precious as in
7206 // the general case since the input file should still be around.
7207 fAutoSave = 0;
7208 TIter next(li);
7209 TTree *tree;
7210 while ((tree = (TTree*)next())) {
7211 if (tree==this) continue;
7212 if (!tree->InheritsFrom(TTree::Class())) {
7213 Error("Add","Attempt to add object of class: %s to a %s", tree->ClassName(), ClassName());
7214 fAutoSave = storeAutoSave;
7215 return -1;
7216 }
7217
7218 Long64_t nentries = tree->GetEntries();
7219 if (nentries == 0) continue;
7220
7221 CopyEntries(tree, -1, options, true);
7222 }
7223 fAutoSave = storeAutoSave;
7224 return GetEntries();
7225}
7226
7227////////////////////////////////////////////////////////////////////////////////
7228/// Merge the trees in the TList into this tree.
7229/// If info->fIsFirst is true, first we clone this TTree info the directory
7230/// info->fOutputDirectory and then overlay the new TTree information onto
7231/// this TTree object (so that this TTree object is now the appropriate to
7232/// use for further merging).
7233/// Trees with no branches will be skipped, the branch structure
7234/// will be taken from the first non-zero-branch Tree of {this+li}
7235///
7236/// Returns the total number of entries in the merged tree.
7239{
7240 if (fBranches.IsEmpty()) {
7241 if (!li || li->IsEmpty())
7242 return 0; // Nothing to do ....
7243 // Let's find the first non-empty
7244 TIter next(li);
7245 TTree *tree;
7246 while ((tree = (TTree *)next())) {
7247 if (tree == this || tree->GetListOfBranches()->IsEmpty()) {
7248 if (gDebug > 2) {
7249 Warning("Merge","TTree %s has no branches, skipping.", tree->GetName());
7250 }
7251 continue;
7252 }
7253 // We could come from a list made up of different names, the first one still wins
7254 tree->SetName(this->GetName());
7255 auto prevEntries = tree->GetEntries();
7256 auto result = tree->Merge(li, info);
7257 if (result != prevEntries) {
7258 // If there is no additional entries, the first write was enough.
7259 tree->Write();
7260 }
7261 // Make sure things are really written out to disk before attempting any reading.
7262 info->fOutputDirectory->GetFile()->Flush();
7263 // Read back the complete info in this TTree, so that TFileMerge does not
7264 // inadvertently write the empty tree.
7265 info->fOutputDirectory->ReadTObject(this, this->GetName());
7266 return result;
7267 }
7268 return 0; // All trees have empty branches
7269 }
7270 const char *options = info ? info->fOptions.Data() : "";
7271 if (info && info->fIsFirst && info->fOutputDirectory && info->fOutputDirectory->GetFile() != GetCurrentFile()) {
7272 if (GetCurrentFile() == nullptr) {
7273 // In memory TTree, all we need to do is ... write it.
7276 fDirectory->WriteTObject(this);
7277 } else if (info->fOptions.Contains("fast")) {
7279 } else {
7281 TIOFeatures saved_features = fIOFeatures;
7282 TTree *newtree = CloneTree(-1, options);
7283 if (info->fIOFeatures)
7284 fIOFeatures = *(info->fIOFeatures);
7285 else
7286 fIOFeatures = saved_features;
7287 if (newtree) {
7288 newtree->Write();
7289 delete newtree;
7290 }
7291 // Make sure things are really written out to disk before attempting any reading.
7292 info->fOutputDirectory->GetFile()->Flush();
7293 info->fOutputDirectory->ReadTObject(this,this->GetName());
7294 }
7295 }
7296 if (!li) return 0;
7297 Long64_t storeAutoSave = fAutoSave;
7298 // Disable the autosave as the TFileMerge keeps a list of key and deleting the underlying
7299 // key would invalidate its iteration (or require costly measure to not use the deleted keys).
7300 // Also since this is part of a merging operation, the output file is not as precious as in
7301 // the general case since the input file should still be around.
7302 fAutoSave = 0;
7303 TIter next(li);
7304 TTree *tree;
7305 while ((tree = (TTree*)next())) {
7306 if (tree==this) continue;
7307 if (!tree->InheritsFrom(TTree::Class())) {
7308 Error("Add","Attempt to add object of class: %s to a %s", tree->ClassName(), ClassName());
7309 fAutoSave = storeAutoSave;
7310 return -1;
7311 }
7312
7313 CopyEntries(tree, -1, options, true);
7314 }
7315 fAutoSave = storeAutoSave;
7316 return GetEntries();
7317}
7318
7319////////////////////////////////////////////////////////////////////////////////
7320/// Move a cache from a file to the current file in dir.
7321/// if src is null no operation is done, if dir is null or there is no
7322/// current file the cache is deleted.
7325{
7326 if (!src) return;
7327 TFile *dst = (dir && dir != gROOT) ? dir->GetFile() : nullptr;
7328 if (src == dst) return;
7329
7331 if (dst) {
7332 src->SetCacheRead(nullptr,this);
7333 dst->SetCacheRead(pf, this);
7334 } else {
7335 if (pf) {
7336 pf->WaitFinishPrefetch();
7337 }
7338 src->SetCacheRead(nullptr,this);
7339 delete pf;
7340 }
7341}
7342
7343////////////////////////////////////////////////////////////////////////////////
7344/// Copy the content to a new new file, update this TTree with the new
7345/// location information and attach this TTree to the new directory.
7346///
7347/// options: Indicates a basket sorting method, see TTreeCloner::TTreeCloner for
7348/// details
7349///
7350/// If new and old directory are in the same file, the data is untouched,
7351/// this "just" does a call to SetDirectory.
7352/// Equivalent to an "in place" cloning of the TTree.
7353bool TTree::InPlaceClone(TDirectory *newdirectory, const char *options)
7354{
7355 if (!newdirectory) {
7357 SetDirectory(nullptr);
7358 return true;
7359 }
7360 if (newdirectory->GetFile() == GetCurrentFile()) {
7361 SetDirectory(newdirectory);
7362 return true;
7363 }
7364 TTreeCloner cloner(this, newdirectory, options);
7365 if (cloner.IsValid())
7366 return cloner.Exec();
7367 else
7368 return false;
7369}
7370
7371////////////////////////////////////////////////////////////////////////////////
7372/// Function called when loading a new class library.
7374bool TTree::Notify()
7375{
7376 TIter next(GetListOfLeaves());
7377 TLeaf* leaf = nullptr;
7378 while ((leaf = (TLeaf*) next())) {
7379 leaf->Notify();
7380 leaf->GetBranch()->Notify();
7381 }
7382 return true;
7383}
7384
7385////////////////////////////////////////////////////////////////////////////////
7386/// This function may be called after having filled some entries in a Tree.
7387/// Using the information in the existing branch buffers, it will reassign
7388/// new branch buffer sizes to optimize time and memory.
7389///
7390/// The function computes the best values for branch buffer sizes such that
7391/// the total buffer sizes is less than maxMemory and nearby entries written
7392/// at the same time.
7393/// In case the branch compression factor for the data written so far is less
7394/// than compMin, the compression is disabled.
7395///
7396/// if option ="d" an analysis report is printed.
7398void TTree::OptimizeBaskets(ULong64_t maxMemory, Float_t minComp, Option_t *option)
7399{
7400 //Flush existing baskets if the file is writable
7401 if (this->GetDirectory()->IsWritable()) this->FlushBasketsImpl();
7402
7403 TString opt( option );
7404 opt.ToLower();
7405 bool pDebug = opt.Contains("d");
7406 TObjArray *leaves = this->GetListOfLeaves();
7407 Int_t nleaves = leaves->GetEntries();
7408 Double_t treeSize = (Double_t)this->GetTotBytes();
7409
7410 if (nleaves == 0 || treeSize == 0) {
7411 // We're being called too early, we really have nothing to do ...
7412 return;
7413 }
7414 Double_t aveSize = treeSize/nleaves;
7415 UInt_t bmin = 512;
7416 UInt_t bmax = 256000;
7417 Double_t memFactor = 1;
7418 Int_t i, oldMemsize,newMemsize,oldBaskets,newBaskets;
7419 i = oldMemsize = newMemsize = oldBaskets = newBaskets = 0;
7420
7421 //we make two passes
7422 //one pass to compute the relative branch buffer sizes
7423 //a second pass to compute the absolute values
7424 for (Int_t pass =0;pass<2;pass++) {
7425 oldMemsize = 0; //to count size of baskets in memory with old buffer size
7426 newMemsize = 0; //to count size of baskets in memory with new buffer size
7427 oldBaskets = 0; //to count number of baskets with old buffer size
7428 newBaskets = 0; //to count number of baskets with new buffer size
7429 for (i=0;i<nleaves;i++) {
7430 TLeaf *leaf = (TLeaf*)leaves->At(i);
7431 TBranch *branch = leaf->GetBranch();
7432 Double_t totBytes = (Double_t)branch->GetTotBytes();
7433 Double_t idealFactor = totBytes/aveSize;
7434 UInt_t sizeOfOneEntry;
7435 if (branch->GetEntries() == 0) {
7436 // There is no data, so let's make a guess ...
7437 sizeOfOneEntry = aveSize;
7438 } else {
7439 sizeOfOneEntry = 1+(UInt_t)(totBytes / (Double_t)branch->GetEntries());
7440 }
7441 Int_t oldBsize = branch->GetBasketSize();
7442 oldMemsize += oldBsize;
7443 oldBaskets += 1+Int_t(totBytes/oldBsize);
7444 Int_t nb = branch->GetListOfBranches()->GetEntries();
7445 if (nb > 0) {
7446 newBaskets += 1+Int_t(totBytes/oldBsize);
7447 continue;
7448 }
7449 Double_t bsize = oldBsize*idealFactor*memFactor; //bsize can be very large !
7450 if (bsize < 0) bsize = bmax;
7451 if (bsize > bmax) bsize = bmax;
7452 UInt_t newBsize = UInt_t(bsize);
7453 if (pass) { // only on the second pass so that it doesn't interfere with scaling
7454 // If there is an entry offset, it will be stored in the same buffer as the object data; hence,
7455 // we must bump up the size of the branch to account for this extra footprint.
7456 // If fAutoFlush is not set yet, let's assume that it is 'in the process of being set' to
7457 // the value of GetEntries().
7458 Long64_t clusterSize = (fAutoFlush > 0) ? fAutoFlush : branch->GetEntries();
7459 if (branch->GetEntryOffsetLen()) {
7460 newBsize = newBsize + (clusterSize * sizeof(Int_t) * 2);
7461 }
7462 // We used ATLAS fully-split xAOD for testing, which is a rather unbalanced TTree, 10K branches,
7463 // with 8K having baskets smaller than 512 bytes. To achieve good I/O performance ATLAS uses auto-flush 100,
7464 // resulting in the smallest baskets being ~300-400 bytes, so this change increases their memory by about 8k*150B =~ 1MB,
7465 // at the same time it significantly reduces the number of total baskets because it ensures that all 100 entries can be
7466 // stored in a single basket (the old optimization tended to make baskets too small). In a toy example with fixed sized
7467 // structures we found a factor of 2 fewer baskets needed in the new scheme.
7468 // rounds up, increases basket size to ensure all entries fit into single basket as intended
7469 newBsize = newBsize - newBsize%512 + 512;
7470 }
7471 if (newBsize < sizeOfOneEntry) newBsize = sizeOfOneEntry;
7472 if (newBsize < bmin) newBsize = bmin;
7473 if (newBsize > 10000000) newBsize = bmax;
7474 if (pass) {
7475 if (pDebug) Info("OptimizeBaskets", "Changing buffer size from %6d to %6d bytes for %s\n",oldBsize,newBsize,branch->GetName());
7476 branch->SetBasketSize(newBsize);
7477 }
7478 newMemsize += newBsize;
7479 // For this number to be somewhat accurate when newBsize is 'low'
7480 // we do not include any space for meta data in the requested size (newBsize) even-though SetBasketSize will
7481 // not let it be lower than 100+TBranch::fEntryOffsetLen.
7482 newBaskets += 1+Int_t(totBytes/newBsize);
7483 if (pass == 0) continue;
7484 //Reset the compression level in case the compression factor is small
7485 Double_t comp = 1;
7486 if (branch->GetZipBytes() > 0) comp = totBytes/Double_t(branch->GetZipBytes());
7487 if (comp > 1 && comp < minComp) {
7488 if (pDebug) Info("OptimizeBaskets", "Disabling compression for branch : %s\n",branch->GetName());
7490 }
7491 }
7492 // coverity[divide_by_zero] newMemsize can not be zero as there is at least one leaf
7493 memFactor = Double_t(maxMemory)/Double_t(newMemsize);
7494 if (memFactor > 100) memFactor = 100;
7495 Double_t bmin_new = bmin*memFactor;
7496 Double_t bmax_new = bmax*memFactor;
7497 static const UInt_t hardmax = 1*1024*1024*1024; // Really, really never give more than 1Gb to a single buffer.
7498
7499 // Really, really never go lower than 8 bytes (we use this number
7500 // so that the calculation of the number of basket is consistent
7501 // but in fact SetBasketSize will not let the size go below
7502 // TBranch::fEntryOffsetLen + (100 + strlen(branch->GetName())
7503 // (The 2nd part being a slight over estimate of the key length.
7504 static const UInt_t hardmin = 8;
7505 bmin = (bmin_new > hardmax) ? hardmax : ( bmin_new < hardmin ? hardmin : (UInt_t)bmin_new );
7506 bmax = (bmax_new > hardmax) ? bmin : (UInt_t)bmax_new;
7507 }
7508 if (pDebug) {
7509 Info("OptimizeBaskets", "oldMemsize = %d, newMemsize = %d\n",oldMemsize, newMemsize);
7510 Info("OptimizeBaskets", "oldBaskets = %d, newBaskets = %d\n",oldBaskets, newBaskets);
7511 }
7512}
7513
7514////////////////////////////////////////////////////////////////////////////////
7515/// Interface to the Principal Components Analysis class.
7516///
7517/// Create an instance of TPrincipal
7518///
7519/// Fill it with the selected variables
7520///
7521/// - if option "n" is specified, the TPrincipal object is filled with
7522/// normalized variables.
7523/// - If option "p" is specified, compute the principal components
7524/// - If option "p" and "d" print results of analysis
7525/// - If option "p" and "h" generate standard histograms
7526/// - If option "p" and "c" generate code of conversion functions
7527/// - return a pointer to the TPrincipal object. It is the user responsibility
7528/// - to delete this object.
7529/// - The option default value is "np"
7530///
7531/// see TTree::Draw for explanation of the other parameters.
7532///
7533/// The created object is named "principal" and a reference to it
7534/// is added to the list of specials Root objects.
7535/// you can retrieve a pointer to the created object via:
7536/// ~~~ {.cpp}
7537/// TPrincipal *principal =
7538/// (TPrincipal*)gROOT->GetListOfSpecials()->FindObject("principal");
7539/// ~~~
7541TPrincipal* TTree::Principal(const char* varexp, const char* selection, Option_t* option, Long64_t nentries, Long64_t firstentry)
7542{
7543 GetPlayer();
7544 if (fPlayer) {
7545 return fPlayer->Principal(varexp, selection, option, nentries, firstentry);
7546 }
7547 return nullptr;
7548}
7549
7550////////////////////////////////////////////////////////////////////////////////
7551/// Print a summary of the tree contents.
7552///
7553/// - If option contains "all" friend trees are also printed.
7554/// - If option contains "toponly" only the top level branches are printed.
7555/// - If option contains "clusters" information about the cluster of baskets is printed.
7556///
7557/// Wildcarding can be used to print only a subset of the branches, e.g.,
7558/// `T.Print("Elec*")` will print all branches with name starting with "Elec".
7560void TTree::Print(Option_t* option) const
7561{
7562 // We already have been visited while recursively looking
7563 // through the friends tree, let's return.
7564 if (kPrint & fFriendLockStatus) {
7565 return;
7566 }
7567 Int_t s = 0;
7568 Int_t skey = 0;
7569 if (fDirectory) {
7570 TKey* key = fDirectory->GetKey(GetName());
7571 if (key) {
7572 skey = key->GetKeylen();
7573 s = key->GetNbytes();
7574 }
7575 }
7576 Long64_t total = skey;
7577 Long64_t zipBytes = GetZipBytes();
7578 if (zipBytes > 0) {
7579 total += GetTotBytes();
7580 }
7582 TTree::Class()->WriteBuffer(b, (TTree*) this);
7583 total += b.Length();
7584 Long64_t file = zipBytes + s;
7585 Float_t cx = 1;
7586 if (zipBytes) {
7587 cx = (GetTotBytes() + 0.00001) / zipBytes;
7588 }
7589 Printf("******************************************************************************");
7590 Printf("*Tree :%-10s: %-54s *", GetName(), GetTitle());
7591 Printf("*Entries : %8lld : Total = %15lld bytes File Size = %10lld *", fEntries, total, file);
7592 Printf("* : : Tree compression factor = %6.2f *", cx);
7593 Printf("******************************************************************************");
7594
7595 // Avoid many check of option validity
7596 if (!option)
7597 option = "";
7598
7599 if (strncmp(option,"clusters",std::char_traits<char>::length("clusters"))==0) {
7600 Printf("%-16s %-16s %-16s %8s %20s",
7601 "Cluster Range #", "Entry Start", "Last Entry", "Size", "Number of clusters");
7602 Int_t index= 0;
7603 Long64_t clusterRangeStart = 0;
7604 Long64_t totalClusters = 0;
7605 bool estimated = false;
7606 bool unknown = false;
7607 auto printer = [this, &totalClusters, &estimated, &unknown](Int_t ind, Long64_t start, Long64_t end, Long64_t recordedSize) {
7608 Long64_t nclusters = 0;
7609 if (recordedSize > 0) {
7610 nclusters = TMath::Ceil(static_cast<double>(1 + end - start) / recordedSize);
7611 Printf("%-16d %-16lld %-16lld %8lld %10lld",
7612 ind, start, end, recordedSize, nclusters);
7613 } else {
7614 // NOTE: const_cast ... DO NOT Merge for now
7615 TClusterIterator iter((TTree*)this, start);
7616 iter.Next();
7617 auto estimated_size = iter.GetNextEntry() - start;
7618 if (estimated_size > 0) {
7619 nclusters = TMath::Ceil(static_cast<double>(1 + end - start) / estimated_size);
7620 Printf("%-16d %-16lld %-16lld %8lld %10lld (estimated)",
7621 ind, start, end, recordedSize, nclusters);
7622 estimated = true;
7623 } else {
7624 Printf("%-16d %-16lld %-16lld %8lld (unknown)",
7625 ind, start, end, recordedSize);
7626 unknown = true;
7627 }
7628 }
7629 start = end + 1;
7630 totalClusters += nclusters;
7631 };
7632 if (fNClusterRange) {
7633 for( ; index < fNClusterRange; ++index) {
7634 printer(index, clusterRangeStart, fClusterRangeEnd[index], fClusterSize[index]);
7635 clusterRangeStart = fClusterRangeEnd[index] + 1;
7636 }
7637 }
7638 printer(index, clusterRangeStart, fEntries - 1, fAutoFlush);
7639 if (unknown) {
7640 Printf("Total number of clusters: (unknown)");
7641 } else {
7642 Printf("Total number of clusters: %lld %s", totalClusters, estimated ? "(estimated)" : "");
7643 }
7644 return;
7645 }
7646
7647 Int_t nl = const_cast<TTree*>(this)->GetListOfLeaves()->GetEntries();
7648 Int_t l;
7649 TBranch* br = nullptr;
7650 TLeaf* leaf = nullptr;
7651 if (strstr(option, "toponly")) {
7652 Long64_t *count = new Long64_t[nl];
7653 Int_t keep =0;
7654 for (l=0;l<nl;l++) {
7655 leaf = (TLeaf *)const_cast<TTree*>(this)->GetListOfLeaves()->At(l);
7656 br = leaf->GetBranch();
7657 // branch is its own (top level) mother only for the top level branches.
7658 if (br != br->GetMother()) {
7659 count[l] = -1;
7660 count[keep] += br->GetZipBytes();
7661 } else {
7662 keep = l;
7663 count[keep] = br->GetZipBytes();
7664 }
7665 }
7666 for (l=0;l<nl;l++) {
7667 if (count[l] < 0) continue;
7668 leaf = (TLeaf *)const_cast<TTree*>(this)->GetListOfLeaves()->At(l);
7669 br = leaf->GetBranch();
7670 Printf("branch: %-20s %9lld",br->GetName(),count[l]);
7671 }
7672 delete [] count;
7673 } else {
7674 TString reg = "*";
7675 if (strlen(option) && strchr(option,'*')) reg = option;
7676 TRegexp re(reg,true);
7677 TIter next(const_cast<TTree*>(this)->GetListOfBranches());
7679 while ((br= (TBranch*)next())) {
7680 TString st = br->GetName();
7681 st.ReplaceAll("/","_");
7682 if (st.Index(re) == kNPOS) continue;
7683 br->Print(option);
7684 }
7685 }
7686
7687 //print TRefTable (if one)
7689
7690 //print friends if option "all"
7691 if (!fFriends || !strstr(option,"all")) return;
7692 TIter nextf(fFriends);
7693 TFriendLock lock(const_cast<TTree*>(this),kPrint);
7694 TFriendElement *fr;
7695 while ((fr = (TFriendElement*)nextf())) {
7696 TTree * t = fr->GetTree();
7697 if (t) t->Print(option);
7698 }
7699}
7700
7701////////////////////////////////////////////////////////////////////////////////
7702/// Print statistics about the TreeCache for this tree.
7703/// Like:
7704/// ~~~ {.cpp}
7705/// ******TreeCache statistics for file: cms2.root ******
7706/// Reading 73921562 bytes in 716 transactions
7707/// Average transaction = 103.242405 Kbytes
7708/// Number of blocks in current cache: 202, total size : 6001193
7709/// ~~~
7710/// if option = "a" the list of blocks in the cache is printed
7713{
7714 TFile *f = GetCurrentFile();
7715 if (!f) return;
7716 TTreeCache *tc = GetReadCache(f);
7717 if (tc) tc->Print(option);
7718}
7719
7720////////////////////////////////////////////////////////////////////////////////
7721/// Process this tree executing the TSelector code in the specified filename.
7722/// The return value is -1 in case of error and TSelector::GetStatus() in
7723/// in case of success.
7724///
7725/// The code in filename is loaded (interpreted or compiled, see below),
7726/// filename must contain a valid class implementation derived from TSelector,
7727/// where TSelector has the following member functions:
7728///
7729/// - `Begin()`: called every time a loop on the tree starts,
7730/// a convenient place to create your histograms.
7731/// - `SlaveBegin()`: called after Begin()
7732/// - `Process()`: called for each event, in this function you decide what
7733/// to read and fill your histograms.
7734/// - `SlaveTerminate()`: called at the end of the loop on the tree
7735/// - `Terminate()`: called at the end of the loop on the tree,
7736/// a convenient place to draw/fit your histograms.
7737///
7738/// If filename is of the form file.C, the file will be interpreted.
7739///
7740/// If filename is of the form file.C++, the file file.C will be compiled
7741/// and dynamically loaded.
7742///
7743/// If filename is of the form file.C+, the file file.C will be compiled
7744/// and dynamically loaded. At next call, if file.C is older than file.o
7745/// and file.so, the file.C is not compiled, only file.so is loaded.
7746///
7747/// ## NOTE1
7748///
7749/// It may be more interesting to invoke directly the other Process function
7750/// accepting a TSelector* as argument.eg
7751/// ~~~ {.cpp}
7752/// MySelector *selector = (MySelector*)TSelector::GetSelector(filename);
7753/// selector->CallSomeFunction(..);
7754/// mytree.Process(selector,..);
7755/// ~~~
7756/// ## NOTE2
7757//
7758/// One should not call this function twice with the same selector file
7759/// in the same script. If this is required, proceed as indicated in NOTE1,
7760/// by getting a pointer to the corresponding TSelector,eg
7761///
7762/// ### Workaround 1
7763///
7764/// ~~~ {.cpp}
7765/// void stubs1() {
7766/// TSelector *selector = TSelector::GetSelector("h1test.C");
7767/// TFile *f1 = new TFile("stubs_nood_le1.root");
7768/// TTree *h1 = (TTree*)f1->Get("h1");
7769/// h1->Process(selector);
7770/// TFile *f2 = new TFile("stubs_nood_le1_coarse.root");
7771/// TTree *h2 = (TTree*)f2->Get("h1");
7772/// h2->Process(selector);
7773/// }
7774/// ~~~
7775/// or use ACLIC to compile the selector
7776///
7777/// ### Workaround 2
7778///
7779/// ~~~ {.cpp}
7780/// void stubs2() {
7781/// TFile *f1 = new TFile("stubs_nood_le1.root");
7782/// TTree *h1 = (TTree*)f1->Get("h1");
7783/// h1->Process("h1test.C+");
7784/// TFile *f2 = new TFile("stubs_nood_le1_coarse.root");
7785/// TTree *h2 = (TTree*)f2->Get("h1");
7786/// h2->Process("h1test.C+");
7787/// }
7788/// ~~~
7791{
7792 GetPlayer();
7793 if (fPlayer) {
7794 return fPlayer->Process(filename, option, nentries, firstentry);
7795 }
7796 return -1;
7797}
7798
7799////////////////////////////////////////////////////////////////////////////////
7800/// Process this tree executing the code in the specified selector.
7801/// The return value is -1 in case of error and TSelector::GetStatus() in
7802/// in case of success.
7803///
7804/// The TSelector class has the following member functions:
7805///
7806/// - `Begin()`: called every time a loop on the tree starts,
7807/// a convenient place to create your histograms.
7808/// - `SlaveBegin()`: called after Begin()
7809/// - `Process()`: called for each event, in this function you decide what
7810/// to read and fill your histograms.
7811/// - `SlaveTerminate()`: called at the end of the loop on the tree
7812/// - `Terminate()`: called at the end of the loop on the tree,
7813/// a convenient place to draw/fit your histograms.
7814///
7815/// If the Tree (Chain) has an associated EventList, the loop is on the nentries
7816/// of the EventList, starting at firstentry, otherwise the loop is on the
7817/// specified Tree entries.
7820{
7821 GetPlayer();
7822 if (fPlayer) {
7823 return fPlayer->Process(selector, option, nentries, firstentry);
7824 }
7825 return -1;
7826}
7827
7828////////////////////////////////////////////////////////////////////////////////
7829/// Make a projection of a tree using selections.
7830///
7831/// Depending on the value of varexp (described in Draw) a 1-D, 2-D, etc.,
7832/// projection of the tree will be filled in histogram hname.
7833/// Note that the dimension of hname must match with the dimension of varexp.
7834///
7836Long64_t TTree::Project(const char* hname, const char* varexp, const char* selection, Option_t* option, Long64_t nentries, Long64_t firstentry)
7837{
7838 TString var;
7839 var.Form("%s>>%s", varexp, hname);
7840 TString opt("goff");
7841 if (option) {
7842 opt.Form("%sgoff", option);
7843 }
7844 Long64_t nsel = Draw(var, selection, opt, nentries, firstentry);
7845 return nsel;
7846}
7847
7848////////////////////////////////////////////////////////////////////////////////
7849/// Loop over entries and return a TSQLResult object containing entries following selection.
7851TSQLResult* TTree::Query(const char* varexp, const char* selection, Option_t* option, Long64_t nentries, Long64_t firstentry)
7852{
7853 GetPlayer();
7854 if (fPlayer) {
7855 return fPlayer->Query(varexp, selection, option, nentries, firstentry);
7856 }
7857 return nullptr;
7858}
7859
7860////////////////////////////////////////////////////////////////////////////////
7861/// Create or simply read branches from filename.
7862///
7863/// if branchDescriptor = "" (default), it is assumed that the Tree descriptor
7864/// is given in the first line of the file with a syntax like
7865/// ~~~ {.cpp}
7866/// A/D:Table[2]/F:Ntracks/I:astring/C
7867/// ~~~
7868/// otherwise branchDescriptor must be specified with the above syntax.
7869/// See all available datatypes [here](\ref addcolumnoffundamentaltypes).
7870///
7871/// - If the type of the first variable is not specified, it is assumed to be "/F"
7872/// - If the type of any other variable is not specified, the type of the previous
7873/// variable is assumed. eg
7874/// - `x:y:z` (all variables are assumed of type "F")
7875/// - `x/D:y:z` (all variables are of type "D")
7876/// - `x:y/D:z` (x is type "F", y and z of type "D")
7877///
7878/// delimiter allows for the use of another delimiter besides whitespace.
7879/// This provides support for direct import of common data file formats
7880/// like csv. If delimiter != ' ' and branchDescriptor == "", then the
7881/// branch description is taken from the first line in the file, but
7882/// delimiter is used for the branch names tokenization rather than ':'.
7883/// Note however that if the values in the first line do not use the
7884/// /[type] syntax, all variables are assumed to be of type "F".
7885/// If the filename ends with extensions .csv or .CSV and a delimiter is
7886/// not specified (besides ' '), the delimiter is automatically set to ','.
7887///
7888/// Lines in the input file starting with "#" are ignored. Leading whitespace
7889/// for each column data is skipped. Empty lines are skipped.
7890///
7891/// A TBranch object is created for each variable in the expression.
7892/// The total number of rows read from the file is returned.
7893///
7894/// ## FILLING a TTree WITH MULTIPLE INPUT TEXT FILES
7895///
7896/// To fill a TTree with multiple input text files, proceed as indicated above
7897/// for the first input file and omit the second argument for subsequent calls
7898/// ~~~ {.cpp}
7899/// T.ReadFile("file1.dat","branch descriptor");
7900/// T.ReadFile("file2.dat");
7901/// ~~~
7903Long64_t TTree::ReadFile(const char* filename, const char* branchDescriptor, char delimiter)
7904{
7905 if (!filename || !*filename) {
7906 Error("ReadFile","File name not specified");
7907 return 0;
7908 }
7909
7910 std::ifstream in;
7911 in.open(filename);
7912 if (!in.good()) {
7913 Error("ReadFile","Cannot open file: %s",filename);
7914 return 0;
7915 }
7916 const char* ext = strrchr(filename, '.');
7917 if(ext && ((strcmp(ext, ".csv") == 0) || (strcmp(ext, ".CSV") == 0)) && delimiter == ' ') {
7918 delimiter = ',';
7919 }
7920 return ReadStream(in, branchDescriptor, delimiter);
7921}
7922
7923////////////////////////////////////////////////////////////////////////////////
7924/// Determine which newline this file is using.
7925/// Return '\\r' for Windows '\\r\\n' as that already terminates.
7927char TTree::GetNewlineValue(std::istream &inputStream)
7928{
7929 Long_t inPos = inputStream.tellg();
7930 char newline = '\n';
7931 while(true) {
7932 char c = 0;
7933 inputStream.get(c);
7934 if(!inputStream.good()) {
7935 Error("ReadStream","Error reading stream: no newline found.");
7936 return 0;
7937 }
7938 if(c == newline) break;
7939 if(c == '\r') {
7940 newline = '\r';
7941 break;
7942 }
7943 }
7944 inputStream.clear();
7945 inputStream.seekg(inPos);
7946 return newline;
7947}
7948
7949////////////////////////////////////////////////////////////////////////////////
7950/// Create or simply read branches from an input stream.
7951///
7952/// \see TTree::ReadFile
7954Long64_t TTree::ReadStream(std::istream& inputStream, const char *branchDescriptor, char delimiter)
7955{
7956 char newline = 0;
7957 std::stringstream ss;
7958 std::istream *inTemp;
7959 Long_t inPos = inputStream.tellg();
7960 if (!inputStream.good()) {
7961 Error("ReadStream","Error reading stream");
7962 return 0;
7963 }
7964 if (inPos == -1) {
7965 ss << std::cin.rdbuf();
7966 newline = GetNewlineValue(ss);
7967 inTemp = &ss;
7968 } else {
7969 newline = GetNewlineValue(inputStream);
7970 inTemp = &inputStream;
7971 }
7972 std::istream& in = *inTemp;
7973 Long64_t nlines = 0;
7974
7975 TBranch *branch = nullptr;
7976 Int_t nbranches = fBranches.GetEntries();
7977 if (nbranches == 0) {
7978 char *bdname = new char[4000];
7979 char *bd = new char[100000];
7980 Int_t nch = 0;
7981 if (branchDescriptor) nch = strlen(branchDescriptor);
7982 // branch Descriptor is null, read its definition from the first line in the file
7983 if (!nch) {
7984 do {
7985 in.getline(bd, 100000, newline);
7986 if (!in.good()) {
7987 delete [] bdname;
7988 delete [] bd;
7989 Error("ReadStream","Error reading stream");
7990 return 0;
7991 }
7992 char *cursor = bd;
7993 while( isspace(*cursor) && *cursor != '\n' && *cursor != '\0') {
7994 ++cursor;
7995 }
7996 if (*cursor != '#' && *cursor != '\n' && *cursor != '\0') {
7997 break;
7998 }
7999 } while (true);
8000 ++nlines;
8001 nch = strlen(bd);
8002 } else {
8003 strlcpy(bd,branchDescriptor,100000);
8004 }
8005
8006 //parse the branch descriptor and create a branch for each element
8007 //separated by ":"
8008 void *address = &bd[90000];
8009 char *bdcur = bd;
8010 TString desc="", olddesc="F";
8011 char bdelim = ':';
8012 if(delimiter != ' ') {
8013 bdelim = delimiter;
8014 if (strchr(bdcur,bdelim)==nullptr && strchr(bdcur,':') != nullptr) {
8015 // revert to the default
8016 bdelim = ':';
8017 }
8018 }
8019 while (bdcur) {
8020 char *colon = strchr(bdcur,bdelim);
8021 if (colon) *colon = 0;
8022 strlcpy(bdname,bdcur,4000);
8023 char *slash = strchr(bdname,'/');
8024 if (slash) {
8025 *slash = 0;
8026 desc = bdcur;
8027 olddesc = slash+1;
8028 } else {
8029 desc.Form("%s/%s",bdname,olddesc.Data());
8030 }
8031 char *bracket = strchr(bdname,'[');
8032 if (bracket) {
8033 *bracket = 0;
8034 }
8035 branch = new TBranch(this,bdname,address,desc.Data(),32000);
8036 if (branch->IsZombie()) {
8037 delete branch;
8038 Warning("ReadStream","Illegal branch definition: %s",bdcur);
8039 } else {
8040 fBranches.Add(branch);
8041 branch->SetAddress(nullptr);
8042 }
8043 if (!colon)break;
8044 bdcur = colon+1;
8045 }
8046 delete [] bdname;
8047 delete [] bd;
8048 }
8049
8050 nbranches = fBranches.GetEntries();
8051
8052 if (gDebug > 1) {
8053 Info("ReadStream", "Will use branches:");
8054 for (int i = 0 ; i < nbranches; ++i) {
8055 TBranch* br = (TBranch*) fBranches.At(i);
8056 Info("ReadStream", " %s: %s [%s]", br->GetName(),
8057 br->GetTitle(), br->GetListOfLeaves()->At(0)->IsA()->GetName());
8058 }
8059 if (gDebug > 3) {
8060 Info("ReadStream", "Dumping read tokens, format:");
8061 Info("ReadStream", "LLLLL:BBB:gfbe:GFBE:T");
8062 Info("ReadStream", " L: line number");
8063 Info("ReadStream", " B: branch number");
8064 Info("ReadStream", " gfbe: good / fail / bad / eof of token");
8065 Info("ReadStream", " GFBE: good / fail / bad / eof of file");
8066 Info("ReadStream", " T: Token being read");
8067 }
8068 }
8069
8070 //loop on all lines in the file
8071 Long64_t nGoodLines = 0;
8072 std::string line;
8073 const char sDelimBuf[2] = { delimiter, 0 };
8074 const char* sDelim = sDelimBuf;
8075 if (delimiter == ' ') {
8076 // ' ' really means whitespace
8077 sDelim = "[ \t]";
8078 }
8079 while(in.good()) {
8080 if (newline == '\r' && in.peek() == '\n') {
8081 // Windows, skip '\n':
8082 in.get();
8083 }
8084 std::getline(in, line, newline);
8085 ++nlines;
8086
8087 TString sLine(line);
8088 sLine = sLine.Strip(TString::kLeading); // skip leading whitespace
8089 if (sLine.IsNull()) {
8090 if (gDebug > 2) {
8091 Info("ReadStream", "Skipping empty line number %lld", nlines);
8092 }
8093 continue; // silently skip empty lines
8094 }
8095 if (sLine[0] == '#') {
8096 if (gDebug > 2) {
8097 Info("ReadStream", "Skipping comment line number %lld: '%s'",
8098 nlines, line.c_str());
8099 }
8100 continue;
8101 }
8102 if (gDebug > 2) {
8103 Info("ReadStream", "Parsing line number %lld: '%s'",
8104 nlines, line.c_str());
8105 }
8106
8107 // Loop on branches and read the branch values into their buffer
8108 branch = nullptr;
8109 TString tok; // one column's data
8110 TString leafData; // leaf data, possibly multiple tokens for e.g. /I[2]
8111 std::stringstream sToken; // string stream feeding leafData into leaves
8112 Ssiz_t pos = 0;
8113 Int_t iBranch = 0;
8114 bool goodLine = true; // whether the row can be filled into the tree
8115 Int_t remainingLeafLen = 0; // remaining columns for the current leaf
8116 while (goodLine && iBranch < nbranches
8117 && sLine.Tokenize(tok, pos, sDelim)) {
8118 tok = tok.Strip(TString::kLeading); // skip leading whitespace
8119 if (tok.IsNull() && delimiter == ' ') {
8120 // 1 2 should not be interpreted as 1,,,2 but 1, 2.
8121 // Thus continue until we have a non-empty token.
8122 continue;
8123 }
8124
8125 if (!remainingLeafLen) {
8126 // next branch!
8127 branch = (TBranch*)fBranches.At(iBranch);
8128 }
8129 TLeaf *leaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
8130 if (!remainingLeafLen) {
8131 remainingLeafLen = leaf->GetLen();
8132 if (leaf->GetMaximum() > 0) {
8133 // This is a dynamic leaf length, i.e. most likely a TLeafC's
8134 // string size. This still translates into one token:
8135 remainingLeafLen = 1;
8136 }
8137
8138 leafData = tok;
8139 } else {
8140 // append token to laf data:
8141 leafData += " ";
8142 leafData += tok;
8143 }
8144 --remainingLeafLen;
8145 if (remainingLeafLen) {
8146 // need more columns for this branch:
8147 continue;
8148 }
8149 ++iBranch;
8150
8151 // initialize stringstream with token
8152 sToken.clear();
8153 sToken.seekp(0, std::ios_base::beg);
8154 sToken.str(leafData.Data());
8155 sToken.seekg(0, std::ios_base::beg);
8156 leaf->ReadValue(sToken, 0 /* 0 = "all" */);
8157 if (gDebug > 3) {
8158 Info("ReadStream", "%5lld:%3d:%d%d%d%d:%d%d%d%d:%s",
8159 nlines, iBranch,
8160 (int)sToken.good(), (int)sToken.fail(),
8161 (int)sToken.bad(), (int)sToken.eof(),
8162 (int)in.good(), (int)in.fail(),
8163 (int)in.bad(), (int)in.eof(),
8164 sToken.str().c_str());
8165 }
8166
8167 // Error handling
8168 if (sToken.bad()) {
8169 // How could that happen for a stringstream?
8170 Warning("ReadStream",
8171 "Buffer error while reading data for branch %s on line %lld",
8172 branch->GetName(), nlines);
8173 } else if (!sToken.eof()) {
8174 if (sToken.fail()) {
8175 Warning("ReadStream",
8176 "Couldn't read formatted data in \"%s\" for branch %s on line %lld; ignoring line",
8177 tok.Data(), branch->GetName(), nlines);
8178 goodLine = false;
8179 } else {
8180 std::string remainder;
8181 std::getline(sToken, remainder, newline);
8182 if (!remainder.empty()) {
8183 Warning("ReadStream",
8184 "Ignoring trailing \"%s\" while reading data for branch %s on line %lld",
8185 remainder.c_str(), branch->GetName(), nlines);
8186 }
8187 }
8188 }
8189 } // tokenizer loop
8190
8191 if (iBranch < nbranches) {
8192 Warning("ReadStream",
8193 "Read too few columns (%d < %d) in line %lld; ignoring line",
8194 iBranch, nbranches, nlines);
8195 goodLine = false;
8196 } else if (pos != kNPOS) {
8197 sLine = sLine.Strip(TString::kTrailing);
8198 if (pos < sLine.Length()) {
8199 Warning("ReadStream",
8200 "Ignoring trailing \"%s\" while reading line %lld",
8201 sLine.Data() + pos - 1 /* also print delimiter */,
8202 nlines);
8203 }
8204 }
8205
8206 //we are now ready to fill the tree
8207 if (goodLine) {
8208 Fill();
8209 ++nGoodLines;
8210 }
8211 }
8212
8213 return nGoodLines;
8214}
8215
8216////////////////////////////////////////////////////////////////////////////////
8217/// Make sure that obj (which is being deleted or will soon be) is no
8218/// longer referenced by this TTree.
8221{
8222 if (obj == fEventList) {
8223 fEventList = nullptr;
8224 }
8225 if (obj == fEntryList) {
8226 fEntryList = nullptr;
8227 }
8228 if (fUserInfo) {
8230 }
8231 if (fPlayer == obj) {
8232 fPlayer = nullptr;
8233 }
8234 if (fTreeIndex == obj) {
8235 fTreeIndex = nullptr;
8236 }
8237 if (fAliases == obj) {
8238 fAliases = nullptr;
8239 } else if (fAliases) {
8241 }
8242 if (fFriends == obj) {
8243 fFriends = nullptr;
8244 } else if (fFriends) {
8246 }
8247}
8248
8249////////////////////////////////////////////////////////////////////////////////
8250/// Refresh contents of this tree and its branches from the current status on disk.
8251///
8252/// One can call this function in case the tree file is being
8253/// updated by another process.
8255void TTree::Refresh()
8256{
8257 if (!fDirectory->GetFile()) {
8258 return;
8259 }
8261 fDirectory->Remove(this);
8262 TTree* tree; fDirectory->GetObject(GetName(),tree);
8263 if (!tree) {
8264 return;
8265 }
8266 //copy info from tree header into this Tree
8267 fEntries = 0;
8268 fNClusterRange = 0;
8269 ImportClusterRanges(tree);
8270
8271 fAutoSave = tree->fAutoSave;
8272 fEntries = tree->fEntries;
8273 fTotBytes = tree->GetTotBytes();
8274 fZipBytes = tree->GetZipBytes();
8275 fSavedBytes = tree->fSavedBytes;
8276 fTotalBuffers = tree->fTotalBuffers.load();
8277
8278 //loop on all branches and update them
8279 Int_t nleaves = fLeaves.GetEntriesFast();
8280 for (Int_t i = 0; i < nleaves; i++) {
8281 TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
8282 TBranch* branch = (TBranch*) leaf->GetBranch();
8283 branch->Refresh(tree->GetBranch(branch->GetName()));
8284 }
8285 fDirectory->Remove(tree);
8286 fDirectory->Append(this);
8287 delete tree;
8288 tree = nullptr;
8289}
8290
8291////////////////////////////////////////////////////////////////////////////////
8292/// Record a TFriendElement that we need to warn when the chain switches to
8293/// a new file (typically this is because this chain is a friend of another
8294/// TChain)
8301}
8302
8303
8304////////////////////////////////////////////////////////////////////////////////
8305/// Removes external friend
8310}
8311
8312
8313////////////////////////////////////////////////////////////////////////////////
8314/// Remove a friend from the list of friends.
8316void TTree::RemoveFriend(TTree* oldFriend)
8317{
8318 // We already have been visited while recursively looking
8319 // through the friends tree, let return
8321 return;
8322 }
8323 if (!fFriends) {
8324 return;
8325 }
8326 TFriendLock lock(this, kRemoveFriend);
8327 TIter nextf(fFriends);
8328 TFriendElement* fe = nullptr;
8329 while ((fe = (TFriendElement*) nextf())) {
8330 TTree* friend_t = fe->GetTree();
8331 if (friend_t == oldFriend) {
8332 fFriends->Remove(fe);
8333 delete fe;
8334 fe = nullptr;
8335 }
8336 }
8337}
8338
8339////////////////////////////////////////////////////////////////////////////////
8340/// Reset baskets, buffers and entries count in all branches and leaves.
8343{
8344 fNotify = nullptr;
8345 fEntries = 0;
8346 fNClusterRange = 0;
8347 fTotBytes = 0;
8348 fZipBytes = 0;
8349 fFlushedBytes = 0;
8350 fSavedBytes = 0;
8351 fTotalBuffers = 0;
8352 fChainOffset = 0;
8353 fReadEntry = -1;
8354
8355 delete fTreeIndex;
8356 fTreeIndex = nullptr;
8357
8359 for (Int_t i = 0; i < nb; ++i) {
8360 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
8361 branch->Reset(option);
8362 }
8363
8364 if (fBranchRef) {
8365 fBranchRef->Reset();
8366 }
8367}
8368
8369////////////////////////////////////////////////////////////////////////////////
8370/// Resets the state of this TTree after a merge (keep the customization but
8371/// forget the data).
8374{
8375 fEntries = 0;
8376 fNClusterRange = 0;
8377 fTotBytes = 0;
8378 fZipBytes = 0;
8379 fSavedBytes = 0;
8380 fFlushedBytes = 0;
8381 fTotalBuffers = 0;
8382 fChainOffset = 0;
8383 fReadEntry = -1;
8384
8385 delete fTreeIndex;
8386 fTreeIndex = nullptr;
8387
8389 for (Int_t i = 0; i < nb; ++i) {
8390 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
8391 branch->ResetAfterMerge(info);
8392 }
8393
8394 if (fBranchRef) {
8396 }
8397}
8398
8399////////////////////////////////////////////////////////////////////////////////
8400/// Tell a branch to set its address to zero.
8401///
8402/// @note If the branch owns any objects, they are deleted.
8405{
8406 if (br && br->GetTree()) {
8407 br->ResetAddress();
8408 }
8409}
8410
8411////////////////////////////////////////////////////////////////////////////////
8412/// Tell all of our branches to drop their current objects and allocate new ones.
8415{
8416 // We already have been visited while recursively looking
8417 // through the friends tree, let return
8419 return;
8420 }
8421 TObjArray* branches = GetListOfBranches();
8422 Int_t nbranches = branches->GetEntriesFast();
8423 for (Int_t i = 0; i < nbranches; ++i) {
8424 TBranch* branch = (TBranch*) branches->UncheckedAt(i);
8425 branch->ResetAddress();
8426 }
8427 if (fFriends) {
8429 for (auto *frEl : TRangeDynCast<TFriendElement>(fFriends)) {
8430 auto *frTree = frEl->GetTree();
8431 if (frTree) {
8432 frTree->ResetBranchAddresses();
8433 }
8434 }
8435 }
8436}
8437
8438////////////////////////////////////////////////////////////////////////////////
8439/// Loop over tree entries and print entries passing selection. Interactive
8440/// pagination break is on by default.
8441///
8442/// - If varexp is 0 (or "") then print only first 8 columns.
8443/// - If varexp = "*" print all columns.
8444///
8445/// Otherwise a columns selection can be made using "var1:var2:var3".
8446///
8447/// \param firstentry first entry to scan
8448/// \param nentries total number of entries to scan (starting from firstentry). Defaults to all entries.
8449/// \note see TTree::SetScanField to control how many lines are printed between pagination breaks (Use 0 to disable pagination)
8450/// \see TTreePlayer::Scan, TTreePlayer::SetScanFileName, TTreePlayer::SetScanRedirect
8452Long64_t TTree::Scan(const char* varexp, const char* selection, Option_t* option, Long64_t nentries, Long64_t firstentry)
8453{
8454 GetPlayer();
8455 if (fPlayer) {
8456 return fPlayer->Scan(varexp, selection, option, nentries, firstentry);
8457 }
8458 return -1;
8459}
8460
8461////////////////////////////////////////////////////////////////////////////////
8462/// Set a tree variable alias.
8463///
8464/// Set an alias for an expression/formula based on the tree 'variables'.
8465///
8466/// The content of 'aliasName' can be used in TTreeFormula (i.e. TTree::Draw,
8467/// TTree::Scan, TTreeViewer) and will be evaluated as the content of
8468/// 'aliasFormula'.
8469///
8470/// If the content of 'aliasFormula' only contains symbol names, periods and
8471/// array index specification (for example event.fTracks[3]), then
8472/// the content of 'aliasName' can be used as the start of symbol.
8473///
8474/// If the alias 'aliasName' already existed, it is replaced by the new
8475/// value.
8476///
8477/// When being used, the alias can be preceded by an eventual 'Friend Alias'
8478/// (see TTree::GetFriendAlias)
8479///
8480/// Return true if it was added properly.
8481///
8482/// For example:
8483/// ~~~ {.cpp}
8484/// tree->SetAlias("x1","(tdc1[1]-tdc1[0])/49");
8485/// tree->SetAlias("y1","(tdc1[3]-tdc1[2])/47");
8486/// tree->SetAlias("x2","(tdc2[1]-tdc2[0])/49");
8487/// tree->SetAlias("y2","(tdc2[3]-tdc2[2])/47");
8488/// tree->Draw("y2-y1:x2-x1");
8489///
8490/// tree->SetAlias("theGoodTrack","event.fTracks[3]");
8491/// tree->Draw("theGoodTrack.fPx"); // same as "event.fTracks[3].fPx"
8492/// ~~~
8494bool TTree::SetAlias(const char* aliasName, const char* aliasFormula)
8495{
8496 if (!aliasName || !aliasFormula) {
8497 return false;
8498 }
8499 if (!aliasName[0] || !aliasFormula[0]) {
8500 return false;
8501 }
8502 if (!fAliases) {
8503 fAliases = new TList;
8504 } else {
8505 TNamed* oldHolder = (TNamed*) fAliases->FindObject(aliasName);
8506 if (oldHolder) {
8507 oldHolder->SetTitle(aliasFormula);
8508 return true;
8509 }
8510 }
8511 TNamed* holder = new TNamed(aliasName, aliasFormula);
8512 fAliases->Add(holder);
8513 return true;
8514}
8515
8516////////////////////////////////////////////////////////////////////////////////
8517/// This function may be called at the start of a program to change
8518/// the default value for fAutoFlush.
8519///
8520/// ### CASE 1 : autof > 0
8521///
8522/// autof is the number of consecutive entries after which TTree::Fill will
8523/// flush all branch buffers to disk.
8524///
8525/// ### CASE 2 : autof < 0
8526///
8527/// When filling the Tree the branch buffers will be flushed to disk when
8528/// more than autof bytes have been written to the file. At the first FlushBaskets
8529/// TTree::Fill will replace fAutoFlush by the current value of fEntries.
8530///
8531/// Calling this function with autof<0 is interesting when it is hard to estimate
8532/// the size of one entry. This value is also independent of the Tree.
8533///
8534/// The Tree is initialized with fAutoFlush=-30000000, ie that, by default,
8535/// the first AutoFlush will be done when 30 MBytes of data are written to the file.
8536///
8537/// ### CASE 3 : autof = 0
8538///
8539/// The AutoFlush mechanism is disabled.
8540///
8541/// Flushing the buffers at regular intervals optimize the location of
8542/// consecutive entries on the disk by creating clusters of baskets.
8543///
8544/// A cluster of baskets is a set of baskets that contains all
8545/// the data for a (consecutive) set of entries and that is stored
8546/// consecutively on the disk. When reading all the branches, this
8547/// is the minimum set of baskets that the TTreeCache will read.
8549void TTree::SetAutoFlush(Long64_t autof /* = -30000000 */ )
8550{
8551 // Implementation note:
8552 //
8553 // A positive value of autoflush determines the size (in number of entries) of
8554 // a cluster of baskets.
8555 //
8556 // If the value of autoflush is changed over time (this happens in
8557 // particular when the TTree results from fast merging many trees),
8558 // we record the values of fAutoFlush in the data members:
8559 // fClusterRangeEnd and fClusterSize.
8560 // In the code we refer to a range of entries where the size of the
8561 // cluster of baskets is the same (i.e the value of AutoFlush was
8562 // constant) is called a ClusterRange.
8563 //
8564 // The 2 arrays (fClusterRangeEnd and fClusterSize) have fNClusterRange
8565 // active (used) values and have fMaxClusterRange allocated entries.
8566 //
8567 // fClusterRangeEnd contains the last entries number of a cluster range.
8568 // In particular this means that the 'next' cluster starts at fClusterRangeEnd[]+1
8569 // fClusterSize contains the size in number of entries of all the cluster
8570 // within the given range.
8571 // The last range (and the only one if fNClusterRange is zero) start at
8572 // fNClusterRange[fNClusterRange-1]+1 and ends at the end of the TTree. The
8573 // size of the cluster in this range is given by the value of fAutoFlush.
8574 //
8575 // For example printing the beginning and end of each the ranges can be done by:
8576 //
8577 // Printf("%-16s %-16s %-16s %5s",
8578 // "Cluster Range #", "Entry Start", "Last Entry", "Size");
8579 // Int_t index= 0;
8580 // Long64_t clusterRangeStart = 0;
8581 // if (fNClusterRange) {
8582 // for( ; index < fNClusterRange; ++index) {
8583 // Printf("%-16d %-16lld %-16lld %5lld",
8584 // index, clusterRangeStart, fClusterRangeEnd[index], fClusterSize[index]);
8585 // clusterRangeStart = fClusterRangeEnd[index] + 1;
8586 // }
8587 // }
8588 // Printf("%-16d %-16lld %-16lld %5lld",
8589 // index, prevEntry, fEntries - 1, fAutoFlush);
8590 //
8591
8592 // Note: We store the entry number corresponding to the end of the cluster
8593 // rather than its start in order to avoid using the array if the cluster
8594 // size never varies (If there is only one value of AutoFlush for the whole TTree).
8595
8596 if( fAutoFlush != autof) {
8597 if ((fAutoFlush > 0 || autof > 0) && fFlushedBytes) {
8598 // The mechanism was already enabled, let's record the previous
8599 // cluster if needed.
8601 }
8602 fAutoFlush = autof;
8603 }
8604}
8605
8606////////////////////////////////////////////////////////////////////////////////
8607/// Mark the previous event as being at the end of the event cluster.
8608///
8609/// So, if fEntries is set to 10 (and this is the first cluster) when MarkEventCluster
8610/// is called, then the first cluster has 9 events.
8612{
8613 if (!fEntries) return;
8614
8615 if ( (fNClusterRange+1) > fMaxClusterRange ) {
8616 if (fMaxClusterRange) {
8617 // Resize arrays to hold a larger event cluster.
8618 Int_t newsize = TMath::Max(10,Int_t(2*fMaxClusterRange));
8620 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
8622 newsize*sizeof(Long64_t),fMaxClusterRange*sizeof(Long64_t));
8623 fMaxClusterRange = newsize;
8624 } else {
8625 // Cluster ranges have never been initialized; create them now.
8626 fMaxClusterRange = 2;
8629 }
8630 }
8632 // If we are auto-flushing, then the cluster size is the same as the current auto-flush setting.
8633 if (fAutoFlush > 0) {
8634 // Even if the user triggers MarkEventRange prior to fAutoFlush being present, the TClusterIterator
8635 // will appropriately go to the next event range.
8637 // Otherwise, assume there is one cluster per event range (e.g., user is manually controlling the flush).
8638 } else if (fNClusterRange == 0) {
8640 } else {
8642 }
8644}
8645
8646/// Estimate the median cluster size for the TTree.
8647/// This value provides e.g. a reasonable cache size default if other heuristics fail.
8648/// Clusters with size 0 and the very last cluster range, that might not have been committed to fClusterSize yet,
8649/// are ignored for the purposes of the calculation.
8651{
8652 std::vector<Long64_t> clusterSizesPerRange;
8653 clusterSizesPerRange.reserve(fNClusterRange);
8654
8655 // We ignore cluster sizes of 0 for the purposes of this function.
8656 // We also ignore the very last cluster range which might not have been committed to fClusterSize.
8657 std::copy_if(fClusterSize, fClusterSize + fNClusterRange, std::back_inserter(clusterSizesPerRange),
8658 [](Long64_t size) { return size != 0; });
8659
8660 std::vector<double> nClustersInRange; // we need to store doubles because of the signature of TMath::Median
8661 nClustersInRange.reserve(clusterSizesPerRange.size());
8662
8663 auto clusterRangeStart = 0ll;
8664 for (int i = 0; i < fNClusterRange; ++i) {
8665 const auto size = fClusterSize[i];
8666 R__ASSERT(size >= 0);
8667 if (fClusterSize[i] == 0)
8668 continue;
8669 const auto nClusters = (1 + fClusterRangeEnd[i] - clusterRangeStart) / fClusterSize[i];
8670 nClustersInRange.emplace_back(nClusters);
8671 clusterRangeStart = fClusterRangeEnd[i] + 1;
8672 }
8673
8674 R__ASSERT(nClustersInRange.size() == clusterSizesPerRange.size());
8675 const auto medianClusterSize =
8676 TMath::Median(nClustersInRange.size(), clusterSizesPerRange.data(), nClustersInRange.data());
8677 return medianClusterSize;
8678}
8679
8680////////////////////////////////////////////////////////////////////////////////
8681/// In case of a program crash, it will be possible to recover the data in the
8682/// tree up to the last AutoSave point.
8683/// This function may be called before filling a TTree to specify when the
8684/// branch buffers and TTree header are flushed to disk as part of
8685/// TTree::Fill().
8686/// The default is -300000000, ie the TTree will write data to disk once it
8687/// exceeds 300 MBytes.
8688/// CASE 1: If fAutoSave is positive the watermark is reached when a multiple of
8689/// fAutoSave entries have been filled.
8690/// CASE 2: If fAutoSave is negative the watermark is reached when -fAutoSave
8691/// bytes can be written to the file.
8692/// CASE 3: If fAutoSave is 0, AutoSave() will never be called automatically
8693/// as part of TTree::Fill().
8695void TTree::SetAutoSave(Long64_t autos)
8696{
8697 fAutoSave = autos;
8698}
8699
8700////////////////////////////////////////////////////////////////////////////////
8701/// Set a branch's basket size.
8702///
8703/// bname is the name of a branch.
8704///
8705/// - if bname="*", apply to all branches.
8706/// - if bname="xxx*", apply to all branches with name starting with xxx
8707///
8708/// see TRegexp for wildcarding options
8709/// bufsize = branch basket size
8711void TTree::SetBasketSize(const char* bname, Int_t bufsize)
8712{
8713 Int_t nleaves = fLeaves.GetEntriesFast();
8714 TRegexp re(bname, true);
8715 Int_t nb = 0;
8716 for (Int_t i = 0; i < nleaves; i++) {
8717 TLeaf* leaf = (TLeaf*) fLeaves.UncheckedAt(i);
8718 TBranch* branch = (TBranch*) leaf->GetBranch();
8719 TString s = branch->GetName();
8720 if (strcmp(bname, branch->GetName()) && (s.Index(re) == kNPOS)) {
8721 continue;
8722 }
8723 nb++;
8724 branch->SetBasketSize(bufsize);
8725 }
8726 if (!nb) {
8727 Error("SetBasketSize", "unknown branch -> '%s'", bname);
8728 }
8729}
8730
8731////////////////////////////////////////////////////////////////////////////////
8732/// Change branch address, dealing with clone trees properly.
8733/// See TTree::CheckBranchAddressType for the semantic of the return value.
8734///
8735/// Note: See the comments in TBranchElement::SetAddress() for the
8736/// meaning of the addr parameter and the object ownership policy.
8738Int_t TTree::SetBranchAddress(const char* bname, void* addr, TBranch** ptr)
8739{
8740 TBranch* branch = GetBranch(bname);
8741 if (!branch) {
8742 if (ptr) *ptr = nullptr;
8743 Error("SetBranchAddress", "unknown branch -> %s", bname);
8744 return kMissingBranch;
8745 }
8746 return SetBranchAddressImp(branch,addr,ptr);
8747}
8748
8749////////////////////////////////////////////////////////////////////////////////
8750/// Verify the validity of the type of addr before calling SetBranchAddress.
8751/// See TTree::CheckBranchAddressType for the semantic of the return value.
8752///
8753/// Note: See the comments in TBranchElement::SetAddress() for the
8754/// meaning of the addr parameter and the object ownership policy.
8756Int_t TTree::SetBranchAddress(const char* bname, void* addr, TClass* ptrClass, EDataType datatype, bool isptr)
8757{
8758 return SetBranchAddress(bname, addr, nullptr, ptrClass, datatype, isptr);
8759}
8761Int_t TTree::SetBranchAddressImp(const char *bname, void *addr, TBranch **ptr, TClass *ptrClass, EDataType datatype,
8762 bool isptr)
8763{
8764 if (auto *branchFromSelf = GetBranchFromSelf(bname)) {
8765 Int_t res = CheckBranchAddressType(branchFromSelf, ptrClass, datatype, isptr);
8766
8767 // This will set the value of *ptr to branch.
8768 if (res >= 0) {
8769 // The check succeeded.
8770 if ((res & kNeedEnableDecomposedObj) && !branchFromSelf->GetMakeClass())
8771 branchFromSelf->SetMakeClass(true);
8772 SetBranchAddressImp(branchFromSelf, addr, ptr);
8773 } else {
8774 if (ptr)
8775 *ptr = nullptr;
8776 }
8777 return res;
8778 }
8779
8780 // Check friends
8781 // The next code section is going to look for the branch name "bname" in the friends. This could in principle be
8782 // achieved by simply calling GetBranchFromFriends, or collapse this whole function to just searching for the branch
8783 // with GetBranch. This may sometimes not be enough, for example when dealing with friendships with TChain, where
8784 // a certain amount of information may not be propagated correctly by simply calling GetBranch.
8785 if (fFriends) {
8786 int status{kMissingBranch};
8787 for (auto *fe : TRangeDynCast<TFriendElement>(fFriends)) {
8788 if (auto *tree = fe->GetTree()) {
8789 status = tree->SetBranchAddress(bname, addr, ptr, ptrClass, datatype, isptr, true);
8790 if (status != kMatch) {
8791 // Try again, the branch name may be prefixed by the tree name
8792 std::string_view bnameView{bname};
8793 if (ROOT::StartsWith(bnameView, fe->GetName())) {
8794 bnameView.remove_prefix(strlen(fe->GetName()));
8795 if (!bnameView.empty() && bnameView.front() == '.') {
8796 bnameView.remove_prefix(1);
8797 status = tree->SetBranchAddress(bnameView.data(), addr, ptr, ptrClass, datatype, isptr, true);
8798 }
8799 }
8800 }
8801 // We exit early from visiting all friends only if a perfect match was found
8802 if (status == kMatch)
8803 return status;
8804 }
8805 }
8806 // This allows for the valid case of friend TChain(s) which might hold
8807 // the requested branch, but might not know it yet since they haven't loaded
8808 // the tree. This is encoded in the kNoCheck == 5 value.
8809 if (status != kMissingBranch)
8810 return status;
8811 }
8812
8813 // Branch not found
8814 if (ptr)
8815 *ptr = nullptr;
8816
8817 return kMissingBranch;
8818}
8819
8820////////////////////////////////////////////////////////////////////////////////
8821/// Verify the validity of the type of addr before calling SetBranchAddress.
8822/// See TTree::CheckBranchAddressType for the semantic of the return value.
8823///
8824/// Note: See the comments in TBranchElement::SetAddress() for the
8825/// meaning of the addr parameter and the object ownership policy.
8827Int_t TTree::SetBranchAddress(const char *bname, void *addr, TBranch **ptr, TClass *ptrClass, EDataType datatype,
8828 bool isptr)
8829{
8830 auto res = SetBranchAddressImp(bname, addr, ptr, ptrClass, datatype, isptr);
8831 if (res == kMissingBranch)
8832 Error("SetBranchAddress", "unknown branch -> %s", bname);
8833 return res;
8834}
8836Int_t TTree::SetBranchAddress(const char *bname, void *addr, TBranch **ptr, TClass *ptrClass, EDataType datatype,
8837 bool isptr, bool)
8838{
8839 // This has been called while setting the branch address of friends of a TTree. We can't know a priori
8840 // which friend actually has the branch bname, so we avoid printing an error in case of missing branch
8841 return SetBranchAddressImp(bname, addr, ptr, ptrClass, datatype, isptr);
8842}
8843
8844////////////////////////////////////////////////////////////////////////////////
8845/// Change branch address, dealing with clone trees properly.
8846/// See TTree::CheckBranchAddressType for the semantic of the return value.
8847///
8848/// Note: See the comments in TBranchElement::SetAddress() for the
8849/// meaning of the addr parameter and the object ownership policy.
8851Int_t TTree::SetBranchAddressImp(TBranch *branch, void* addr, TBranch** ptr)
8852{
8853 if (ptr) {
8854 *ptr = branch;
8855 }
8856 if (fClones) {
8857 void* oldAddr = branch->GetAddress();
8858 TIter next(fClones);
8859 TTree* clone = nullptr;
8860 const char *bname = branch->GetName();
8861 while ((clone = (TTree*) next())) {
8862 TBranch* cloneBr = clone->GetBranch(bname);
8863 if (cloneBr && (cloneBr->GetAddress() == oldAddr)) {
8864 cloneBr->SetAddress(addr);
8865 }
8866 }
8867 }
8868 branch->SetAddress(addr);
8869 return kVoidPtr;
8870}
8871
8872////////////////////////////////////////////////////////////////////////////////
8873/// Set branch status to Process or DoNotProcess.
8874///
8875/// When reading a Tree, by default, all branches are read.
8876/// One can speed up considerably the analysis phase by activating
8877/// only the branches that hold variables involved in a query.
8878///
8879/// bname is the name of a branch.
8880///
8881/// - if bname="*", apply to all branches.
8882/// - if bname="xxx*", apply to all branches with name starting with xxx
8883///
8884/// see TRegexp for wildcarding options
8885///
8886/// - status = 1 branch will be processed
8887/// - = 0 branch will not be processed
8888///
8889/// Example:
8890///
8891/// Assume a tree T with sub-branches a,b,c,d,e,f,g,etc..
8892/// when doing T.GetEntry(i) all branches are read for entry i.
8893/// to read only the branches c and e, one can do
8894/// ~~~ {.cpp}
8895/// T.SetBranchStatus("*",0); //disable all branches
8896/// T.SetBranchStatus("c",1);
8897/// T.setBranchStatus("e",1);
8898/// T.GetEntry(i);
8899/// ~~~
8900/// bname is interpreted as a wild-carded TRegexp (see TRegexp::MakeWildcard).
8901/// Thus, "a*b" or "a.*b" matches branches starting with "a" and ending with
8902/// "b", but not any other branch with an "a" followed at some point by a
8903/// "b". For this second behavior, use "*a*b*". Note that TRegExp does not
8904/// support '|', and so you cannot select, e.g. track and shower branches
8905/// with "track|shower".
8906///
8907/// __WARNING! WARNING! WARNING!__
8908///
8909/// SetBranchStatus is matching the branch based on match of the branch
8910/// 'name' and not on the branch hierarchy! In order to be able to
8911/// selectively enable a top level object that is 'split' you need to make
8912/// sure the name of the top level branch is prefixed to the sub-branches'
8913/// name (by adding a dot ('.') at the end of the Branch creation and use the
8914/// corresponding bname.
8915///
8916/// I.e If your Tree has been created in split mode with a parent branch "parent."
8917/// (note the trailing dot).
8918/// ~~~ {.cpp}
8919/// T.SetBranchStatus("parent",1);
8920/// ~~~
8921/// will not activate the sub-branches of "parent". You should do:
8922/// ~~~ {.cpp}
8923/// T.SetBranchStatus("parent*",1);
8924/// ~~~
8925/// Without the trailing dot in the branch creation you have no choice but to
8926/// call SetBranchStatus explicitly for each of the sub branches.
8927///
8928/// An alternative to this function is to read directly and only
8929/// the interesting branches. Example:
8930/// ~~~ {.cpp}
8931/// TBranch *brc = T.GetBranch("c");
8932/// TBranch *bre = T.GetBranch("e");
8933/// brc->GetEntry(i);
8934/// bre->GetEntry(i);
8935/// ~~~
8936/// If found is not 0, the number of branch(es) found matching the regular
8937/// expression is returned in *found AND the error message 'unknown branch'
8938/// is suppressed.
8940void TTree::SetBranchStatus(const char* bname, bool status, UInt_t* found)
8941{
8942 // We already have been visited while recursively looking
8943 // through the friends tree, let return
8945 return;
8946 }
8947
8948 if (!bname || !*bname) {
8949 Error("SetBranchStatus", "Input regexp is an empty string: no match against branch names will be attempted.");
8950 return;
8951 }
8952
8953 TBranch *branch, *bcount, *bson;
8954 TLeaf *leaf, *leafcount;
8955
8956 Int_t i,j;
8957 Int_t nleaves = fLeaves.GetEntriesFast();
8958 TRegexp re(bname,true);
8959 Int_t nb = 0;
8960
8961 // first pass, loop on all branches
8962 // for leafcount branches activate/deactivate in function of status
8963 for (i=0;i<nleaves;i++) {
8964 leaf = (TLeaf*)fLeaves.UncheckedAt(i);
8965 branch = (TBranch*)leaf->GetBranch();
8966 TString s = branch->GetName();
8967 if (strcmp(bname,"*")) { //Regexp gives wrong result for [] in name
8968 TString longname;
8969 longname.Form("%s.%s",GetName(),branch->GetName());
8970 if (strcmp(bname,branch->GetName())
8971 && longname != bname
8972 && s.Index(re) == kNPOS) continue;
8973 }
8974 nb++;
8975 if (status) branch->ResetBit(kDoNotProcess);
8976 else branch->SetBit(kDoNotProcess);
8977 leafcount = leaf->GetLeafCount();
8978 if (leafcount) {
8979 bcount = leafcount->GetBranch();
8980 if (status) bcount->ResetBit(kDoNotProcess);
8981 else bcount->SetBit(kDoNotProcess);
8982 }
8983 }
8984 if (nb==0 && !strchr(bname,'*')) {
8985 branch = GetBranch(bname);
8986 if (branch) {
8987 if (status) branch->ResetBit(kDoNotProcess);
8988 else branch->SetBit(kDoNotProcess);
8989 ++nb;
8990 }
8991 }
8992
8993 //search in list of friends
8994 UInt_t foundInFriend = 0;
8995 if (fFriends) {
8996 TFriendLock lock(this,kSetBranchStatus);
8997 TIter nextf(fFriends);
8998 TFriendElement *fe;
8999 TString name;
9000 while ((fe = (TFriendElement*)nextf())) {
9001 TTree *t = fe->GetTree();
9002 if (!t) continue;
9003
9004 // If the alias is present replace it with the real name.
9005 const char *subbranch = strstr(bname,fe->GetName());
9006 if (subbranch!=bname) subbranch = nullptr;
9007 if (subbranch) {
9008 subbranch += strlen(fe->GetName());
9009 if ( *subbranch != '.' ) subbranch = nullptr;
9010 else subbranch ++;
9011 }
9012 if (subbranch) {
9013 name.Form("%s.%s",t->GetName(),subbranch);
9014 } else {
9015 name = bname;
9016 }
9017 t->SetBranchStatus(name,status, &foundInFriend);
9018 }
9019 }
9020 if (!nb && !foundInFriend) {
9021 if (!found) {
9022 if (status) {
9023 if (strchr(bname,'*') != nullptr)
9024 Error("SetBranchStatus", "No branch name is matching wildcard -> %s", bname);
9025 else
9026 Error("SetBranchStatus", "unknown branch -> %s", bname);
9027 } else {
9028 if (strchr(bname,'*') != nullptr)
9029 Warning("SetBranchStatus", "No branch name is matching wildcard -> %s", bname);
9030 else
9031 Warning("SetBranchStatus", "unknown branch -> %s", bname);
9032 }
9033 }
9034 return;
9035 }
9036 if (found) *found = nb + foundInFriend;
9037
9038 // second pass, loop again on all branches
9039 // activate leafcount branches for active branches only
9040 for (i = 0; i < nleaves; i++) {
9041 leaf = (TLeaf*)fLeaves.UncheckedAt(i);
9042 branch = (TBranch*)leaf->GetBranch();
9043 if (!branch->TestBit(kDoNotProcess)) {
9044 leafcount = leaf->GetLeafCount();
9045 if (leafcount) {
9046 bcount = leafcount->GetBranch();
9047 bcount->ResetBit(kDoNotProcess);
9048 }
9049 } else {
9050 //Int_t nbranches = branch->GetListOfBranches()->GetEntriesFast();
9051 Int_t nbranches = branch->GetListOfBranches()->GetEntries();
9052 for (j=0;j<nbranches;j++) {
9053 bson = (TBranch*)branch->GetListOfBranches()->UncheckedAt(j);
9054 if (!bson) continue;
9055 if (!bson->TestBit(kDoNotProcess)) {
9056 if (bson->GetNleaves() <= 0) continue;
9057 branch->ResetBit(kDoNotProcess);
9058 break;
9059 }
9060 }
9061 }
9062 }
9063}
9064
9065////////////////////////////////////////////////////////////////////////////////
9066/// Set the current branch style. (static function)
9067///
9068/// - style = 0 old Branch
9069/// - style = 1 new Bronch
9074}
9075
9076////////////////////////////////////////////////////////////////////////////////
9077/// Set maximum size of the file cache (TTreeCache) in bytes.
9078//
9079/// - if cachesize = 0 the existing cache (if any) is disabled (deleted if any).
9080/// - if cachesize > 0, the cache is enabled or extended, if necessary
9081/// - if cachesize = -1 (default) it is set to the AutoFlush value when writing
9082/// the Tree (default is 30 MBytes).
9083///
9084/// The cacheSize might be clamped, see TFileCacheRead::SetBufferSize
9085///
9086/// TTreeCache's 'real' job is to actually prefetch (early grab from disk) the compressed data.
9087/// The cachesize controls the size of the read bytes from disk.
9088///
9089/// Returns:
9090/// - 0 size set, cache was created if possible
9091/// - -1 on error
9094{
9095 // remember that the user has requested an explicit cache setup
9096 fCacheUserSet = true;
9097
9098 return SetCacheSizeAux(false, cacheSize);
9099}
9100
9101////////////////////////////////////////////////////////////////////////////////
9102/// Set the maximum size of the file cache (TTreeCache) in bytes and create it if possible.
9103///
9104/// If autocache is true:
9105/// this may be an autocreated cache, possibly enlarging an existing
9106/// autocreated cache. The size is calculated. The value passed in cacheSize:
9107/// - cacheSize = 0 make cache if default cache creation is enabled.
9108/// - cachesize > 0 the cache is enabled or extended, if necessary
9109/// - cacheSize = -1 make a default sized cache in any case
9110///
9111/// If autocache is false:
9112/// this is a user requested cache. cacheSize is used to size the cache.
9113/// This cache should never be automatically adjusted. If cachesize is
9114/// 0, the cache is disabled (deleted if any).
9115///
9116/// The cacheSize might be clamped, see TFileCacheRead::SetBufferSize
9117///
9118/// TTreeCache's 'real' job is to actually prefetch (early grab from disk) the compressed data.
9119/// The cachesize controls the size of the read bytes from disk.
9120///
9121/// Returns:
9122/// - 0 size set, or existing autosized cache almost large enough.
9123/// (cache was created if possible)
9124/// - -1 on error
9126Int_t TTree::SetCacheSizeAux(bool autocache /* = true */, Long64_t cacheSize /* = 0 */ )
9127{
9128 if (autocache) {
9129 // used as a once only control for automatic cache setup
9130 fCacheDoAutoInit = false;
9131 }
9132
9133 if (!autocache) {
9134 // negative size means the user requests the default
9135 if (cacheSize < 0) {
9136 cacheSize = GetCacheAutoSize(true);
9137 }
9138 } else {
9139 if (cacheSize == 0) {
9140 cacheSize = GetCacheAutoSize();
9141 } else if (cacheSize < 0) {
9142 cacheSize = GetCacheAutoSize(true);
9143 }
9144 }
9145
9146 TFile* file = GetCurrentFile();
9147 if (!file || GetTree() != this) {
9148 // if there's no file or we are not a plain tree (e.g. if we're a TChain)
9149 // do not create a cache, only record the size if one was given
9150 if (!autocache) {
9151 fCacheSize = cacheSize;
9152 }
9153 if (GetTree() != this) {
9154 return 0;
9155 }
9156 if (!autocache && cacheSize>0) {
9157 Warning("SetCacheSizeAux", "A TTreeCache could not be created because the TTree has no file");
9158 }
9159 return 0;
9160 }
9161
9162 // Check for an existing cache
9163 TTreeCache* pf = GetReadCache(file);
9164 if (pf) {
9165 if (autocache) {
9166 // reset our cache status tracking in case existing cache was added
9167 // by the user without using one of the TTree methods
9168 fCacheSize = pf->GetBufferSize();
9170
9171 if (fCacheUserSet) {
9172 // existing cache was created by the user, don't change it
9173 return 0;
9174 }
9175 } else {
9176 // update the cache to ensure it records the user has explicitly
9177 // requested it
9178 pf->SetAutoCreated(false);
9179 }
9180
9181 // if we're using an automatically calculated size and the existing
9182 // cache is already almost large enough don't resize
9183 if (autocache && Long64_t(0.80*cacheSize) < fCacheSize) {
9184 // already large enough
9185 return 0;
9186 }
9187
9188 if (cacheSize == fCacheSize) {
9189 return 0;
9190 }
9191
9192 if (cacheSize == 0) {
9193 // delete existing cache
9194 pf->WaitFinishPrefetch();
9195 file->SetCacheRead(nullptr,this);
9196 delete pf;
9197 pf = nullptr;
9198 } else {
9199 // resize
9200 Int_t res = pf->SetBufferSize(cacheSize);
9201 if (res < 0) {
9202 return -1;
9203 }
9204 cacheSize = pf->GetBufferSize(); // update after potential clamp
9205 }
9206 } else {
9207 // no existing cache
9208 if (autocache) {
9209 if (fCacheUserSet) {
9210 // value was already set manually.
9211 if (fCacheSize == 0) return 0;
9212 // Expected a cache should exist; perhaps the user moved it
9213 // Do nothing more here.
9214 if (cacheSize) {
9215 Error("SetCacheSizeAux", "Not setting up an automatically sized TTreeCache because of missing cache previously set");
9216 }
9217 return -1;
9218 }
9219 }
9220 }
9221
9222 fCacheSize = cacheSize;
9223 if (cacheSize == 0 || pf) {
9224 return 0;
9225 }
9226
9227#ifdef R__USE_IMT
9229 pf = new TTreeCacheUnzip(this, cacheSize);
9230 else
9231#endif
9232 pf = new TTreeCache(this, cacheSize);
9233
9234 pf->SetAutoCreated(autocache);
9235
9236 return 0;
9237}
9238
9239////////////////////////////////////////////////////////////////////////////////
9240///interface to TTreeCache to set the cache entry range
9241///
9242/// Returns:
9243/// - 0 entry range set
9244/// - -1 on error
9247{
9248 if (!GetTree()) {
9249 if (LoadTree(0)<0) {
9250 Error("SetCacheEntryRange","Could not load a tree");
9251 return -1;
9252 }
9253 }
9254 if (GetTree()) {
9255 if (GetTree() != this) {
9256 return GetTree()->SetCacheEntryRange(first, last);
9257 }
9258 } else {
9259 Error("SetCacheEntryRange", "No tree is available. Could not set cache entry range");
9260 return -1;
9261 }
9262
9263 TFile *f = GetCurrentFile();
9264 if (!f) {
9265 Error("SetCacheEntryRange", "No file is available. Could not set cache entry range");
9266 return -1;
9267 }
9268 TTreeCache *tc = GetReadCache(f,true);
9269 if (!tc) {
9270 Error("SetCacheEntryRange", "No cache is available. Could not set entry range");
9271 return -1;
9272 }
9273 tc->SetEntryRange(first,last);
9274 return 0;
9275}
9276
9277////////////////////////////////////////////////////////////////////////////////
9278/// Interface to TTreeCache to set the number of entries for the learning phase
9283}
9284
9285////////////////////////////////////////////////////////////////////////////////
9286/// Enable/Disable circularity for this tree.
9287///
9288/// if maxEntries > 0 a maximum of maxEntries is kept in one buffer/basket
9289/// per branch in memory.
9290/// Note that when this function is called (maxEntries>0) the Tree
9291/// must be empty or having only one basket per branch.
9292/// if maxEntries <= 0 the tree circularity is disabled.
9293///
9294/// #### NOTE 1:
9295/// Circular Trees are interesting in online real time environments
9296/// to store the results of the last maxEntries events.
9297/// #### NOTE 2:
9298/// Calling SetCircular with maxEntries <= 0 is necessary before
9299/// merging circular Trees that have been saved on files.
9300/// #### NOTE 3:
9301/// SetCircular with maxEntries <= 0 is automatically called
9302/// by TChain::Merge
9303/// #### NOTE 4:
9304/// A circular Tree can still be saved in a file. When read back,
9305/// it is still a circular Tree and can be filled again.
9307void TTree::SetCircular(Long64_t maxEntries)
9308{
9309 if (maxEntries <= 0) {
9310 // Disable circularity.
9311 fMaxEntries = 1000000000;
9312 fMaxEntries *= 1000;
9314 //in case the Tree was originally created in gROOT, the branch
9315 //compression level was set to -1. If the Tree is now associated to
9316 //a file, reset the compression level to the file compression level
9317 if (fDirectory) {
9318 TFile* bfile = fDirectory->GetFile();
9320 if (bfile) {
9321 compress = bfile->GetCompressionSettings();
9322 }
9324 for (Int_t i = 0; i < nb; i++) {
9325 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
9326 branch->SetCompressionSettings(compress);
9327 }
9328 }
9329 } else {
9330 // Enable circularity.
9331 fMaxEntries = maxEntries;
9333 }
9334}
9335
9336////////////////////////////////////////////////////////////////////////////////
9337/// Set the debug level and the debug range.
9338///
9339/// For entries in the debug range, the functions TBranchElement::Fill
9340/// and TBranchElement::GetEntry will print the number of bytes filled
9341/// or read for each branch.
9343void TTree::SetDebug(Int_t level, Long64_t min, Long64_t max)
9344{
9345 fDebug = level;
9346 fDebugMin = min;
9347 fDebugMax = max;
9348}
9349
9350////////////////////////////////////////////////////////////////////////////////
9351/// Update the default value for the branch's fEntryOffsetLen.
9352/// If updateExisting is true, also update all the existing branches.
9353/// If newdefault is less than 10, the new default value will be 10.
9355void TTree::SetDefaultEntryOffsetLen(Int_t newdefault, bool updateExisting)
9356{
9357 if (newdefault < 10) {
9358 newdefault = 10;
9359 }
9360 fDefaultEntryOffsetLen = newdefault;
9361 if (updateExisting) {
9362 TIter next( GetListOfBranches() );
9363 TBranch *b;
9364 while ( ( b = (TBranch*)next() ) ) {
9365 b->SetEntryOffsetLen( newdefault, true );
9366 }
9367 if (fBranchRef) {
9368 fBranchRef->SetEntryOffsetLen( newdefault, true );
9369 }
9370 }
9371}
9372
9373////////////////////////////////////////////////////////////////////////////////
9374/// Change the tree's directory.
9375///
9376/// Remove reference to this tree from current directory and
9377/// add reference to new directory dir. The dir parameter can
9378/// be 0 in which case the tree does not belong to any directory.
9379///
9382{
9383 if (fDirectory == dir) {
9384 return;
9385 }
9386 if (fDirectory) {
9387 fDirectory->Remove(this);
9388
9389 // Delete or move the file cache if it points to this Tree
9390 TFile *file = fDirectory->GetFile();
9391 MoveReadCache(file,dir);
9392 }
9393 fDirectory = dir;
9394 if (fDirectory) {
9395 fDirectory->Append(this);
9396 }
9397 TFile* file = nullptr;
9398 if (fDirectory) {
9399 file = fDirectory->GetFile();
9400 }
9401 if (fBranchRef) {
9402 fBranchRef->SetFile(file);
9403 }
9404 TBranch* b = nullptr;
9405 TIter next(GetListOfBranches());
9406 while((b = (TBranch*) next())) {
9407 b->SetFile(file);
9408 }
9409}
9410
9411////////////////////////////////////////////////////////////////////////////////
9412/// Change number of entries in the tree.
9413///
9414/// If n >= 0, set number of entries in the tree = n.
9415///
9416/// If n < 0, set number of entries in the tree to match the
9417/// number of entries in each branch. (default for n is -1)
9418///
9419/// This function should be called only when one fills each branch
9420/// independently via TBranch::Fill without calling TTree::Fill.
9421/// Calling TTree::SetEntries() make sense only if the number of entries
9422/// in each branch is identical, a warning is issued otherwise.
9423/// The function returns the number of entries.
9424///
9427{
9428 // case 1 : force number of entries to n
9429 if (n >= 0) {
9430 fEntries = n;
9431 return n;
9432 }
9433
9434 // case 2; compute the number of entries from the number of entries in the branches
9435 TBranch* b(nullptr), *bMin(nullptr), *bMax(nullptr);
9436 Long64_t nMin = kMaxEntries;
9437 Long64_t nMax = 0;
9438 TIter next(GetListOfBranches());
9439 while((b = (TBranch*) next())){
9440 Long64_t n2 = b->GetEntries();
9441 if (!bMin || n2 < nMin) {
9442 nMin = n2;
9443 bMin = b;
9444 }
9445 if (!bMax || n2 > nMax) {
9446 nMax = n2;
9447 bMax = b;
9448 }
9449 }
9450 if (bMin && nMin != nMax) {
9451 Warning("SetEntries", "Tree branches have different numbers of entries, eg %s has %lld entries while %s has %lld entries.",
9452 bMin->GetName(), nMin, bMax->GetName(), nMax);
9453 }
9454 fEntries = nMax;
9455 return fEntries;
9456}
9457
9458////////////////////////////////////////////////////////////////////////////////
9459/// Set an EntryList
9461void TTree::SetEntryList(TEntryList *enlist, Option_t * /*opt*/)
9462{
9463 if (fEntryList) {
9464 //check if the previous entry list is owned by the tree
9466 delete fEntryList;
9467 }
9468 }
9469 fEventList = nullptr;
9470 if (!enlist) {
9471 fEntryList = nullptr;
9472 return;
9473 }
9474 fEntryList = enlist;
9475 fEntryList->SetTree(this);
9476
9477}
9478
9479////////////////////////////////////////////////////////////////////////////////
9480/// This function transfroms the given TEventList into a TEntryList
9481/// The new TEntryList is owned by the TTree and gets deleted when the tree
9482/// is deleted. This TEntryList can be returned by GetEntryList() function.
9484void TTree::SetEventList(TEventList *evlist)
9485{
9486 fEventList = evlist;
9487 if (fEntryList){
9489 TEntryList *tmp = fEntryList;
9490 fEntryList = nullptr; // Avoid problem with RecursiveRemove.
9491 delete tmp;
9492 } else {
9493 fEntryList = nullptr;
9494 }
9495 }
9496
9497 if (!evlist) {
9498 fEntryList = nullptr;
9499 fEventList = nullptr;
9500 return;
9501 }
9502
9503 fEventList = evlist;
9504 char enlistname[100];
9505 snprintf(enlistname,100, "%s_%s", evlist->GetName(), "entrylist");
9506 fEntryList = new TEntryList(enlistname, evlist->GetTitle());
9507 fEntryList->SetDirectory(nullptr); // We own this.
9508 Int_t nsel = evlist->GetN();
9509 fEntryList->SetTree(this);
9510 Long64_t entry;
9511 for (Int_t i=0; i<nsel; i++){
9512 entry = evlist->GetEntry(i);
9513 fEntryList->Enter(entry);
9514 }
9517}
9518
9519////////////////////////////////////////////////////////////////////////////////
9520/// Set number of entries to estimate variable limits.
9521/// If n is -1, the estimate is set to be the current maximum
9522/// for the tree (i.e. GetEntries() + 1)
9523/// If n is less than -1, the behavior is undefined.
9525void TTree::SetEstimate(Long64_t n /* = 1000000 */)
9526{
9527 if (n == 0) {
9528 n = 10000;
9529 } else if (n < 0) {
9530 n = fEntries - n;
9531 }
9532 fEstimate = n;
9533 GetPlayer();
9534 if (fPlayer) {
9536 }
9537}
9538
9539////////////////////////////////////////////////////////////////////////////////
9540/// Provide the end-user with the ability to enable/disable various experimental
9541/// IO features for this TTree.
9542///
9543/// Returns all the newly-set IO settings.
9546{
9547 // Purposely ignore all unsupported bits; TIOFeatures implementation already warned the user about the
9548 // error of their ways; this is just a safety check.
9549 UChar_t featuresRequested = features.GetFeatures() & static_cast<UChar_t>(TBasket::EIOBits::kSupported);
9550
9551 UChar_t curFeatures = fIOFeatures.GetFeatures();
9552 UChar_t newFeatures = ~curFeatures & featuresRequested;
9553 curFeatures |= newFeatures;
9554 fIOFeatures.Set(curFeatures);
9555
9556 ROOT::TIOFeatures newSettings(newFeatures);
9557 return newSettings;
9558}
9559
9560////////////////////////////////////////////////////////////////////////////////
9561/// Set fFileNumber to number.
9562/// fFileNumber is used by TTree::Fill to set the file name
9563/// for a new file to be created when the current file exceeds fgTreeMaxSize.
9564/// (see TTree::ChangeFile)
9565/// if fFileNumber=10, the new file name will have a suffix "_11",
9566/// ie, fFileNumber is incremented before setting the file name
9568void TTree::SetFileNumber(Int_t number)
9569{
9570 if (fFileNumber < 0) {
9571 Warning("SetFileNumber", "file number must be positive. Set to 0");
9572 fFileNumber = 0;
9573 return;
9574 }
9575 fFileNumber = number;
9576}
9577
9578////////////////////////////////////////////////////////////////////////////////
9579/// Set all the branches in this TTree to be in decomposed object mode
9580/// (also known as MakeClass mode).
9581///
9582/// For MakeClass mode 0, the TTree expects the address where the data is stored
9583/// to be set by either the user or the TTree to the address of a full object
9584/// through the top level branch.
9585/// For MakeClass mode 1, this address is expected to point to a numerical type
9586/// or C-style array (variable or not) of numerical type, representing the
9587/// primitive data members.
9588/// The function's primary purpose is to allow the user to access the data
9589/// directly with numerical type variable rather than having to have the original
9590/// set of classes (or a reproduction thereof).
9591/// In other words, SetMakeClass sets the branch(es) into a
9592/// mode that allow its reading via a set of independent variables
9593/// (see the result of running TTree::MakeClass on your TTree) by changing the
9594/// interpretation of the address passed to SetAddress from being the beginning
9595/// of the object containing the data to being the exact location where the data
9596/// should be loaded. If you have the shared library corresponding to your object,
9597/// it is better if you do
9598/// `MyClass *objp = 0; tree->SetBranchAddress("toplevel",&objp);`, whereas
9599/// if you do not have the shared library but know your branch data type, e.g.
9600/// `Int_t* ptr = new Int_t[10];`, then:
9601/// `tree->SetMakeClass(1); tree->GetBranch("x")->SetAddress(ptr)` is the way to go.
9603void TTree::SetMakeClass(Int_t make)
9604{
9605 fMakeClass = make;
9606
9608 for (Int_t i = 0; i < nb; ++i) {
9609 TBranch* branch = (TBranch*) fBranches.UncheckedAt(i);
9610 branch->SetMakeClass(make);
9611 }
9612}
9613
9614////////////////////////////////////////////////////////////////////////////////
9615/// Set the maximum size in bytes of a Tree file (static function).
9616/// The default size is 100000000000LL, ie 100 Gigabytes.
9617///
9618/// In TTree::Fill, when the file has a size > fgMaxTreeSize,
9619/// the function closes the current file and starts writing into
9620/// a new file with a name of the style "file_1.root" if the original
9621/// requested file name was "file.root".
9623void TTree::SetMaxTreeSize(Long64_t maxsize)
9624{
9625 fgMaxTreeSize = maxsize;
9626}
9627
9628////////////////////////////////////////////////////////////////////////////////
9629/// Change the name of this tree.
9631void TTree::SetName(const char* name)
9632{
9633 if (gPad) {
9634 gPad->Modified();
9635 }
9636 // Trees are named objects in a THashList.
9637 // We must update hashlists if we change the name.
9638 TFile *file = nullptr;
9639 TTreeCache *pf = nullptr;
9640 if (fDirectory) {
9641 fDirectory->Remove(this);
9642 if ((file = GetCurrentFile())) {
9643 pf = GetReadCache(file);
9644 file->SetCacheRead(nullptr,this,TFile::kDoNotDisconnect);
9645 }
9646 }
9647 // This changes our hash value.
9648 fName = name;
9649 if (fDirectory) {
9650 fDirectory->Append(this);
9651 if (pf) {
9653 }
9654 }
9655}
9657void TTree::SetNotify(TObject *obj)
9658{
9659 if (obj && fNotify && dynamic_cast<TNotifyLinkBase *>(fNotify)) {
9660 auto *oldLink = static_cast<TNotifyLinkBase *>(fNotify);
9661 auto *newLink = dynamic_cast<TNotifyLinkBase *>(obj);
9662 if (!newLink) {
9663 Warning("TTree::SetNotify",
9664 "The tree or chain already has a fNotify registered and it is a TNotifyLink, while the new object is "
9665 "not a TNotifyLink. Setting fNotify to the new value will lead to an orphan linked list of "
9666 "TNotifyLinks and it is most likely not intended. If this is the intended goal, please call "
9667 "SetNotify(nullptr) first to silence this warning.");
9668 } else if (newLink->GetNext() != oldLink && oldLink->GetNext() != newLink) {
9669 // If newLink->GetNext() == oldLink then we are prepending the new head, as in TNotifyLink::PrependLink
9670 // If oldLink->GetNext() == newLink then we are removing the head of the list, as in TNotifyLink::RemoveLink
9671 // Otherwise newLink and oldLink are unrelated:
9672 Warning("TTree::SetNotify",
9673 "The tree or chain already has a TNotifyLink registered, and the new TNotifyLink `obj` does not link "
9674 "to it. Setting fNotify to the new value will lead to an orphan linked list of TNotifyLinks and it is "
9675 "most likely not intended. If this is the intended goal, please call SetNotify(nullptr) first to "
9676 "silence this warning.");
9677 }
9678 }
9679
9680 fNotify = obj;
9681}
9682
9683////////////////////////////////////////////////////////////////////////////////
9684/// Change the name and title of this tree.
9686void TTree::SetObject(const char* name, const char* title)
9687{
9688 if (gPad) {
9689 gPad->Modified();
9690 }
9691
9692 // Trees are named objects in a THashList.
9693 // We must update hashlists if we change the name
9694 TFile *file = nullptr;
9695 TTreeCache *pf = nullptr;
9696 if (fDirectory) {
9697 fDirectory->Remove(this);
9698 if ((file = GetCurrentFile())) {
9699 pf = GetReadCache(file);
9700 file->SetCacheRead(nullptr,this,TFile::kDoNotDisconnect);
9701 }
9702 }
9703 // This changes our hash value.
9704 fName = name;
9705 fTitle = title;
9706 if (fDirectory) {
9707 fDirectory->Append(this);
9708 if (pf) {
9710 }
9711 }
9712}
9713
9714////////////////////////////////////////////////////////////////////////////////
9715/// Enable or disable parallel unzipping of Tree buffers.
9717void TTree::SetParallelUnzip(bool opt, Float_t RelSize)
9718{
9719#ifdef R__USE_IMT
9720 if (GetTree() == nullptr) {
9722 if (!GetTree())
9723 return;
9724 }
9725 if (GetTree() != this) {
9726 GetTree()->SetParallelUnzip(opt, RelSize);
9727 return;
9728 }
9729 TFile* file = GetCurrentFile();
9730 if (!file)
9731 return;
9732
9733 TTreeCache* pf = GetReadCache(file);
9734 if (pf && !( opt ^ (nullptr != dynamic_cast<TTreeCacheUnzip*>(pf)))) {
9735 // done with opt and type are in agreement.
9736 return;
9737 }
9738 delete pf;
9739 auto cacheSize = GetCacheAutoSize(true);
9740 if (opt) {
9741 auto unzip = new TTreeCacheUnzip(this, cacheSize);
9742 unzip->SetUnzipBufferSize( Long64_t(cacheSize * RelSize) );
9743 } else {
9744 pf = new TTreeCache(this, cacheSize);
9745 }
9746#else
9747 (void)opt;
9748 (void)RelSize;
9749#endif
9750}
9751
9752////////////////////////////////////////////////////////////////////////////////
9753/// Set perf stats
9756{
9757 fPerfStats = perf;
9758}
9759
9760////////////////////////////////////////////////////////////////////////////////
9761/// The current TreeIndex is replaced by the new index.
9762/// Note that this function does not delete the previous index.
9763/// This gives the possibility to play with more than one index, e.g.,
9764/// ~~~ {.cpp}
9765/// TVirtualIndex* oldIndex = tree.GetTreeIndex();
9766/// tree.SetTreeIndex(newIndex);
9767/// tree.Draw();
9768/// tree.SetTreeIndex(oldIndex);
9769/// tree.Draw(); etc
9770/// ~~~
9773{
9774 if (fTreeIndex) {
9775 fTreeIndex->SetTree(nullptr);
9776 }
9777 fTreeIndex = index;
9778}
9779
9780////////////////////////////////////////////////////////////////////////////////
9781/// Set tree weight.
9782///
9783/// The weight is used by TTree::Draw to automatically weight each
9784/// selected entry in the resulting histogram.
9785///
9786/// For example the equivalent of:
9787/// ~~~ {.cpp}
9788/// T.Draw("x", "w")
9789/// ~~~
9790/// is:
9791/// ~~~ {.cpp}
9792/// T.SetWeight(w);
9793/// T.Draw("x");
9794/// ~~~
9795/// This function is redefined by TChain::SetWeight. In case of a
9796/// TChain, an option "global" may be specified to set the same weight
9797/// for all trees in the TChain instead of the default behaviour
9798/// using the weights of each tree in the chain (see TChain::SetWeight).
9801{
9802 fWeight = w;
9803}
9804
9805////////////////////////////////////////////////////////////////////////////////
9806/// Print values of all active leaves for entry.
9807///
9808/// - if entry==-1, print current entry (default)
9809/// - if a leaf is an array, a maximum of lenmax elements is printed.
9811void TTree::Show(Long64_t entry, Int_t lenmax)
9812{
9813 if (entry != -1) {
9814 Int_t ret = LoadTree(entry);
9815 if (ret == -2) {
9816 Error("Show()", "Cannot read entry %lld (entry does not exist)", entry);
9817 return;
9818 } else if (ret == -1) {
9819 Error("Show()", "Cannot read entry %lld (I/O error)", entry);
9820 return;
9821 }
9822 ret = GetEntry(entry);
9823 if (ret == -1) {
9824 Error("Show()", "Cannot read entry %lld (I/O error)", entry);
9825 return;
9826 } else if (ret == 0) {
9827 Error("Show()", "Cannot read entry %lld (no data read)", entry);
9828 return;
9829 }
9830 }
9831 printf("======> EVENT:%lld\n", fReadEntry);
9832 TObjArray* leaves = GetListOfLeaves();
9833 Int_t nleaves = leaves->GetEntriesFast();
9834 Int_t ltype;
9835 for (Int_t i = 0; i < nleaves; i++) {
9836 TLeaf* leaf = (TLeaf*) leaves->UncheckedAt(i);
9837 TBranch* branch = leaf->GetBranch();
9838 if (branch->TestBit(kDoNotProcess)) {
9839 continue;
9840 }
9841 Int_t len = leaf->GetLen();
9842 if (len <= 0) {
9843 continue;
9844 }
9845 len = TMath::Min(len, lenmax);
9846 if (leaf->IsA() == TLeafElement::Class()) {
9847 leaf->PrintValue(lenmax);
9848 continue;
9849 }
9850 if (branch->GetListOfBranches()->GetEntriesFast() > 0) {
9851 continue;
9852 }
9853 ltype = 10;
9854 if (leaf->IsA() == TLeafF::Class()) {
9855 ltype = 5;
9856 }
9857 if (leaf->IsA() == TLeafD::Class()) {
9858 ltype = 5;
9859 }
9860 if (leaf->IsA() == TLeafC::Class()) {
9861 len = 1;
9862 ltype = 5;
9863 };
9864 printf(" %-15s = ", leaf->GetName());
9865 for (Int_t l = 0; l < len; l++) {
9866 leaf->PrintValue(l);
9867 if (l == (len - 1)) {
9868 printf("\n");
9869 continue;
9870 }
9871 printf(", ");
9872 if ((l % ltype) == 0) {
9873 printf("\n ");
9874 }
9875 }
9876 }
9877}
9878
9879////////////////////////////////////////////////////////////////////////////////
9880/// Start the TTreeViewer on this tree.
9881///
9882/// - ww is the width of the canvas in pixels
9883/// - wh is the height of the canvas in pixels
9885void TTree::StartViewer()
9886{
9887 GetPlayer();
9888 if (fPlayer) {
9889 fPlayer->StartViewer(600, 400);
9890 }
9891}
9892
9893////////////////////////////////////////////////////////////////////////////////
9894/// Stop the cache learning phase
9895///
9896/// Returns:
9897/// - 0 learning phase stopped or not active
9898/// - -1 on error
9901{
9902 if (!GetTree()) {
9903 if (LoadTree(0)<0) {
9904 Error("StopCacheLearningPhase","Could not load a tree");
9905 return -1;
9906 }
9907 }
9908 if (GetTree()) {
9909 if (GetTree() != this) {
9910 return GetTree()->StopCacheLearningPhase();
9911 }
9912 } else {
9913 Error("StopCacheLearningPhase", "No tree is available. Could not stop cache learning phase");
9914 return -1;
9915 }
9916
9917 TFile *f = GetCurrentFile();
9918 if (!f) {
9919 Error("StopCacheLearningPhase", "No file is available. Could not stop cache learning phase");
9920 return -1;
9921 }
9922 TTreeCache *tc = GetReadCache(f,true);
9923 if (!tc) {
9924 Error("StopCacheLearningPhase", "No cache is available. Could not stop learning phase");
9925 return -1;
9926 }
9927 tc->StopLearningPhase();
9928 return 0;
9929}
9930
9931////////////////////////////////////////////////////////////////////////////////
9932/// Set the fTree member for all branches and sub branches.
9935{
9936 Int_t nb = branches.GetEntriesFast();
9937 for (Int_t i = 0; i < nb; ++i) {
9938 TBranch* br = (TBranch*) branches.UncheckedAt(i);
9939 br->SetTree(tree);
9940
9941 Int_t writeBasket = br->GetWriteBasket();
9942 for (Int_t j = writeBasket; j >= 0; --j) {
9943 TBasket *bk = (TBasket*)br->GetListOfBaskets()->UncheckedAt(j);
9944 if (bk) {
9946 }
9947 }
9948
9949 tree->RegisterBranchFullName({std::string{br->GetFullName()}, br});
9950
9952 }
9953}
9954
9955////////////////////////////////////////////////////////////////////////////////
9956/// Set the fTree member for all friend elements.
9958void TFriendElement__SetTree(TTree *tree, TList *frlist)
9959{
9960 if (frlist) {
9961 TObjLink *lnk = frlist->FirstLink();
9962 while (lnk) {
9963 TFriendElement *elem = (TFriendElement*)lnk->GetObject();
9964 elem->fParentTree = tree;
9965 lnk = lnk->Next();
9966 }
9967 }
9968}
9969
9970////////////////////////////////////////////////////////////////////////////////
9971/// Stream a class object.
9974{
9975 if (b.IsReading()) {
9976 UInt_t R__s, R__c;
9977 if (fDirectory) {
9978 fDirectory->Remove(this);
9979 //delete the file cache if it points to this Tree
9980 TFile *file = fDirectory->GetFile();
9981 MoveReadCache(file,nullptr);
9982 }
9983 fDirectory = nullptr;
9984 fCacheDoAutoInit = true;
9985 fCacheUserSet = false;
9986 fNamesToBranches.clear();
9987 Version_t R__v = b.ReadVersion(&R__s, &R__c);
9988 if (R__v > 4) {
9989 b.ReadClassBuffer(TTree::Class(), this, R__v, R__s, R__c);
9990
9991 fBranches.SetOwner(true); // True needed only for R__v < 19 and most R__v == 19
9992
9993 if (fBranchRef) fBranchRef->SetTree(this);
9996
9997 if (fTreeIndex) {
9998 fTreeIndex->SetTree(this);
9999 }
10000 if (fIndex.fN) {
10001 Warning("Streamer", "Old style index in this tree is deleted. Rebuild the index via TTree::BuildIndex");
10002 fIndex.Set(0);
10003 fIndexValues.Set(0);
10004 }
10005 if (fEstimate <= 10000) {
10006 fEstimate = 1000000;
10007 }
10008
10009 if (fNClusterRange) {
10010 // The I/O allocated just enough memory to hold the
10011 // current set of ranges.
10013 }
10014
10015 // Throughs calls to `GetCacheAutoSize` or `EnableCache` (for example
10016 // by TTreePlayer::Process, the cache size will be automatically
10017 // determined unless the user explicitly call `SetCacheSize`
10018 fCacheSize = 0;
10019 fCacheUserSet = false;
10020
10022 return;
10023 }
10024 //====process old versions before automatic schema evolution
10025 Stat_t djunk;
10026 Int_t ijunk;
10031 b >> fScanField;
10032 b >> ijunk; fMaxEntryLoop = (Long64_t)ijunk;
10033 b >> ijunk; fMaxVirtualSize = (Long64_t)ijunk;
10034 b >> djunk; fEntries = (Long64_t)djunk;
10035 b >> djunk; fTotBytes = (Long64_t)djunk;
10036 b >> djunk; fZipBytes = (Long64_t)djunk;
10037 b >> ijunk; fAutoSave = (Long64_t)ijunk;
10038 b >> ijunk; fEstimate = (Long64_t)ijunk;
10039 if (fEstimate <= 10000) fEstimate = 1000000;
10041 if (fBranchRef) fBranchRef->SetTree(this);
10045 if (R__v > 1) fIndexValues.Streamer(b);
10046 if (R__v > 2) fIndex.Streamer(b);
10047 if (R__v > 3) {
10048 TList OldInfoList;
10049 OldInfoList.Streamer(b);
10050 OldInfoList.Delete();
10051 }
10052 fNClusterRange = 0;
10055 b.CheckByteCount(R__s, R__c, TTree::IsA());
10056 //====end of old versions
10057 } else {
10058 if (fBranchRef) {
10059 fBranchRef->Clear();
10060 }
10062 if (table) TRefTable::SetRefTable(nullptr);
10063
10064 b.WriteClassBuffer(TTree::Class(), this);
10065
10066 if (table) TRefTable::SetRefTable(table);
10067 }
10068}
10069
10070////////////////////////////////////////////////////////////////////////////////
10071/// Unbinned fit of one or more variable(s) from a tree.
10072///
10073/// funcname is a TF1 function.
10074///
10075/// \note see TTree::Draw for explanations of the other parameters.
10076///
10077/// Fit the variable varexp using the function funcname using the
10078/// selection cuts given by selection.
10079///
10080/// The list of fit options is given in parameter option.
10081///
10082/// - option = "Q" Quiet mode (minimum printing)
10083/// - option = "V" Verbose mode (default is between Q and V)
10084/// - option = "E" Perform better Errors estimation using Minos technique
10085/// - option = "M" More. Improve fit results
10086///
10087/// You can specify boundary limits for some or all parameters via
10088/// ~~~ {.cpp}
10089/// func->SetParLimits(p_number, parmin, parmax);
10090/// ~~~
10091/// if parmin>=parmax, the parameter is fixed
10092///
10093/// Note that you are not forced to fix the limits for all parameters.
10094/// For example, if you fit a function with 6 parameters, you can do:
10095/// ~~~ {.cpp}
10096/// func->SetParameters(0,3.1,1.e-6,0.1,-8,100);
10097/// func->SetParLimits(4,-10,-4);
10098/// func->SetParLimits(5, 1,1);
10099/// ~~~
10100/// With this setup:
10101///
10102/// - Parameters 0->3 can vary freely
10103/// - Parameter 4 has boundaries [-10,-4] with initial value -8
10104/// - Parameter 5 is fixed to 100.
10105///
10106/// For the fit to be meaningful, the function must be self-normalized.
10107///
10108/// i.e. It must have the same integral regardless of the parameter
10109/// settings. Otherwise the fit will effectively just maximize the
10110/// area.
10111///
10112/// It is mandatory to have a normalization variable
10113/// which is fixed for the fit. e.g.
10114/// ~~~ {.cpp}
10115/// TF1* f1 = new TF1("f1", "gaus(0)/sqrt(2*3.14159)/[2]", 0, 5);
10116/// f1->SetParameters(1, 3.1, 0.01);
10117/// f1->SetParLimits(0, 1, 1); // fix the normalization parameter to 1
10118/// data->UnbinnedFit("f1", "jpsimass", "jpsipt>3.0");
10119/// ~~~
10120/// 1, 2 and 3 Dimensional fits are supported. See also TTree::Fit
10121///
10122/// Return status:
10123///
10124/// - The function return the status of the fit in the following form
10125/// fitResult = migradResult + 10*minosResult + 100*hesseResult + 1000*improveResult
10126/// - The fitResult is 0 is the fit is OK.
10127/// - The fitResult is negative in case of an error not connected with the fit.
10128/// - The number of entries used in the fit can be obtained via mytree.GetSelectedRows();
10129/// - If the number of selected entries is null the function returns -1
10131Int_t TTree::UnbinnedFit(const char* funcname, const char* varexp, const char* selection, Option_t* option, Long64_t nentries, Long64_t firstentry)
10132{
10133 GetPlayer();
10134 if (fPlayer) {
10135 return fPlayer->UnbinnedFit(funcname, varexp, selection, option, nentries, firstentry);
10136 }
10137 return -1;
10138}
10139
10140////////////////////////////////////////////////////////////////////////////////
10141/// Replace current attributes by current style.
10164}
10165
10166////////////////////////////////////////////////////////////////////////////////
10167/// Write this object to the current directory. For more see TObject::Write
10168/// If option & kFlushBasket, call FlushBasket before writing the tree.
10170Int_t TTree::Write(const char *name, Int_t option, Int_t bufsize) const
10171{
10174 return 0;
10175 return TObject::Write(name, option, bufsize);
10176}
10177
10178////////////////////////////////////////////////////////////////////////////////
10179/// Write this object to the current directory. For more see TObject::Write
10180/// If option & kFlushBasket, call FlushBasket before writing the tree.
10182Int_t TTree::Write(const char *name, Int_t option, Int_t bufsize)
10183{
10184 return ((const TTree*)this)->Write(name, option, bufsize);
10185}
10186
10187////////////////////////////////////////////////////////////////////////////////
10188/// \class TTreeFriendLeafIter
10189///
10190/// Iterator on all the leaves in a TTree and its friend
10191
10192
10193////////////////////////////////////////////////////////////////////////////////
10194/// Create a new iterator. By default the iteration direction
10195/// is kIterForward. To go backward use kIterBackward.
10198: fTree(const_cast<TTree*>(tree))
10199, fLeafIter(nullptr)
10200, fTreeIter(nullptr)
10201, fDirection(dir)
10202{
10203}
10204
10205////////////////////////////////////////////////////////////////////////////////
10206/// Copy constructor. Does NOT copy the 'cursor' location!
10209: TIterator(iter)
10210, fTree(iter.fTree)
10211, fLeafIter(nullptr)
10212, fTreeIter(nullptr)
10213, fDirection(iter.fDirection)
10214{
10215}
10216
10217////////////////////////////////////////////////////////////////////////////////
10218/// Overridden assignment operator. Does NOT copy the 'cursor' location!
10221{
10222 if (this != &rhs && rhs.IsA() == TTreeFriendLeafIter::Class()) {
10223 const TTreeFriendLeafIter &rhs1 = (const TTreeFriendLeafIter &)rhs;
10224 fDirection = rhs1.fDirection;
10225 }
10226 return *this;
10227}
10228
10229////////////////////////////////////////////////////////////////////////////////
10230/// Overridden assignment operator. Does NOT copy the 'cursor' location!
10233{
10234 if (this != &rhs) {
10235 fDirection = rhs.fDirection;
10236 }
10237 return *this;
10238}
10239
10240////////////////////////////////////////////////////////////////////////////////
10241/// Go the next friend element
10244{
10245 if (!fTree) return nullptr;
10246
10247 TObject * next;
10248 TTree * nextTree;
10249
10250 if (!fLeafIter) {
10251 TObjArray *list = fTree->GetListOfLeaves();
10252 if (!list) return nullptr; // Can happen with an empty chain.
10253 fLeafIter = list->MakeIterator(fDirection);
10254 if (!fLeafIter) return nullptr;
10255 }
10256
10257 next = fLeafIter->Next();
10258 if (!next) {
10259 if (!fTreeIter) {
10261 if (!list) return next;
10262 fTreeIter = list->MakeIterator(fDirection);
10263 if (!fTreeIter) return nullptr;
10264 }
10265 TFriendElement * nextFriend = (TFriendElement*) fTreeIter->Next();
10266 ///nextTree = (TTree*)fTreeIter->Next();
10267 if (nextFriend) {
10268 nextTree = const_cast<TTree*>(nextFriend->GetTree());
10269 if (!nextTree) return Next();
10272 if (!fLeafIter) return nullptr;
10273 next = fLeafIter->Next();
10274 }
10275 }
10276 return next;
10277}
10278
10279////////////////////////////////////////////////////////////////////////////////
10280/// Returns the object option stored in the list.
10283{
10284 if (fLeafIter) return fLeafIter->GetOption();
10285 return "";
10286}
10288TBranch *ROOT::Internal::TreeUtils::CallBranchImpRef(TTree &tree, const char *branchname, TClass *ptrClass,
10289 EDataType datatype, void *addobj, Int_t bufsize, Int_t splitlevel)
10290{
10291 return tree.BranchImpRef(branchname, ptrClass, datatype, addobj, bufsize, splitlevel);
10292}
10294TBranch *ROOT::Internal::TreeUtils::CallBranchImp(TTree &tree, const char *branchname, TClass *ptrClass, void *addobj,
10295 Int_t bufsize, Int_t splitlevel)
10296{
10297 return tree.BranchImp(branchname, ptrClass, addobj, bufsize, splitlevel);
10298}
#define R__unlikely(expr)
Definition RConfig.hxx:568
#define SafeDelete(p)
Definition RConfig.hxx:507
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
double * dst
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
bool Bool_t
Boolean (0=false, 1=true) (bool)
Definition RtypesCore.h:78
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
short Version_t
Class version identifier (short)
Definition RtypesCore.h:80
unsigned char UChar_t
Unsigned Character 1 byte (unsigned char)
Definition RtypesCore.h:53
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:69
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int)
Definition RtypesCore.h:61
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:72
double Double_t
Double 8 bytes.
Definition RtypesCore.h:74
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
Definition RtypesCore.h:132
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:84
unsigned long long ULong64_t
Portable unsigned long integer 8 bytes.
Definition RtypesCore.h:85
const char Option_t
Option string (const char)
Definition RtypesCore.h:81
const Int_t kDoNotProcess
Definition TBranch.h:56
EDataType
Definition TDataType.h:28
@ kNoType_t
Definition TDataType.h:33
@ kFloat_t
Definition TDataType.h:31
@ kULong64_t
Definition TDataType.h:32
@ kInt_t
Definition TDataType.h:30
@ kchar
Definition TDataType.h:31
@ kLong_t
Definition TDataType.h:30
@ kDouble32_t
Definition TDataType.h:31
@ kShort_t
Definition TDataType.h:29
@ kBool_t
Definition TDataType.h:32
@ kBits
Definition TDataType.h:34
@ kULong_t
Definition TDataType.h:30
@ kLong64_t
Definition TDataType.h:32
@ kUShort_t
Definition TDataType.h:29
@ kDouble_t
Definition TDataType.h:31
@ kCharStar
Definition TDataType.h:34
@ kChar_t
Definition TDataType.h:29
@ kUChar_t
Definition TDataType.h:29
@ kCounter
Definition TDataType.h:34
@ kUInt_t
Definition TDataType.h:30
@ kFloat16_t
Definition TDataType.h:33
@ kOther_t
Definition TDataType.h:32
#define gDirectory
Definition TDirectory.h:385
R__EXTERN TEnv * gEnv
Definition TEnv.h:126
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:130
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:208
#define N
static unsigned int total
Option_t Option_t option
Option_t Option_t SetLineWidth
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t cursor
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t SetFillStyle
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t SetLineColor
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t SetFillColor
Option_t Option_t SetMarkerStyle
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void reg
Option_t Option_t style
char name[80]
Definition TGX11.cxx:142
int nentries
R__EXTERN TInterpreter * gCling
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:792
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:417
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2585
R__EXTERN TStyle * gStyle
Definition TStyle.h:442
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
constexpr Int_t kNEntriesResort
Definition TTree.cxx:475
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:4864
static char DataTypeToChar(EDataType datatype)
Definition TTree.cxx:486
void TFriendElement__SetTree(TTree *tree, TList *frlist)
Set the fTree member for all friend elements.
Definition TTree.cxx:9957
bool CheckReshuffling(TTree &mainTree, TTree &friendTree)
Definition TTree.cxx:1268
constexpr Float_t kNEntriesResortInv
Definition TTree.cxx:476
#define R__LOCKGUARD(mutex)
#define gPad
Bool_t HasRuleWithSourceClass(const TString &source) const
Return True if we have any rule whose source class is 'source'.
A helper class for managing IMT work during TTree:Fill operations.
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 Foreach(F func, unsigned nTimes, unsigned nChunks=0)
Execute a function without arguments several times in parallel, dividing the execution in nChunks.
void Streamer(TBuffer &) override
Stream a TArrayD object.
Definition TArrayD.cxx:148
void Set(Int_t n) override
Set size of this array to n doubles.
Definition TArrayD.cxx:105
void Set(Int_t n) override
Set size of this array to n ints.
Definition TArrayI.cxx:104
void Streamer(TBuffer &) override
Stream a TArrayI object.
Definition TArrayI.cxx:147
Int_t fN
Definition TArray.h:38
Fill Area Attributes class.
Definition TAttFill.h:21
virtual void Streamer(TBuffer &)
virtual Color_t GetFillColor() const
Return the fill area color.
Definition TAttFill.h:32
virtual Style_t GetFillStyle() const
Return the fill area style.
Definition TAttFill.h:33
Line Attributes class.
Definition TAttLine.h:21
virtual void Streamer(TBuffer &)
virtual Color_t GetLineColor() const
Return the line color.
Definition TAttLine.h:36
virtual void SetLineStyle(Style_t lstyle)
Set the line style.
Definition TAttLine.h:46
virtual Width_t GetLineWidth() const
Return the line width.
Definition TAttLine.h:38
virtual Style_t GetLineStyle() const
Return the line style.
Definition TAttLine.h:37
Marker Attributes class.
Definition TAttMarker.h:22
virtual Style_t GetMarkerStyle() const
Return the marker style.
Definition TAttMarker.h:35
virtual Color_t GetMarkerColor() const
Return the marker color.
Definition TAttMarker.h:34
virtual Size_t GetMarkerSize() const
Return the marker size.
Definition TAttMarker.h:36
virtual void SetMarkerStyle(Style_t mstyle=1)
Set the marker style.
virtual void SetMarkerSize(Size_t msize=1)
Set the marker size.
virtual void Streamer(TBuffer &)
virtual void SetMarkerColor(Color_t mcolor=1)
Set the marker color.
Each class (see TClass) has a linked list of its base class(es).
Definition TBaseClass.h:33
ROOT::ESTLType IsSTLContainer()
Return which type (if any) of STL container the data member is.
Manages buffers for branches of a Tree.
Definition TBasket.h:34
virtual Int_t DropBuffers()
Drop buffers of this basket if it is not the current basket.
Definition TBasket.cxx:174
Int_t GetBufferSize() const
Definition TBasket.h:122
A Branch for the case of an array of clone objects.
A Branch for the case of an object.
virtual bool IsObjectOwner() const
virtual void SetBranchFolder()
static TClass * Class()
Int_t GetClassVersion()
const char * GetClassName() const override
Return the name of the user class whose content is stored in this branch, if any.
void ResetAddress() override
Set branch address to zero and free all allocated memory.
Int_t Unroll(const char *name, TClass *cltop, TClass *cl, char *ptr, Int_t basketsize, Int_t splitlevel, Int_t btype)
Split class cl into sub-branches of this branch.
void SetAddress(void *addobj) override
Point this branch at an object.
virtual void SetTargetClass(const char *name)
Set the name of the class of the in-memory object into which the data will loaded.
void SetObject(void *objadd) override
Set object this branch is pointing to.
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
virtual TLeaf * GetLeaf(const char *name) const
Return pointer to the 1st Leaf named name in thisBranch.
Definition TBranch.cxx:2053
virtual bool GetMakeClass() const
Return whether this branch is in a mode where the object are decomposed or not (Also known as MakeCla...
Definition TBranch.cxx:2115
virtual void SetupAddresses()
If the branch address is not set, we set all addresses starting with the top level parent branch.
Definition TBranch.cxx:3313
virtual void ResetAddress()
Reset the address of the branch.
Definition TBranch.cxx:2649
virtual Long64_t GetBasketSeek(Int_t basket) const
Return address of basket in the file.
Definition TBranch.cxx:1300
virtual char * GetAddress() const
Definition TBranch.h:221
void SetCompressionSettings(Int_t settings=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault)
Set compression settings.
Definition TBranch.cxx:2816
TTree * GetTree() const
Definition TBranch.h:261
static TClass * Class()
virtual TString GetFullName() const
Return the 'full' name of the branch.
Definition TBranch.cxx:2029
Int_t GetWriteBasket() const
Definition TBranch.h:247
virtual void DropBaskets(Option_t *option="")
Loop on all branch baskets.
Definition TBranch.cxx:755
TObjArray * GetListOfBranches()
Definition TBranch.h:255
virtual void SetTree(TTree *tree)
Definition TBranch.h:296
virtual Int_t GetEntry(Long64_t entry=0, Int_t getall=0)
Read all leaves of entry and return total number of bytes read.
Definition TBranch.cxx:1704
TClass * IsA() const override
Definition TBranch.h:304
void Print(Option_t *option="") const override
Print TBranch parameters.
Definition TBranch.cxx:2339
static void ResetCount()
Static function resetting fgCount.
Definition TBranch.cxx:2672
virtual void SetObject(void *objadd)
Set object this branch is pointing to.
Definition TBranch.cxx:2947
Int_t FlushBaskets()
Flush to disk all the baskets of this branch and any of subbranches.
Definition TBranch.cxx:1134
virtual void SetAddress(void *add)
Set address of this branch.
Definition TBranch.cxx:2693
Int_t GetNleaves() const
Definition TBranch.h:258
virtual void SetFile(TFile *file=nullptr)
Set file where this branch writes/reads its buffers.
Definition TBranch.cxx:2874
virtual void SetEntryOffsetLen(Int_t len, bool updateSubBranches=false)
Update the default value for the branch's fEntryOffsetLen if and only if it was already non zero (and...
Definition TBranch.cxx:2832
TObjArray * GetListOfBaskets()
Definition TBranch.h:254
Long64_t GetEntries() const
Definition TBranch.h:260
virtual void UpdateFile()
Refresh the value of fDirectory (i.e.
Definition TBranch.cxx:3323
Int_t GetReadBasket() const
Definition TBranch.h:245
Int_t GetMaxBaskets() const
Definition TBranch.h:257
virtual TFile * GetFile(Int_t mode=0)
Return pointer to the file where branch buffers reside, returns 0 in case branch buffers reside in th...
Definition TBranch.cxx:1851
virtual void KeepCircular(Long64_t maxEntries)
keep a maximum of fMaxEntries in memory
Definition TBranch.cxx:2281
virtual void ResetAfterMerge(TFileMergeInfo *)
Reset a Branch.
Definition TBranch.cxx:2596
virtual TBranch * FindBranch(const char *name)
Find the immediate sub-branch with passed name.
Definition TBranch.cxx:1033
virtual Int_t LoadBaskets()
Baskets associated to this branch are forced to be in memory.
Definition TBranch.cxx:2307
void SetIOFeatures(TIOFeatures &features)
Definition TBranch.h:292
Long64_t GetTotBytes(Option_t *option="") const
Return total number of bytes in the branch (excluding current buffer) if option ="*" includes all sub...
Definition TBranch.cxx:2218
virtual void SetOffset(Int_t offset=0)
Definition TBranch.h:294
virtual Int_t GetExpectedType(TClass *&clptr, EDataType &type)
Fill expectedClass and expectedType with information on the data type of the object/values contained ...
Definition TBranch.cxx:1832
virtual Int_t GetBasketSize() const
Definition TBranch.h:226
Long64_t GetZipBytes(Option_t *option="") const
Return total number of zip bytes in the branch if option ="*" includes all sub-branches of this branc...
Definition TBranch.cxx:2236
virtual void Refresh(TBranch *b)
Refresh this branch using new information in b This function is called by TTree::Refresh.
Definition TBranch.cxx:2506
virtual bool SetMakeClass(bool decomposeObj=true)
Set the branch in a mode where the object are decomposed (Also known as MakeClass mode).
Definition TBranch.cxx:2938
TObjArray * GetListOfLeaves()
Definition TBranch.h:256
Int_t Fill()
Definition TBranch.h:214
virtual void Reset(Option_t *option="")
Reset a Branch.
Definition TBranch.cxx:2555
virtual void SetBasketSize(Int_t bufsize)
Set the basket size The function makes sure that the basket size is greater than fEntryOffsetlen.
Definition TBranch.cxx:2740
TBranch * GetMother() const
Get our top-level parent branch in the tree.
Definition TBranch.cxx:2125
virtual Int_t FillImpl(ROOT::Internal::TBranchIMTHelper *)
Loop on all leaves of this branch to fill Basket buffer.
Definition TBranch.cxx:854
Int_t GetEntryOffsetLen() const
Definition TBranch.h:236
Using a TBrowser one can browse all ROOT objects.
Definition TBrowser.h:37
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket.
Definition TBufferFile.h:47
Buffer base class used for serializing objects.
Definition TBuffer.h:43
void Expand(Int_t newsize, Bool_t copy=kTRUE)
Expand (or shrink) the I/O buffer to newsize bytes.
Definition TBuffer.cxx:222
Int_t BufferSize() const
Definition TBuffer.h:98
@ kWrite
Definition TBuffer.h:73
@ kRead
Definition TBuffer.h:73
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
Bool_t CanSplit() const
Return true if the data member of this TClass can be saved separately.
Definition TClass.cxx:2331
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition TClass.cxx:2912
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition TClass.cxx:5111
Bool_t HasDataMemberInfo() const
Definition TClass.h:420
Bool_t HasCustomStreamerMember() const
The class has a Streamer method and it is implemented by the user or an older (not StreamerInfo based...
Definition TClass.h:524
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition TClass.cxx:5533
void BuildRealData(void *pointer=nullptr, Bool_t isTransient=kFALSE)
Build a full list of persistent data members.
Definition TClass.cxx:2043
const std::type_info * GetTypeInfo() const
Definition TClass.h:512
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition TClass.cxx:3833
TList * GetListOfRealData() const
Definition TClass.h:468
Bool_t CanIgnoreTObjectStreamer()
Definition TClass.h:406
const ROOT::Detail::TSchemaRuleSet * GetSchemaRules() const
Return the set of the schema rules if any.
Definition TClass.cxx:1939
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition TClass.cxx:3699
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition TClass.cxx:6080
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:6106
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0, Bool_t isTransient=kFALSE) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist,...
Definition TClass.cxx:4720
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4995
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2923
TVirtualStreamerInfo * GetConversionStreamerInfo(const char *onfile_classname, Int_t version) const
Return a Conversion StreamerInfo from the class 'classname' for version number 'version' to this clas...
Definition TClass.cxx:7272
TVirtualStreamerInfo * FindConversionStreamerInfo(const char *onfile_classname, UInt_t checksum) const
Return a Conversion StreamerInfo from the class 'classname' for the layout represented by 'checksum' ...
Definition TClass.cxx:7379
Version_t GetClassVersion() const
Definition TClass.h:434
TClass * GetActualClass(const void *object) const
Return a pointer to the real class of the object.
Definition TClass.cxx:2619
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2999
Int_t WriteBuffer(TBuffer &b, void *pointer, const char *info="")
Function called by the Streamer functions to serialize object at p to buffer b.
Definition TClass.cxx:6950
An array of clone (identical) objects.
void BypassStreamer(Bool_t bypass=kTRUE)
When the kBypassStreamer bit is set, the automatically generated Streamer can call directly TClass::W...
TClass * GetClass() const
static TClass * Class()
Collection abstract base class.
Definition TCollection.h:65
virtual TObject ** GetObjectRef(const TObject *obj) const =0
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).
virtual Bool_t IsEmpty() const
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.
void Append(TObject *obj, Bool_t replace=kFALSE) override
Append object 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 Bool_t cd()
Change current directory to "this" directory.
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
virtual Long64_t GetEntry(Int_t index) const
Return value of entry at index in the list.
virtual bool GetReapplyCut() const
Definition TEventList.h:57
virtual Int_t GetN() const
Definition TEventList.h:56
A cache when reading files over the network.
virtual void WaitFinishPrefetch()
virtual Int_t GetBufferSize() const
A class to pass information from the TFileMerger to the objects being merged.
TIOFeatures * fIOFeatures
Any ROOT IO features that should be explicitly enabled.
Bool_t fIsFirst
True if this is the first call to Merge for this series of object.
TString fOptions
Additional text based option being passed down to customize the merge.
TDirectory * fOutputDirectory
Target directory where the merged object will be written.
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:2432
Int_t GetCompressionSettings() const
Definition TFile.h:489
Int_t GetCompressionLevel() const
Definition TFile.h:483
virtual Long64_t GetEND() const
Definition TFile.h:319
virtual void WriteStreamerInfo()
Write the list of TStreamerInfo as a single object in this file The class Streamer description for al...
Definition TFile.cxx:3505
@ kDoNotDisconnect
Definition TFile.h:148
virtual void Flush()
Synchronize a file's in-memory and on-disk states.
Definition TFile.cxx:1166
virtual void MakeFree(Long64_t first, Long64_t last)
Mark unused bytes on the file.
Definition TFile.cxx:1510
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:3802
virtual void WriteHeader()
Write File Header.
Definition TFile.cxx:2682
@ kCancelTTreeChangeRequest
Definition TFile.h:275
Int_t GetRecordHeader(char *buf, Long64_t first, Int_t maxbytes, Int_t &nbytes, Int_t &objlen, Int_t &keylen)
Read the logical record header starting at a certain postion.
Definition TFile.cxx:1326
TFileCacheRead * GetCacheRead(const TObject *tree=nullptr) const
Return a pointer to the current read cache.
Definition TFile.cxx:1287
<div class="legacybox"><h2>Legacy Code</h2> TFolder is a legacy interface: there will be no bug fixes...
Definition TFolder.h:30
TCollection * GetListOfFolders() const
Definition TFolder.h:55
virtual Int_t Occurence(const TObject *obj) const
Return occurrence number of object in the list of objects of this folder.
Definition TFolder.cxx:427
static TClass * Class()
A TFriendElement TF describes a TTree object TF in a file.
virtual const char * GetTreeName() const
Get the actual TTree name of the friend.
virtual TTree * GetTree()
Return pointer to friend TTree.
bool IsUpdated() const
virtual TFile * GetFile()
Return pointer to TFile containing this friend TTree.
TTree * fParentTree
! pointer to the parent TTree
virtual Int_t DeleteGlobal(void *obj)=0
void Reset()
Iterator abstract base class.
Definition TIterator.h:30
virtual TObject * Next()=0
virtual TClass * IsA() const
Definition TIterator.h:48
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 Double_t GetValue(Int_t i=0) const
Definition TLeaf.h:186
virtual void * GetValuePointer() const
Definition TLeaf.h:141
virtual Int_t GetLenType() const
Definition TLeaf.h:136
virtual void ReadValue(std::istream &, Char_t=' ')
Definition TLeaf.h:159
virtual Int_t GetMaximum() const
Definition TLeaf.h:137
virtual Int_t GetLen() const
Return the number of effective elements of this leaf, for the current entry.
Definition TLeaf.cxx:407
virtual TLeaf * GetLeafCount() const
If this leaf stores a variable-sized array or a multi-dimensional array whose last dimension has vari...
Definition TLeaf.h:124
TClass * IsA() const override
Definition TLeaf.h:171
virtual bool IncludeRange(TLeaf *)
Definition TLeaf.h:149
virtual void SetAddress(void *add=nullptr)
Definition TLeaf.h:188
TBranch * GetBranch() const
Definition TLeaf.h:119
@ 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
virtual void PrintValue(Int_t i=0) const
Definition TLeaf.h:187
A doubly linked list.
Definition TList.h:38
void Streamer(TBuffer &) override
Stream all objects in the collection to or from the I/O buffer.
Definition TList.cxx:1323
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
TObject * First() const override
Return the first object in the list. Returns 0 when list is empty.
Definition TList.cxx:789
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
TObject * Clone(const char *newname="") const override
Make a clone of an object using the Streamer facility.
Definition TNamed.cxx:73
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:173
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
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:149
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.
TObject * Last() const override
Return the object in the last filled slot. Returns 0 if no entries.
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.
TIterator * MakeIterator(Bool_t dir=kIterForward) const override
Returns an array iterator.
virtual void Compress()
Remove empty slots from array.
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 * RemoveAt(Int_t idx) override
Remove object at index idx.
TObject * FindObject(const char *name) const override
Find an object in this collection using its name.
void Add(TObject *obj) override
Definition TObjArray.h:68
Mother of all ROOT objects.
Definition TObject.h:42
virtual Bool_t Notify()
This method must be overridden to handle object notification (the base implementation is no-op).
Definition TObject.cxx:617
@ kBitMask
Definition TObject.h:95
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:461
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:204
@ kOnlyPrepStep
Used to request that the class specific implementation of TObject::Write just prepare the objects to ...
Definition TObject.h:115
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:226
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1082
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition TObject.h:161
virtual Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0)
Write this object to the current directory.
Definition TObject.cxx:987
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:886
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:548
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1096
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1124
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:506
virtual TClass * IsA() const
Definition TObject.h:248
void ResetBit(UInt_t f)
Definition TObject.h:203
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:71
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition TObject.h:73
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1070
Principal Components Analysis (PCA)
Definition TPrincipal.h:21
The TRealData class manages the effective list of all data members for a given class.
Definition TRealData.h:30
const char * GetName() const override
Returns name of object.
Definition TRealData.h:52
TDataMember * GetDataMember() const
Definition TRealData.h:53
Bool_t IsObject() const
Definition TRealData.h:56
Long_t GetThisOffset() const
Definition TRealData.h:55
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.
void ForceWriteInfo(TFile *file, Bool_t force=kFALSE) override
Recursively mark streamer infos for writing to a file.
Basic string class.
Definition TString.h:137
Ssiz_t Length() const
Definition TString.h:426
void ToLower()
Change string to lower-case.
Definition TString.cxx:1190
static constexpr Ssiz_t kNPOS
Definition TString.h:285
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition TString.cxx:1171
Double_t Atof() const
Return floating-point value contained in string.
Definition TString.cxx:2135
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition TString.cxx:546
const char * Data() const
Definition TString.h:385
Bool_t EqualTo(const char *cs, ECaseCompare cmp=kExact) const
Definition TString.h:655
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:714
@ kLeading
Definition TString.h:283
@ kTrailing
Definition TString.h:283
@ kIgnoreCase
Definition TString.h:284
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition TString.cxx:939
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition TString.cxx:2345
Bool_t IsNull() const
Definition TString.h:423
TString & Remove(Ssiz_t pos)
Definition TString.h:695
TString & Append(const char *cs)
Definition TString.h:582
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2460
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2438
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:642
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:661
void SetHistFillColor(Color_t color=1)
Definition TStyle.h:383
Color_t GetHistLineColor() const
Definition TStyle.h:235
Bool_t IsReading() const
Definition TStyle.h:300
void SetHistLineStyle(Style_t styl=0)
Definition TStyle.h:386
Style_t GetHistFillStyle() const
Definition TStyle.h:236
Color_t GetHistFillColor() const
Definition TStyle.h:234
void SetHistLineColor(Color_t color=1)
Definition TStyle.h:384
Style_t GetHistLineStyle() const
Definition TStyle.h:237
void SetHistFillStyle(Style_t styl=0)
Definition TStyle.h:385
Width_t GetHistLineWidth() const
Definition TStyle.h:238
void SetHistLineWidth(Width_t width=1)
Definition TStyle.h:387
A zero length substring is legal.
Definition TString.h:83
TString & String()
Definition TString.h:122
virtual const char * Getenv(const char *env)
Get environment variable.
Definition TSystem.cxx:1687
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:1318
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
bool IsAutoCreated() const
Definition TTreeCache.h:150
Int_t SetBufferSize(Long64_t buffersize) override
Change the underlying buffer size of the cache.
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...
TTree * GetTree() const
Definition TTreeCache.h:149
virtual void SetEntryRange(Long64_t emin, Long64_t emax)
Set the minimum and maximum entry number to be processed this information helps to optimize the numbe...
virtual Int_t DropBranch(TBranch *b, bool subbranches=false)
Remove a branch to the list of branches to be stored in the cache this function is called by TBranch:...
void SetAutoCreated(bool val)
Definition TTreeCache.h:164
virtual void StopLearningPhase()
This is the counterpart of StartLearningPhase() and can be used to stop the learning phase.
void Print(Option_t *option="") const override
Print cache statistics.
Int_t AddBranch(TBranch *b, bool subgbranches=false) override
Add a branch to the list of branches to be stored in the cache this function is called by the user vi...
Class implementing or helping the various TTree cloning method.
Definition TTreeCloner.h:31
const char * GetWarning() const
bool Exec()
Execute the cloning.
bool NeedConversion()
bool IsValid()
void SetCacheSize(Long64_t size)
Set the cache size used by the matching TFile.
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:10219
TObject * Next() override
Go the next friend element.
Definition TTree.cxx:10242
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:10281
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:639
Long64_t Previous()
Move on to the previous cluster and return the starting entry of this previous cluster.
Definition TTree.cxx:722
Long64_t Next()
Move on to the next cluster and return the starting entry of this next cluster.
Definition TTree.cxx:678
Long64_t GetNextEntry()
Definition TTree.h:359
TClusterIterator(TTree *tree, Long64_t firstEntry)
Regular constructor.
Definition TTree.cxx:588
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:554
TFriendLock(const TFriendLock &)
Copy constructor.
Definition TTree.cxx:544
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:567
A TTree represents a columnar dataset.
Definition TTree.h:89
virtual Int_t Fill()
Fill all branches.
Definition TTree.cxx:4676
virtual TFriendElement * AddFriend(const char *treename, const char *filename="")
Add a TFriendElement to the list of friends.
Definition TTree.cxx:1360
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:6458
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:2683
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:5407
virtual Int_t SetBranchAddress(const char *bname, void *add, TBranch **ptr, TClass *realClass, EDataType datatype, bool isptr, bool suppressMissingBranchError)
Definition TTree.cxx:8835
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:4971
virtual void SetBranchStatus(const char *bname, bool status=true, UInt_t *found=nullptr)
Set branch status to Process or DoNotProcess.
Definition TTree.cxx:8939
bool EnableCache()
Enable the TTreeCache unless explicitly disabled for this TTree by a prior call to SetCacheSize(0).
Definition TTree.cxx:2716
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition TTree.cxx:5459
static Int_t GetBranchStyle()
Static function returning the current branch style.
Definition TTree.cxx:5500
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:5485
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:5207
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:9810
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:9899
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:5747
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:9306
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:1087
Long64_t GetMedianClusterSize()
Estimate the median cluster size for the TTree.
Definition TTree.cxx:8649
virtual TClusterIterator GetClusterIterator(Long64_t firstentry)
Return an iterator over the cluster of baskets starting at firstentry.
Definition TTree.cxx:5572
virtual void ResetBranchAddress(TBranch *)
Tell a branch to set its address to zero.
Definition TTree.cxx:8403
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:7926
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:6019
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:9425
virtual TObjArray * GetListOfLeaves()
Definition TTree.h:584
TLeaf * SearchLeafInListOfLeaves(const char *branchName, const char *leafName)
Definition TTree.cxx:6227
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:2105
virtual Int_t GetEntryWithIndex(Long64_t major, Long64_t minor=0)
Read entry corresponding to major and minor number.
Definition TTree.cxx:6037
Long64_t GetCacheAutoSize(bool withDefault=false)
Used for automatic sizing of the cache.
Definition TTree.cxx:5512
virtual TBranch * BranchRef()
Build the optional branch supporting the TRefTable.
Definition TTree.cxx:2359
TFile * GetCurrentFile() const
Return pointer to the current file.
Definition TTree.cxx:5584
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:3760
virtual Int_t DropBranchFromCache(const char *bname, bool subbranches=false)
Remove the branch with name 'bname' from the Tree cache.
Definition TTree.cxx:1170
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:5157
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:9972
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:8219
TVirtualTreePlayer * GetPlayer()
Load the TTreePlayer (if not already done).
Definition TTree.cxx:6561
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:7032
virtual Long64_t ReadStream(std::istream &inputStream, const char *branchDescriptor="", char delimiter=' ')
Create or simply read branches from an input stream.
Definition TTree.cxx:7953
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:9342
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:6085
virtual void SetNotify(TObject *obj)
Sets the address of the object to be notified when the tree is loaded.
Definition TTree.cxx:9656
virtual Double_t GetMaximum(const char *columname)
Return maximum of column with name columname.
Definition TTree.cxx:6535
virtual Long64_t GetEntryNumberWithBestIndex(Long64_t major, Long64_t minor=0) const
Return entry number corresponding to major and minor number.
Definition TTree.cxx:5999
static void SetMaxTreeSize(Long64_t maxsize=100000000000LL)
Set the maximum size in bytes of a Tree file (static function).
Definition TTree.cxx:9622
void Print(Option_t *option="") const override
Print a summary of the tree contents.
Definition TTree.cxx:7559
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:10130
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:7711
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:6222
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:9602
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:7352
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:6574
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:2780
virtual TEntryList * GetEntryList()
Returns the entry list assigned to this tree.
Definition TTree.cxx:5963
virtual void SetWeight(Double_t w=1, Option_t *option="")
Set tree weight.
Definition TTree.cxx:9799
void InitializeBranchLists(bool checkLeafCount)
Divides the top-level branches into two vectors: (i) branches to be processed sequentially and (ii) b...
Definition TTree.cxx:5890
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:9754
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:9279
TEntryList * fEntryList
! Pointer to event selection list (if one)
Definition TTree.h:136
TBranch * FindBranchFromFriends(const char *branchName)
Definition TTree.cxx:4927
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:7166
virtual void SetMaxVirtualSize(Long64_t size=0)
Definition TTree.h:725
virtual void DropBaskets()
Remove some baskets from memory.
Definition TTree.cxx:4591
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:8694
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:9716
virtual void SetDirectory(TDirectory *dir)
Change the tree's directory.
Definition TTree.cxx:9380
void SortBranchesByTime()
Sorts top-level branches by the last average task time recorded per branch.
Definition TTree.cxx:5943
void Delete(Option_t *option="") override
Delete this tree from memory or/and disk.
Definition TTree.cxx:3788
virtual TBranchRef * GetBranchRef() const
Definition TTree.h:505
TLeaf * SearchLeafInListOfFriends(const char *branchName, const char *leafName)
Definition TTree.cxx:6276
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:7789
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:1663
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:9483
void MoveReadCache(TFile *src, TDirectory *dir)
Move a cache from a file to the current file in dir.
Definition TTree.cxx:7323
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:8372
@ kSplitCollectionOfPointers
Definition TTree.h:318
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:9524
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:9125
virtual Long64_t AutoSave(Option_t *option="")
AutoSave tree header every fAutoSave bytes.
Definition TTree.cxx:1528
virtual Long64_t GetEntryNumber(Long64_t entry) const
Return entry number corresponding to entry.
Definition TTree.cxx:5974
virtual TTree * CloneTree(Long64_t nentries=-1, Option_t *option="")
Create a clone of this tree and copy nentries.
Definition TTree.cxx:3174
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:6327
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:8341
virtual void KeepCircular()
Keep a maximum of fMaxEntries in memory.
Definition TTree.cxx:6671
virtual void SetDefaultEntryOffsetLen(Int_t newdefault, bool updateExisting=false)
Update the default value for the branch's fEntryOffsetLen.
Definition TTree.cxx:9354
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:3860
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:7086
virtual void SetObject(const char *name, const char *title)
Change the name and title of this tree.
Definition TTree.cxx:9685
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:5371
TTree()
Default constructor and I/O constructor.
Definition TTree.cxx:765
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:7117
bool MemoryFull(Int_t nbytes)
Check if adding nbytes to memory we are still below MaxVirtualsize.
Definition TTree.cxx:7101
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:9460
bool Notify() override
Function called when loading a new class library.
Definition TTree.cxx:7373
virtual void AddZipBytes(Int_t zip)
Definition TTree.h:384
virtual Long64_t LoadTree(Long64_t entry)
Set current entry.
Definition TTree.cxx:6729
virtual Long64_t ReadFile(const char *filename, const char *branchDescriptor="", char delimiter=' ')
Create or simply read branches from filename.
Definition TTree.cxx:7902
virtual const char * GetAlias(const char *aliasName) const
Returns the expanded value of the alias. Search in the friends if any.
Definition TTree.cxx:5304
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:9544
virtual TBasket * CreateBasket(TBranch *)
Create a basket for this tree and given branch.
Definition TTree.cxx:3772
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:6553
virtual void RemoveFriend(TTree *)
Remove a friend from the list of friends.
Definition TTree.cxx:8315
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:2640
virtual TList * GetUserInfo()
Return a pointer to the list containing user objects associated to this tree.
Definition TTree.cxx:6612
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:5619
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:7850
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:2435
virtual void SetBasketSize(const char *bname, Int_t buffsize=16000)
Set a branch's basket size.
Definition TTree.cxx:8710
static void SetBranchStyle(Int_t style=1)
Set the current branch style.
Definition TTree.cxx:9070
~TTree() override
Destructor.
Definition TTree.cxx:948
void ImportClusterRanges(TTree *fromtree)
Appends the cluster range information stored in 'fromtree' to this tree, including the value of fAuto...
Definition TTree.cxx:6628
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:5224
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:6821
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:10181
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:10142
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:1582
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:9771
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:7397
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:7835
virtual Int_t SetCacheEntryRange(Long64_t first, Long64_t last)
interface to TTreeCache to set the cache entry range
Definition TTree.cxx:9245
static Long64_t GetMaxTreeSize()
Static function which returns the tree file size limit in bytes.
Definition TTree.cxx:6543
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:8493
virtual void CopyAddresses(TTree *, bool undo=false)
Set branch addresses of passed tree equal to ours.
Definition TTree.cxx:3340
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:2668
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:4604
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:8254
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:8548
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:8610
TBranch * FindBranchFromSelf(const char *branchName)
Definition TTree.cxx:4907
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:9567
virtual TLeaf * FindLeaf(const char *name)
Find first leaf containing searchname.
Definition TTree.cxx:4994
virtual void StartViewer()
Start the TTreeViewer on this tree.
Definition TTree.cxx:9884
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:6904
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:8413
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:9630
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:8295
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:8760
virtual Int_t SetCacheSize(Long64_t cachesize=-1)
Set maximum size of the file cache (TTreeCache) in bytes.
Definition TTree.cxx:9092
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:1247
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:2902
TBuffer * GetTransientBuffer(Int_t size)
Returns the transient buffer currently used by this TTree for reading/writing baskets.
Definition TTree.cxx:1065
ROOT::TIOFeatures GetIOFeatures() const
Returns the current set of IO settings.
Definition TTree.cxx:6214
virtual Int_t MakeClass(const char *classname=nullptr, Option_t *option="")
Generate a skeleton analysis class for this tree.
Definition TTree.cxx:6871
virtual const char * GetFriendAlias(TTree *) const
If the 'tree' is a friend, this method returns its alias name.
Definition TTree.cxx:6142
virtual void RemoveExternalFriend(TFriendElement *)
Removes external friend.
Definition TTree.cxx:8306
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:1759
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:8451
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:2443
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:3575
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:6707
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:7540
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.
virtual EDataType GetType() const =0
If the value type is a fundamental data type, return its type (see enumeration EDataType).
virtual TClass * GetValueClass() const =0
If the value type is a user-defined class, return a pointer to the TClass representing the value type...
virtual Bool_t HasPointers() const =0
Return true if the content is of type 'pointer to'.
Abstract interface for Tree Index.
virtual const char * GetMajorName() const =0
virtual Long64_t GetEntryNumberWithIndex(Long64_t major, Long64_t minor) const =0
virtual Long64_t GetEntryNumberFriend(const TTree *)=0
virtual void Append(const TVirtualIndex *, bool delaySort=false)=0
virtual const char * GetMinorName() const =0
virtual void SetTree(TTree *T)=0
virtual Long64_t GetN() const =0
virtual bool IsValidFor(const TTree *parent)=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:10293
TBranch * CallBranchImpRef(TTree &tree, const char *branchname, TClass *ptrClass, EDataType datatype, void *addobj, Int_t bufsize=32000, Int_t splitlevel=99)
Definition TTree.cxx:10287
void TBranch__SetTree(TTree *tree, TObjArray &branches)
Set the fTree member for all branches and sub branches.
Definition TTree.cxx:9933
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
Definition TROOT.cxx:673
ESTLType
Definition ESTLType.h:28
@ kSTLmap
Definition ESTLType.h:33
@ kSTLmultimap
Definition ESTLType.h:34
void CallRecursiveRemoveIfNeeded(TObject &obj)
call RecursiveRemove for obj if gROOT is valid and obj.TestBit(kMustCleanup) is true.
Definition TROOT.h:406
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)
Returns the median of the array a where each entry i has weight w[i] .
Definition TMath.h:1365
Double_t Ceil(Double_t x)
Rounds x upward, returning the smallest integral value that is not less than x.
Definition TMath.h:681
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:197
Long64_t BinarySearch(Long64_t n, const T *array, T value)
Binary search in an array of n values to locate value.
Definition TMathBase.h:329
TCanvas * slash()
Definition slash.C:1
@ kUseGlobal
Use the global compression algorithm.
Definition Compression.h:93
@ kInherit
Some objects use this value to denote that the compression algorithm should be inherited from the par...
Definition Compression.h:91
@ kUseCompiledDefault
Use the compile-time default setting.
Definition Compression.h:53
th1 Draw()
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4