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