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 when you had to draw two histograms at once. 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).