Writing histograms kept in std::vector<TH1F*> after filling them in TSelector in PROOF mode

Hi!

I am using a class inheriting from TSelector in PROOF mode, which is working fine for me until I want to fill a couple of TH1F histograms that are kept in a std::vector (using ROOT version 6.10.04).

I have a member variable called
std::vector <TH1F*> vec_hist_rpt_hs;
I initialize the vector in the Begin() method with

for (Int_t i=0; i<20; i++) {
    vec_hist_rpt_hs.push_back(nullptr);
}

Then in the SlaveBegin() I define the histograms and add them to the output list

 for (Int_t i=0; i<20; i++) {
      TString histname = Form("histname_%d", i);
      vec_hist_rpt_hs.at(i) = new TH1F(histname, ";x;y", 100, 0., 10.);
}
...
 for (Int_t i=0; i<20; i++) {
      GetOutputList()->Add(vec_hist_rpt_hs.at(i));
}

and fill them in the Process() method

Int_t ntracks = *m_jet_ntracks;
if (ntracks > 19) {ntracks = 19;}
vec_hist_rpt_hs.at(ntracks)->Fill(*somevariable);

until here the code runs and does not complain. I can’t however write the histograms to file.
If I write them in the Terminate() method, I get segmentation faults

TFile *output_file = new TFile("output.root", "RECREATE");
for (Int_t i=0; i<20; i++) {
    vec_hist_rpt_hs.at(i)->Write();
}
output_file->Close();

So it looks like the filled histograms can’t be called from the vector anymore, or aren’t merged back they way that I thought they would be. Is there a way to make this work?

Thanks a lot for your help!

Alex

Histograms are associated with files at creation time. You should use SetDirectory() before calling Write(), as the histograms will not know where to write themselves otherwise.

Hi amadio!
Thanks for your reply!
The primary problem doesn’t seem to be that the histogram doesn’t know where to write to, but that the histograms that are created in the slaves are not merged back into the vector(elements) after running over the files.
If I print out the address of all the vector elements in the Terminate() function, I get 0 for each of them.

for (Int_t i=0; i<20; i++) {
    std::cout <<  vec_hist_rpt_hs.at(i) << std::endl;
}

So the segmentation fault comes from calling “->Write()” on a null pointer.

If I just use TH1F* objects, initialize them, add them to the output list, fill them in the slaves, and write them afterwards to a file, everything works fine. The problem arises when I store the TH1F* objects in a vector, and I don’t know how this has to be dealt with exactly in a TSelector.

Best,
Alex

I see. You are adding the histograms to an output list. If that involves a TFile, when it’s closed, it will destroy objects associated with it by calling RecursiveRemove(). You may have to change your code in any case to not associate the histograms with files so they are not destroyed by ROOT.

for (Int_t i=0; i&lt;20; i++) {
      TString histname = Form("histname_%d", i);
      vec_hist_rpt_hs.at(i) = new TH1F(histname, ";x;y", 100, 0., 10.);
      vec_hist_rpt_hs.at(i)->SetDirectory(nullptr);
}

Hi! thanks for your answers. Unfortunately calling SetDirectory(nullptr) does not help either.

You can look at the complete code here: https://gitlab.cern.ch/aleopold/HGTDPlottingScripts/tree/ttbar_analysis/tchain/selectors
The files of interest are JetSelector.h and JetSelector.C.
The vector that gives me the problems is called vec_hist_rpt_hs
In the Terminate() function, I can’t access the histograms that are written to the entries of the vector any more.
They are filled in the Process() method (line 249), so I guess there the histograms have to still be connected to the vector, otherwise this would give me an error there already…

Any idea is highly appreciated!

Best,
alex

At this point, I am not guessing what is wrong. Can you report what valgrind says when running your script (and/or executable).

valgrind --suppressions=$ROOTSYS/etc/valgrind-root.supp root.exe -b -l -q ......

I use valgrind with the command

process=true
valgrind --suppressions=$ROOTSYS/etc/valgrind-root.supp root.exe -l -b -q mainScript.C'("selectors/JetSelector.C+", "jet_tree", '"${process}"')'

which gives me the following output

==21147== Memcheck, a memory error detector
==21147== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==21147== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==21147== Command: root.exe -l -b -q mainScript.C("selectors/JetSelector.C+",\ "jet_tree",\ true)
==21147== 
location should be "...", or should start with "fun:" or "obj:"
==21147== FATAL: in suppressions file "/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase/x86_64/root/6.10.04-x86_64-slc6-gcc62-opt/etc/valgrind-root.supp" near line 25:
==21147==    location should be "...", or should start with "fun:" or "obj:"
==21147== exiting now.

Is there something wrong in how I call it? Tried it both on our local server and on lxplus, same output.

Dear aleopold,

I think the problem is related to the fact that only simple member types are automatically filled back with the merged results.
In Terminate the histograms should still be available in the fOutput list: can you check that? For example adding a fOutput->Print() in Terminate?
The solution would then be to fill vec_hist_rpt_hs by yourself form fOutput at the beginning of Terminate.
Note, howeevr, if the only thing you want is to safe the results to a file, you can pass the option
"of=mymergedoutput.root" . See Handling outputs in PROOF.

G Ganis

Dear G Ganis,

thank you very much for the hint, this solved my problem! After using the Print function on the fOutput list, I found that the histograms are indeed still in there. So I can put them back into the vector with

for (Int_t i=0; i<20; i++) {
    TString histname = Form("hist_rpt_hs_ntracks_%d", i);
    vec_hist_rpt_hs.at(i) = (TH1F*) GetOutputList()->FindObject(histname.Data());
  }

inside the Terminate method or use them directly from there.

Many thanks!
Alex

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