Equivalence of TH1::SetDirectory(0) and TH1::AddDirectory(0)

Hi,

I am not sure if this is a documentation problem or if I am doing something stupid, I will assume the latter for now.

On both pages 24 and 101 of the User Guide, my reading of the text leads me to believe that the functions TH1::SetDirectory(0) (when used on a particular histogram) and TH1::AddDirectory(kFALSE) (used as a global switch) do essentially the same thing. I appear to have found a case where they don’t.

I have a class, DiObjectSpectrum, that inherits from TSelector. Within its Begin() function, I open a file as follows:

After checking if it’s a Zombie, I then call a function (ClusterEff is a std::map<TString,TH1F*>, or inputtype in the code below)

This then calls yet more functions:

void DiObjectSpectrum::InputMap(TFile& input, inputtype& inputmap, TString type, TString offline) { FillMapFromFile(input, inputmap, "LJets"+type+offline+"_Efficiency", "OL"+type+"LJets"); //... more of the same }

and finally the function FillMapFromFile retrieves the histograms:

void DiObjectSpectrum::FillMapFromFile(TFile& inputfile, inputtype& inputmap, TString histname, TString maptag) { TH1F* hist = NULL; inputfile.GetObject(histname.Data(),hist); if (hist) { hist->SetDirectory(0); inputmap.insert(make_pair(maptag,hist)); } else cout << "Didn't find histogram named " << histname << endl; }

To my mind, from reading the Users Guide, calling hist->SetDirectory(0) should “detach” it from the file, meaning the function-call-from-a-function-call-from-a-function-call is not a problem. But it is, and this code seg faults.

The solution I found is to call TH1::AddDirectory(kFALSE); before any of the code I’ve pasted. Seems to work. In which case, AddDirectory and SetDirectory seem to do different things in this case. Who is right, me or the documentation?

Cheers,
Mike

If you get a segfault when calling hist->SetDirectory(0), it is likely that your pointer hist is invalid.
You say that in the selector Begin function you open the file with

TFile f(... instead of

TFile *f = TFile::Open(.. Are you sure that the TFile object is still in the scope when your function calling hist->SetDirectory is called?

Rene

Hi,

I’m sorry, I didn’t explain that part very clearly. It doesn’t seg fault at the line hist->SetDirectory(0) (notice I do check that hist isn’t NULL). Also, I pass the TFile& to each function in turn, so it cannot go out of scope.

The problem is when I try to access the TH1F*s inside the map in the Process() function, once the TFile is out of scope (and I would like it to be - I feel uncomfortable having an unnecessary TFile hanging around, especially as it’s quite a large one).

The point is that I want to detach the TH1F*s from the TFile. Using hist->SetDirectory(0) as given does not work, using TH1::AddDirectory(kFALSE) does, when I thought these functions were supposed to be equivalent, except for the fact that one is local and the other is global.

Cheers,
Mike

hist->SetDirectory(0) detaches hist from the directory/file where it had been attached.
When you say that you get a problem when accessing the TH1F* object from your map, is it when calling a function from the TH1 object or when accessing this object from the map?

Rene

Actually, it appears in an even stranger place.

There is one more layer of functions that I didn’t think was relevant. all the code I pasted is called in a function BookHistos() which is called from Begin(). I’ll summarise as this is getting too complicated:

DiObjectSpectrum::Begin()
calls
DiObjectSpectrum::BookHistos()
which calls (several times)
DiObjectSpectrum::InputMap(…)
which calls (several times)
DiObjectSpectrum::FillMapFromFile(…)
which does the filling and SetDirectory(0)

The seg fault occurs AS BookHistos() ends. By this, I mean that every command in BookHistos() is executed, but the next command in Begin() is not.

If this is relevant, BookHistos(), as well as retrieving TH1Fs from a TFile, also produces a std::map<TString,TH1F> of empty histograms for the results of the algorithm. That’s TH1F, not TH1F, it’s not a typo. These are accessed fine from within BookHistos() - I call TH1::Sumw2() on each element of the map.

I don’t know if this helps much. Next, I will try accessing the TH1F*s from within BookHistos().

Cheers,
Mike

It is not obvious to follow your description of the problem without a concrete piece of code that we can use for tests.
Could you simplify the problem by taking out from your big framework only
the strict minimum necessary to understand the problem.
As you know, the time to solve a problem is ALWAYS inversely proportional to the number of lines of code ::slight_smile:

Rene

True, I’ve tried to simplify things as much as I can for now. I’ll see what I can do over the weekend. Physics results call! :slight_smile:

Cheers,
Mike