ssh -X lapw.lancs.ac.uk
Once on lapw we can launch the installed version of root:
rootYou should see the ROOT splash screen, followed by the ROOT prompt:
******************************************* * * * W E L C O M E to R O O T * * * * Version 5.18/00d 29 May 2008 * * * * You are welcome to visit our Web site * * http://root.cern.ch * * * ******************************************* ROOT 5.18/00d (branches/v5-18-00-patches@24036, Jun 02 2008, 10:09:00 on linux) CINT/ROOT C/C++ Interpreter version 5.16.29, Jan 08, 2008 Type ? for help. Commands must be C++ statements. Enclose multiple statements between { }. root [0]Quit ROOT:
root [1] .q
Make your own local directory for the tutorial:
mkdir rootTut cd rootTut
Copy the tutorial files into this directory:
cp ~ajf/public_html/C++Course/rootTutorial/* .
int, long, float, double, char, bool ....
. int myInt; double myDouble=3.14; //Variable's value initialize to 3.14 char myChar='c'; bool myBool = true; |
//
clause is used for commenting the rest of the line.
int myFunction (int x, int y) { int sum = x + y; cout << "x + y = " << sum << endl; return sum; } |
{
and }
clauses define the block of code that belongs to the function.cout
is used to print out content of variables or strings. Indenting is useful for humans reading the code but not required. In contrast to Python it is the {}
and ;
which show where blocks of code start and end, and lines end, not how they are laid out. int z; z = myFunction( 1, 2 ); |
if ( ( x > 10 && y < 20 ) || z == 30 ) { // do something } else { // do something else } |
==
operator is the equal-to operator (not to be confused with =
which is the assignment operator). &&
and ||
operators are logical AND and logical OR operators.
for (int i=0; i<20; i++) { //do something } |
int myArray[10]; |
myArray[4]
(for the 5th element).
Sometimes it is not clear prior to running the program how many elements an array requires. For example, when running your analysis code, you will not know for certain how many muons are in your event until runtime. For this reason it is possible to dynamically set the size of arrays during runtime. This requires a different syntax than the one we've just discussed. We will cover this when we talk of dynamic variable allocation.
int myInt = 5; // Define a variable whose content is 5 int* p_myInt; // Define a pointer to an int variable p_myInt = &myInt; // Assign the memory address of myInt (&myInt) to p_myInt. cout<<myInt<<endl; // prints out 5 cout<<p_myInt<<endl; // prints out 0x80ec118 - the memory address of myInt cout<<*p_myInt<<endl; // prints out 5 - the content of the variable to which p_myInt points to |
&
operator is called the reference operator and gives the memory address to a variable.*
operator is called the dereference operator and gives the content of the variable to which a pointer points to.For more information see: Pointers
int myInt;
). When a program begins, or when a function is accessed, its variables are reserved a place in an area of memory (called the stack).
When the program or the function ends, the variables declared in it
lose scope and their allocated space on the stack is automatically
deallocated. This means that after the scope of the
program/function/code block in which the variable was declared, one
cannot access it any longer.int globVar = 5; int* p_locVar; if (globVar > 0) { //Inside the scope of the if block {} int locVar = globVar*2; p_locVar = &locVar; cout<<globVar<<endl; // Prints 5; cout<<locVar<<endl; // Prints 10; cout<<*p_locVar<<endl; // Prints 10; } // Leaving the scope of the if block, locVar memory is freed cout<<globVar<<endl; // Prints 5 cout<<locVar<<endl; // ERROR. locVar is not declared in this scope cout<<*p_locVar<<endl; // ERROR. The address p_locVar points to is no longer reserved (contains a random value) |
locVar
declared within the block has been automatically destroyed once exiting the block. Any pointers pointing to it (like p_locVar
) are now pointing to an area of memory which may contain anything (that area of memory it is no longer reserved to locVar
).
Dynamic allocation: Also known as heap
allocation. Automatic allocation works well for most variables, but
there are cases in which it is not enough. Such cases occur when data
is needed to be accessed outside the scope in which it was created ,
or memory needs to be reserved for variables on the fly during
run-time. For this reason, dynamic variable allocation was invented.
The memory-allocation for dynamic variables is done in a different area
of memory (called the heap) and is controlled
entirely by the user. Once declared the memory reserved for these
variables will not be deallocated until either the user deallocates it
directly or the program ends.
Example:
int globVar = 5; int* p_locVar; if (globVar < 0) { //Inside the scope of the if block {} int* locVar = new int (globVar*2); p_locVar = locVar; cout<<globVar<<endl; // Prints 5 cout<<*locVar<<endl; // Prints 10 cout<<*p_locVar<<endl; // Prints 10 } // Leaving the scope of the if block cout<<globVar<<endl; // Prints 5 cout<<*locVar<<endl; // ERROR. locVar pointer is not declared in this scope. A copy of the address it contained is in p_locVar cout<<*p_locVar<<endl; // Prints 10 delete p_locVar; // Freeing the memory reserved for locVar earlier |
locVar
is created dynamically and therefore the memory reserved for it will
not be released when leaving the block (like previous example).
However, locVar
itself will be destroyed once leaving the block, hence it is essential to save its address in some global pointer (p_locVar
) to be accessed outside the block.
A struct is a way to group several related variables into one place. Each variable in the structure is known as a member of the structure.
Unlike an array, a structure can contain many different data types (int, string, bool, etc.).
To create a structure, use the struct keyword and declare each of its members inside curly braces.
After the declaration, specify the name of the structure variable (myStructure in the example below): struct { // Structure declaration int myNum; // Member (int variable) string myString; // Member (string variable) } myStructure; // Structure variable Access Structure Members
To access members of a structure, use the dot syntax (.):
Example
Assign data to members of a structure and print it: // Create a structure variable called myStructure
struct { int myNum; string myString; } myStructure;
Assign values to members of myStructure
myStructure.myNum = 1; myStructure.myString = "Hello World!";
Print members of myStructure
cout << myStructure.myNum << "\n"; cout << myStructure.myString << "\n";
class MyClass { public: int m_x; void print() { cout<<"m_x="<<m_x<<endl;} }; |
MyClass classExample; // Declares an object of type MyClass classExample.m_x = 5; // Assigns a value to variable x inside classExample classExample.print(); // Calls the print function inside classExample |
Classes customarily have constructor functions. A constructor
function is a function that is called right at the creation of the
class object and is used to initialize the various member variables of
the class.
For example, in ROOT:
TH1 hist("h_eta", "Eta Distrubition", 100, -3., 3.); |
root[] .? //this command will list all the CINT commands root[] .L <filename> //load [filename] root[] .x <filename> //load and execute [filename] root[] .q // quits ROOT root[] .qqqqq // REALLY quits ROOT |
Shell commands start with ".!":
root[] .! ls |
root[] .! cat macroName.C |
cat
is the Unix command to dump the content of a file to stdout.
C++ commands follow C++ syntax:
root[] TBrowser *b = new TBrowser() |
Tab-completion also works in CINT:
root[] TLine *l = new TL<TAB> |
<TAB>
means pressing the TAB key)
myMacro.C
: void myMacro(int param1, int param 2) { ... // list of commands } |
myMacro.C
: { ... // list of commands } |
gROOT->Reset();
in the beginning of each unnamed macro.
Load and execute the rootTutorial/histGaus.C macro:
root[] .x histGaus.C |
root[] .! emacs histGaus.C & |
{ TH1F h1 ("h1", "histogram title", 100, -5.0 , 5.0); // Create a 1D histogram object of floats // Filling up histogram with random events: TRandom rGen (0); // Creates a random number generator object with seed 0 for (int i=0; i<10000; i++) { // Repeat 10000 times float x = rGen.Gaus(0.0, 1.0); // Generate a random number according to the gaus distribution with mean=0, sigma=1 h1.Fill(x); // Fill the histogram with x } h1.Draw(); // Draw the histogram onto the screen } |
TH1F
constructor take are:
Result:
The same thing can be done in a more concise way by doing: rootTutorial/histGaus2.C
{ TH1F h2 ("h2", "histogram title", 100, -5.0 , 5.0); // Create a 1D histogram object of floats h2.FillRandom("gaus",10000); // Calls the FillRandom function of the TH1F class which fills the histogram with 10000 gaus-distributed events h2.Draw(); // Draw the histogram } |
Creating 2- and 3D histograms is done similarly: rootTutorial/histGaus3.C
{ TH2F h3 ("h3", "histogram title", 100, -5.0 , 5.0, 200, 0.0, 1.0); // Create a 1D histogram object of floats TF2 func ("gaus2","xgaus(0)*ygaus(3)"); // Create a 2-param gaussian distribution function // Set the parameters of the function we created: func.SetParameters(1. , 0., 1., // Set the parameters of the first gaussian to N=1, mean=0, sigma=1 1. , 0.5, 0.1); // Set the parameters of the second gaussian to N=1, mean=0.5, sigma=0.1 h3.FillRandom("gaus2",1000000); // Calls the FillRandom function of the TH1F class which fills the histogram with 10000 gaus-distributed events gStyle->SetPalette(1); // Sets a better-looking color-palette than the default ROOT one h3.Draw("COLZ"); // Draw the histogram } |
This code creates a 2D (TH*2*F
) histogram with 100 x
bins in range (-5,5) and 200 y bins in range (0,1). It then declares a
2D function according to which the random variables are going to be
selected. Then it fills the histogram with random variables according
to the declared function and draws it.
Let's look in detail into each line:
TH2F h3 ("h3", "histogram title", 100, -5.0 , 5.0, 200, 0.0, 1.0);
: Declares a TH2F
object with name, title, xbinx, xrange, ybins, yrange
TF2 func ("gaus2","xgaus(0)*ygaus(3)");
: Declares a TF2
(2-variable function) object with the name "gaus2" and the equation "xgaus(0)*ygaus(3)" (equivalent to func.SetParameters(1. , 0., 1.,1. , 0.5, 0.1);
: Sets the parameter of this function. The function had 6 parameters, P0-2 belong to xgaus, P3-5 belong to ygaus
h3.FillRandom("gaus2",1000000);
: Fills the histogram with 1000000 events distributed according to a function called "gaus2" which we created earlier
h3.Draw("COLZ");
: Draws the histogram
Try right-clicking on the histogram in different places and playing with the different menu items. For example, try changing values in "SetLineAttributes" menu.
h.SetTitle("my new title");
h.SetXTitle("my X axis title");
h.GetXaxis()->SetTitle("my X axis title");
GetAxis()
calls the histogram's GetAxis function which returns the histogram's axis. Then SetTitle("")
calls the axis' SetTitle function which sets the title for the axis.
h.SetAxisRange(-1,1,"X");
c1.Modified(); c1.Update();
which tells the canvas c1
that its contents was modified, then updates it.
h.Scale(10);
For a complete set of changeable properties (and much more) see class TH1 in the ROOT reference guide.
{ gROOT->Reset(); // Resets the ROOT environment THStack hs("hs","test stacked histograms"); // Define the histogram stack object // Setting the histograms: TH1F *h1 = new TH1F("h1","test hstack",100,-4,4); // Dynamically create a new histogram h1->FillRandom("gaus",20000); // Fill histogram h1->SetFillColor(kRed); // Set histogram fill color to red h1->SetFillStyle(3001); hs.Add(h1); // Add histogram to the histogram stack object TH1F *h2 = new TH1F("h2","test hstack",100,-4,4); h2->FillRandom("expo",15000); h2->SetFillColor(kBlue); h2->SetFillStyle(3001); hs.Add(h2); TH1F *h3 = new TH1F("h3","test hstack",100,-4,4); h3->FillRandom("landau",10000); h3->SetFillColor(kGreen); h3->SetFillStyle(3001); hs.Add(h3); // Printing the histograms: TCanvas c1("c1","stacked hists", 10, 10, 1000, 500); // Create a canvas, setting the position to (10,10) and size to (1000,500) c1.Divide (3); // Divide the canvas in 3 c1.cd(1); // Go to the first pane of the canvas hs.Draw(); // Draw the histogram stack with the histograms stacked on top of each other c1.cd(2); // Go to the second pane of the canvas hs->Draw("NOSTACK"); // Draw the histogram stack without stacking c1.cd(3); // Go to the third pane of the canvas hs.Draw("PADS"); // Draw the histogram stack with the histograms stacked on top of each other } |
Draw()
function with draw parameters
For 2D histograms:
rootTutorial/histDraws2.C
For a complete list, see: Histogram's plotting options in THistPainterClass
For more examples of possible histogram styles, see: Histogram examples in THistPainter class (notice you can switch between picture and the source used to draw it)
TLegend
. A legend is merely a block which contains the graph/histogram style (fill color, line color, marker color) and a text label.
To create one, simply call the TLegend
constructor: TLegend legend(xMin, yMin, xMax, yMax);
with: xMin/yMin
being the position of the lower left corner of the legend block (in pad coordinates, i.e. between 0 and 1)
xMax/yMax
being the position of the higher top corner of the legend block (in pad coordinates, i.e. between 0 and 1)
To add an entry to a legend, we will use the AddEntry
method:
legend.AddEntry(object, "Entry name")
- which reads the style of the object to the legend entry whose name is in ""
For a detailed documentation of the TLegend class, see: TLegend class
We will revisit the stacked histogram example and add a legend to it: rootTutorial/legends.C
{ gROOT->Reset(); // Resets the ROOT environment THStack hs("hs","test stacked histograms"); // Define the histogram stack object // Setting the histograms: TH1F *h1 = new TH1F("h1","test hstack",100,-4,4); // Dynamically create a new histogram h1->FillRandom("gaus",20000); // Fill histogram h1->SetFillColor(kRed); // Set histogram fill color to red h1->SetFillStyle(3001); hs.Add(h1); // Add histogram to the histogram stack object TH1F *h2 = new TH1F("h2","test hstack",100,-4,4); h2->FillRandom("expo",15000); h2->SetFillColor(kBlue); h2->SetFillStyle(3001); hs.Add(h2); TH1F *h3 = new TH1F("h3","test hstack",100,-4,4); h3->FillRandom("landau",10000); h3->SetFillColor(kGreen); h3->SetFillStyle(3001); hs.Add(h3); /***************************************************/ // Make the legend: TLegend legend(0.6,0.7,0.99,0.99); // Dimensions of the legend block // Adds legend entries: legend.AddEntry(h1, "Gaussian"); legend.AddEntry(h2, "Exponential"); legend.AddEntry(h3, "Landau"); /***************************************************/ // Printing the histograms: TCanvas c1("c1","stacked hists", 10, 10, 1000, 500); // Create a canvas, setting the position to (10,10) and size to (1000,500) c1.Divide (3); // Divide the canvas in 2 c1.cd(1); // Go to the first pane of the canvas hs.Draw(); // Draw the histogram stack with the histograms stacked on top of each other legend.Draw(); // Draws the legend c1.cd(2); // Go to the second pane of the canvas hs->Draw("NOSTACK"); // Draw the histogram stack without stacking legend.Draw(); // Draws the legend c1.cd(3); // Go to the third pane of the canvas hs.Draw("PADS"); // Draw the histogram stack with the histograms stacked on top of each other legend.Draw(); // Draws the legend } |
Fit
method:
hist.Fit(function, "fitOptions", "drawOptions", lowRange, hiRange); |
hist.Fit("[0]*x+[1]*sin(x)", "", "", 0, 10);... doesn't work for me (Stephen Haywood; 23-Dec-08)
TF1 func("myFunction","[0]*x+[1]*sin(x)", 0, 10); // Define TF1 function object hist.Fit("myFunction","","",0,0); // Send function *name* to the Fit method. range [0,0] means fit the entire range hist.Fit(&func,"","",0,0); // Send *a pointer* to the func object to the fit method
"QML"
for a quiet, improved fit using logliklihood method
A fitted histogram would look like this:
rootTutorial/histFit.C
For a detailed documentation of the Fit
method, see: TH1:Fit
TFile
(see: TFile).tutorial.root
.
TFile myFile("filename.root", option);option tells ROOT how to open the file. If option =
"NEW"
or "CREATE"
create a new file and open it for writing, if the file already exists the file is not opened.
"RECREATE"
create a new file, if the file already exists it will be overwritten.
"UPDATE"
open an existing file for writing. if no file exists, it is created.
"READ"
open an existing file for reading (default).
""
(default), READ
is assumed.
So to open a file for reading do: TFile myFile("filename","READ");
Make sure that you close
the file before your program is finished. Large number of open files
that have not been closed might cause ROOT to crash and the file to be
corrupted.
To close a file, do: myFile.Close();
NOTE:
Once a file is closed, all objects that were read from it lose scope
and can no longer be accessed (so if you opened a file, read a
histogram from it and printer it to screen, once the file closes, the
histogram will disappear). If you wish to avoid that and read an object
to memory, you will need to clone it.
Try it with the tutorial.root
file.
myFile.ls(); |
For example, we will look at the tutorial.root file:
root [0] TFile myFile("tutorial.root","READ") root [1] myFile.ls() TFile** tutorial.root TFile* tutorial.root KEY: TTree Muon;1 Muon
You can see a TTree
object called "Muon" inside the file.
To get a certain object from a file you need to use the Get
method:
myFile.Get("objectName"); |
Try it with the tutorial.root
file.
Notice that ROOT returns a line similar to:
(class TObject*)0x216b6e0
This means that the command we issued (Get
) returns a pointer (*) to object TObject
. You may wonder why we get a TObject
back instead of a TTree
, which is the real type of the object in the file. To ensure ROOT works generically on all types of objects, the Get
method returns a pointer to a generic TObject
object (TObject
is the parent object from which all ROOT objects are derived from). TObject
objects have the most basic functionality shared between all ROOT objects. To make sure the returned object is a TTree
(and as such has all the functionality of TTree
s) one needs to statically cast the returned object to its real type type. This is done like this:
root [0] (TTree*) myFile.Get("Muon"); (class TTree*)0x216b6e0We see here that we get a TTree pointer back.
To assign this returned value to a variable so we can use it later, do:
TTree* muonTree = (TTree*) myFile.Get("Muon");This will allow us to use
muonTree
later on.
In newer versions of ROOT the static cast is done automatically to the
object it is assigned to. Still, it is good practice to do it
explicitly.
Write
method:
myObject.Write(); |
myObject.Write("objectNameInFile");
myFile.mkdir("subdirName");
myFile.cd("subdirName");
myFile.Get("subdirName/objectName");
myFile.GetDirectory("subdirName")->ls();
gROOT->Reset()
) and try to read the histogram back from the file and print it.
To call TBrowser, do:
TBrowser myTBrowser;This creates an object called
myTBrowser
and opens the TBrowser GUI window.
TTree
s are the main physics-analysis objects in ROOT. A TTree
is a container of measured quantities with simple interfaces to plot,
cut, filter, cross-correlate and write the data it contains. It can be
optimized to reduce disk-space or enhance access speed.TTree
is basically a long table containing a variety of different objects. Each column in this table is called a branch, while each line is an entry.
A branch can contain a single variable, an array, or a complex object.
For example, in the table above, muon_pt, muon_eta, muon_phi and
muon_ismuon are all arrays containing the values of the n
muons measured for each event (entry). The number of muons found in the event in specified by muon_nParticle
.
TTrees are meant to be write-once read-many sort of objects. After a
tree is written and closed, it is not recommended (though possible) to
add branches/entries to it. The recommended way add more data is to
create a new tree in a new file and "chain" the two files together
using TChain.
However, this will not be covered in this tutorial. You can find more
information in the "Chains" subsection of the Trees chapter in the ROOT Users Guide.
TTrees are incredibly versatile and many things that can be accomplished with trees will not be covered in this tutorial. It is highly recommended to read the TTree section in the ROOT Users Guide. For more information, see the TTree class
TBrowser
,
TreeViewer is a GUI for tree handling. It is a quick and easy way to
examine a tree and also learn how to plot tree branches in
command-line. tree.StartViewer();
. For example, for our tutorial.root
file:
{ TFile myFile("tutorial.root","READ"); TTree *myTree = (TTree*) myFile.Get("Muon"); myTree->StartViewer(); myFile.Close(); // AFTER you have examined file with TreeViewer } |
X:
and Y:
in TreeViewer) and click the Draw button (button in TreeViewer with a small graph - bottom left).
E()
icons and click EditExpression, then specify the formula.
Notice that the Rec checkbox on the top right of the
window is ticked. This means that whatever you do in the TreeView is
recorded and can be reviewed later in the command-line. This is a great
learning tool as it lets you see different ways to use tree->Draw()
.
After you you succeed to do a complex plot using the GUI, you can look
it up in the command-line and copy it to your macro, instead of
repeating the same process in the GUI every time you want to plot it.
Take some time to go through the different menus/options for the TreeView window.
Print
and Scan
.
myTree->Print();
****************************************************************************** *Tree :Muon : Muon * *Entries : 2750 : Total = 616365 bytes File Size = 233741 * * : : Tree compression factor = 1.94 * ****************************************************************************** *Br 0 :muon_nParticle : muon_nParticle/I * *Entries : 2750 : Total Size= 11688 bytes One basket in memory * *Baskets : 0 : Basket Size= 32000 bytes Compression= 1.00 * *............................................................................* *Br 1 :muon_nSel : muon_nSel/I * *Entries : 2750 : Total Size= 11658 bytes One basket in memory * *Baskets : 0 : Basket Size= 32000 bytes Compression= 1.00 * *............................................................................* *Br 2 :muon_pt : * *Entries : 2750 : Total Size= 103382 bytes File Size = 34244 * *Baskets : 2 : Basket Size= 32000 bytes Compression= 1.63 * *............................................................................*In red you see the name of the tree, followed by the number of entries for this tree. After the tree data, specific branch information is given, starting with the name of the branch, then the type of variable the branch holds (
I
means integer. For a complete list of branch variable types, see "Case A" in ROOT TTree reference).
myTree->Scan();
. If you are only interested in specific branches, give them in a colon-separated list: myTree->Scan("muon_nPar:muon_nSel:muon_pt");The output of
myTree->Scan()
looks like this: *********************************************************************************************************************** * Row * Instance * muon_nPar * muon_nSel * muon_pt * muon_eta * muon_phi * muon_chi2 * muon_etis * muon_ismu * *********************************************************************************************************************** * 0 * 0 * 2 * 2 * 7899.7685 * 0.1218577 * 2.7316445 * 0 * 6291.3779 * 1 * * 0 * 1 * 2 * 2 * 6769.6751 * -0.171118 * 3.0469719 * 0.3129153 * 6490.0097 * 1 * * 1 * 0 * 2 * 2 * 20658.150 * -0.902265 * 0.3631487 * 1.5234277 * 8323.7158 * 1 * * 1 * 1 * 2 * 2 * 6840.4902 * -1.159864 * 0.3936874 * 0.4210140 * 7002.5869 * 1 *Note that the same row (entry) repeats several times. This is due to the array of values in muon_pt, muon_eta, etc'.
Draw
method:
myTree->Draw("branchName(s)", "selection", "draw options", number_of_entries, first_entry); |
"branchName(s)"
is the branch name you want to draw. To draw a correlation plot of one branch against the other, do: "first_branch:second_branch"
.
"selection"
is the cuts you want to apply to your plot. For example: "param_1 == 1 && param_2 < 0.5"
.
"draw options"
is the conventional histogram drawing options (specified here).
number_of_entries
is the number of entries you would like to plot. The default is all, so this is rarely used.
first entry
is the first entry you want to start drawing from. The default is 0, so this is rarely used.
Look at these examples: rootTutorial/treeDraw.C
{ gROOT->Reset(); gStyle->SetPalette(1); // Set the "COLZ" palette to a nice one TFile myFile("tutorial.root"); // Open the file TTree* myTree = (TTree*) myFile.Get("Muon"); // Get the Muon tree from the file // Draw examples: TCanvas c1; // Open a new canvas myTree->Draw("muon_pt"); // Simple draw of the muon_pt parameter TCanvas c2; // Open a new canvas myTree->Draw("muon_pt", "muon_nSel==2"); // Apply a cut to the draw TCanvas c3; // Open a new canvas myTree->Draw("muon_pt", "muon_nSel==2", "C"); // Apply draw options (smooth curve) TCanvas c4; // Open a new canvas // Plot eta vs. phi correlation: // "PSR" - plot using Pseudorapidity/Phi coordinates (X axis is phi) // "COLZ" - A box is drawn for each cell with a color scale varying with contents myTree->Draw("muon_eta:muon_phi", "muon_nParticle>0 && muon_chi2<1", "PSR COLZ"); TCanvas c5; // Open a new canvas // Plot pT of first[0] versus the pT of second[1] muon divided by the combined pt // "BOX" - A box diagram myTree->Draw("muon_pt[0]/(muon_pt[0]+muon_pt[1]):muon_pt[1]/(muon_pt[0]+muon_pt[1])", "muon_nParticle==2", "BOX"); TCanvas c6; // Open a new canvas c6.SetGrid(); // Plot a grid on this canvas // Dump the contents of the draw into a histogram for future manipulation: // "goff" - Do not plot to the screen, just dump to histogram myTree->Draw("muon_pt/1000>>h_pt", "muon_pt<60000", "goff"); // Manipulate the histogram: h_pt->SetFillColor(kGreen); // Set fill color h_pt->SetTitle("P_{T} distribution"); // Set histogram title h_pt->SetXTitle("P_{T} [GeV]"); // Set the X title gStyle->SetOptFit(1); // Draw the fit parameters on the histogram h_pt->Fit("landau"); // Fit to a landau distribution h_pt->Draw(); // Draw the histogram myFile.Close(); // Close file } |
For more information of tree drawing methods, see the "TTree::Draw Examples" in the TTree section of the ROOT Users Guide.
TTree::Draw()
is good for most of the simple cases you'll
encounter, but sometime you will find you need to run on the actual
tree data for your analysis.
We will look at a simple example of how to read TTree
s directly, even though this example can easily be implemented using Draw
as well.
{ gROOT->Reset(); TFile myFile("tutorial.root"); // Open the file TTree* myTree = (TTree*) myFile.Get("Muon"); // Get the Muon tree from the file // Preparing the containers to be filled with data from the tree: int muon_nParticle; // Number of muons in an entry vector<double>* muon_pt; // An array of the pT values for each of the muons vector<double>* muon_eta; // An array of the eta vlues for each of the muons vector<double>* muon_phi; // An array of the phi vlues for each of the muons // Linking the local variables to the tree branches myTree->SetBranchAddress("muon_nParticle", &muon_nParticle); myTree->SetBranchAddress("muon_pt", &muon_pt); myTree->SetBranchAddress("muon_eta", &muon_eta); myTree->SetBranchAddress("muon_phi", &muon_phi); // After this stage the local variables are still empty. // With every subsequent call to myTree->GetEntry(i) the local variables // will be filled with the content of branches // Create a histogram with 100 bins between 0-100000 to be filled later: gROOT->cd(0); // This tells ROOT to create next object in memory and not in file TH1D h("h_muon_pt", "Muon P_{T} histogram",20, 0, 20000); gStyle->SetOptStat(111111); // Tells ROOT to list histogram overflow/underflow // Loop over all entries in the tree // for each entry, print the pt values and fill them to a histogram int nEntries = myTree->GetEntries(); // Get the number of entries in this tree for (int iEnt = 0; iEnt < nEntries; iEnt++) { myTree->GetEntry(iEnt); // Gets the next entry (filling the linked variables) cout<<"Entry #"<< iEnt << endl; for (int iPar = 0; iPar < muon_nParticle; iPar++) { cout<<" muon_pt["<< iPar <<"] = "<< muon_pt->at(iPar) << endl; h.Fill(muon_pt->at(iPar)); } } h.Draw(); // Draw histogram myFile.Close(); // Close file } |
{ gROOT->Reset(); // Open the file for writing TFile f("treeFile.root","RECREATE"); // Define the tree TTree* myTree = new TTree("bonsai", "tree title"); // Define auxilary variaqbles: Double_t x; Double_t y; Double_t z; // Create tree branches: // this will link the addresses of x, y, z variables to the content of the branch // so that every file myTree->Fill() is called, the content of x,y,z is filled // into a new entry in the tree. myTree->Branch("a", &x, "a/D"); // Create a branch called a, linked to local variable x, of type D (double) myTree->Branch("b", &y, "b/D"); myTree->Branch("c", &z, "c/D"); Int_t n=100000; // Number of entries to fill TRandom rGen(0); // Create the random number generator // Loop over n entries and fill the tree: for (Int_t i=0; i < n; i++) { x = rGen.Gaus(0.0, 1.0); // Generate a gaussian-distributed random number y = x * 5. + 1.; z = x + rGen.Gaus(0.0, 0.1); // Fills tree: myTree->Fill(); } cout<<"Entries in tree: "<<myTree->GetEntries()<<endl; // Write tree to file: myTree->Write("", TObject::kOverwrite); // Close file: f.Close(); } |
The rule of thumb for writing verbose DAQ code is to write down every
quantity that you produce to a tree. This way, when something goes
wrong with the DAQ, it is very easy to understand where the problem
occurred just by looking at the produced trees. Also, when you are
later required to extend the DAQ analysis (to produce more plots, for
instance), you can be sure that all the quantities are already written
down and there's no need to rewrite the DAQ code. It's just a matter of
plotting them.
MakeClass
function was introduced to TTree
. MakeClass
creates a skeleton analysis code for the tree.myTree.MakeClass("filename", "options");
MakeClass
takes two parameters: Loop
which loops over all tree entries and does nothing. Whatever
functionality you wish to implement in the tree reading phase should go
into the Loop
function.
Open the tutorial.root file, get the Muon
tree, and run its MakeClass? function.
Let's look at the results:
////////////////////////////////////////////////////////// // This class has been automatically generated on // Mon Oct 20 08:44:13 2008 by ROOT version 5.18/00 // from TTree Muon/Muon // found on file: tutorial.root ////////////////////////////////////////////////////////// #ifndef myMuon_h #define myMuon_h #include <TROOT.h> #include <TChain.h> #include <TFile.h> class myMuon { public : TTree *fChain; //!pointer to the analyzed TTree or TChain Int_t fCurrent; //!current Tree number in a TChain // Declaration of leaf types Int_t muon_nParticle; Int_t muon_nSel; vector<double> *muon_pt; vector<double> *muon_eta; vector<double> *muon_phi; vector<double> *muon_chi2; vector<double> *muon_etisol; vector<long> *muon_ismuon; // List of branches TBranch *b_muon_nParticle; //! TBranch *b_muon_nSel; //! TBranch *b_muon_pt; //! TBranch *b_muon_eta; //! TBranch *b_muon_phi; //! TBranch *b_muon_chi2; //! TBranch *b_muon_etisol; //! TBranch *b_muon_ismuon; //! myMuon(TTree *tree=0); virtual ~myMuon(); virtual Int_t Cut(Long64_t entry); virtual Int_t GetEntry(Long64_t entry); virtual Long64_t LoadTree(Long64_t entry); virtual void Init(TTree *tree); virtual void Loop(); // The Loop method running over all entries virtual Bool_t Notify(); virtual void Show(Long64_t entry = -1); }; #endif #ifdef myMuon_cxx myMuon::myMuon(TTree *tree) { // if parameter tree is not specified (or zero), connect the file // used to generate this class and read the Tree. if (tree == 0) { TFile *f = (TFile*)gROOT->GetListOfFiles()->FindObject("tutorial.root"); if (!f) { f = new TFile("tutorial.root"); } tree = (TTree*)gDirectory->Get("Muon"); } Init(tree); } myMuon::~myMuon() { if (!fChain) return; delete fChain->GetCurrentFile(); } Int_t myMuon::GetEntry(Long64_t entry) { // Read contents of entry. if (!fChain) return 0; return fChain->GetEntry(entry); } Long64_t myMuon::LoadTree(Long64_t entry) { // Set the environment to read one entry if (!fChain) return -5; Long64_t centry = fChain->LoadTree(entry); if (centry < 0) return centry; if (!fChain->InheritsFrom(TChain::Class())) return centry; TChain *chain = (TChain*)fChain; if (chain->GetTreeNumber() != fCurrent) { fCurrent = chain->GetTreeNumber(); Notify(); } return centry; } void myMuon::Init(TTree *tree) { // The Init() function is called when the selector needs to initialize // a new tree or chain. Typically here the branch addresses and branch // pointers of the tree will be set. // It is normally not necessary to make changes to the generated // code, but the routine can be extended by the user if needed. // Init() will be called many times when running on PROOF // (once per file to be processed). // Set object pointer muon_pt = 0; muon_eta = 0; muon_phi = 0; muon_chi2 = 0; muon_etisol = 0; muon_ismuon = 0; // Set branch addresses and branch pointers if (!tree) return; fChain = tree; fCurrent = -1; fChain->SetMakeClass(1); fChain->SetBranchAddress("muon_nParticle", &muon_nParticle, &b_muon_nParticle); fChain->SetBranchAddress("muon_nSel", &muon_nSel, &b_muon_nSel); fChain->SetBranchAddress("muon_pt", &muon_pt, &b_muon_pt); fChain->SetBranchAddress("muon_eta", &muon_eta, &b_muon_eta); fChain->SetBranchAddress("muon_phi", &muon_phi, &b_muon_phi); fChain->SetBranchAddress("muon_chi2", &muon_chi2, &b_muon_chi2); fChain->SetBranchAddress("muon_etisol", &muon_etisol, &b_muon_etisol); fChain->SetBranchAddress("muon_ismuon", &muon_ismuon, &b_muon_ismuon); Notify(); } Bool_t myMuon::Notify() { // The Notify() function is called when a new file is opened. This // can be either for a new TTree in a TChain or when when a new TTree // is started when using PROOF. It is normally not necessary to make changes // to the generated code, but the routine can be extended by the // user if needed. The return value is currently not used. return kTRUE; } void myMuon::Show(Long64_t entry) { // Print contents of entry. // If entry is not specified, print current entry if (!fChain) return; fChain->Show(entry); } Int_t myMuon::Cut(Long64_t entry) { // This function may be called from Loop. // returns 1 if entry is accepted. // returns -1 otherwise. return 1; } #endif // #ifdef myMuon_cxx |
#define myMuon_cxx #include "myMuon.h" #include <TH2.h> #include <TStyle.h> #include <TCanvas.h> void myMuon::Loop() { // In a ROOT session, you can do: // Root > .L myMuon.C // Root > myMuon t // Root > t.GetEntry(12); // Fill t data members with entry number 12 // Root > t.Show(); // Show values of entry 12 // Root > t.Show(16); // Read and show values of entry 16 // Root > t.Loop(); // Loop on all entries // // This is the loop skeleton where: // jentry is the global entry number in the chain // ientry is the entry number in the current Tree // Note that the argument to GetEntry must be: // jentry for TChain::GetEntry // ientry for TTree::GetEntry and TBranch::GetEntry // // To read only selected branches, Insert statements like: // METHOD1: // fChain->SetBranchStatus("*",0); // disable all branches // fChain->SetBranchStatus("branchname",1); // activate branchname // METHOD2: replace line // fChain->GetEntry(jentry); //read all branches //by b_branchname->GetEntry(ientry); //read only this branch if (fChain == 0) return; Long64_t nentries = fChain->GetEntriesFast(); Long64_t nbytes = 0, nb = 0; for (Long64_t jentry=0; jentry<nentries;jentry++) { Long64_t ientry = LoadTree(jentry); if (ientry < 0) break; nb = fChain->GetEntry(jentry); nbytes += nb; // if (Cut(ientry) < 0) continue; // HERE GOES YOUR CODE } } |
For more information see: MakeClass function in ROOT reference guide
treeFile.root
file and plot its variables. Look at correlation plots and use various cuts. Fit the distribution of each of the variables.
Responsible: NirAmram
Last reviewed by: Examples worked through by StephenHaywood - 24 Dec 2008
I | Attachment | Action | Size | Date | Who | Comment |
---|---|---|---|---|---|---|
![]() | TBrowser.png | manage | 94.5 K | 23 Sep 2008 - 15:25 | NirAmram | |
![]() | TreeTable.png | manage | 23.7 K | 23 Sep 2008 - 18:11 | NirAmram | |
![]() | TreeViewer.png | manage | 23.1 K | 24 Sep 2008 - 08:57 | NirAmram | |
![]() | histDraws.png | manage | 24.5 K | 22 Sep 2008 - 08:34 | NirAmram | |
![]() | histDraws2.png | manage | 64.9 K | 22 Sep 2008 - 08:35 | NirAmram | |
![]() | histFit.png | manage | 16.5 K | 22 Sep 2008 - 08:35 | NirAmram | |
![]() | histGaus.png | manage | 10.2 K | 22 Sep 2008 - 08:32 | NirAmram |