TTree::MakeSelector and branch based on a class

Hello,

I’m trying to use TSelector to automate comparison of two trees/chains.

The trees I would like to compare contain a super branch based on a class.
I would like to be able to call methods of that class while processing entries of the tree.

When I use TTree::MakeSelector method, to generate a skeleton that will be used to process entries, I get following list of leaves:

// Declaration of leave types //Event *Event; UInt_t fUniqueID; UInt_t fBits; Int_t value; vector<int> array;
As one can see leaf that corresponds to my class is commented out.
I looked through TTreePlayer::MakeClass and I found there:

[code]const char *headOK = " “;
const char *headcom = " //”;
const char *head;

if (!leafobj->GetClass()) {leafStatus[l] = 1; head = headcom;}[/code]
So if TLeafObject::GetClass will return NULL, then such leaf will be commented out, and no branch pointer will be created for it.

I was only able to make TLeafObject::GetClass return proper TClass pointer, when I created the branch with TTree::BranchOld method. But then TTree::MakeSelector does not create an variable for my Event leaf and it also skips the std::vector leaf.

So how should I create the tree so that TTree::MakeSelector will enable me to access my Event object directly?

Of course I could simply edit resulting .h and .C files to make it happen. But I would like to use TTree::MakeSelector inside a script which would automatically fill Begin, Process and Terminate methods. After which it would run TTree::Process.

It would be a lot easier if I wouldn’t have to duplicate TTree::MakeSelector functionality :smiley:

Regards,
Konrad

Hi Konrad

It looks as though your “Event” branch is split…
What do you see if you ‘Print()’ the TTree ?

John

Hi,

Indeed it was split - intentionally.

[code]******************************************************************************
*Tree :Tree : Test tree *
*Entries : 2 : Total = 4395 bytes File Size = 1000 *

  •    :          : Tree compression factor =   1.00                       *
    

*Branch :Event *
*Entries : 2 : BranchElement (see below) *

*Br 0 :fUniqueID : *
*Entries : 2 : Total Size= 662 bytes One basket in memory *
*Baskets : 0 : Basket Size= 32000 bytes Compression= 1.00 *

*Br 1 :fBits : *
*Entries : 2 : Total Size= 650 bytes One basket in memory *
*Baskets : 0 : Basket Size= 32000 bytes Compression= 1.00 *

*Br 2 :value : *
*Entries : 2 : Total Size= 638 bytes One basket in memory *
*Baskets : 0 : Basket Size= 32000 bytes Compression= 1.00 *

*Br 3 :array : *
*Entries : 2 : Total Size= 678 bytes One basket in memory *
*Baskets : 0 : Basket Size= 32000 bytes Compression= 1.00 *

[/code]

When I set split level to 0, then it works. I have access to my object, through MakeSelector generated code. Unfortunately in this approach I won’t be able to retrieve only selected branches in cases when I won’t need to use objects methods…

Is it possible to have a tree that was split and still access my superbranch object via code prepared by MakeSlector?
I know it is possible to do it by hand. It would be great if it could be achieved automatically.

Regards,
Konrad

Hi
I’ve been playing around with a simple TTree (in v5.13/03) with a branch for a TObject, and I found the same behaviour you report, which is very odd.
I mean - OK, when you generate code for a split or unsplit branch, the TSelector is not the same, this I can accept.
However, if you take the tree with the split branch and Process it with the TSelector generated by the unsplit tree, the object “goes weird” in some way I don’t understand, because if I do exactly the same operations interactively, there is no problem…

I created two trees, one with
tree->Branch(“obj_branch”, “TObject”, &obj, 32000, 0)
the other with
tree->Branch(“obj_branch”, “TObject”, &obj, 32000, 1)

In the TSelector for the unsplit TTree, the Init method does this (obj_branch is the automatically generated TObject* leaf pointer):

[code] // Set object pointer
obj_branch = 0;
// Set branch addresses and branch pointers
if (!tree) return;
fChain = tree;
fChain->SetMakeClass(1);

fChain->SetBranchAddress(“obj_branch”, &obj_branch, &b_obj_branch);
[/code]

I added just after SetBranchAddress

In the Process method I added

GetEntry(entry); printf("Process: obj_branch=%#x\n", (UInt_t)obj_branch); obj_branch->ls();

Running this analysis with the unsplit tree gives:

Init: obj_branch=0xa282b48
Process: obj_branch=0xa282b48
OBJ: TObject    TObject Basic ROOT object : 0 at: 0xa282b48
(Long64_t)0

whereas for the split tree it gives:

Init: obj_branch=0x9c61da0
Process: obj_branch=0x9c61da0

 *** Break *** segmentation violation
 Generating stack trace...
 0x06b2e130 in TTreePlayer::Process(TSelector*, char const*, long long, long long) + 0x3b4 from /space/indra/franklan/root/lib/libTreePlayer.so

(I ran it through ‘gdb’ to check that it really dies at the TObject::ls, but I don’t know why, as I don’t have a ‘debug’ build of ROOT).

Meanwhile, in an interactive session, if I do exactly the same operations with the split tree as in the TSelector I get:

root [7] my_tree->Print()                            
******************************************************************************
*Tree    :my_tree   : Tree with split branch                                 *
*Entries :        1 : Total =            2467 bytes  File  Size =        716 *
*        :          : Tree compression factor =   1.00                       *
******************************************************************************
*Branch  :obj_branch                                                         *
*Entries :        1 : BranchElement (see below)                              *
*............................................................................*
*Br    0 :fUniqueID :                                                        *
*Entries :        1 : Total  Size=        664 bytes  One basket in memory    *
*Baskets :        0 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*
*Br    1 :fBits     :                                                        *
*Entries :        1 : Total  Size=        648 bytes  One basket in memory    *
*Baskets :        0 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*
root [8] TObject*obj_branch=0                        
root [9] my_tree->SetBranchAddress("obj_branch",&obj_branch)
root [10] obj_branch
(class TObject*)0x8ad6e80
root [11] my_tree->GetEntry(0)                               
(Int_t)8
root [12] obj_branch                                         
(class TObject*)0x8ad6e80
root [13] obj_branch->ls()    
OBJ: TObject    TObject Basic ROOT object : 0 at: 0x8ad6e80

Is CINT being especially kind to me and protecting me from the nasty seg fault ?
:laughing:
john

Hi,

You should test out the result of MakeProxy (instead of MakeSelector). [Do read the TTree::MakeProxy documentation :slight_smile: ].

Alternative, you could use the MakeSelector you got from the TTree split with level 0 in conjunction with the TTree split with higher level. This should work and give your access to your data.

HOWEVER using the MakeSelector technique can only EITHER access the full object (by having SetMakeClass(0)) OR accessing the individual element (by having SetMakeClass(1)).

One could achieve both (by having SetMakeClass(0)) as is done in the result of MakeProxy …

Cheers,
Philippe