How to read array variable in a Tree

Hi again guys,

I have a few, probably, naive questions related to my script. I’m trying to read a variable length array as a branch of a TTree (not mine). I do not understand how to get, for each entry of the related root file, the dimension of the array and to access to the data inside the array. I understand I miss something basic in the understanding of how to refere to variables, since I get always or “0” or 10^-300 numbers. I tried to read the related guide for ROOT 5.34 (https://root.cern.ch/root/html534/guides/users-guide/ROOTUsersGuideA4.pdf section 12.14-15) but I still cannot manage.
I know how to do it in ROOT 6.24 (thanks to the help received here) but not in ROOT 5.34/38.
However, this is my code:

#include <TFile.h>
#include <TH1.h>
#include <TH1F.h>
#include <TH1D.h>
#include <TTree.h>
#include <TCanvas.h>
#include <iostream>

void Extracting_Macro(){
  TFile *fopen=TFile::Open("file.root");                                                                                                         

  TTree *myData=(TTree*)fopen->Get("Data");

  TH1D *myAziHist=new TH1D("Azimuth","Azimuth Distribution",100,0.,6.);
                                                                                                 
  Int_t k=0;
  Int_t Nentries=(Int_t)myData->GetEntries();

  for(Int_t i=0;i<Nentries;i++){

    Double_t fAzimuth[5];
    myData->SetBranchAddress("fAzimuth",&fAzimuth);

    myData->GetEntry(i);
    std::cout<<"i: "<<i<<std::endl;
      
    for(Int_t j=0;j<5;j++){
    std:cout<<"azimuth["<<j<<"]: "<<fAzimuth[j]<<std::endl;
      //myAziHist->Fill(fAzimuth[j]);                                                                                                                                             
      k=k+1;
      std::cout<<"k: "<<k<<std::endl;
      }
    std::cout<<"##############################################################"<<std::endl;
    //    delete[] fAzimuth;                                                                                                                                                      
  }
 }

I put the dimensionof the array as 5 since I noticed that the values of the array varies between 1 and 4 for different entries. But I would like to keep the dimension as it is for each event.

I load and compile with

.x Extracting_Macro.C+

Thanks in advance for the help.

ROOT Version: 5.37/38
Platform: Unix CentOS 7.9.2009
Compiler: CINT 5.18


Use ROOT 6 to generate an “analysis skeleton” (it can be used with ROOT 5, too):
root -l -q -b file.root -e 'Data->MakeClass();'

Hi thanks for the reply.
However, I can’t use ROOT 6 (unfortunately). I’m working on a machine that has ROOT 5.34 installed.
I was trying to understand what I should expect from your command, also becasue it gives me back that it cvannot find the Tree Data:

Warning in <TApplication::GetOptions>: macro Data- not found

Usually the dimensions are also saved in the same tree and another branch. Open the file in ROOT and print the tree:

Data->Print();

and look for the description of the “array” (maybe it’s a vector, actually), which would say the name of the variable. For example:

root [1] T->Print()
******************************************************************************
*Tree    :T         : T                                                      *
*Entries :        3 : Total =            2081 bytes  File  Size =        778 *
*        :          : Tree compression factor =   1.09                       *
******************************************************************************
*Br    0 :n         : n/I                                                    *
*Entries :        3 : Total  Size=        546 bytes  File Size  =         77 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*
*Br    1 :x         : x[n]/I                                                 *
*Entries :        3 : Total  Size=        662 bytes  File Size  =        111 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   1.13     *
*............................................................................*
*Br    2 :y         : y[5]/I                                                 *
*Entries :        3 : Total  Size=        600 bytes  File Size  =        111 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   1.13     *
*............................................................................*
root [2] T->Scan("n")
************************
*    Row   *         n *
************************
*        0 *         3 *
*        1 *         5 *
*        2 *         2 *
************************
(long long) 3

tells you that branch x has variable size vectors, each one of size “n” (hence x[n]), and the branch n tells you the size of each of those vectors. Then you can take the maximum of n as the size for your array when reading.

1 Like

So, run:

[...]$ root file.root
root [1] Data->MakeClass();
root [2] .q

Hi,
thanks for spending time to explain it. You answer was very helpful, you clarified me a few things that were not so clear, even after reading the guide and other similar topics here.

So, in order to set a dynamical allocated array (in order to do not have 0 values where there are no data) I can just add a SetBranchAddress to the “n” branch and use it later when on

SetBranchAddreess("n",&n,"n/I");
SetBranchAddress("fAzimuth",fAzimuth,"fAzimuth[n]/F");   

To create (not read):

vector <int> x;
int n;
T->Branch("n",&n,"n/I");
T->Branch("x",&x[0],"x[n]/I");

ok ok, I understood my previous suggestion ha no meaning.
Thanks

Ok. I got the meaning of MakeClass() command and related things (creation of Data.h and Data.C related files).
So if I understood correctly from the guide, I should modify the Data.C file, consistently with what I want ( my program above) and run the Data.C macro.

See the description in the automatically generated “Data.C” file and the relevant links in this old post:

ok, thanks for the help.
Your both answers have been very helpful!

Of course, you can use the generated “Data.[hC]” “analysis skeleton” as an example of how to deal with your data (i.e., you can reuse relevant parts of the generated source code in your own code, which could be much smaller).

Also, compare the data members in the “Data.h” file with the output of: Data->Print();

ok, thanks for clarified it.

BTW. @dastudillo The address passed to “T->Branch” MUST be valid (and it MUST remain valid).

[...]$ root
root [0] vector <int> x;
root [1] std::cout << &x[0] << "\n";
0
root [2] x.push_back(1);
root [3] std::cout << &x[0] << "\n";
0x5651d3af4c00
root [4] x.push_back(1);
root [5] std::cout << &x[0] << "\n";
0x5651d399ed30
root [6] x.push_back(1);
root [7] std::cout << &x[0] << "\n";
0x5651d396d6b0

Yes, right @Wile_E_Coyote, I had not tested that; the vectors are saved but with garbage. This works:

vector <int> *x = new vector<int>;
int n;

T->Branch("n",&n,"n/I");
T->Branch("x",&x);   // or  T->Branch("x","vector<int>",&x);

@dastudillo You do not need “n” at all.

static std::vector<int> x; // must live as long as the tree
T->Branch("x", &x);