Add branches to a TTree

Hello, I’m working to a Geant4 simulation (not made by me) in which ROOT is used… Currently the simulation save the deposited energy in a TTree and all other data in histograms.
I need to save in the TTree some information (currently saved in histograms).
I started with the interaction position that is saved into an histogram (line 116)


then I added the line 117 to save it into the TTree

tree1->Branch("zint", fParPos[i].z());

but when I open the root file, there isn’t the branch. (7.6 KB)

Please read tips for efficient and successful posting and posting code

ROOT Version: Not Provided
Platform: Not Provided
Compiler: Not Provided

I suggest you to have a look a the TTree tutorial to understand how TTrees work. Have a look especially a the tree1w() function.

You are just declaring a new branch.

  • You should add the new branch below line 200 where the tree is iniziatilzed and one branch is added.
  • Create a function like the one of line 60 to fill the variable.
  • The tree is already filled at line 75.

Probably the variables used have been declared in the AnalysisManager.hh file.


Hello @Dilicus thanks.
I moved the branch declaration.

  1. You said to write a function to fill the parpos.z branch. Isn’t possible to do it in AnalysisManager::FillhSecondaries ? Because, as you can see in line 116, the filling of the histogram is made in a for cycle and 2 if conditions. Then I’ve to use the for cycle and the if condition also to fill the branch.

  2. Please, could you write the function to fill the branch for parpos.z so that I will use it as example to fill the other needed quantities?

Thanks (7.6 KB)
AnalysisManager.hh (2.4 KB)

You must need to give a stable address to Branch for the user data (instead of a temporary object here).

You should probably create the branch at the same place as the other branch (i.e. end of AnalysisManager::BeginOfRun)

And where you currently have the 'zint` branch creation you probably just want:

data_member_for_zint = fParPos[i].z()

I modified your .cc and .hh files.
I added few comments to help you understand what the code should do now.

If everything works in the right way, I you should have a TTree with 2 more branches, one for the number of secondaries produced and one with a vector with max length 200 filled in the first part with the Zs of the interaction and the second part is padded with 0s.

In principle you could create a branch with variable size vector but is slightly more complicated. (9.0 KB)
AnalysisManager_mod.hh (3.0 KB)


Hello thank you the both @pcanal and @dilicus

I tried your modified files, but I got the error

include/AnalysisManager.hh:58:28: error: invalid use of non-static data member ‘AnalysisManager::kMaxTrack’
   58 |     G4double Z_interaction[kMaxTrack];//<------------- new lines
      |                            ^~~~~~~~~
include/AnalysisManager.hh:46:14: note: declared here
   46 |     G4double kMaxTrack=200; // I set the max number of second

