Problems with reading TChain

I am trying to read a TChain with dynamical buffers. The TBranch “NBucket” gives me the length of the array in the TBranches “B1_Exists” and “B1_BCID”. If I append more than one file to the chain, only the first file is read (correctly!). For the further files the buffers are not updated anymore. Does anyone know what I am doing wrong? I have attach the relevant part of the code:

[size=85]ULong64_t i_BufferTime;
Long64_t i_Buffer_Quan;

Long64_t i_ChainEntry_Quan=this->ch_Chain->GetEntries(); //ch_Chain of type TChain*

for (Long64_t i_ChainEntry_Cnt=0; i_ChainEntry_Cnt<i_ChainEntry_Quan ; i_ChainEntry_Cnt++) {
LoadTree(i_ChainEntry_Cnt);

  this->TB_time=this->ch_Chain->GetBranch("Time");                        //TB_time of type TBranch*
  this->TB_entry_num=this->ch_Chain->GetBranch("NBucket");         //TB_entry_num of type TBranch*
  this->TB_time->SetAddress(&i_BufferTime);
  this->TB_entry_num->SetAddress(&i_Buffer_Quan);

  this->TB_time->GetEntry(i_ChainEntry_Cnt);
  this->TB_entry_num->GetEntry(i_ChainEntry_Cnt);

//Checking wether in correct time interval

  i_b1_BufferExists=new Int_t[i_Buffer_Quan];
  f_b1_BufferBcid=new Float_t[i_Buffer_Quan];

 this->TB_b1_exists=this->ch_Chain->GetBranch("B1_Exists");
 this->TB_b1_bcid=this->ch_Chain->GetBranch("B1_BCID");

 this->TB_b1_exists->SetAddress(i_b1_BufferExists);
 this->TB_b1_bcid->SetAddress(f_b1_BufferBcid);

 this->TB_b1_exists->GetEntry(i_ChainEntry_Cnt);
 this->TB_b1_bcid->GetEntry(i_ChainEntry_Cnt);

//Data reading from Buffers

 this->TB_time->ResetAddress();
 this->TB_entry_num->ResetAddress();
 this->TB_b1_exists->ResetAddress();
 this->TB_b1_bcid->ResetAddress();

 delete i_b1_BufferExists;
 delete f_b1_BufferBcid;

}[/size]

Hi,

The main issue is that the entry number of the chain is not the same as the entry number to be passed to the branch. For the branch you need to pass the entry number of the underlying TTree. Concretely this means that you need something like:Long64_t localEntry = LoadTree(i_ChainEntry_Cnt); ... this->TB_time->GetEntry(localEntry);For all but the first file, the value of i_ChainEntry_Cnt and localEntry will be different (and i_ChainEntry_Cnt will be to large for the branch).

In addition, the setting of the branch address can be factor out of the loop in order to greatly optimize your code. The sample you shown can be refactored as:[code]ULong64_t i_BufferTime;
Int_t i_Buffer_Quan; // in the original code this was a Long64_t, however it is used an array size … and in ROOT only Int_t is supported as an array size.
i_b1_BufferExists = 0;
f_b1_BufferBcid = 0;

