Directories in ROOT

A question for you: What will happen if you execute the following code in C++?

TFile* file = new TFile("experiment.root");
TH1D* hist = new TH1D("example","example",100,-3,3);
hist->FillRandom("gaus",10000);
file->Close();
hist->Draw();
c1->Draw();

If you’re more accustomed to Python:

import ROOT
file = ROOT.TFile("experiment.root")
hist = ROOT.TH1D("example","example",100,-3,3)
hist.FillRandom("gaus",10000)
file.Close()
hist.Draw()

Did you guess that the code will crash? The C++ version will give a segmentation fault; the Python version will complain that hist is now an object of 'PyROOT_NoneType'. You may have even seen a crash like this before when working on Exercise 10. You’ve probably already guessed that the cause of the problem are “directories” (since that’s in the title of this section), but how?

A directory in ROOT (the TDirectory class) is a way of organizing ROOT’s objects. It’s like a directory or folder on disk, but ROOT’s directories typically hold only ROOT classes: trees, histograms, etc. They’re mostly used to organize the contents of ROOT disk files (see Exercise 12 for more) but you can define a directory in ROOT’s memory without writing it to disk, the same way you can have a histogram in ROOT’s memory without it being written to a file.

For the most part, you don’t have to think about directories during an active ROOT session, but the example code above illustrates an exception. Let’s see why it fails. To see the name of the directory you’re using in ROOT, execute the following in C++:

TDirectory::CurrentDirectory()->GetName()

In Python:

ROOT.TDirectory.CurrentDirectory().GetName()

Give it a try: Start an interactive ROOT session and copy-and-paste the above command to see the name of the current directory (it will probably be RInt or PyROOT). Then copy-and-paste the TFile command in the example code above, then look at the directory name again.

Note

It looks like when you open a file, ROOT automatically creates a TDirectory with that file’s name and makes that your default directory. This may remind you a bit of Exercise 3. There you had to be careful about which TCanvas you wrote to. Here it’s important to understand which TDirectory you’re creating objects in.

Look at the line in the example code that defines a new histogram. In which TDirectory will the histogram be created? I’m sure you got the correct answer: experiment.root.

Now execute the example code up to and including the line where we close the file. Once again, look at the directory name. We’re not in experiment.root anymore.

What happens if we try to draw hist now? We’ll get an error. The reason why is that when we closed the file, ROOT also removed the associated directory in its memory. When the TDirectory “experiment.root” was removed, everything in it was removed as well, including hist. The reason for the error when we try to draw the histogram is that hist refers to a region of memory that doesn’t exist anymore.

The fix for the above example code is simple: swap the TFile and TH1D lines. Then hist is defined in a TDirectory that isn’t going away.

Note

Again, for the most part you don’t have be concerned with the TDirectory class. However, it’s a good idea to keep to the practice: Don’t create objects when you have an open file, unless you’re going to write that object to that file.

Perhaps you’re asking yourself: hist was created while experiment.root was open. Does this mean the histogram was added to the disk file? No, for two reasons: we didn’t use a Write() method on anything, and the file was opened read-only (see Exercise 10).