Creating TBranches in a loop with 1 entry per branch


ROOT Version: 5
Platform: Scientific Linux 6.10
Compiler: g++ 4.4.7


Hi everyone! I am trying to create a ROOT file with TTrees that contain several TBranches, which contain a single entry each. Here is a working test code displaying the issue. In this code, I am trying to create a TTree with 10 TBranches. Each TBranch has two TLeaves, both ranging from 0 to 9. Instead, I get 10 TTrees with 10 TBranches of varying number of entries. The values get appended to TBranches that have already been created, instead of ā€œfreezingā€ their values and making a new branch.

#include <iostream>
#include <string>
#include <sstream>
#include "TFile.h"
#include "TTree.h"
#include "TBranch.h"
#include "TString.h"

using namespace std;

struct Values{ 

  int val1, val2;
};

int main(){

  int i = 0;
  int j = 0;
  string name;
  stringstream nameformat;
  TString t_name;
	
  TFile* data = TFile::Open("Test.root", "recreate");
	
  for(i = 0; i < 10; i++){
	
    name = "Test";
    nameformat << i;
    name += nameformat.str();
    nameformat.str("");
    t_name = name;
	
    TTree* tree = new TTree(t_name, t_name); //Make 10 TTrees in the TFile, each TTree will contain 10 branches with two values from 0 to 9
		
    for(j = 0; j < 10; j++){
	
      name = "Test";
      nameformat << j;
      name += nameformat.str();
      nameformat.str("");
      t_name = name;
			
      Values Val;
			
      Val.val1 = i;
      Val.val2 = j;
		
      TBranch* b1 = tree->Branch(t_name, &Val, "Value1/I:Value2/I"); //Each branch should contain only one instance i and only one instance of j
    }
		
    tree->Fill();
    tree->Write(); //The resulting tree will have branches with varying number of entries from 0 to 9
  }
	
  data->Close();
  return 0;
} 

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.

This is confusing as the code says:

for(i = 0; i < 10; i++){
   ... 
  TTree* tree = new TTree(t_name, t_name); //Make 10 TTrees in the TFile, each TTree will contain 10 branches with two values from 0 to 9

this is due to the address you assign to the branch.

You have

    for(j = 0; j < 10; j++){
      Values Val;
      TBranch* b1 = tree->Branch(t_name, &Val, "Value1/I:Value2/I"); //Each branch should contain only one instance i and only one instance of j
    }	
    tree->Fill();    

The Values ā€˜Valā€™ is allocated on the stack and goes out of scope (is destroyed) at each iteration.
Consequently all the branch are technically reading their data out of a dangling pointer and the result will be arbitrary/random.
By happenstance, since this is a tight loop the Values object is allocated at the same place in memory at each iteration.
Consequently all the branch are pointing to the same address.

When tree->Fill is called, the last time the address that all branches point to have been updated is the last iteration of the loop and because the tree->Fill is the first statement after the iteration it is possible it is not updated/reused until the Fill does it work and all branches might store [tree_number, 9].

To solve the problem you can either give to each branch a completely separate address and make sure that the lifetime of the object at that address is longer that the scope that contains the call to tree->Fill.

Alternatively and only because you want a single entry, you can also use the following:

#include <iostream>
#include <string>
#include <sstream>
#include "TFile.h"
#include "TTree.h"
#include "TBranch.h"
#include "TString.h"

using namespace std;

struct Values{ 

  int val1, val2;
};

int main(){

  int i = 0;
  int j = 0;
  string name;
  stringstream nameformat;
  TString t_name;
	
  TFile* data = TFile::Open("Test.root", "recreate");
	
  for(i = 0; i < 10; i++) {

    name = "Test";
    nameformat << i;
    name += nameformat.str();
    nameformat.str("");
    t_name = name;

    TTree* tree = new TTree(t_name, t_name); //Make 10 TTrees in the TFile, each TTree will contain 10 branches with two values from 0 to 9
		
    for(j = 0; j < 10; j++){
	
      name = "Test";
      nameformat << j;
      name += nameformat.str();
      nameformat.str("");
      t_name = name;
			
      Values Val;
			
      Val.val1 = i;
      Val.val2 = j;
		
      TBranch* b1 = tree->Branch(t_name, &Val, "Value1/I:Value2/I"); //Each branch should contain only one instance i and only one instance of j
      b1->Fill(); // Capture the value immediately.
      b1->ResetAddress(); // The object we point to is about to go out of scope, let's forget about it.
    }
		
    // We called Fill for each branch individually, let's inform the TTree we are done.
    tree->SetEntries( 1 );
    tree->Write(); //The resulting tree will have branches with varying number of entries from 0 to 9
  }
	
  data->Close();
  return 0;
} 

Cheers,
Philippe.

1 Like

Hi

Thanks for the reply! I have had a further look at the code (my actual code is considerably larger) and after a fair bit of digging was able to implement your first suggestion. Again, thanks for the thorough explanation!