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-split
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 split
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:101
const Bool_t kTRUE
Definition RtypesCore.h:100
const char Option_t
Definition RtypesCore.h:66
#define R__ASSERT(e)
Definition TError.h:118
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:404
TString fBranchName
Name of the branch.
TBranchDescriptor * fParent
Descriptor of the parent branch (NULL for topmost)
TString fContainerName
Name of the container.
TString fSubBranchPrefix
Prefix (e.g. if the branch name is "A." the prefix is "A".
Base class for code generators like TTreeProxyGenerator and TTreeReaderGenerator.
TList fListOfHeaders
List of included headers.
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.
TTree * fTree
Pointer to the tree.
TString fOptionStr
User options as a string.
TString fBranchName
Branch corresponding to the reader.
ReaderType fType
Type of the reader: Value or Array.
std::vector< TString > fIncludeStruct
Branches whom should be included.
void AnalyzeTree(TTree *tree)
Analyze tree and extract readers.
TString fClassname
Class name of the selector.
std::vector< TString > fIncludeLeaves
Branches whose leaves should be included.
UInt_t AnalyzeBranches(TBranchDescriptor *desc, TBranchElement *branch, TVirtualStreamerInfo *info)
Analyse sub-branches of 'branch' recursively and extract readers.
void ParseOptions()
Parse the user options.
Bool_t fIncludeAllTopmost
Should all topmost branches be included.
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.
Bool_t fIncludeAllLeaves
Should all leaves be included.
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:4585
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2895
@ 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:2966
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:220
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:81
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:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
Int_t GetEntries() const
Return the number of objects in array (i.e.
TObject * UncheckedAt(Int_t i) const
Definition TObjArray.h:84
TObject * At(Int_t idx) const
Definition TObjArray.h:164
Collectable string class.
Definition TObjString.h:28
Mother of all ROOT objects.
Definition TObject.h:41
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:201
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:515
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:473
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:916
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition TString.cxx:2222
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:2314
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:5279
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
ELocation
0 for the general case, 1 when this a split clases inside a TClonesArray, 2 when this is a split clas...
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