Simple way to automatically TTree::Branch?

Hi, when I write TTrees I usually name & label the Branches the same as the original variable name in my source code, so I end up with blocks of code like this:

Int_t a,b,c;
mytree->Branch("a",&a,"a/I");
mytree->Branch("b",&b,"b/I");
mytree->Branch("c",&c,"c/I");

It’s a lot of repetitive coding and typo-prone. I am wondering if there is a simple way to implement something like:

Int_t a,b,c;
auto_branch(mytree,a,b,c);

which would detect the variable type and set the branches accordingly. It can probably be done using preprocessor macros, but I am wondering if there is a better way to get it done, like with a templated function or something.

I mean for this to only work for built-in types (like int, double, for example). For objects like vectors and such I understand that it will be non-trivial and I am more ok with typing out the Branch statement.

Thanks,
Jean-François

I think, it can be an interesting exercise. It should not be to difficult to do and you are not limited by built-in type only. There is a well know stringification pp-operation:

#include <iostream>

#define literal_builder(a) std::cout<<#a<<std::endl;

int main()
{
   int a;
   literal_builder(a);
}

So here you create a string literal (== branch name) out of identifier. There is no other good way to have
a bridge between “compiler-world-entity” (identifier, identifier-name) and “runtime-entity” (string, which you pass as an argument).
The only thing, of course, it’s still error-prone - what if you have a “typo” when naming identifier?
Anyway, the really good generic library-quality solution must care about checking names at a runtime at least.

The next step is to create a “type description” part like “a/I” out of name and a type. And this will be a bit more difficult - since #macro_parameter_name is a pp-part of translation, but the type of variable exists only in a completely different phase of translation and you have to concatenate them somehow. Something like:

#include <iostream>
#include <string>

template<class T>
struct Type2Literal;

template<>
struct Type2Literal<int>
{
   constexpr static const char * const  typeName = "/I";
};

#define literal_builder(a) std::cout<<#a<<std::endl;
#define typed_literal_builder(a) std::cout<<std::string(#a) + Type2Literal<decltype(a)>::typeName<<std::endl;

int main()
{
   int a;
   literal_builder(a);
   typed_literal_builder(a);
}

This code requires -std=c++11 to compile. May be it’s too verbose, it’s just a sketch/idea (I mainly program Objective-C these days, so my C++ is bit out of date :slight_smile: )

P.S. I think, I can participate in creating such a macro/function if you want :slight_smile:

P.P.S.

The solution without decltype/constexpr etc. is also quite simple (still must be compiled e.g. ACLiC):

#include <iostream>
#include <string>

//We need some template magic instead of simple functions to
//suppress implicit type conversions (thus wrong type suffix).
template<class T>
struct InvalidConversion;

template<> 
struct InvalidConversion<int>
{};

template<>
struct InvalidConversion<double>
{};

inline const char * type_suffix(InvalidConversion<int>)
{
   return "/I";
}

inline const char * type_suffix(InvalidConversion<double>)
{
   return "/D";
}

template<class T>
const char * type_suffix(T a)
{
   return type_suffix(InvalidConversion<T>());
}

#define literal_builder(a) std::cout<<#a<<std::endl;
#define typed_literal_builder(a) std::cout<<std::string(#a) + type_suffix(a)<<std::endl;

int main()
{
   int a;
   literal_builder(a);
   typed_literal_builder(a);
   //short unsigned s = 0;//check, that we do not generate "/I" for short unsigned int!
   //typed_literal_builder(s);
}

P.P.P.S

And finally:

#include <iostream>
#include <string>

//We need some template magic instead of simple functions to
//suppress implicit type conversions (thus wrong type suffix).
template<class T>
struct InvalidConversion;

template<> 
struct InvalidConversion<int>
{};

template<>
struct InvalidConversion<double>
{};

inline const char * type_suffix(InvalidConversion<int>)
{
   return "/I";
}

inline const char * type_suffix(InvalidConversion<double>)
{
   return "/D";
}

template<class T>
const char * type_suffix(T a)
{
   return type_suffix(InvalidConversion<T>());
}

#define literal_builder(a) std::cout<<#a<<std::endl;
#define name_with_type_suffix(a) (std::string(#a) + type_suffix(a)).c_str()

class TTree {
public:
   void Branch(void *, const char *branchName, const char *branchNameTyped)
   {
      std::cout<<"branch: "<<branchName<<' '<<branchNameTyped<<std::endl;
   }
};

//Now, the ugly part: this is the solution for
#define auto_branch1(tree, a) (tree)->Branch(&a, #a, name_with_type_suffix(a));
#define auto_branch2(tree, a, b) \
auto_branch1(tree, a) \
auto_branch1(tree, b)

#define auto_branch3(tree, a, b, c) \
auto_branch2(tree, a, b) \
auto_branch1(tree, c)