then, in the .hh I tried to replace G4double Z_interaction[kMaxTrack]
G4double Z_interaction[200]
and in .cc //for(int i=0;i<kMaxTrack;i++) {//<------------- new lines
for(int i=0;i<200;i++) {/

I don’t get errors during compiling, but when I run I get:

### Run 0 starts.
--> Event 0 starts.
GeSD::Initialize:  GeSD   GeCollection

### CAUGHT SIGNAL: 11 ### address: 0,  signal =  SIGSEGV, value =   11, description = segmentation violation. Unknown segmentation fault error: 128.

[PID=18494, TID=-1][ 0/16]> ./Sim() [0x461149]
[PID=18494, TID=-1][ 1/16]> /nfs/GEANT4/geant4-v11.0.0-install/lib64/ [0x7f0f22e80b89]
[PID=18494, TID=-1][ 2/16]> /nfs/GEANT4/geant4-v11.0.0-install/lib64/ [0x7f0f2313dc6f]
[PID=18494, TID=-1][ 3/16]> /nfs/GEANT4/geant4-v11.0.0-install/lib64/ [0x7f0f2313b8ae]
[PID=18494, TID=-1][ 4/16]> /nfs/GEANT4/geant4-v11.0.0-install/lib64/ [0x7f0f231720c2]
[PID=18494, TID=-1][ 5/16]> /nfs/GEANT4/geant4-v11.0.0-install/lib64/ [0x7f0f1ec3cf20]
[PID=18494, TID=-1][ 6/16]> /nfs/GEANT4/geant4-v11.0.0-install/lib64/ [0x7f0f1ec5b9d1]
[PID=18494, TID=-1][ 7/16]> /nfs/GEANT4/geant4-v11.0.0-install/lib64/ [0x7f0f1ec2cc4d]
[PID=18494, TID=-1][ 8/16]> /nfs/GEANT4/geant4-v11.0.0-install/lib64/ [0x7f0f1ec2dd46]
[PID=18494, TID=-1][ 9/16]> /nfs/GEANT4/geant4-v11.0.0-install/lib64/ [0x7f0f1ec5d4bc]
[PID=18494, TID=-1][10/16]> /nfs/GEANT4/geant4-v11.0.0-install/lib64/ [0x7f0f1ec4a28a]
[PID=18494, TID=-1][11/16]> /nfs/GEANT4/geant4-v11.0.0-install/lib64/ [0x7f0f1ec3cf20]
[PID=18494, TID=-1][12/16]> /nfs/GEANT4/geant4-v11.0.0-install/lib64/ [0x7f0f1ec5b9d1]
[PID=18494, TID=-1][13/16]> ./Sim() [0x419d59]
[PID=18494, TID=-1][14/16]> /lib64/ [0x7f0f1d5f9b15]
[PID=18494, TID=-1][15/16]> ./Sim() [0x41dd41]

: Segmentation fault (Signal sent by the kernel [(nil)])

I upload here the files, because I had to fix 3-4 typos. (9.1 KB)
AnalysisManager.hh (3.1 KB)

@pcanal I also tried as you suggested i.e.

zintvec = fParPos[i].z();

tree1->Branch("zint", &zintvec);

and it looks like that it saved the informatio. What is the difference between your simpler and @Dilicus’s more complicated methods?

Since you have a for loop iterating over the secondaries I suppose you have several secondaries.
The method suggested by pcanal should save the zintvec of the last secondary.

My idea was to save for each event a vector with all the secondaries z interaction vertex.

What I did should be very similar to what done with the totE_Ge variable.

Since you have a segmentation fault maybe you try to access vector outside boundaries, maybe you have more than 200 secondaries, try to increase that number and check if the code works.

By the way I slightly changed the files, now the size of vector of z interaction vertices should change according to the number of secondaries. (9.1 KB)
AnalysisManager.hh (3.1 KB)

Hi @Dilicus thank you for your time.

I tried to compile your code, but I got the errors

/src/ error: ‘N_Sec’ does not name a type
   54 |     N_Sec=0;//<------------- new lines
      |     ^~~~~
/src/ error: ‘MomSrcGamma’ does not name a type
   56 |     MomSrcGamma[0] = G4ThreeVector(-999,-999,-999);
      |     ^~~~~~~~~~~
/src/ error: ‘MomSrcGamma’ does not name a type
   57 |     MomSrcGamma[1] = G4ThreeVector(-999,-999,-999);
      |     ^~~~~~~~~~~
/src/ error: expected unqualified-id before ‘for’
   59 |     for(int i=0;i<100;i++) {
      |     ^~~
/src/ error: ‘i’ does not name a type
   59 |     for(int i=0;i<100;i++) {
      |                 ^
/src/ error: ‘i’ does not name a type
   59 |     for(int i=0;i<100;i++) {
      |                       ^
/src/ error: ‘MomIon’ does not name a type
   63 |     MomIon[0] = G4ThreeVector(-999,-999,-999);
      |     ^~~~~~
/src/ error: ‘MomIon’ does not name a type
   64 |     MomIon[1] = G4ThreeVector(-999,-999,-999);
      |     ^~~~~~
/src/ error: ‘MomCapIon’ does not name a type
   66 |     MomCapIon[0] = G4ThreeVector(-999,-999,-999);
      |     ^~~~~~~~~
/src/ error: expected declaration before ‘}’ token
   67 | }
      | ^
/src/ error: no matching function for call to ‘TTree::Branch(const char [9], std::vector<double>&)’
  217 |     tree1->Branch("Z_vertex", Z_interaction);//Branch for the vector  of Z interaction of  secondary

then, looking the code I noticed a typo error, i.e. an entra “}” just after the line Z_interaction.resize(0);//<------------- new lines
as you can see (lines 40-57)

void AnalysisManager::ClearVariables()
    for(int i=0;i<2;i++) {
        totE_Ge[i] = 0;
        totEGauss_Ge[i] = 0;
    //here I clean the Z interaction
    //for(int i=0;i<kMaxTrack;i++) {//<------------- new lines
    //for(int i=0;i<200;i++) {//<------------- new lines
    Z_interaction.resize(0);//<------------- new lines
    //here I clean the N_secondaries
    N_Sec=0;//<------------- new lines
    MomSrcGamma[0] = G4ThreeVector(-999,-999,-999);
    MomSrcGamma[1] = G4ThreeVector(-999,-999,-999);

I deleted that “}” (i.e line 51), but I still get the error related to TTree Branch

error: no matching function for call to ‘TTree::Branch(const char [9], std::vector<double>&)’
  217 |     tree1->Branch("Z_vertex", Z_interaction);//Branch for the vector  of Z interaction of  secondary
      |                                            ^

Sorry my fault change
this line
tree1->Branch("Z_vertex", Z_interaction);

into this

tree1->Branch("Z_vertex", &Z_interaction);

and should work.

Just for curiosity can you add before the for of line 122 this line


So I can understand if the first code failed because fNofSec was too large, in that case also the first code I sent to you should work but maybe with 1000 instead of 200

Hi @dilicus, thank you.
I’ve some doubts:

  1. It saves the z_int, but the entries are lower than in the histogram (as you can see)

  1. Edep was a vector then, in the original version, by

TString henecut = TString::Format("EdepRaw>> htemp(7000, 0., 7000.)");

I got the total energy in the two detectors, and by

TString henecut0 = TString::Format("EdepRaw[0]>> htemp(7000, 0., 7000.)");
TString henecut0 = TString::Format("EdepRaw[1]>> htemp(7000, 0., 7000.)");

the energy in each one of the detectors.

Now it looks like to me that it just save the total energy as you can see in the graph and in the result file


Det 1

Results-deposited-energy.txt (398 Bytes)

1 Like

Here is where you fill the energy vector, I do not know what are the values passed and why there is
totE_Ge[fcopyNo]+=feDep instead of just totE_Ge[fcopyNo]=feDep

void AnalysisManager::FillhGeTotEdep(G4double feDep,G4double feDepGauss,G4int fcopyNo,G4int fNofHits,G4int fparticleCode)
    totE_Ge[fcopyNo] += feDep;
    totEGauss_Ge[fcopyNo] += feDepGauss;

The reason because there are lower entries could be the condition you have on the energy when you fill the ttree.

Two simple way to check are:

  • remove the if condition at line 85 where the tree is filled.

  • create a new tree for the zint variable that you fill outside of an if statement

Hi @Dilicus thank you!
The reason of lower number of entries was the if condition!

1 Like

Hi dilicus,
following your example, I filled the TTree with the needed quantities.

I’ve this vector


in which I store the gamma energies and I store it in a branch:

tree1->Branch("Egamma", &PrimGammaKinEne);

Egamma is a vector and, in particular if I plot Egamma[0] by ROOT, I get the energy of the gammas emitted by the first de-exitation (primary gamma).
Given that I’m just interested to the primary gamma (i.e. Egamma[0]), is there a way to just save in the TTree Egamma[0]? (9.7 KB)

Is quite easy in the .hh
and add just a variable
G4double Egamma_1st=0

And in your .cc file just simply add the new branch at line 241

    tree1->Branch("Egamma_1st_de-exc", &Egamma_1st);

and remove the branch for the vector

tree1->Branch("Egamma", &PrimGammaKinEne); 

At line 175 just before closing the FillSecondaries function add;

I will also add in AnalysisManager::ClearVariables()


Hi @Dilicus thank you.

I compiled without errors, but when I run I get this error

### Run 0 starts.
--> Event 0 starts.
GeSD::Initialize:  GeSD   GeCollection
terminate called after throwing an instance of 'std::out_of_range'
  what():  vector::_M_range_check: __n (which is 0) >= this->size() (which is 0)

### CAUGHT SIGNAL: 6 ### address: 0xa5b00000f30,  signal =  SIGABRT, value =    6, description = abort program (formerly SIGIOT).

[PID=3888, TID=-1][ 0/24]> /lib64/ [0x7fbc737c8387]
[PID=3888, TID=-1][ 1/24]> /lib64/ [0x7fbc737c9a78]
[PID=3888, TID=-1][ 2/24]> /software/gcc/10.2.0/lib64/ [0x7fbc74334bfa]
[PID=3888, TID=-1][ 3/24]> /software/gcc/10.2.0/lib64/ [0x7fbc743329d6]
[PID=3888, TID=-1][ 4/24]> /software/gcc/10.2.0/lib64/ [0x7fbc74332a41]
[PID=3888, TID=-1][ 5/24]> /software/gcc/10.2.0/lib64/ [0x7fbc74332ce5]
[PID=3888, TID=-1][ 6/24]> /software/gcc/10.2.0/lib64/ [0x7fbc7435c6f3]
[PID=3888, TID=-1][ 7/24]> ./Sim() [0x46225a]
[PID=3888, TID=-1][ 8/24]> ./Sim() [0x469f41]
[PID=3888, TID=-1][ 9/24]> /GEANT4/geant4-v11.0.0-install/lib64/ [0x7fbc78ffbb89]
[PID=3888, TID=-1][10/24]> /GEANT4/geant4-v11.0.0-install/lib64/ [0x7fbc792b4c6f]
[PID=3888, TID=-1][11/24]> /GEANT4/geant4-v11.0.0-install/lib64/ [0x7fbc792b28ae]
[PID=3888, TID=-1][12/24]> /GEANT4/geant4-v11.0.0-install/lib64/ [0x7fbc792e90c2]
[PID=3888, TID=-1][13/24]> /GEANT4/geant4-v11.0.0-install/lib64/ [0x7fbc74de8f20]
[PID=3888, TID=-1][14/24]> /GEANT4/geant4-v11.0.0-install/lib64/ [0x7fbc74e079d1]
[PID=3888, TID=-1][15/24]> /GEANT4/geant4-v11.0.0-install/lib64/ [0x7fbc74dd8c4d]
[PID=3888, TID=-1][16/24]> /GEANT4/geant4-v11.0.0-install/lib64/ [0x7fbc74dd9d46]
[PID=3888, TID=-1][17/24]> /GEANT4/geant4-v11.0.0-install/lib64/ [0x7fbc74e094bc]
[PID=3888, TID=-1][18/24]> /GEANT4/geant4-v11.0.0-install/lib64/ [0x7fbc74df628a]
[PID=3888, TID=-1][19/24]> /GEANT4/geant4-v11.0.0-install/lib64/ [0x7fbc74de8f20]
[PID=3888, TID=-1][20/24]> /GEANT4/geant4-v11.0.0-install/lib64/ [0x7fbc74e079d1]
[PID=3888, TID=-1][21/24]> ./SimLuna() [0x419f81]
[PID=3888, TID=-1][22/24]> /lib64/ [0x7fbc737b4555]
[PID=3888, TID=-1][23/24]> ./Sim() [0x41df6f]

: Aborted (Signal sent by tkill() 3888 2651)

maybe should I define Egamma_1st as a vector, to avoid it? i.e.:

std::vector<G4double> Egamma (9.8 KB)
AnalysisManager.hh (2.9 KB)

Just add a check to avoid to access the element 0 even if does not exist

 Egamma_1st =;

Thank you @dilicus!

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