ROOT tutorial I¶
TF1, TGraph, TRandom3, TH1, TH2, TFile
ROOT provides the basic tools needed for data visualization, data storage, and numerical analysis in experimental physics. In this lecture, the goal is not advanced data analysis yet. The goal is to learn how to use a few important ROOT classes in a clear and practical way: how to define functions, display measured points, generate random numbers, build histograms, make two-dimensional plots, and save results into a ROOT file. ROOT’s class references define TF1 as a 1D function class, TGraph as an object made of two arrays X and Y, TH1 as the base class of histogram classes, TRandom3 as a random-number generator, and TFile as a file that stores serialized ROOT objects. (ROOT)
0. ROOT in interactive mode¶
ROOT can be used interactively. The notebook-style workflow uses %jsroot on and a TCanvas for display.
%jsroot on
TCanvas *c1 = new TCanvas("c1","c1",800,600);
ROOT also allows direct use of C++ statements:
double x = 2.0;
cout << TMath::Sqrt(x) << endl;
cout << TMath::Pi() << endl;
1.41421 3.14159
A useful reminder:
- use
.for an object - use
->for a pointer to an object
TF1 f1("f1","x*x",0,10);
TF1 *f2 = new TF1("f2","x*x",0,10);
1. TF1: one-dimensional functions¶
TF1 represents a one-dimensional function. In practice, such functions are often used for calibration curves, fit models, and peak-shape descriptions. (ROOT)
1.1 A linear calibration function¶
Suppose the detector energy calibration is approximately linear:
$$
E = a + b \times \text{channel}
$$
This can be written as a TF1:
TF1 *fcal = new TF1("fcal","[0] + [1]*x",0,4000);
fcal->SetParameters(0.2, 0.5);
fcal->SetTitle("Linear calibration;Channel;Energy (keV)");
fcal->Draw();
c1->Draw();
Evaluate the function at a given channel:
cout << "Channel 1500 -> Energy = "
<< fcal->Eval(1500) << " keV" << endl;
Channel 1500 -> Energy = 750.2 keV
1.2 A Gaussian peak model¶
A Gaussian function is widely used to describe detector peaks:
TF1 *fpeak = new TF1("fpeak",
"[0]*exp(-0.5*((x-[1])/[2])^2)",
400,700);
fpeak->SetParameters(1000, 550, 20);
fpeak->SetTitle("Gaussian peak model;Energy (keV);Counts");
fpeak->Draw();
c1->Draw();
2. TGraph: measured points¶
A TGraph is an object made of two arrays X and Y with the same number of points. This is ideal for calibration data, efficiency curves, and other measured point-by-point relations. (ROOT)
2.1 Example: calibration points¶
Assume a set of measured ADC channels and known reference energies:
double ch[5] = {512, 1024, 1538, 2049, 2561};
double E[5] = {122.1, 245.4, 367.8, 489.0, 612.3};
TGraph *gcal = new TGraph(5, ch, E);
gcal->SetName("gcal");
gcal->SetTitle("Energy calibration;Channel;Energy (keV)");
gcal->SetMarkerStyle(20);
gcal->Draw("AP");
c1->Draw();
2.2 Fit the graph¶
A linear fit gives the calibration coefficients:
TF1 *flin = new TF1("flin","pol1",0,3000);
gcal->Fit(flin);
c1->Draw();
**************************************** Minimizer is Linear / Migrad Chi2 = 1.09576 NDf = 3 p0 = 0.143912 +/- 0.633828 p1 = 0.238922 +/- 0.000373056
Read the parameters:
cout << "Offset = " << flin->GetParameter(0) << endl;
cout << "Slope = " << flin->GetParameter(1)
<< " keV/channel" << endl;
Offset = 0.143912 Slope = 0.238922 keV/channel
2.3 Another way to fill a TGraph¶
Points can also be filled one by one:
TGraph *g2 = new TGraph();
for(int i=0; i<5; i++) {
g2->SetPoint(i, ch[i], E[i]);
}
g2->SetTitle("Calibration graph filled with SetPoint;Channel;Energy (keV)");
g2->SetMarkerStyle(21);
g2->Draw("AP");
c1->Draw();
3. TRandom3: random numbers for detector simulation¶
TRandom3 is a random-number generator based on the Mersenne Twister. The random numbers are used to model detector response, background, and counting fluctuations. (ROOT)
3.1 Gaussian smearing: detector resolution¶
This mimics a measured energy fluctuating around the true value.
TRandom3 rng(0);
for(int i=0; i<10; i++) {
double Etrue = 548.0;
double Emeas = rng.Gaus(Etrue, 8.0);
cout << Emeas << ", ";
}
cout << endl;
550.105, 545.232, 539.4, 535.131, 546.106, 552.976, 537.688, 558.004, 538.035, 548.706,
3.2 Uniform background¶
This is a simple flat background model.
for(int i=0; i<10; i++) {
cout << rng.Uniform(0, 2000) << ", " ;
}
cout << endl;
1941.32, 513.72, 1177.85, 1021.41, 971.767, 530.412, 1278.18, 1909.77, 246.505, 1002.49,
3.3 Poisson fluctuation¶
This is useful for counting statistics.
for(int i=0; i<10; i++) {
cout << rng.Poisson(120) << ", ";
}
cout << endl;
140, 132, 128, 113, 118, 131, 120, 129, 112, 114,
4. TH1: one-dimensional histograms¶
TH1 is the base class of ROOT histogram classes. Histograms are one of the most important objects in ROOT because experimental data analysis often begins with filling and inspecting distributions. ROOT’s histogram documentation centers on filling and drawing histograms through TH1::Draw(). (ROOT)
4.1 Build a simple energy spectrum¶
Create a spectrum with two peaks and a flat background:
TH1F *hspec = new TH1F("hspec",
"Simulated energy spectrum;Energy (keV);Counts",
400, 0, 2000);
TRandom3 r1(0);
for(int i=0; i<30000; i++) hspec->Fill(r1.Gaus(548, 10));
for(int i=0; i<18000; i++) hspec->Fill(r1.Gaus(1250, 18));
for(int i=0; i<30000; i++) hspec->Fill(r1.Uniform(0, 2000));
hspec->Draw();
c1->Draw();
4.2 Inspect the histogram¶
cout << "Entries = " << hspec->GetEntries() << endl;
cout << "Mean = " << hspec->GetMean() << endl;
cout << "RMS = " << hspec->GetRMS() << endl;
Entries = 78000 Mean = 884.984 RMS = 455.742
4.3 Fit one peak¶
Rather than fitting the full spectrum with one Gaussian, fit only the region of one peak:
hspec->Fit("gaus","","",500,600);
c1->Draw();
**************************************** Minimizer is Minuit2 / Migrad Chi2 = 530.589 NDf = 17 Edm = 1.35485e-05 NCalls = 65 Constant = 5833.42 +/- 42.9144 Mean = 547.92 +/- 0.0601365 Sigma = 10.575 +/- 0.0493527 (limited)
4.4 Change appearance¶
hspec->SetLineWidth(2);
hspec->SetFillStyle(0);
hspec->Draw();
c1->Draw();
TH2F *hxy = new TH2F("hxy",
"Beam spot on detector plane;x (mm);y (mm)",
120, -30, 30, 120, -30, 30);
TRandom3 r2(0);
for(int i=0; i<50000; i++) {
hxy->Fill(r2.Gaus(2.0, 6.0), r2.Gaus(-1.0, 4.0));
}
hxy->Draw("colz");
c1->Draw();
TFile *fout = new TFile("root_tutorial1.root","recreate");
gcal->Write();
hspec->Write();
hxy->Write();
fout->Close();
6.2 Open the file and inspect its contents¶
TFile *fin = new TFile("root_tutorial1.root");
fin->ls();
TFile** root_tutorial1.root TFile* root_tutorial1.root KEY: TGraph gcal;1 Energy calibration KEY: TH1F hspec;1 Simulated energy spectrum KEY: TH2F hxy;1 Beam spot on detector plane
6.3 Read back one object¶
TH1F *hread = (TH1F*)fin->Get("hspec");
hread->Draw();
c1->Draw();
A useful distinction:
Draw()displays an objectWrite()stores an objectGet()retrieves an object from a file
7. A complete short example¶
The following macro combines the classes discussed in this lecture. To run this script:
- Save the file as
root_tutorial1_example.C(The filename must match the function name). - Open your terminal and start ROOT, then execute the script using the
.xcommand:
root [0] .x root_tutorial1_example.C
void root_tutorial1_example()
{
// 1. calibration points
double ch[5] = {512, 1024, 1538, 2049, 2561};
double E[5] = {122.1, 245.4, 367.8, 489.0, 612.3};
TGraph *gcal = new TGraph(5, ch, E);
gcal->SetName("gcal");
gcal->SetTitle("Energy calibration;Channel;Energy (keV)");
gcal->SetMarkerStyle(20);
TF1 *flin = new TF1("flin","pol1",0,3000);
gcal->Fit(flin);
// 2. spectrum
TH1F *hspec1 = new TH1F("hspec",
"Simulated energy spectrum;Energy (keV);Counts",
400, 0, 2000);
TRandom3 rng(0);
for(int i=0; i<30000; i++) hspec->Fill(rng.Gaus(548, 10));
for(int i=0; i<18000; i++) hspec->Fill(rng.Gaus(1250, 18));
for(int i=0; i<30000; i++) hspec->Fill(rng.Uniform(0, 2000));
// 3. beam spot
TH2F *hxy = new TH2F("hxy",
"Beam spot on detector plane;x (mm);y (mm)",
120, -30, 30, 120, -30, 30);
for(int i=0; i<50000; i++) {
hxy->Fill(rng.Gaus(2.0, 6.0), rng.Gaus(-1.0, 4.0));
}
// 4. save
TFile *fout = new TFile("root_tutorial1.root","recreate");
gcal->Write();
hspec1->Write();
hxy->Write();
fout->Close();
}
root_tutorial1_example()
**************************************** Minimizer is Linear / Migrad Chi2 = 1.09576 NDf = 3 p0 = 0.143912 +/- 0.633828 p1 = 0.238922 +/- 0.000373056
Warning in <TFile::Append>: Replacing existing TH1: hspec (Potential memory leak).
Comparison: ROOT Terminal vs. Jupyter Notebook¶
1. Entering and Exiting¶
- Terminal:
- To start: Type
rootin your shell. - To open a file directly: Type
root file.root. - To exit: Type
.q.
- To start: Type
- Jupyter:
- You write code directly in cells and press
Shift + Enterto run. There is no "exiting" other than closing the browser tab or stopping the kernel.
- You write code directly in cells and press
2. Inspecting Files and Objects¶
The way you "look inside" a file differs:
- Terminal: You can use "dot commands" (shortcuts).
- Type
.lsat the prompt to see all objects currently in memory or in the opened file.
- Type
- Jupyter: You must use standard C++ method calls on your file pointer.
- If you have
TFile *f = new TFile("data.root"), you must typef->ls();to see the contents in the output area.
- If you have
3. Displaying Graphics (The TCanvas Rule)¶
This is the most important difference when plotting:
- Terminal:
- When you type
h->Draw(), ROOT automatically creates a default window to show the plot. You usually do not need to callc1->Draw().
- When you type
- Jupyter:
- ROOT cannot automatically pop up a window in your browser.
- Mandatory Step: You must explicitly create a canvas (
TCanvas *c1 = new TCanvas(...)) and, at the end of your code cell, you must callc1->Draw();. Without this line, no plot will appear in the notebook.
4. Interactive Macros¶
- Terminal: You run a script file (
xxx.C) using.x xxx.C. - Jupyter: You can copy the content of the script into a cell. If the script contains
%jsroot on, it enables interactive web-based graphics (zooming, rotating), which is very useful for inspection.
Summary Table for Quick Reference¶
| Action | ROOT Terminal | Jupyter Notebook |
|---|---|---|
| Start | root or root a.root |
(Open .ipynb file) |
| Show Objects | .ls |
fin->ls(); |
| Quit | .q |
(Close Tab) |
| Plotting | h->Draw() (Automatic window) |
h->Draw() then c1->Draw() |