Campuses:
This is an old revision of the document!
The ROOT team says that the main features of ROOT are:
This is completely unhelpful and totally misleading. Only somewhat more to the point, they describe the mission of ROOT thusly:
The ROOT system provides a set of OO frameworks with all the functionality needed to handle and analyse large amounts of data in a very efficient way. Having the data defined as a set of objects, specialised storage methods are used to get direct access to the separate attributes of the selected objects, without having to touch the bulk of the data. Included are histograming methods in 1, 2 and 3 dimensions, curve fitting, function evaluation, minimisation, graphics and visualization classes to allow the easy setup of an analysis system that can query and process the data interactively or in batch mode.
This description is still singularly unhelpful for the novice trying to make sense of how to accomplish his or her first task. A more useful description would be to say that, depending on the user, ROOT is:
The ROOT team goes on to say:
It also provides a good environment to learn C++.
In fact, ROOT is a terrible environment to learn C++. ROOT was designed before the Standard Template Libraries, which provide the bulk of the familiar C++ functionality, were implemented. It therefore has separate, totally incompatible implementations of things like vectors and strings. Code written using ROOT does not translate easily to the 99.999% of C++ world that does not use ROOT.
ROOT also makes heavy use of “interpreted C++” (using Cint, the C++ Interpreter), a concept which essentially does not exist outside of ROOT. It encourages sloppiness with pointers and other woes.
ROOT is written without the use of namespaces, a C++ concept that helps organize code. This is why all ROOT classes start with “T”, as in TTree, TFile, etc. The correct (or perhaps “modern”) way to do this would be to make a ROOT namespace so that the objects are called ROOT::Tree and ROOT::File. Or with “using namespace ROOT;” at the top of your code, they would be simply Tree and File.
The ROOT code shows evidence of having been developed without a good understanding of object-oriented ideas. The most commonly cited example is the wonky use of inheritance. The notion of one class inheriting from another is supposed to mean that the inheriting object has the relationship “is a kind of” with its parent. For instance, an object that represents squares should inherit from one that represents quadrilaterals, which should inherit from one that represents polygons. However, the root class TH2, a 2-dimensional histogram, inherits from a TH1, a 1-dimensional histogram. Most people would agree that a 1-dimensional histogram is a kind of 2-dimensional histogram; it's one where the second dimension is 1 bin wide. The ROOT inheritance is exactly backwards here.
ROOT's internal objects often do not correspond well to the user's idea of what an object should be. For instance, suppose there's a window on the screen that contains several histograms. In ROOT-speak, the window is called a “canvas” or a “pad” (all fine and good). Since, in the user's mind, the canvas has several attributes (size, background color), the histogram has several more (number of bins, bin contents) and the axis yet more (range, number of tick marks), it's clear that to modify the behaviour of the axis, one would do something to the axis object. Yet in fact, to switch an axis between logarithmic and linear, the user must call a function on the canvas.
The Standard Template Library, which defines the usual versions of strings, vectors, lists, maps, and so on, is documented at sgi.com and in many books and other webpages. Always use these instead of the incompatible versions that ROOT provides (i.e. TString, TVector) unless you are forced not to by pre-existing code.
If you follow this, your code will be easier to port to a different system if you decide to move away from ROOT. You will also be able to communicate better with people outside of the ROOT world and you will have better programming skills for when you are outside of the ROOT world.
ROOT's documentation encourages use of objects when writing procedural code would be easier and more clear. For instance, they push you to load your data into an object which has functions defined on it that print and loop over the data (abbreviated from this Fermilab page):
class MyClass { public : TTree *fTree; //pointer to the analyzed TTree //Declaration of leaves types Event *event; //List of branches TBranch *b_event; MyClass(TTree *tree=0); ~MyClass() {;} Int_t GetEntry(Int_t entry); void Init(TTree *tree); void Loop(); void Show(Int_t entry = -1); };
This is insanity. Instead, simply prepare your TTree object (probably loaded from a file) and write ordinary functions that operate on it:
void Loop(TTree * awesomedata) { for(int i = 0; i < awesomedata->GetEntries(); i++){ awesomedata->GetEntry(i); // brilliant analysis code goes here } } void analysis() { TFile * datafile = new TFile("newdata.root"); TTree * awesomedata = (TTree *)datafile->Get("fish"); Loop(awesomedata); }
Root encourages or uses the following names:
These names are extremely problematic. “MyClass” is bad because it is totally undescriptive. Use a name that actually represents what data your class holds. (It also may give the impression that the names of classes have to start with “My”. This is not the case.) The other, very short, names are bad both because they are undescriptive and because it is nearly impossible to search for them in files.
C++ has, in practical terms, no limit on the length of variable or function names. While it's not good to use extremely long names either, it's perfectly fine to name your histogram “december_data_hist”. If you totally can't think of a good name for the new variable you just made, run:
/local/minos/bin/variablename
It outputs two short nouns stuck together. It probably won't be very descriptive, but at least it will be searchable.
There are three generic options for running ROOT-based code:
The first two options are widely used and well documented (?) elsewhere. Briefly, if one has the program “domyanalysis.C”, it must contain the function domyanalysis(). It is run interpreted with
root 'domyanalysis.C("datafile1.root", 47)'
where the single quotes protect the parentheses and double quotes from the shell, which otherwise assigns special meaning to them. To run compiled:
root 'domyanalysis.C+("datafile1.root", 47)'
or
root 'domyanalysis.C++("datafile1.root", 47)'
where the second form forces recompilation (sometimes necessary if you move to a new machine, for instance).
The third is rarely used, but probably should be used more. In this case, you write an ordinary C++ program with the function main() that uses some ROOT objects, i.e.:
using namespace std; #include "TRandom3.h" #include <iostream> #include <string> int main(int argc, char ** argv) { int seed = 0; string filename; if(argc >= 2) seed = atoi(argv[1]); TRandom3 atomlitre(seed); cout << "Your random number is " << atomlitre.Rndm() << endl; if(argc >= 3){ filename = argv[2]; cout << "Your file name is " << filename << endl; } return 0; }
and compile it with:
g++ -o printrandomnumber printrandomnumber.C `root-config --cflags --libs`
and run it with:
printrandomnumber 17 datafile.root
This has two big advantages. First, you do not need to type all of those quotation marks and parentheses. Second, your compiled program can run on machines that don't have ROOT installed. Third, your code is less likely to stop working when the ROOT version changes. Fourth, it probably runs faster because it doesn't have all the overhead of running root itself. Fifth, your code looks much more like the ordinary C++ that most programmers are familiar with. Ok, more than two.
The default ROOT plot is quite nice for screen display. However, when you print it or use it in a talk, you will discover that the background is grey, which is ugly and wastes toner. The lines used for histograms and axes are often too thin for easy reading when shown in a talk or paper. Canvases have beveled edges and legends have drop shadows; whiz-bang, but not really suitable for many environments.
These things can all be modified either by fiddling with the individual objects or by setting things in the active TStyle. This code sets things up in a sensible way, although you probably want to pick and choose to suit your own tastes:
void SetOKStyle() { TStyle* OKStyle = new TStyle("OKStyle", "OK Default Style"); // Colors //set the background color to white OKStyle->SetFillColor(10); OKStyle->SetFrameFillColor(10); OKStyle->SetFrameFillStyle(0); OKStyle->SetFillStyle(0); OKStyle->SetCanvasColor(10); OKStyle->SetPadColor(10); OKStyle->SetTitleFillColor(0); OKStyle->SetStatColor(10); // Get rid of drop shadow on legends // This doesn't seem to work. Call SetBorderSize(1) directly on your TLegends OKStyle->SetLegendBorderSize(1); //don't put a colored frame around the plots OKStyle->SetFrameBorderMode(0); OKStyle->SetCanvasBorderMode(0); OKStyle->SetPadBorderMode(0); //use the primary color palette OKStyle->SetPalette(1,0); //set the default line color for a histogram to be black OKStyle->SetHistLineColor(kBlack); //set the default line color for a fit function to be red OKStyle->SetFuncColor(kRed); //make the axis labels black OKStyle->SetLabelColor(kBlack,"xyz"); //set the default title color to be black OKStyle->SetTitleColor(kBlack); //set the margins OKStyle->SetPadBottomMargin(0.15); OKStyle->SetPadLeftMargin(0.15); OKStyle->SetPadTopMargin(0.075); OKStyle->SetPadRightMargin(0.15); //set axis label and title text sizes OKStyle->SetLabelSize(0.05,"xyz"); OKStyle->SetTitleSize(0.07,"xyz"); OKStyle->SetTitleOffset(0.9,"xyz"); OKStyle->SetStatFontSize(0.05); OKStyle->SetTextSize(0.07); OKStyle->SetTitleBorderSize(0); //set line widths OKStyle->SetHistLineWidth(2); OKStyle->SetFrameLineWidth(2); OKStyle->SetFuncWidth(2); // Misc //align the titles to be centered //OKStyle->SetTextAlign(22); //turn off xy grids OKStyle->SetPadGridX(0); OKStyle->SetPadGridY(0); //set the tick mark style OKStyle->SetPadTickX(1); OKStyle->SetPadTickY(1); //don't show the fit parameters in a box OKStyle->SetOptFit(0000); //set the default stats shown OKStyle->SetOptStat("neimr"); //marker settings OKStyle->SetMarkerStyle(8); OKStyle->SetMarkerSize(0.7); // Fonts OKStyle->SetStatFont(12); OKStyle->SetLabelFont(12,"xyz"); OKStyle->SetTitleFont(12,"xyz"); OKStyle->SetTextFont(12); // Set the paper size for output OKStyle->SetPaperSize(TStyle::kUSLetter); //done OKStyle->cd(); cout << "Using OKStyle" << endl; }