Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TTreeReaderGenerator.cxx
Go to the documentation of this file.
1// @(#)root/treeplayer:$Id$
2// Author: Akos Hajdu 22/06/2015
3
4/*************************************************************************
5 * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers and al. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
13#include <algorithm>
14#include <stdio.h>
15#include <fstream>
16
17#include "TBranchElement.h"
18#include "TChain.h"
19#include "TClass.h"
20#include "TClassEdit.h"
21#include "TClonesArray.h"
22#include "TError.h"
23#include "TFile.h"
24#include "TLeaf.h"
25#include "TLeafC.h"
26#include "TLeafObject.h"
27#include "TROOT.h"
28#include "TStreamerElement.h"
29#include "TStreamerInfo.h"
30#include "TTree.h"
31#include "TObjString.h"
34
35namespace ROOT {
36namespace Internal {
37
38 ////////////////////////////////////////////////////////////////////////////////
39 /// Constructor. Analyzes the tree and writes selector.
40
42 TTreeGeneratorBase(tree, option), fClassname(classname),
43 fIncludeAllLeaves(kFALSE), fIncludeAllTopmost(kFALSE)
44 {
48 }
49
50 ////////////////////////////////////////////////////////////////////////////////
51 /// Add a reader to the generated code.
52
54 TString branchName, TBranchDescriptor *parent, Bool_t isLeaf)
55 {
56 if(BranchNeedsReader(branchName, parent, isLeaf)) {
57 // Ignore unknown types
58 if (dataType.EqualTo("")) {
59 Warning("TTreeReaderGenerator::AddReader", "Ignored branch %s because type is unsupported.", branchName.Data());
60 return;
61 }
62 // Loop through existing readers to check duplicate branch names
63 TIter next(&fListOfReaders);
64 TTreeReaderDescriptor *descriptor;
65 while ( ( descriptor = (TTreeReaderDescriptor*)next() ) ) {
66 if (descriptor->fBranchName.EqualTo(branchName)) {
67 Warning("AddReader", "Ignored branch %s because a branch with the same name already exists. "
68 "TTreeReader requires an unique name for the branches. You may need to "
69 "put a dot at the end of the name of top-level branches.", branchName.Data());
70 return;
71 }
72 }
73 name.ReplaceAll('.', '_'); // Replace dots with underscore
74 // Remove array dimensions from name
75 while (name.Index('[') >= 0 && name.Index(']') >= 0 && name.Index(']') > name.Index('[')) {
76 name.Remove(name.Index('['), name.Index(']') - name.Index('[') + 1);
77 }
78 fListOfReaders.Add( new TTreeReaderDescriptor(type, dataType, name, branchName) );
79 }
80 }
81
82 ////////////////////////////////////////////////////////////////////////////////
83 /// Analyse sub-branches of 'branch' recursively and extract readers.
84
86 {
87 if (info==0) info = branch->GetInfo();
88
89 TIter branches(branch->GetListOfBranches());
90
91 return AnalyzeBranches(desc, branches, info);
92 }
93
94 ////////////////////////////////////////////////////////////////////////////////
95 /// Analyse sub-branches 'branches' recursively and extract readers.
96
98 {
99 UInt_t lookedAt = 0; // Number of sub-branches analyzed
100 ELocation outer_isclones = kOut; // Is the parent branch a container
101 TString containerName; // Container name
102 TString subBranchPrefix; // Prefix of sub-branch (if the elements and sub-branches do not match).
103 Bool_t skipped = false; // Should the branch be skipped
104
105 // Check for containers (TClonesArray or STL)
106 {
107 TIter peek = branches;
108 TBranchElement *branch = (TBranchElement*)peek();
109 if (desc && desc->IsClones()) {
110 outer_isclones = kClones;
111 containerName = "TClonesArray";
112 } else if (desc && desc->IsSTL()) {
113 outer_isclones = kSTL;
114 containerName = desc->fContainerName;
115 } else if (!desc && branch && branch->GetBranchCount() == branch->GetMother()) {
116 if ( ((TBranchElement*)(branch->GetMother()))->GetType()==3) {
117 outer_isclones = kClones;
118 containerName = "TClonesArray";
119 } else {
120 outer_isclones = kSTL;
121 containerName = branch->GetMother()->GetClassName();
122 }
123 }
124 // FIXME: this is wrong because 'branch' is the first sub-branch and even though
125 // it can be a collection, it does not mean that the other sub-branches are
126 // collections as well.
127 /* else if (branch->GetType() == 3) {
128 outer_isclones = kClones;
129 containerName = "TClonesArray";
130 } else if (branch->GetType() == 4) {
131 outer_isclones = kSTL;
132 containerName = branch->GetMother()->GetSubBranch(branch)->GetClassName();
133 }*/
134 if (desc) {
135 subBranchPrefix = desc->fSubBranchPrefix;
136 } else {
137 TBranchElement *mom = (TBranchElement*)branch->GetMother();
138 subBranchPrefix = mom->GetName();
139 if (subBranchPrefix[subBranchPrefix.Length()-1]=='.') {
140 subBranchPrefix.Remove(subBranchPrefix.Length()-1);
141 } else if (mom->GetType()!=3 && mom->GetType() != 4) {
142 subBranchPrefix = "";
143 }
144 }
145 }
146
147 // Loop through elements (i.e., sub-branches). The problem is that the elements
148 // and sub-branches do not always match. For example suppose that class A contains
149 // members x and y, and there is a class B inheriting from A and containing an extra
150 // member z. It is possible that B has two elements: A and z but three sub-branches
151 // x, y and z. Therefore, the branch iterator is treated differently.
152 TIter elements( info->GetElements() );
153 for( TStreamerElement *element = (TStreamerElement*)elements();
154 element;
155 element = (TStreamerElement*)elements() )
156 {
157 Bool_t isBase = false; // Does the element correspond to a base class
158 Bool_t usedBranch = kTRUE; // Does the branch correspond to the element (i.e., they match)
159 Bool_t isLeaf = true; // Is the branch a leaf (i.e. no sub-branches)
160 TIter peek = branches; // Iterator for sub-branches
161 // Always start with the first available sub-branch and if it does not match the element,
162 // try the next ones
163 TBranchElement *branch = (TBranchElement*)peek();
164 // There is a problem if there are more elements than branches
165 if (branch==0) {
166 if (desc) {
167 Error("AnalyzeBranches","Ran out of branches when looking in branch %s, class %s",
168 desc->fBranchName.Data(), info->GetName());
169 } else {
170 Error("AnalyzeBranches","Ran out of branches when looking in class %s, element %s",
171 info->GetName(), element->GetName());
172 }
173 return lookedAt;
174 }
175
176 if (info->GetClass()->GetCollectionProxy() && strcmp(element->GetName(),"This")==0) {
177 continue; // Skip the artifical streamer element.
178 }
179
180 if (element->GetType() == -1) {
181 continue; // This is an ignored TObject base class.
182 }
183
184 // Get branch name
185 TString branchname = branch->GetName();
186 TString branchEndName;
187 {
188 TLeaf *leaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
189 if (leaf && outer_isclones == kOut
190 && !(branch->GetType() == 3 || branch->GetType() == 4)) branchEndName = leaf->GetName();
191 else branchEndName = branch->GetName();
192 Int_t pos;
193 pos = branchEndName.Index(".");
194 if (pos!=-1) {
195 if (subBranchPrefix.Length() && branchEndName.BeginsWith(subBranchPrefix)) {
196 branchEndName.Remove(0, subBranchPrefix.Length() + 1);
197 }
198 }
199 }
200
201 TString dataType; // Data type of reader
203 Bool_t ispointer = false;
204 ELocation isclones = outer_isclones; // Is the actual sub-branch a collection (inherit from parent branch)
205 // Get data type
206 switch(element->GetType()) {
207 // Built-in types
208 case TVirtualStreamerInfo::kBool: { dataType = "Bool_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
209 case TVirtualStreamerInfo::kChar: { dataType = "Char_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
210 case TVirtualStreamerInfo::kShort: { dataType = "Short_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
211 case TVirtualStreamerInfo::kInt: { dataType = "Int_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
212 case TVirtualStreamerInfo::kLong: { dataType = "Long_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
213 case TVirtualStreamerInfo::kLong64: { dataType = "Long64_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
214 case TVirtualStreamerInfo::kFloat: { dataType = "Float_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
215 case TVirtualStreamerInfo::kFloat16: { dataType = "Float16_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
216 case TVirtualStreamerInfo::kDouble: { dataType = "Double_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
217 case TVirtualStreamerInfo::kDouble32:{ dataType = "Double32_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
218 case TVirtualStreamerInfo::kUChar: { dataType = "UChar_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
219 case TVirtualStreamerInfo::kUShort: { dataType = "unsigned short"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
220 case TVirtualStreamerInfo::kUInt: { dataType = "unsigned int"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
221 case TVirtualStreamerInfo::kULong: { dataType = "ULong_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
222 case TVirtualStreamerInfo::kULong64: { dataType = "ULong64_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
223 case TVirtualStreamerInfo::kBits: { dataType = "unsigned int"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
224 // Character arrays
225 case TVirtualStreamerInfo::kCharStar: { dataType = "Char_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
226 // Array of built-in types [8]
238 case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kUShort: { dataType = "unsigned short"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
239 case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kUInt: { dataType = "unsigned int"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
242 case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kBits: { dataType = "unsigned int"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
243 // Array of built-in types [n]
255 case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kUShort: { dataType = "unsigned short"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
256 case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kUInt: { dataType = "unsigned int"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
259 case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kBits: { dataType = "unsigned int"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
260 // array counter [n]
261 case TVirtualStreamerInfo::kCounter: { dataType = "Int_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
262 // other stuff (containers, classes, ...)
271 // set as pointers and fall through to the next switches
272 ispointer = true;
274 // This means an array of objects, but then fall through
283 TClass *cl = element->GetClassPointer();
284 R__ASSERT(cl);
285 dataType = cl->GetName();
286 // Check for containers
287 if (cl == TClonesArray::Class()) { // TClonesArray
288 isclones = kClones;
289 containerName = "TClonesArray";
290 if (outer_isclones != kOut) { // If the parent is already a collection
291 isclones = outer_isclones;
292 dataType = "TClonesArray";
293 } else {
295 dataType = GetContainedClassName(branch, element, ispointer);
296 }
297 } else if (cl->GetCollectionProxy()) { // STL collection
298 isclones = kSTL;
299 containerName = cl->GetName();
300 if (outer_isclones != kOut || containerName.EqualTo("vector<bool>")) {
301 // If the parent is already a collection we can only add this collection as a whole
302 // Also TTreeReaderArray does currently not support vectors of bool so
303 // that need to be added as a whole.
304 // Also getting the inner type of vector would return "unsigned" so the full
305 // name has to be compared
306 isclones = outer_isclones;
307 dataType = cl->GetName();
308 } else {
310 TClass *valueClass = cl->GetCollectionProxy()->GetValueClass();
311 if (valueClass) { // Get class inside container
312 dataType = valueClass->GetName();
313 }
314 else { // Get built-in type inside container
315 TDataType *valueClassBuiltIn = TDataType::GetDataType(cl->GetCollectionProxy()->GetType());
316 if (valueClassBuiltIn) dataType = valueClassBuiltIn->GetName();
317 else Error("AnalyzeBranches", "Could not get type from collection %s in branch %s", cl->GetName(), branch->GetName());
318 }
319 }
320 }
321
322 // Analyze the actual element
323 // Possible cases:
324 // - Base class
325 // - Element and branch matches
326 // - Non-split: do nothing
327 // - Split: recurse with sub-sub-branches
328 // - Element and branch does not match: recurse with same branches
329 // - Not base class
330 // - Element and branch matches
331 // - Non-split: do nothing
332 // - Split: recurse with sub-sub-branches
333 // - Element and branch does not match: recurse with same branches
334 TBranch *parent = branch->GetMother()->GetSubBranch(branch);
335 TVirtualStreamerInfo *objInfo = 0;
336 if (branch->GetListOfBranches()->GetEntries()) {
337 objInfo = ((TBranchElement*)branch->GetListOfBranches()->At(0))->GetInfo();
338 } else {
339 objInfo = branch->GetInfo();
340 }
341 if (element->IsBase()) { // Base class
342 isBase = true;
343 if (cl == TObject::Class() && info->GetClass()->CanIgnoreTObjectStreamer())
344 {
345 continue; // Ignore TObject
346 }
347
348 TBranchDescriptor *bdesc = 0;
349
350 if (branchEndName == element->GetName()) { // The element and the branch matches
351 if (branch->GetListOfBranches()->GetEntries() == 0) { // The branch contains a non-split base class
352 // FIXME: nothing to do in such cases, because readers cannot access
353 // non-split members and a reader for the whole branch will be added
354 } else { // The branch contains a split base class
355 Int_t pos = branchname.Last('.');
356 if (pos != -1) {
357 branchname.Remove(pos);
358 }
359 TString local_prefix = desc ? desc->fSubBranchPrefix : TString(parent->GetName());
360 bdesc = new TBranchDescriptor(cl->GetName(), objInfo, branchname.Data(), local_prefix.Data(),
361 isclones, containerName, desc);
362 // Recurse: analyze sub-branches of the sub-branch
363 lookedAt += AnalyzeBranches(bdesc, branch, objInfo);
364 isLeaf = false;
365
366 }
367 } else { // The element and the branch does not match, we need to loop over the next branches
368 Int_t pos = branchname.Last('.');
369 if (pos != -1) {
370 branchname.Remove(pos);
371 }
372 TString local_prefix = desc ? desc->fSubBranchPrefix : TString(parent->GetName());
373 objInfo = GetBaseClass(element);
374 if (objInfo == 0) {
375 continue; // There is no data in this base class
376 }
377 cl = objInfo->GetClass();
378 bdesc = new TBranchDescriptor(cl->GetName(), objInfo, branchname.Data(), local_prefix.Data(),
379 isclones, containerName, desc);
380 usedBranch = kFALSE;
381 // Recurse: analyze the sub-elements with the same branches
382 lookedAt += AnalyzeBranches(bdesc, branches, objInfo);
383 }
384 delete bdesc;
385 } else { // Not base class
386 TBranchDescriptor *bdesc = 0;
387 if (branchEndName == element->GetName()) { // The element and the branch matches
388 if (branch->GetListOfBranches()->GetEntries() == 0) { // The branch contains a non-split class
389 // FIXME: nothing to do in such cases, because readers cannot access
390 // non-split members and a reader for the whole branch will be added
391 } else { // The branch contains a split class
392 if (isclones != kOut) {
393 // We have to guess the version number!
394 cl = TClass::GetClass(dataType);
395 objInfo = GetStreamerInfo(branch, branch->GetListOfBranches(), cl);
396 }
397 bdesc = new TBranchDescriptor(cl->GetName(), objInfo, branch->GetName(), branch->GetName(),
398 isclones, containerName, desc);
399 // Recurse: analyze sub-branches of the sub-branch
400 lookedAt += AnalyzeBranches(bdesc, branch, objInfo);
401 isLeaf = false;
402 }
403 } else { // The element and the branch does not match, we need to loop over the next branches
404 TString local_prefix = desc ? desc->fSubBranchPrefix : TString(parent->GetName());
405 if (local_prefix.Length()) local_prefix += ".";
406 local_prefix += element->GetName();
407 objInfo = branch->GetInfo();
408 Int_t pos = branchname.Last('.');
409 if (pos != -1) {
410 branchname.Remove(pos);
411 }
412 if (isclones != kOut) {
413 // We have to guess the version number!
414 cl = TClass::GetClass(dataType);
415 objInfo = GetStreamerInfo(branch, branches, cl);
416 }
417 bdesc = new TBranchDescriptor(cl->GetName(), objInfo, branchname.Data(), local_prefix.Data(),
418 isclones, containerName, desc);
419 usedBranch = kFALSE;
420 skipped = kTRUE;
421 // Recurse: analyze the sub-elements with the same branches
422 lookedAt += AnalyzeBranches(bdesc, branches, objInfo);
423 }
424 delete bdesc;
425 }
426
427 break;
428 }
429 default:
430 Error("AnalyzeBranch", "Unsupported type for %s (%d).", branch->GetName(), element->GetType());
431 }
432
433 if (!isBase && !skipped) { // Add reader for the whole branch
434 if (outer_isclones != kOut && readerType == TTreeReaderDescriptor::ReaderType::kArray) {
435 Error("AnalyzeBranch", "Arrays inside collections are not supported yet (branch: %s).", branch->GetName());
436 } else {
437 if (outer_isclones != kOut || isclones != kOut) {
439 }
440 AddReader(readerType, dataType, branch->GetName(), branch->GetName(), desc, isLeaf);
441 }
442 }
443
444 // If the branch was used, jump to the next
445 if (usedBranch) {
446 branches.Next();
447 ++lookedAt;
448 }
449 }
450
451 return lookedAt;
452 }
453
454 ////////////////////////////////////////////////////////////////////////////////
455 /// Analyze branch and add the variables found. The number of analyzed
456 /// sub-branches is returned.
457
459 {
460 UInt_t extraLookedAt = 0;
461 TString prefix;
462
463 TString branchName = branch->GetName();
464
465 TObjArray *leaves = branch->GetListOfLeaves();
466 Int_t nleaves = leaves ? leaves->GetEntriesFast() : 0;
467
468 // Loop through leaves and analyze them
469 for(int l=0;l<nleaves;l++) {
470 TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
471 extraLookedAt += AnalyzeOldLeaf(leaf, nleaves);
472 }
473
474 return extraLookedAt;
475 }
476
477 ////////////////////////////////////////////////////////////////////////////////
478 /// Analyze the leaf and add the variables found.
479
481 {
482 if (leaf->IsA()==TLeafObject::Class()) {
483 Error("AnalyzeOldLeaf","TLeafObject not supported yet");
484 return 0;
485 }
486
487 TString leafTypeName = leaf->GetTypeName();
488 Int_t pos = leafTypeName.Last('_');
489 //if (pos != -1) leafTypeName.Remove(pos); // FIXME: this is not required since it makes Float_t -> Float
490
491 // Analyze dimensions
492 UInt_t dim = 0;
493 std::vector<Int_t> maxDim;
494
495 TString dimensions;
496 TString temp = leaf->GetName();
497 pos = temp.Index("[");
498 if (pos != -1) {
499 if (pos) temp.Remove(0, pos);
500 dimensions.Append(temp);
501 }
502 temp = leaf->GetTitle();
503 pos = temp.Index("[");
504 if (pos != -1) {
505 if (pos) temp.Remove(0, pos);
506 dimensions.Append(temp);
507 }
508
509 Int_t dimlen = dimensions.Length();
510
511 if (dimlen) {
512 const char *current = dimensions.Data();
513
514 Int_t index;
515 Int_t scanindex ;
516 while (current) {
517 current++;
518 if (current[0] == ']') {
519 maxDim.push_back(-1); // maxDim[dim] = -1; // Loop over all elements;
520 } else {
521 scanindex = sscanf(current,"%d",&index);
522 if (scanindex) {
523 maxDim.push_back(index); // maxDim[dim] = index;
524 } else {
525 maxDim.push_back(-2); // maxDim[dim] = -2; // Index is calculated via a variable.
526 }
527 }
528 dim ++;
529 current = (char*)strstr( current, "[" );
530 }
531 }
532
533 if (dim == 0 && leaf->IsA() == TLeafC::Class()) {
534 dim = 1; // For C style strings
535 }
536
538 TString dataType;
539 switch (dim) {
540 case 0: {
542 dataType = leafTypeName;
543 break;
544 }
545 case 1: {
547 dataType = leafTypeName;
548 break;
549 }
550 default: {
551 // TODO: transform this
552 /*type = "TArrayProxy<";
553 for(Int_t ind = dim - 2; ind > 0; --ind) {
554 type += "TMultiArrayType<";
555 }
556 type += "TArrayType<";
557 type += leaf->GetTypeName();
558 type += ",";
559 type += maxDim[dim-1];
560 type += "> ";
561 for(Int_t ind = dim - 2; ind > 0; --ind) {
562 type += ",";
563 type += maxDim[ind];
564 type += "> ";
565 }
566 type += ">";*/
567 break;
568 }
569 }
570
571 // If there are multiple leaves (leaflist) the name of the branch is
572 // <branch_name>.<leaf_name>
573 // (Otherwise the brach name does not change)
574 TString branchName = leaf->GetBranch()->GetName();
575 if (nleaves > 1) {
576 branchName.Form("%s.%s", leaf->GetBranch()->GetName(), leaf->GetName());
577 }
578
579 AddReader(type, dataType, leaf->GetName(), branchName, 0, kTRUE);
580
581 return 0;
582 }
583
584 ////////////////////////////////////////////////////////////////////////////////
585 /// Check whether a branch should have a corresponding reader added, depending
586 /// on the options provided by the user.
587
589 {
590 if (isLeaf) { // Branch is a leaf
591 // Include if all leaves should be included or it is contained in any of the lists.
592 if (fIncludeAllLeaves) return kTRUE;
593 if (std::find(fIncludeLeaves.begin(), fIncludeLeaves.end(), branchName) != fIncludeLeaves.end()) return kTRUE;
594 if (std::find(fIncludeStruct.begin(), fIncludeStruct.end(), branchName) != fIncludeStruct.end()) return kTRUE;
595 if (!parent) { // Branch is topmost (top-level leaf)
596 if (fIncludeAllTopmost) return kTRUE;
597 } else { // Branch is not topmost
598 while (parent) { // Check if any parent is in the list of "include as leaves"
599 if (std::find(fIncludeLeaves.begin(), fIncludeLeaves.end(), parent->fBranchName) != fIncludeLeaves.end()) {
600 return kTRUE;
601 }
602 parent = parent->fParent;
603 }
604 }
605 } else { // Branch is not a leaf (has sub-branches)
606 if (std::find(fIncludeStruct.begin(), fIncludeStruct.end(), branchName) != fIncludeStruct.end()) return kTRUE;
607 if (!parent) { // Branch is topmost
608 if (fIncludeAllTopmost) return kTRUE;
609 }
610 }
611 return false;
612 }
613
614 ////////////////////////////////////////////////////////////////////////////////
615 /// Parse the user options.
616
618 if (fOptionStr.EqualTo("")) { // Empty -> include all leaves
620 } else if (fOptionStr.EqualTo("@")) { // "@" -> include all topmost
622 } else { // Otherwise split at ";" to get names
623 TObjArray *tokens = fOptionStr.Tokenize(TString(";"));
624 for (Int_t i = 0; i < tokens->GetEntries(); ++i) {
625 TString token = ((TObjString*)tokens->At(i))->GetString();
626 if ( token.Length() == 0 || (token.Length() == 1 && token[0] == '@') ) {
627 Warning("ParseOptions", "Ignored empty branch name in option string.");
628 } else if (token[0] == '@') { // "@X" means include X as a whole
629 token = TString(token.Data()+1);
630 fIncludeStruct.push_back(token);
631 } else { // "X" means include leaves of X
632 fIncludeLeaves.push_back(token);
633 }
634 if (!fTree->GetBranch(token)) { // Display a warning for non-existing branch names
635 Warning("ParseOptions", "Tree %s does not contain a branch named %s.", fTree->GetName(), token.Data());
636 }
637 }
638 delete tokens;
639 }
640 }
641
642 ////////////////////////////////////////////////////////////////////////////////
643 /// Analyze tree and extract readers.
644
646 {
647 TIter next(tree->GetListOfBranches());
648 TBranch *branch;
649
650 // Loop through branches
651 while ( (branch = (TBranch*)next()) ) {
652 TVirtualStreamerInfo *info = 0;
653 // Get the name and the class of the branch
654 const char *branchName = branch->GetName();
655 const char *branchClassName = branch->GetClassName();
656 TClass *cl = TClass::GetClass(branchClassName);
657
658 // Add headers for user classes
659 if (branchClassName && strlen(branchClassName)) {
660 AddHeader(cl);
661 }
662
663 TString type = "unknown"; // Type of branch
664 ELocation isclones = kOut; // Type of container
665 TString containerName = ""; // Name of container
666 TBranchDescriptor *desc = 0;
667 // Check whether the branch is a container
668 if (cl) {
669 // Check if it is a TClonesArray
670 if (cl == TClonesArray::Class()) {
671 isclones = kClones;
672 containerName = "TClonesArray";
673 if (branch->IsA()==TBranchElement::Class()) {
674 // Get the class inside the TClonesArray
675 const char *cname = ((TBranchElement*)branch)->GetClonesName();
676 TClass *ncl = TClass::GetClass(cname);
677 if (ncl) {
678 cl = ncl;
679 info = GetStreamerInfo(branch, branch->GetListOfBranches(), cl);
680 } else {
681 Error("AnalyzeTree",
682 "Introspection of TClonesArray in older file not implemented yet.");
683 }
684 } else {
685 TClonesArray **ptr = (TClonesArray**)branch->GetAddress();
686 TClonesArray *clones = 0;
687 if (ptr==0) {
688 clones = new TClonesArray;
689 branch->SetAddress(&clones);
690 ptr = &clones;
691 }
692 branch->GetEntry(0);
693 TClass *ncl = *ptr ? (*ptr)->GetClass() : 0;
694 if (ncl) {
695 cl = ncl;
696 } else {
697 Error("AnalyzeTree",
698 "Introspection of TClonesArray for %s failed.",branch->GetName());
699 }
700 }
701 // Check if it is an STL container
702 } else if (cl->GetCollectionProxy()) {
703 isclones = kSTL;
704 containerName = cl->GetName();
705 // Get the type inside container
706 if (cl->GetCollectionProxy()->GetValueClass()) { // Class inside container
707 cl = cl->GetCollectionProxy()->GetValueClass();
708 } else { // RAW type (or missing class) inside container
709 // TODO: CheckForMissingClass?
710 // TTreeReaderArray does currently not support vectors of bool so that need to
711 // be added as a TTreeReaderValue<vector<bool>>. Also getting the inner type of
712 // vector would return "unsigned" so the full name has to be compared.
713 if (containerName.EqualTo("vector<bool>")) {
715 containerName,
716 branch->GetName(), branch->GetName(), 0, kTRUE);
717 } else { // Otherwise we can generate a TTreeReaderArray with the inner type
720 branch->GetName(), branch->GetName(), 0, kTRUE);
721 }
722 continue; // Nothing else to with this branch in these cases
723 }
724 }
725
726 // Check class inside container and create a descriptor or add a reader
727 if (cl) {
728 if (cl->TestBit(TClass::kIsEmulation) || branchName[strlen(branchName)-1] == '.' || branch->GetSplitLevel()) {
729 TBranchElement *be = dynamic_cast<TBranchElement*>(branch);
730 TVirtualStreamerInfo *beinfo = (be && isclones == kOut)
731 ? be->GetInfo() : cl->GetStreamerInfo(); // the 2nd hand need to be fixed
732 // Create descriptor
733 desc = new TBranchDescriptor(cl->GetName(), beinfo, branchName, branchName, isclones, containerName);
734 info = beinfo;
735 } else {
736 // Add a reader for non-split classes
737 AddReader(isclones == kOut ?
740 cl->GetName(), branchName, branchName, 0, kTRUE);
741 // TODO: can't we just put a continue here?
742 }
743 }
744 }
745
746 // Analyze sub-branches (if exist) and add readers
747 if (branch->GetListOfBranches()->GetEntries() == 0) { // Branch is non-splitted
748 if (cl) { // Non-split object
749 if (desc) { // If there is a descriptor add reader (otherwise
750 // it was already added).
751 AddReader(isclones == kOut ?
754 desc->GetName(), desc->fBranchName, desc->fBranchName, 0, kTRUE);
755 }
756 } else { // Top-level RAW type
757 AnalyzeOldBranch(branch); // Analyze branch and extract readers
758 }
759 } else { // Branch is splitted
760 TIter subnext( branch->GetListOfBranches() );
761 if (desc) {
762 // Analyze sub-branches and extract readers
763 TBranchElement *branchElem = dynamic_cast<TBranchElement*>(branch);
764 if (branchElem) {
765 AnalyzeBranches(desc, branchElem, info);
766 } else {
767 Error("AnalyzeTree", "Cannot analyze branch %s because it is not a TBranchElement.", branchName);
768 }
769 // Also add a reader for the whole branch
770 AddReader(isclones == kOut ?
773 desc->GetName(), desc->fBranchName, desc->fBranchName, 0, kFALSE);
774 }
775 }
776 delete desc;
777 }
778 }
779
780 ////////////////////////////////////////////////////////////////////////////////
781 /// Generate code for selector class.
782
784 {
785 // If no name is given, set to default (name of the tree)
787
788 TString treefile;
789 if (fTree->GetDirectory() && fTree->GetDirectory()->GetFile()) {
790 treefile = fTree->GetDirectory()->GetFile()->GetName();
791 } else {
792 treefile = "Memory Directory";
793 }
794 // In the case of a chain, the GetDirectory information usually does
795 // pertain to the Chain itself but to the currently loaded tree.
796 // So we can not rely on it.
797 Bool_t ischain = fTree->InheritsFrom(TChain::Class());
798 Bool_t isHbook = fTree->InheritsFrom("THbookTree");
799 if (isHbook)
800 treefile = fTree->GetTitle();
801
802 //======================Generate classname.h=====================
803 TString thead;
804 thead.Form("%s.h", fClassname.Data());
805 std::ofstream ofs (thead, std::ofstream::out);
806 if (!ofs) {
807 Error("WriteSelector","cannot open output file %s", thead.Data());
808 return;
809 }
810 // Print header
811 TDatime td;
812 ofs <<
813R"CODE(//////////////////////////////////////////////////////////
814// This class has been automatically generated on
815// )CODE" << td.AsString() << R"CODE( by ROOT version )CODE" << gROOT->GetVersion() << std::endl;
816 if (!ischain) {
817 ofs << "// from TTree " << fTree->GetName() << "/" << fTree->GetTitle() << std::endl
818 << "// found on file: " << treefile << std::endl;
819 } else {
820 ofs << "// from TChain " << fTree->GetName() << "/" << fTree->GetTitle() << std::endl;
821 }
822 ofs <<
823R"CODE(//////////////////////////////////////////////////////////
824
825#ifndef )CODE" << fClassname << R"CODE(_h
826#define )CODE" << fClassname << R"CODE(_h
827
828#include <TROOT.h>
829#include <TChain.h>
830#include <TFile.h>
831)CODE";
832 if (isHbook) ofs << "#include <THbookFile.h>" << std::endl;
833 ofs <<
834R"CODE(#include <TSelector.h>
835#include <TTreeReader.h>
836#include <TTreeReaderValue.h>
837#include <TTreeReaderArray.h>
838
839// Headers needed by this particular selector
840)CODE";
841
842 TIter next(&fListOfHeaders);
843 TObject *header;
844 while ( (header = next()) ) {
845 ofs << header->GetTitle() << std::endl;
846 }
847 ofs << std::endl << std::endl;
848
849 // Generate class declaration with TTreeReaderValues and Arrays
850 ofs <<
851R"CODE(class )CODE" << fClassname << R"CODE( : public TSelector {
852public :
853 TTreeReader fReader; //!the tree reader
854 TTree *fChain = 0; //!pointer to the analyzed TTree or TChain
855
856 // Readers to access the data (delete the ones you do not need).
857)CODE";
858 next = &fListOfReaders;
859 TTreeReaderDescriptor *descriptor;
860 while ( ( descriptor = (TTreeReaderDescriptor*)next() ) ) {
861 ofs << " TTreeReader" << (descriptor->fType == TTreeReaderDescriptor::ReaderType::kValue ? "Value" : "Array")
862 << "<" << descriptor->fDataType
863 << "> " << descriptor->fName
864 << " = {fReader, \"" << descriptor->fBranchName << "\"};" << std::endl;
865 }
866 // Generate class member functions prototypes
867 ofs <<
868R"CODE(
869
870 )CODE" << fClassname << R"CODE((TTree * /*tree*/ =0) { }
871 virtual ~)CODE" << fClassname << R"CODE(() { }
872 virtual Int_t Version() const { return 2; }
873 virtual void Begin(TTree *tree);
874 virtual void SlaveBegin(TTree *tree);
875 virtual void Init(TTree *tree);
876 virtual Bool_t Notify();
877 virtual Bool_t Process(Long64_t entry);
878 virtual Int_t GetEntry(Long64_t entry, Int_t getall = 0) { return fChain ? fChain->GetTree()->GetEntry(entry, getall) : 0; }
879 virtual void SetOption(const char *option) { fOption = option; }
880 virtual void SetObject(TObject *obj) { fObject = obj; }
881 virtual void SetInputList(TList *input) { fInput = input; }
882 virtual TList *GetOutputList() const { return fOutput; }
883 virtual void SlaveTerminate();
884 virtual void Terminate();
885
886 ClassDef()CODE" << fClassname << R"CODE(,0);
887
888};
889
890#endif
891
892#ifdef )CODE" << fClassname << R"CODE(_cxx
893void )CODE" << fClassname << R"CODE(::Init(TTree *tree)
894{
895 // The Init() function is called when the selector needs to initialize
896 // a new tree or chain. Typically here the reader is initialized.
897 // It is normally not necessary to make changes to the generated
898 // code, but the routine can be extended by the user if needed.
899 // Init() will be called many times when running on PROOF
900 // (once per file to be processed).
901
902 fReader.SetTree(tree);
903}
904
905Bool_t )CODE" << fClassname << R"CODE(::Notify()
906{
907 // The Notify() function is called when a new file is opened. This
908 // can be either for a new TTree in a TChain or when when a new TTree
909 // is started when using PROOF. It is normally not necessary to make changes
910 // to the generated code, but the routine can be extended by the
911 // user if needed. The return value is currently not used.
912
913 return kTRUE;
914}
915
916
917#endif // #ifdef )CODE" << fClassname << R"CODE(_cxx
918)CODE";
919 ofs.close();
920
921 //======================Generate classname.C=====================
922 TString tcimp;
923 tcimp.Form("%s.C", fClassname.Data());
924 std::ofstream ofsc (tcimp, std::ofstream::out);
925 if (!ofsc) {
926 Error("WriteSelector","cannot open output file %s", tcimp.Data());
927 return;
928 }
929
930 ofsc <<
931R"CODE(#define )CODE" << fClassname << R"CODE(_cxx
932// The class definition in )CODE" << fClassname << R"CODE(.h has been generated automatically
933// by the ROOT utility TTree::MakeSelector(). This class is derived
934// from the ROOT class TSelector. For more information on the TSelector
935// framework see $ROOTSYS/README/README.SELECTOR or the ROOT User Manual.
936
937
938// The following methods are defined in this file:
939// Begin(): called every time a loop on the tree starts,
940// a convenient place to create your histograms.
941// SlaveBegin(): called after Begin(), when on PROOF called only on the
942// slave servers.
943// Process(): called for each event, in this function you decide what
944// to read and fill your histograms.
945// SlaveTerminate: called at the end of the loop on the tree, when on PROOF
946// called only on the slave servers.
947// Terminate(): called at the end of the loop on the tree,
948// a convenient place to draw/fit your histograms.
949//
950// To use this file, try the following session on your Tree T:
951//
952// root> T->Process(")CODE" << fClassname << R"CODE(.C")
953// root> T->Process(")CODE" << fClassname << R"CODE(.C","some options")
954// root> T->Process(")CODE" << fClassname << R"CODE(.C+")
955//
956
957
958#include ")CODE" << thead << R"CODE("
959#include <TH2.h>
960#include <TStyle.h>
961
962void )CODE" << fClassname << R"CODE(::Begin(TTree * /*tree*/)
963{
964 // The Begin() function is called at the start of the query.
965 // When running with PROOF Begin() is only called on the client.
966 // The tree argument is deprecated (on PROOF 0 is passed).
967
968 TString option = GetOption();
969}
970
971void )CODE" << fClassname << R"CODE(::SlaveBegin(TTree * /*tree*/)
972{
973 // The SlaveBegin() function is called after the Begin() function.
974 // When running with PROOF SlaveBegin() is called on each slave server.
975 // The tree argument is deprecated (on PROOF 0 is passed).
976
977 TString option = GetOption();
978
979}
980
981Bool_t )CODE" << fClassname << R"CODE(::Process(Long64_t entry)
982{
983 // The Process() function is called for each entry in the tree (or possibly
984 // keyed object in the case of PROOF) to be processed. The entry argument
985 // specifies which entry in the currently loaded tree is to be processed.
986 // When processing keyed objects with PROOF, the object is already loaded
987 // and is available via the fObject pointer.
988 //
989 // This function should contain the \"body\" of the analysis. It can contain
990 // simple or elaborate selection criteria, run algorithms on the data
991 // of the event and typically fill histograms.
992 //
993 // The processing can be stopped by calling Abort().
994 //
995 // Use fStatus to set the return value of TTree::Process().
996 //
997 // The return value is currently not used.
998
999 fReader.SetLocalEntry(entry);
1000
1001 return kTRUE;
1002}
1003
1004void )CODE" << fClassname << R"CODE(::SlaveTerminate()
1005{
1006 // The SlaveTerminate() function is called after all entries or objects
1007 // have been processed. When running with PROOF SlaveTerminate() is called
1008 // on each slave server.
1009
1010}
1011
1012void )CODE" << fClassname << R"CODE(::Terminate()
1013{
1014 // The Terminate() function is the last function to be called during
1015 // a query. It always runs on the client, it can be used to present
1016 // the results graphically or save the results to file.
1017
1018})CODE";
1019 ofsc.close();
1020 }
1021
1022} // namespace Internal
1023} // namespace ROOT
const Bool_t kFALSE
Definition RtypesCore.h:92
const Bool_t kTRUE
Definition RtypesCore.h:91
const char Option_t
Definition RtypesCore.h:66
#define R__ASSERT(e)
Definition TError.h:120
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:187
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:231
char name[80]
Definition TGX11.cxx:110
int type
Definition TGX11.cxx:121
#define gROOT
Definition TROOT.h:406
void AddHeader(TClass *cl)
Add a header inclusion request.
TVirtualStreamerInfo * GetStreamerInfo(TBranch *branch, TIter current, TClass *cl)
Return the correct TStreamerInfo of class 'cl' in the list of branches (current) [Assuming these bran...
TVirtualStreamerInfo * GetBaseClass(TStreamerElement *element)
Check if element is a base class and if yes, return the base class.
TString GetContainedClassName(TBranchElement *branch, TStreamerElement *element, Bool_t ispointer)
Get name of class inside a container.
void AnalyzeTree(TTree *tree)
Analyze tree and extract readers.
UInt_t AnalyzeBranches(TBranchDescriptor *desc, TBranchElement *branch, TVirtualStreamerInfo *info)
Analyse sub-branches of 'branch' recursively and extract readers.
void ParseOptions()
Parse the user options.
TTreeReaderGenerator(TTree *tree, const char *classname, Option_t *option)
Constructor. Analyzes the tree and writes selector.
void AddReader(TTreeReaderDescriptor::ReaderType type, TString dataType, TString name, TString branchName, TBranchDescriptor *parent=0, Bool_t isLeaf=kTRUE)
Add a reader to the generated code.
Bool_t BranchNeedsReader(TString branchName, TBranchDescriptor *parent, Bool_t isLeaf)
Check whether a branch should have a corresponding reader added, depending on the options provided by...
UInt_t AnalyzeOldLeaf(TLeaf *leaf, Int_t nleaves)
Analyze the leaf and add the variables found.
UInt_t AnalyzeOldBranch(TBranch *branch)
Analyze branch and add the variables found.
void WriteSelector()
Generate code for selector class.
A Branch for the case of an object.
TBranchElement * GetBranchCount() const
TStreamerInfo * GetInfo() const
Get streamer info for the branch class.
Int_t GetType() const
A TTree is a list of TBranches.
Definition TBranch.h:89
virtual const char * GetClassName() const
Return the name of the user class whose content is stored in this branch, if any.
Definition TBranch.cxx:1324
virtual char * GetAddress() const
Definition TBranch.h:208
TObjArray * GetListOfBranches()
Definition TBranch.h:242
Int_t GetSplitLevel() const
Definition TBranch.h:246
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:1652
TBranch * GetSubBranch(const TBranch *br) const
Find the parent branch of child.
Definition TBranch.cxx:2102
virtual void SetAddress(void *add)
Set address of this branch.
Definition TBranch.cxx:2620
TObjArray * GetListOfLeaves()
Definition TBranch.h:243
TBranch * GetMother() const
Get our top-level parent branch in the tree.
Definition TBranch.cxx:2065
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:80
Bool_t CanIgnoreTObjectStreamer()
Definition TClass.h:391
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:4576
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2886
@ kIsEmulation
Definition TClass.h:101
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:2957
An array of clone (identical) objects.
TClass * GetClass() const
Basic data type descriptor (datatype information is obtained from CINT).
Definition TDataType.h:44
static TDataType * GetDataType(EDataType type)
Given a EDataType type, get the TDataType* that represents it.
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition TDatime.h:37
const char * AsString() const
Return the date & time as a string (ctime() format).
Definition TDatime.cxx:102
virtual TFile * GetFile() const
Definition TDirectory.h:174
TObject * Next()
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition TLeaf.h:57
virtual const char * GetTypeName() const
Definition TLeaf.h:139
TBranch * GetBranch() const
Definition TLeaf.h:116
virtual void Add(TObject *obj)
Definition TList.h:87
virtual const char * GetTitle() const
Returns title of object.
Definition TNamed.h:48
virtual const char * GetName() const
Returns name of object.
Definition TNamed.h:47
An array of TObjects.
Definition TObjArray.h:37
Int_t GetEntriesFast() const
Definition TObjArray.h:64
Int_t GetEntries() const
Return the number of objects in array (i.e.
TObject * UncheckedAt(Int_t i) const
Definition TObjArray.h:90
TObject * At(Int_t idx) const
Definition TObjArray.h:166
Collectable string class.
Definition TObjString.h:28
Mother of all ROOT objects.
Definition TObject.h:37
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:187
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:445
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:403
Basic string class.
Definition TString.h:136
Ssiz_t Length() const
Definition TString.h:410
const char * Data() const
Definition TString.h:369
Bool_t EqualTo(const char *cs, ECaseCompare cmp=kExact) const
Definition TString.h:633
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition TString.cxx:912
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition TString.cxx:2217
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition TString.h:615
TString & Remove(Ssiz_t pos)
Definition TString.h:673
TString & Append(const char *cs)
Definition TString.h:564
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2309
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:639
A TTree represents a columnar dataset.
Definition TTree.h:79
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition TTree.cxx:5275
TDirectory * GetDirectory() const
Definition TTree.h:459
virtual EDataType GetType() const =0
virtual TClass * GetValueClass() const =0
Abstract Interface class describing Streamer information for one class.
virtual TObjArray * GetElements() const =0
virtual TClass * GetClass() const =0
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Definition tree.py:1
auto * l
Definition textangle.C:4