MakeSelector and output saving

Hi ROOTers,
I’m analysing a tree using MakeSelector.
I write a huge number of histograms, so I declare an array of histograms as a global variable

#include "testSelector.h"
#include <TH1.h>
#include <TH2.h>
#include <TStyle.h>
#include <TCanvas.h>
#include <TMath.h>
#include "histo2.h"
#include <iostream>
#include "TObjArray.h"

...

//Initialize Histograms
TH1D His[5000];
TH2D His2[5000];
TObjArray Hlist(0);

I want to write the Hlist on a file at the end of the job to store only the histograms I declare.

Into the ‘Begin’ scope I call a function (written in histo2.h) to declare the histograms:

After the analysis I write a file into the Terminate function:

   TFile *g = new TFile("test.root","RECREATE");
   Hlist.Write();
   g->Close();

When I open the file in a ROOT session every histogram is empty.
Where am I wrong?

Maurizio

[quote=“puma”]Hi ROOTers,
I’m analysing a tree using MakeSelector.
I write a huge number of histograms, so I declare an array of histograms as a global variable

//Initialize Histograms
TH1D His[5000];
TH2D His2[5000];
TObjArray Hlist(0);

When I open the file in a ROOT session every histogram is empty.
Where am I wrong?
[/quote]

You are probvably calling the copy constuctor somewhere. I wouln’t use TH1D His[5000]; – better use an array of pointers to TH1D (TH1D His[5000]:wink: or a std::vector<TH1D>! Then the histos really get initialized the moment you use “new” - and more important you don’t call the copy constructor at places where you don’t expect it :slight_smile:

Also, when writing a selector, you should create (“new”) the histograms in SlaveBegin and add them to fOutput. And get them back in Terminate. Then your selector can also be run in PROOF.

Hi Wolf,

I don’t think that it is the problem, because the same code works using MakeClass. On the other way, working with an array of pointers, I get a segmentation violation after having successfully compiled my code.

I run the code using

I have turned to MakeSelector because I want to use the code I wrote for a test tree, for all the trees I need to analyse. So, if anybody knows how to use the code written for a single tree using MakeClass for a chain I would be really happy.
Consider that I would like to put this code into a repository for everybody who wants to perform my analysis using a different version of the dataset, so I would like to write a file that everybody can use without having to modify it, but only changing the list of input trees into the chain.

Another really strange thing I noticed is that when I put these lines in the Begin()

// Test histo
  TH1I *htest= new TH1I("htest","test",50,0.,100000.);

I get these errors:

In member function `virtual void testSelector::Begin(TTree*)':
[path]/testSelector.C:95: warning: unused variable `TH1I*htest'
In file included from [path]/fileFYzR7u.h:32,
                 from [path]/fileFYzR7u.cxx:16:
[path]/testSelector.C: In member function `virtual Bool_t testSelector::Process(long long int)':
[path]/testSelector.C:180: `htest' undeclared (first use this function)

in Process() I Fill htest with nentries, an integer declared global which I post-increment every step.
I finally draw htest in Terminate().

The most interesting thing is that, if I declare htest as a global variable, it will be filled and drawn. So what is the Begin function written for?

Maurizio

You have something wrong in the bookkeeping of your histogram.
The pointer(s) to your histogram(s) like htest should be a data member of your TSelector derived class. In this way you can communicate between the Begin and Process function.

Rene

Hi,
making some cross-checks I verified that the histos are build correctly.
The problem is that a data member which is a branch of my tree seems to be 0 for each entry and I use it to apply some cuts.
But if I take a look into my tree using TBrowser, I can clearly see that it is not zero for each entry.
I tried also another data member of my tree and it is read as 0 for each entry.
Here I put an example of my code:
into the .h file:

   Int_t           nDstar;
...
   TBranch        *b_nDstar;   //!

into the .C file:

His[2].Fill(nDstar);

where His[2] is an histogram that I plot into the Terminate(). I guess the histograms are right because if I put His[2] before a cut that I apply on nDstar it is filled with the complete number of entries (and 0 for each entry), while if I put it after the cut it is empty.

Maurizio

Hi Maurizio,

[quote]Where am I wrong? [/quote]There is nothing obviously wrong in the snippets of example you have shown, however they leave enough for interpretation/guess that many things could be wrong. To be able to able you further you would need a complete running example (i.e including all required source and header and root files) that reproduce the problem(s) as well as a description of what you see and what you expected to see.

Cheers,
Philippe

Ok, here is the running example:

http://www.slac.stanford.edu/~martinel/testSample.root
http://www.slac.stanford.edu/~martinel/testSelector.C
http://www.slac.stanford.edu/~martinel/testSelector.h

I run it from ROOTv5.18(CINT/ROOT C/C++ Interpreter version 5.16.29)
root[0] TFile f(“testSample.root”);
root[1] TTree T = (TTree)f.Get(“ntp1”);
root[2] T->Process(“testSelector.C+”)

I solved my problem: I needed to insert the line

into the Process() function.
Now everything works fine.

That seems a trivial error, but I’ve looked into the manual and through all the examples I found on the net, and I didn’t see that line.

humm … your file are no longer available.
From your solution I am guessing that you customized your selector to point to a 2nd tree. TTree::Process will only control (and call GetEntry) for the tree it is called on, any additional tree will need to be handled explicit, as you did.

Cheers,
Philippe.

Please note in the documentation of the Process function itself (just above the code your entered, it mentions: ... The entry argument // specifies which entry in the currently loaded tree is to be processed. // It can be passed to either testSelector::GetEntry() or TBranch::GetEntry() // to read either all or the required parts of the data. The GetEntry is not automated so that you can restrict the reading to only the part of the TTree you need (by call the branches’ GetEntry). Note that the result of TTree::MakeProxy automates this part (i.e. in that case, the access to the data member induces the reading of the corresponding branch – i.e. load on demand).

Cheers,
Philippe.

Hello,

I am trying to save an array of TH1F in such a way:

test.h
class test:public TSelector{
TH1F*h[20];
}

test.C
void test::SlaveBegin(TTree*){
for(int i=0; i<20; i++){h[i]=new TH1F(Form(h%d,i),Form(“h%d”,i)); fOutput->Add(h[i]);}
}
void test::Terminate(){
for(int i=0; i<20; i++){h[i]->Write();}
}

but the code crashes at runtime with the following message:

#5 0x00007f6f2c62006e in proof::Terminate() () from /raid/01/home/corsi/macros/./proof_C.so
#6 0x00007f6f2c8a7660 in TProofPlayerLite::Finalize(bool, bool) () from /opt/root/v5.34.25/lib/libProofPlayer.so
#7 0x00007f6f2c8a8ec8 in TProofPlayerLite::Process(TDSet*, char const*, char const*, long long, long long) () from /opt/root/v5.34.25/lib/libProofPlayer.so
#8 0x00007f6f2dbb15ce in TProofLite::Process(TDSet*, char const*, char const*, long long, long long) () from /opt/root/v5.34.25/lib/libProof.so

How can I pass the array of TH1F to the output file?
Thanks in advance,
Anna

Hi,

All I can say is there is a typo in your code:

Should be:

Beside that, you could maybe try something like:

for(int i=0; i<20; i++) { h[i] = dynamic_cast<TH1F*>(fOutput->FindObject(Form("h%d",i))); if (h[i]) h[i]->Write(); }
Cheers, Bertrand.

Hi,

Thanks for the reply. The missing “” where an error in the post, sorry.
I tried putting in BeginSlave:
for(int i=0; i<20; i++) {
h[i] = dynamic_cast<TH1F*>(fOutput->FindObject(Form(“h%d”,i)));
}
and in Terminate
for(int i=0; i<20; i++) {
if (h[i]) h[i]->Write();
}
Is that what you meant? But still:

#5 0x00007f0f793fd07b in proof::Terminate() () from /raid/01/home/corsi/macros/./proof_C.so
#6 0x00007f0f79684660 in TProofPlayerLite::Finalize(bool, bool) () from /opt/root/v5.34.25/lib/libProofPlayer.so
#7 0x00007f0f79685ec8 in TProofPlayerLite::Process(TDSet*, char const*, char const*, long long, long long) () from /opt/root/v5.34.25/lib/libProofPlayer.so
#8 0x00007f0f7a98e5ce in TProofLite::Process(TDSet*, char const*, char const*, long long, long long) () from /opt/root/v5.34.25/lib/libProof.so

Anna

Well, no… I meant:

void test::SlaveBegin(TTree*)
{
   for (int i=0; i<20; i++) {
      h[i] = new TH1F(Form("h%d", i), Form("h%d", i));
      fOutput->Add(h[i]);
   }
}
void test::Terminate()
{
   for (int i=0; i<20; i++) {
      h[i] = dynamic_cast<TH1F*>(fOutput->FindObject(Form("h%d", i)));
      if (h[i]) h[i]->Write();
   }
}

I.e. You have to add the histograms to the output list before trying to find them… :wink:

Cheers, Bertrand.

That worked, thanks!