#define auto_branch4(tree, a, b, c, d) \
auto_branch3(tree, a, b, c) \
auto_branch1(tree, d)

int main()
{
   TTree tree;
   int a = 0, b = 0, c = 0;
   double d = 0., e = 0., f = 0.;
   
   auto_branch1(&tree, a);
   std::cout<<"-------------\n";
   auto_branch1(&tree, d);
   std::cout<<"-------------\n";
   auto_branch2(&tree, a, d);
   std::cout<<"-------------\n";
   auto_branch2(&tree, d, e);
   std::cout<<"-------------\n";
   auto_branch3(&tree, a, e, c);
   std::cout<<"-------------\n";
   auto_branch4(&tree, a, b, c, d);
}

I’m afraid ugly “macro-magic” is inevitable, you need a macro for “#name conversion” :frowning:
But this is just an idea. I think, there are a lot of examples, how you can create a “generic” macro (hiding
all these auto_branchN and using variadic macros - either GNU extension or a C++11 feature).

I also tried various things following advice from people on IRC. Using CPP macros with the stringification operator didn’t really lead anywhere. I was able to reduce the tree.Branch(“var”,&var,“var/I”) statements to BR_INT(var) and similarly BR_DBL(var), but I still needed one statement per variable, which gets out of hand quickly. I’ll admit I’m not a very good C++ programmer, so possibly my macros and template code were not properly written, but things just didn’t seem to work out.

My latest solution seems pretty extensible: I make a std::map<TString,Int_t> which contains all the integer variables that I want to branch, and another for the Double_t variables. The string key is the intended name of the variable. Then I can use a range-based for loop to iterate over the map and branch accordingly. Here is an example:

std::map<TString,Int_t> vars_ints = {
  {"i_clu",0},{"n_clu",0},{"i_e",0},{"n_ava",0},{"i_ava",0}
};
for(auto & kv: vars_ints) outtree.Branch(kv.first.Data(),&(kv.second),(kv.first+TString("/I")).Data());

It does make accessing the variables in my analysis loops kind of annoying. Instead of n_ava, I need to do vars_ints[“n_ava”], but it makes the branching part easily extensible and repeats less code.

Jean-François

In my quite long answer (see above) I’ve already explained you how and what to do and even gave you a working code (with a fake TTree class, which can be replaced by the real TTree). It’s a pity you’ve ignored it.
I demonstrated, how you create a name and a type description from just an identifier you have in your code, without any maps/shmaps additional things.
Also notice, I do not have to specify _INT / _DBL - I have auto_branch(tree, i) etc. - type information is deduced by template function.
Also notice, I have a generic solution which knows nothing about your variables, you simply pass them as parameters to something function-like looking and you get what you need.
The remaining part is to create a macro accepting variable number of parameters and internally calling other named macros - you can easily find this code somewhere else.
And you do not have to care about macros inside, after all, it’s an implementation detail which will be hidden in some header file. It’s ok to use a macro, have a look how many macros are for example in the boost library.

Hi Jean-Francois,

The best and easiest way to create a struct that includes all the variable you need and generate the dictionary for it.
For example, when compiling with ACliC (to get the dictionary the easy way):

[code]struct Event {
Int_t a;
Int_t b;
Int_t c;
};


Event e;
mytree->Branch(“event”,&e);

[/code]The advantage is that it will work for all type (for which you have a dictionary).

Cheers,
Philippe.

[quote=“pcanal”]Hi Jean-Francois,

The best and easiest way to create a struct that includes all the variable you need and generate the dictionary …
skipped
[/quote]

Yes, nice, so now if he has many TBs of ROOT files he’ll just convert all this into nice Event-like structures and generate dictionaries. This is really the best and easiest way, I agree.

I posted my solution because it’s easier for me to understand and still has the salient features that I want: a) it uses descriptive names for variables & branch labels and b) doesn’t require me to type each of those variable names many times to put them into a TTree.

I got to the map solution before reading your reply tpochep, but to be honest I couldn’t really follow your explanation. My few years of ROOT and PyROOT experience have not trained me to easily read templated C++ code, yet alone with CPP macros involved. I will return to this thread to look at your solution if I need to go beyond the map.

The map solution to me looks similar to Philippe’s struct, but it involves typing the “e.” part of the e.varname both during the analysis stage that fills the tree and during the next stage which plays with that tree to make plots. In the map solution, I get “bare” branches after the first stage, but then I need multiple loops for multiple data types. They both seem convenient (and easily understood).

Jean-François

Hi Jean-Francois,

[quote]The map solution to me looks similar to Philippe’s struct, but it involves typing the “e.” part of the e.varname both during the analysis stage that fills the tree and during the next stage which plays with that tree to make plots[/quote]With the struct and dictionary solution, if you do not add the trailing dot in the top level branch name, the branch will be accessible with just ‘varname’.

Cheers,
Philippe.