Plotting a histogram from entries containing arrays of instances

_ROOT Version:6.12/06
_Platform:Linux Mint 19.2
Compiler: Not Provided


Hello,
So i need to create a histogram from a TTree in a .root file, i used MakeClass() to create a skeleton and everything i have been able to find shows a really simple process to filling your histogram and drawing it, however when i try it i get only 17 endries drawn, which is the number of entries but not the number of instances that are actually included in the branch that i want to draw. I have attempted a second for loop in the .C file that did get the instances, but every entry has a different number of instances and i have not been able to make it break when the entry is read, so it just goes to the next entry, duplicating values in the process. I will include a block with the .C generated code and the definitions from the .h file, sadly because i am a new user i can not upload the root file that i need to access, but i hope that this will be enough.

#define lots_cxx
#include "lots.h"
#include <TH2.h>
#include <TStyle.h>
#include <TCanvas.h>
using namespace std;

void lots::Loop()
{
//   In a ROOT session, you can do:
//      root> .L lots.C
//      root> lots t
//      root> t.GetEntry(12); // Fill t data members with entry number 12
//      root> t.Show();       // Show values of entry 12
//      root> t.Show(16);     // Read and show values of entry 16
//      root> t.Loop();       // Loop on all entries
//

//     This is the loop skeleton where:
//    jentry is the global entry number in the chain
//    ientry is the entry number in the current Tree
//  Note that the argument to GetEntry must be:
//    jentry for TChain::GetEntry
//    ientry for TTree::GetEntry and TBranch::GetEntry
//
//       To read only selected branches, Insert statements like:
// METHOD1:
//    fChain->SetBranchStatus("*",0);  // disable all branches
//    fChain->SetBranchStatus("branchname",1);  // activate branchname
// METHOD2: replace line
//    fChain->GetEntry(jentry);       //read all branches
//by  b_branchname->GetEntry(ientry); //read only this branch
   if (fChain == 0) return;
    TH1F *hist1 = new TH1F("hist1", "title", 165, -80, 85);


   Long64_t nentries = fChain->GetEntriesFast();

   Long64_t nbytes = 0, nb = 0;
   for (Long64_t jentry=0; jentry<nentries;jentry++) {
      Long64_t ientry = LoadTree(jentry);
      if (ientry < 0) break;
    
     nb = fChain->GetEntry(jentry);   nbytes += nb;
      // if (Cut(ientry) < 0) continue;
   
//for(Long64_t i=0; i<137; i++){
//if (FgdHit_fX[i]==0) break;
//cout<<i<<"="<<FgdHit_fX[i]<<endl;
    
   
    
   
    hist1->Fill(FgdHit_fX[kMaxcbmout_EsbFgdDetector_FgdHit]);
    

//}
    
   }
    hist1->Draw();
//////////////////////////////////////////////////////////
// This class has been automatically generated on
// Sat Apr 27 16:10:40 2024 by ROOT version 6.12/06
// from TTree cbmsim//cbmout
// found on file: fgd_dig.root
//////////////////////////////////////////////////////////

#ifndef lots_h
#define lots_h

#include <TROOT.h>
#include <TChain.h>
#include <TFile.h>

// Header file for the classes stored in the TTree if any.
#include "FairEventHeader.h"
#include "TClonesArray.h"
#include "TObject.h"
#include "FairMultiLinkedData_Interface.h"
#include "FairTimeStamp.h"
#include "FairHit.h"
#include "EsbData/EsbSuperFGD/FgdHit.h"

class lots {
public :
   TTree          *fChain;   //!pointer to the analyzed TTree or TChain
   Int_t           fCurrent; //!current Tree number in a TChain

// Fixed size dimensions of array or collections stored in the TTree if any.
   static constexpr Int_t kMaxcbmout_EvtHeader_EventHeader = 1;
   static constexpr Int_t kMaxcbmout_EsbFgdDetector_FgdHit = 137;

   // Declaration of leaf types
   FairEventHeader *EventHeader_;
   Int_t           FgdHit_;
   UInt_t          FgdHit_fUniqueID[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   UInt_t          FgdHit_fBits[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   Double_t        FgdHit_fTimeStamp[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   Double_t        FgdHit_fTimeStampError[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   Double32_t      FgdHit_fDx[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   Double32_t      FgdHit_fDy[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   Double32_t      FgdHit_fDz[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   Int_t           FgdHit_fRefIndex[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   Int_t           FgdHit_fDetectorID[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   Double32_t      FgdHit_fX[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   Double32_t      FgdHit_fY[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   Double32_t      FgdHit_fZ[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   TVector3        FgdHit_fmppcLoc[kMaxcbmout_EsbFgdDetector_FgdHit];
   TVector3        FgdHit_fphotoE[kMaxcbmout_EsbFgdDetector_FgdHit];
   TVector3        FgdHit_fdpos[kMaxcbmout_EsbFgdDetector_FgdHit];
   Double_t        FgdHit_ftime[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   TVector3        FgdHit_fmom[kMaxcbmout_EsbFgdDetector_FgdHit];
   TVector3        FgdHit_fmomExit[kMaxcbmout_EsbFgdDetector_FgdHit];
   Double_t        FgdHit_ftrackLength[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   Double_t        FgdHit_ftrackLengthOrigin[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   TVector3        FgdHit_fphotoE_dist1[kMaxcbmout_EsbFgdDetector_FgdHit];
   TVector3        FgdHit_fmppcLoc_dist1[kMaxcbmout_EsbFgdDetector_FgdHit];
   TVector3        FgdHit_fphotoE_dist2[kMaxcbmout_EsbFgdDetector_FgdHit];
   TVector3        FgdHit_fmppcLoc_dist2[kMaxcbmout_EsbFgdDetector_FgdHit];
   Int_t           FgdHit_fpdg[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   Int_t           FgdHit_ftrackId[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   Double_t        FgdHit_fedep[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]
   Double_t        FgdHit_fpe[kMaxcbmout_EsbFgdDetector_FgdHit];   //[cbmout.EsbFgdDetector.FgdHit_]

   // List of branches
   TBranch        *b_cbmout_EvtHeader_EventHeader_;   //!
   TBranch        *b_cbmout_EsbFgdDetector_FgdHit_;   //!
   TBranch        *b_FgdHit_fUniqueID;   //!
   TBranch        *b_FgdHit_fBits;   //!
   TBranch        *b_FgdHit_fTimeStamp;   //!
   TBranch        *b_FgdHit_fTimeStampError;   //!
   TBranch        *b_FgdHit_fDx;   //!
   TBranch        *b_FgdHit_fDy;   //!
   TBranch        *b_FgdHit_fDz;   //!
   TBranch        *b_FgdHit_fRefIndex;   //!
   TBranch        *b_FgdHit_fDetectorID;   //!
   TBranch        *b_FgdHit_fX;   //!
   TBranch        *b_FgdHit_fY;   //!
   TBranch        *b_FgdHit_fZ;   //!
   TBranch        *b_FgdHit_fmppcLoc;   //!
   TBranch        *b_FgdHit_fphotoE;   //!
   TBranch        *b_FgdHit_fdpos;   //!
   TBranch        *b_FgdHit_ftime;   //!
   TBranch        *b_FgdHit_fmom;   //!
   TBranch        *b_FgdHit_fmomExit;   //!
   TBranch        *b_FgdHit_ftrackLength;   //!
   TBranch        *b_FgdHit_ftrackLengthOrigin;   //!
   TBranch        *b_FgdHit_fphotoE_dist1;   //!
   TBranch        *b_FgdHit_fmppcLoc_dist1;   //!
   TBranch        *b_FgdHit_fphotoE_dist2;   //!
   TBranch        *b_FgdHit_fmppcLoc_dist2;   //!
   TBranch        *b_FgdHit_fpdg;   //!
   TBranch        *b_FgdHit_ftrackId;   //!
   TBranch        *b_FgdHit_fedep;   //!
   TBranch        *b_FgdHit_fpe;   //!

Thank you for the help in advance.
-Boris.

Hi Boris,

Hard to say, you might need to debug a bit your code: I do not see any issue linked to ROOT.

Are you perhaps accessing the arrays beyond their length?

Best,
D

Hello,
Thank you for the quick response,
yes i am accessing arrays beyond they’r length, i get a warning when loading into the macro, the problem is that i have 17 entries, and each of them has a different length, the largest is 137(as indicated by the .h MakeClass file), while the smallest has a length of 4, and i dont know how to get the length of each entry as a variable, if i could i could use the second for loop that is commented in this code and actually fill the histogram, but for now another for loop just duplicates instances and i dont know how to not go out of bounds on all the arrays of different sizes.

Dear @boris_haydukov ,

Thanks for reaching out to the forum! Let me try to give you further guidance with your case.

yes i am accessing arrays beyond they’r length

This is undefined behaviour, your program may crash your computer, things may catch on fire, do not do this ever under any circumstance.

hist1->Fill(FgdHit_fX[kMaxcbmout_EsbFgdDetector_FgdHit]);

So practically in your code you are filling the histogram with only one value per entry, that is why you get 17 entries in total in the histogram.

if i could i could use the second for loop that is commented in this code and actually fill the histogram,

I am not sure what you mean here. I am going to guess that for every event you want to run an inner loop to get the actual values of a certain array inside a branch for that particular event. Clearly you need to know the size of the array.

In the generated .h it is quite clear to see that the array stored at each event in the branch has always size 137

Double32_t FgdHit_fX[kMaxcbmout_EsbFgdDetector_FgdHit];

So you can in principle iterate over the 137 elements of the array. Now, since you are then describing that the 137 elements may not always convey real information, I expect there will be some kind of flag that tells you about this. I’m just wildly guessing now, but maybe if a certain array only has 4 real values, the value from the 5th onward will always be set to 999 or something like this and you could check on that. This depends on your particular dataset schema.

Finally, while I understand that you are trying to make this particular example work, have you also tried the same use case with the RDataFrame tool? It seems like it would be a good fit in this example.

Cheers,

Vincenzo

Hello,
When i run a tree->Scan() on the variable i want to fit the arrays simply end before reaching 137(except the one that has 137 instances), without any values or even a mark that more exist. same happens when i try things like Scan(FgdHit.fX[136]), which shows just one entry having a value, while the rest are blank.

As for using RDataFrame, simply writing tree->Draw() also works, so do TBrowser and TTreeViewer, but in the future i will be running far larger simulations with this software and doing all kinds of data analysis, so i need to learn how to do it with c++ code, preferably with a MakeClass generated skeleton, which for now is managing to keep me beyond confused.

Thank you for the help,
Boris

Dear @boris_haydukov ,

Thanks for the further details. I believe you already have all the ingredients needed. The branch you are trying to use contains arrays of 137 elements, so you can traverse them from index 0 to index 136 safely. Furthermore, the header you generated also indicates the amount of elements of each array of each event in the comment (it should be the //[cbmout.EsbFgdDetector.FgdHit_] part). You could use that to restrict the iterations on the array. Is there anything else missing?

Cheers,
Vincenzo

Hello,
I understand now that all the information i need about the length of the arrays is stored in //[cbmout.EsbFgdDetector.FgdHit_], however i still dont know how to extract that information in the loop itself or how to fill the histogram, i cannot seem to understand what to add to my .C file so that the branch can be read and the histogram may be filled properly.

Dear @boris_haydukov ,

You can use the value read by the branch cbmout.EsbFgdDetector.FgdHit_ as the condition of the for loop to stop. I believe that is stored in the variable FgdHit_.

Cheers,
Vincenzo

1 Like

Hello,
It worked, the correct entries have been gathered and filled and the histogram can be drawn. For anyone looking at this thread i will post the working code here:

#define lots_cxx
#include "lots.h"
#include <TH2.h>
#include <TStyle.h>
#include <TCanvas.h>
using namespace std;

void lots::Loop()
{
//   In a ROOT session, you can do:
//      root> .L lots.C
//      root> lots t
//      root> t.GetEntry(12); // Fill t data members with entry number 12
//      root> t.Show();       // Show values of entry 12
//      root> t.Show(16);     // Read and show values of entry 16
//      root> t.Loop();       // Loop on all entries
//

//     This is the loop skeleton where:
//    jentry is the global entry number in the chain
//    ientry is the entry number in the current Tree
//  Note that the argument to GetEntry must be:
//    jentry for TChain::GetEntry
//    ientry for TTree::GetEntry and TBranch::GetEntry
//
//       To read only selected branches, Insert statements like:
// METHOD1:
//    fChain->SetBranchStatus("*",0);  // disable all branches
//    fChain->SetBranchStatus("branchname",1);  // activate branchname
// METHOD2: replace line
//    fChain->GetEntry(jentry);       //read all branches
//by  b_branchname->GetEntry(ientry); //read only this branch
   if (fChain == 0) return;
    TH1F *hist1 = new TH1F("hist1", "title", 165, -80, 85);


   Long64_t nentries = fChain->GetEntriesFast();

   Long64_t nbytes = 0, nb = 0;
   for (Long64_t jentry=0; jentry<nentries;jentry++) {
      Long64_t ientry = LoadTree(jentry);
      if (ientry < 0) break;
    
     nb = fChain->GetEntry(jentry);   nbytes += nb;
      // if (Cut(ientry) < 0) continue;
   
for(Long64_t i=0; i<FgdHit_; i++){

    
   
    
   
    hist1->Fill(FgdHit_fX[i]);
    

}
    
   }
    hist1->Draw();
}

Thank you very much for the help, you are a life saver.
-Boris

1 Like

Dear @boris_haydukov ,

Glad to know you made good progress. Let me just highlight that the equivalent code in RDataFrame would have been

ROOT::RDataFrame df{"mydataset","myfile.root"};
auto h = df.Histo1D("FgdHit_fX");
h->Draw();

Cheers,
Vincenzo

1 Like