this->ch_Chain->SetBranchAddress(“Time”,&i_BufferTime,&this->TB_time);
this->ch_Chain->SetBranchAddress(“NBucket”,&i_Buffer_Quan,&this->TB_entry_num);
this->ch_Chain->SetBranchAddress(“B1_Exists”, i_b1_BufferExists, &this->TB_b1_exists);
this->ch_Chain->SetBranchAddress(B1_BCID", f_b1_BufferBcid, &this->TB_b1_bcid);

for (Long64_t i_ChainEntry_Cnt=0; i_ChainEntry_Cnt<i_ChainEntry_Quan ; i_ChainEntry_Cnt++) {
Long64_t localEntry = LoadTree(i_ChainEntry_Cnt);
if (localEntry < 0) break;
this->TB_time->GetEntry(localEntry);
this->TB_entry_num->GetEntry(localEntry);
this->TB_b1_exists->GetEntry(localEntry);
this->TB_b1_bcid->GetEntry(localEntry);
}[/code]

Cheers,
Philippe.

Does in this case Root allocate the buffer memory?

Yes, it should (assuming I guessed properly the way you defined the branches).

Cheers,
Philippe.

Unfortuantely, this code is not working. The pointer “this->TB_b1_exists” is still 0 after proceeding “this->ch_Chain->SetBranchAddress(“B1_Exists”, i_b1_BufferExists, &this->TB_b1_exists);” which means there is a segmantation violation when proceeding “this->TB_b1_exists->GetEntry(localEntry);”. I have initialised all Branch Pointers to zero in the beginning, the same for the buffer pointers as you wrote.

[quote]nfortuantely, this code is not working. The pointer “this->TB_b1_exists” is still 0 after proceeding “this->ch_Chain->SetBranchAddress(“B1_Exists”, i_b1_BufferExists, &this->TB_b1_exists);” which means there is a segmantation violation when proceeding “this->TB_b1_exists->GetEntry(localEntry);”. [/quote]If the branch actually exist in the underlying TTree, the pointer should be set during the call to ’ LoadTree(i_ChainEntry_Cnt);’ (assuming it turns around and calls this->ch_Chain->LoadTree(i_ChainEntry_Cnt); as expected).

The call to SetBranchAddress does not change the value of the pointers, only LoadTree changes the value of the branch pointer.

Cheers,
Philippe.

After proceeding “this->ch_Chain->LoadTree(i_ChainEntry_Cnt);” the TB pointers “this->TB_b1_exists” and “this->TB_b1_bcid” are still zero, but the pointers “this->TB_time” and “this->TB_entry_num” have been assigned an adress. Which means teh simple leafs are read correctly but not the leafs containing an array. I had exactly this problem a long time ago and therefore I changed the reading structure completely. So has anyone an idea, what is going wrong?

Hi,

It is not clear what is going wrong. Could you send me a complete running example reproducing the problem?

Cheers,
Philippe.

Before I start sending code, I have a questions: The pointer in des second argument of SetBranchAdress is zero, so Root owns the object in the leaf. How is it then possible to access the data in the leaf? The pointer cannot be assigned another value than zero as it is call by value. This pointer is in this case actually not necessary, or am I wrong? Is their in the internet somewhere a tutorial which discusses in more detail how to properly read TChains/TTrees in various ways (besides the ROOT documentation)? I really would like to understand this in more detail. Thanks for your help.

Hi,

[quote]The pointer in des second argument of SetBranchAdress is zero, so Root owns the object in the leaf. [/quote]Humm … I thought you were saying that the pointer to the branch was staying equal to zero. For the 2nd argument, you are right as long as the branch were created with the ‘leaflist’ technique. If they were not, the 2nd argument would actually be passed the address of a pointer.

And indeed if some of the branch created with the leaflist technique are arrays you will need to allocate them explicitly with a large enough size. If you only have only one TTree, you can get the exact value needed with tree->GetLeaf("name_of_the_index")->GetMaximum();

Cheers,
Philippe.

PS. Beside the documentation to investigate further the use cases, you would have to dive into the source code.

delete

I was talking about that and this is indeed the case. As I have to read the leafs per branch and not with the TChain GetEntry() function all at once (I have to loop several times through the file and avoid reading data which is irrelevant because of the wrong time stamp), I have to call GetEntry() for each branch seperatly.

So you say that the second argument is overwritten with an adress? But the argument is of type void* which means only if I enter something like &var with var is of any non-pointer type the routine is able to write in var. If I insert a pointer I cannot change the adress which the pointe points to.
If i insert 0 this actually should work like the first example in http://root.cern.ch/root/html/TBranchElement.html#TBranchElement:SetAddress. But now I still have the problem that my Branches adresses are not set correctly. If I insert a non-zero adress then they are set correctly.

GetLeaf returns the first leaf (at least this is what the documentation tells to me) and GetMaximum() returns 0 (c.f. http://root.cern.ch/root/html/TLeaf.html#TLeaf:GetMaximum, but I hope that I am simply reading something wrong now) which means that I will get the array size of the first leaf in the branch. This quantity is already saved in the branch “NBucket”. But the array size changes for every entry in the tree (and gets even larger), so I would allocate the wrong buffer size.

[quote]I was talking about that and this is indeed the case. As I have to read the leafs per branch and not with the TChain GetEntry() function all at once (I have to loop several times through the file and avoid reading data which is irrelevant because of the wrong time stamp), I have to call GetEntry() for each branch seperatly.[/quote]This is the problem I don’t understand and would need an example to reproduce it.

[quote]So you say that the second argument is overwritten with an adress?[/quote]Not always. Only if the branch was created using objects (which seems to not be your case).

[quote]But now I still have the problem that my Branches adresses are not set correctly. If I insert a non-zero adress then they are set correctly.[/quote]You could get the address that was assigned automatically using GetAddress.

[quote]GetLeaf returns the first leaf (at least this is what the documentation tells to me) and GetMaximum() returns 0 (c.f. root.cern.ch/root/html/TLeaf.htm … GetMaximum,[/quote]None of the leaf objects are actually of type TLeaf ; they are all of some derived type (like TLeafI where GetMaximum is overloaded).

Cheers,
Philippe.

I could solve the problem within my old code (mainly by replacing the chain entry number by the tree entry number in the GetEntry calls). Thanks for your help.