Was ist ROOT?
▸ ROOT ist ein am CERN entwickeltes Softwarepaket zurDatenanalyse (insbesondere in der Teilchenphysik)
▸ ROOT basiert auf C++ Klassen.▸ Es ist nicht notwendig C++ im Detail zu können.Kenntnisse schaden aber nicht.
▸ Wobei kann mir ROOT helfen?▸ Datenverarbeitung (Einlesen, Fitten, . . . )▸ Visualisierung
2/1
Warum ROOT?
▸ ROOT ist nicht sehr einsteigerfreundlich, aber▸ einfach, häufig benutzte Schritte zu wiederholen▸ mächtige Statistik-Funktionen und robustes Fitting
▸ gerade fürs FP: Gute Möglichkeit Methoden anhand„einfacher“ Beispiele auszuprobieren
Alternativen
▸ PYTHON mit numpy, scipy, . . .▸ GNUPLOT
▸ . . .
3/1
Hilfe rund um ROOT
▸ vom CERN: root.cern.chUser’s Guide in „Buchform“ (PDFs)Reference Guide Erklärung aller KlassenHowTo’s Anleitungen und Beispiele
▸ mit Google:▸ z. B. TH1F site:root.cern.ch
▸ bei uns: Gustav-Mie-Haus3. StockBüro 03-016Hausruf 5872
4/1
Installation
▸ Im CIP-Pool installiert▸ Für die meisten großen Linux-Distributionen in denPaketquellen enthalten
Ubuntu apt-get install root-system
Fedora yum install root
▸ Mac OS X und Windows binaries aufroot.cern.ch/drupal/content/downloading-root
5/1
Erste Schritte
Es gibt mehrere Möglichkeiten ROOT zu benutzen▸ über eine interaktive Shell (CINT)▸ schreiben von Makros welche von ROOT ausgeführtwerden können
▸ Einbinden von ROOT-Klassen in kompilierfähigenC++-Code
▸ ROOT-Modul für Python
6/1
Erste Schritte: Interaktiv
▸ Starten durch Eingabe von rootoder Klick auf Desktop Icon
▸ Root hat einen eingebauten C++Interpreter (CINT)
▸ Mit den Tasten ↑ und ↓ erreichtman die zuletzt benutzten Befehle
▸ Beenden mit .q(bzw. .qqqqqq bei Problemen)
▸ Sollte nur zum Testen benutztwerden
user@machine:∼$ root******************************************** ** W E L C O M E to R O O T ** ** Version 5.34/18 14 March 2014 ** ** You are welcome to visit our Web site ** http :// root.cern.ch ** ********************************************
ROOT 5.34/18 ⤦Ç (heads/v5 -34-00- patches@v5 -34-17-156- g60f5d99 , ⤦Ç Mar 22 2014, 11:40:00 on linuxx8664gcc)
CINT/ROOT C/C++ Interpreter version 5.18.00 , ⤦Ç July 2, 2010
Type ? for help. Commands must be C++ statements.Enclose multiple statements between { }.root [0] 2+2(const int)4root [1] pow(10,2)(const double)1.00000000000000000e+02root [2] std::cout << "hello world" << std::endl;hello worldroot [3] int i = 5root [4] i(int)5root [5] .quser@machine:∼$
7/1
Erste Schritte: Makros
▸ Makros automatisierenwiederkehrende Arbeiten
▸ Werden in Textdateien geschrieben(z. B. beispiel.C) und mit.x beispiel.C ausgeführt
▸ Dateiname beispiel.C muss demNamen der Funktionvoid beispiel() entsprechen.
user@machine:∼$ root******************************************** ** W E L C O M E to R O O T ** ** Version 5.34/18 14 March 2014 ** ** You are welcome to visit our Web site ** http :// root.cern.ch ** ********************************************
ROOT 5.34/18 ⤦Ç (heads/v5 -34-00- patches@v5 -34-17-156- g60f5d99 , ⤦Ç Mar 22 2014, 11:40:00 on linuxx8664gcc)
CINT/ROOT C/C++ Interpreter version 5.18.00 , ⤦Ç July 2, 2010
Type ? for help. Commands must be C++ statements.Enclose multiple statements between { }.root [0] .x beispiel.CBeispiel 1:Wurzel aus 2 = 1.41421root [1] .quser@machine:∼$
void beispiel (){gROOT ->Reset();cout << "Beispiel 1: "<<endl;cout << "Wurzel aus 2 = " << sqrt (2.) << endl;
}
beispiel.C
8/1
Sehr kurze C++-Einführung
void vartypen (){
int ganz =1;double fliesskomma =2.5;TString text="Hello world!";
cout << text << endl;
// Rechnen ist moeglichdouble dkf=fliesskomma+ganz;
cout << fliesskomma<< " + "<< ganz<< " = "<< dkf << endl;
TH1F* myHist=new TH1F("myHisto","Distribution" ,10,0.,1.);myHist ->Fill (1.);
}
vartypen.C
Funktionsdefinition Ausgabetyp name(Eingabetyp parameter)
Funktionsaufruf name() bzw. name(1)
Variablendefinition Typ name=wert;
Ausgabe cout << "var = "<< 5 << endl;
var = 5 (Zeilenumbruch)
Komplexere Objekte Typ* name=new Typ(Parameter);
Methodenaufruf objekt->name() bzw. objekt->name(1);
9/1
ROOT Klassen
▸ ROOT bietet verschiedene Datenstrukturen in denenMesswerte gespeichert werden können, die für das FPrelevant sind
▸ Histogramme TH1F, TH2F▸ Graphen TGraph, TGraphErrors, TGraphAsymmErrors
▸ Funktions-Klasse TF1 zur Definition vonbenutzerdefinierten Funktionen und zum Fitten
▸ . . .
10/1
Histogramme
1 + 3 = 4
5 + 2 = 7
2 + 2 = 4
5 + 2 = 7
6 + 4 = 10
3 + 6 = 9
3 + 6 = 9
5 + 1 = 6
6 + 3 = 9
1 + 1 = 2
⋮
2 4 6 8 10 120
0.2
0.4
0.6
0.8
1
Dice Roll DistributionmyHisto
Entries 1Mean 4RMS 0
Dice Roll Distribution
11/1
Histogramme
1 + 3 = 4
5 + 2 = 7
2 + 2 = 4
5 + 2 = 7
6 + 4 = 10
3 + 6 = 9
3 + 6 = 9
5 + 1 = 6
6 + 3 = 9
1 + 1 = 2
⋮
myHistoEntries 1Mean 4RMS 0
2 4 6 8 10 120
0.2
0.4
0.6
0.8
1
Dice Roll DistributionmyHisto
Entries 2Mean 5.5RMS 1.5
Dice Roll Distribution
11/1
Histogramme
1 + 3 = 4
5 + 2 = 7
2 + 2 = 4
5 + 2 = 7
6 + 4 = 10
3 + 6 = 9
3 + 6 = 9
5 + 1 = 6
6 + 3 = 9
1 + 1 = 2
⋮
myHistoEntries 2Mean 5.5RMS 1.5
2 4 6 8 10 120
0.2
0.4
0.6
0.8
1
1.2
1.4
1.6
1.8
2
Dice Roll DistributionmyHisto
Entries 3Mean 5RMS 1.414
Dice Roll Distribution
11/1
Histogramme
1 + 3 = 4
5 + 2 = 7
2 + 2 = 4
5 + 2 = 7
6 + 4 = 10
3 + 6 = 9
3 + 6 = 9
5 + 1 = 6
6 + 3 = 9
1 + 1 = 2
⋮
myHistoEntries 3Mean 5RMS 1.414
2 4 6 8 10 120
0.2
0.4
0.6
0.8
1
1.2
1.4
1.6
1.8
2
Dice Roll DistributionmyHisto
Entries 4Mean 5.5RMS 1.5
Dice Roll Distribution
11/1
Histogramme
1 + 3 = 4
5 + 2 = 7
2 + 2 = 4
5 + 2 = 7
6 + 4 = 10
3 + 6 = 9
3 + 6 = 9
5 + 1 = 6
6 + 3 = 9
1 + 1 = 2
⋮
myHistoEntries 4Mean 5.5RMS 1.5
2 4 6 8 10 120
0.2
0.4
0.6
0.8
1
1.2
1.4
1.6
1.8
2
Dice Roll DistributionmyHisto
Entries 5Mean 6.4RMS 2.245
Dice Roll Distribution
11/1
Histogramme
1 + 3 = 4
5 + 2 = 7
2 + 2 = 4
5 + 2 = 7
6 + 4 = 10
3 + 6 = 9
3 + 6 = 9
5 + 1 = 6
6 + 3 = 9
1 + 1 = 2
⋮
myHistoEntries 5Mean 6.4RMS 2.245
2 4 6 8 10 120
0.2
0.4
0.6
0.8
1
1.2
1.4
1.6
1.8
2
Dice Roll DistributionmyHisto
Entries 6Mean 6.833RMS 2.267
Dice Roll Distribution
11/1
Histogramme
1 + 3 = 4
5 + 2 = 7
2 + 2 = 4
5 + 2 = 7
6 + 4 = 10
3 + 6 = 9
3 + 6 = 9
5 + 1 = 6
6 + 3 = 9
1 + 1 = 2
⋮
myHistoEntries 6Mean 6.833RMS 2.267
2 4 6 8 10 120
0.5
1
1.5
2
2.5
3
Dice Roll DistributionmyHisto
Entries 10Mean 6.7RMS 2.532
Dice Roll Distribution
11/1
Histogramme
1 + 3 = 4
5 + 2 = 7
2 + 2 = 4
5 + 2 = 7
6 + 4 = 10
3 + 6 = 9
3 + 6 = 9
5 + 1 = 6
6 + 3 = 9
1 + 1 = 2
⋮
myHistoEntries 10Mean 6.7RMS 2.532
2 4 6 8 10 12200
400
600
800
1000
1200
1400
1600
Dice Roll DistributionmyHisto
Entries 10000Mean 7.028RMS 2.405
Dice Roll Distribution
11/1
Histogramme
▸ Histogramm erstellen:TH1F* hist = new TH1F("myHisto","Dice Roll ⤦
Ç Distribution",11,1.5,12.5);▸ mehrfach befüllen:
hist->Fill(x);▸ zeichnen:
hist->Draw(opt);
wobei opt="", opt="E" für Fehlerbalken, opt="SAME"für Überlagerung, opt="C" für glatte Kurve, opt="L" fürLinie, . . . – oder Kombinationen daraus
12/1
Histogramme
void histogram (){gROOT ->Reset();gROOT ->SetStyle("Plain");TH1F* myHist = new ⤦Ç TH1F("myHist","Distribution ⤦Ç from 0 to 1" ,10,0.,1.);
myHist ->Fill (0.37); //Bin 4myHist ->Fill (0.35); //Bin 4myHist ->Fill (0.78); //Bin 8myHist ->Fill (0.51); //Bin 6myHist ->Draw("HF1");
}
histogram.C
13/1
Histogramme
user@machine:∼$ root******************************************** ** W E L C O M E to R O O T ** ** Version 5.34/18 14 March 2014 ** ** You are welcome to visit our Web site ** http :// root.cern.ch ** ********************************************
ROOT 5.34/18 ⤦Ç (heads/v5 -34-00- patches@v5 -34-17-156- g60f5d99 , ⤦Ç Mar 22 2014, 11:40:00 on linuxx8664gcc)
CINT/ROOT C/C++ Interpreter version 5.18.00 , ⤦Ç July 2, 2010
Type ? for help. Commands must be C++ statements.Enclose multiple statements between { }.root [0] .x examples/histogram.CInfo in <TCanvas :: MakeDefCanvas >: created ⤦Ç default TCanvas with name c1
▸ speichern mittels File → Save Asin viele Formate (u. a. PDF)
▸ viele Style-Optionen über Rechtsclick erreichbar
14/1
Optionen
▸ Für Linienhist->SetLineStyle(x);hist->SetLineColor(x);hist->SetLineWidth(x);
▸ Für Markerhist->SetMarkerStyle(x);hist->SetMarkerColor(x);hist->SetMarkerSize(x);
▸ Für Flächenhist->SetFillStyle(x);hist->SetFillColor(x);
▸ Für Achsenhist->GetXaxis()->SetTitle("#phi_2^2"); LATEX mit # statt \hist->GetYaxis()->SetRangeUser(-1.,1.);
▸ Für den Titelhist->SetTitle("Titel");
15/1
Farben, Linien, Marker, . . .
0
10
20
30
40
1
11
21
31
41
2
12
22
32
42
3
13
23
33
43
4
14
24
34
44
5
15
25
35
45
6
16
26
36
46
7
17
27
37
47
8
18
28
38
48
9
19
29
39
49
123456789
10
1
20
2
21
3
22
4
23
5
24
6
25
7
26
8
27
9
28
10
29
11
30
12
31
13
32
14
33
15
34
3001 3002 3003 3004 3005
3006 3007 3008 3009 3010
3011 3012 3013 3014 3015
3016 3017 3018 3019 3020
3021 3022 3023 3024 3025
3144 3305 3350 3490 3609
3244 3315 3351 3481 3618
3344 3325 3352 3472 3627
3444 3335 3353 3463 3636
3544 3345 3354 3444 3644
3644 3365 3356 3436 3663
3744 3375 3357 3427 3672
3844 3385 3358 3418 3681
3944 3395 3359 3409 3690
16/1
Eine typische FP-Auswertung
▸ Aus dem Versuch: Messwerte in Textdatei▸ Ziel ist es die Werte darzustellen und eineAnpassung (Fit) durchzuführen1. Daten einlesen2. Messwerte in Datenstruktur füllen3. Funktionsanpassung an die Daten
322323322312314335291331329317
peaks.dat
17/1
Einlesen von Daten
void auswertung (){gROOT ->Reset();gROOT ->SetStyle("Plain");ifstream in; // Input Streamin.open("peaks.dat"); // Oeffnen der DateiFloat_t xi;Int_t nlines = 0;
while( !in.eof() ){ //Bis zum Ende der Dateiif(in >> xi){ // Einlesen einer Zeile
nlines ++;cout << nlines << ": " << xi <<endl;
}}cout <<"found "<<nlines <<" data points"<<endl;in.close();matrix ->Print();c1->SaveAs("../ plots/peaks -fitted.pdf");
auswertung.C
18/1
Einlesen von Daten in ein Histogramm
void auswertung (){gROOT ->Reset();gROOT ->SetStyle("Plain");ifstream in; // Input Streamin.open("peaks.dat"); // Oeffnen der DateiFloat_t xi;Int_t nlines = 0;TH1F* histo = new TH1F("histo","Peaks", 1250, 0., 125 );while( !in.eof() ){ //Bis zum Ende der Datei
if(in >> xi){ // Einlesen einer Zeilehisto ->SetBinContent( nlines , xi ); // Setzen des Bin -Inhaltsnlines ++;cout << nlines << ": " << xi <<endl;
}}cout <<"found "<<nlines <<" data points"<<endl;in.close();matrix ->Print();c1->SaveAs("../ plots/peaks -fitted.pdf");
auswertung.C
19/1
Einlesen von Daten in ein Histogramm
void auswertung (){gROOT ->Reset();gROOT ->SetStyle("Plain");ifstream in; // Input Streamin.open("peaks.dat"); // Oeffnen der DateiFloat_t xi;Int_t nlines = 0;TH1F* histo = new TH1F("histo","Peaks", 1250, 0., 125 );while( !in.eof() ){ //Bis zum Ende der Datei
if(in >> xi){ // Einlesen einer Zeilehisto ->SetBinContent( nlines , xi ); // Setzen des Bin -Inhaltsnlines ++;cout << nlines << ": " << xi <<endl;
}}cout <<"found "<<nlines <<" data points"<<endl;in.close();histo ->Draw();c1->SaveAs("../ plots/peaks -fitted.pdf");
}
auswertung.C
20/1
Einlesen von Daten in ein Histogramm
0 20 40 60 80 100 1200
100
200
300
400
500
600
Peaks histoEntries 1250Mean 56.52RMS 34.6
Peaks
21/1
Einschub: Funktionen
ROOT kann▸ exp(x), sin(x), log(x),sqrt(x)
▸ gaus (mit σ = 1),Landau,...
▸ TMath Funktionen▸ Beliebige Funktionen x
0 1 2 3 4 5 6
f(x)
=sin
(x)/
x
-0.2
0
0.2
0.4
0.6
0.8
1
Funktion
void function (){gROOT ->Reset();gROOT ->SetStyle("Plain");TF1 *myFunc = new TF1("myFunction", "sin(x)/x" ,0.,6.5.);myFunc ->Draw();myFunc ->GetXaxis ()->SetTitle("x");myFunc ->GetYaxis ()->SetTitle("f(x)=sin(x)/x");myFunc ->SetTitle("Funktion");c1->SaveAs("../ plots/function.pdf");
}
function.C
22/1
Fitting
⋮ ⋮
histo ->Draw();c1->SaveAs("../ plots/peaks.pdf");
// Polynom ersten Grades [0]+[1]*x Parameternummerierung startet bei 0)// Gaussfunktion [2]* exp(-((x-[3]) /(2*[4]))^2) (Parameternummerierung ⤦Ç startet bei 2)
TF1* fitFunc = new TF1("fitFunc","pol1 (0)+gaus (2)" ,0,130);fitFunc ->SetParameter (3,70); // Startwerte setzenfitFunc ->SetParameter (4,5);fitFunc ->SetLineColor(kRed);histo ->Fit("fitFunc","", "", 55,83); // Fit durchfuehrencout <<" --------------------------------" <<endl;c1->SaveAs("../ plots/peaks -fitted.pdf");
}
auswertung.C
23/1
Fitting
FCN =259.977 FROM MIGRAD STATUS=CONVERGED 742 CALLS 743 TOTALEDM =2.72382e-08 STRATEGY= 1 ERROR MATRIX UNCERTAINTY 2.3 per cent
EXT PARAMETER STEP FIRSTNO. NAME VALUE ERROR SIZE DERIVATIVE1 p0 2.75816e+02 1.72775e+01 3.78476e-02 -1.28064e-042 p1 -1.71104e+00 2.07468e-01 -4.33484e-04 -8.50550e-033 p2 2.62425e+02 4.11337e+00 -9.82297e-03 -7.07876e-054 p3 6.72119e+01 8.48930e-02 1.70257e-04 1.89167e-035 p4 5.62171e+00 1.19757e-01 -1.81880e-04 -4.27276e-03
histoEntries 1250Mean 56.52RMS 34.6
0 20 40 60 80 100 1200
100
200
300
400
500
600
histoEntries 1250Mean 56.52RMS 34.6
Peaks
24/1
Kovarianzmatrix
TF1* fitFunc = new TF1("fitFunc","pol1 (0)+gaus (2)" ,0,130);fitFunc ->SetParameter (3,70); // Startwerte setzenfitFunc ->SetParameter (4,5);fitFunc ->SetLineColor(kRed);histo ->Fit("fitFunc","", "", 55,83); // Fit durchfuehrencout <<" --------------------------------" <<endl;cout <<" chi2/dof: "<< fitFunc ->GetChisquare ()/fitFunc ->GetNDF ()<<endl;
TVirtualFitter *fitter = TVirtualFitter :: GetFitter ();TMatrixD *matrix = new TMatrixD (5,5,fitter ->GetCovarianceMatrix ());matrix ->Print();c1->SaveAs("../ plots/peaks -fitted.pdf");
auswertung.C
5x5 matrix is as follows| 0 | 1 | 2 | 3 | 4 |
----------------------------------------------------------------------0 | 298.5 -3.534 -50.87 1.117 -1.421 | -3.534 0.04304 0.5477 -0.01382 0.014332 | -50.87 0.5477 16.92 -0.1617 0.27893 | 1.117 -0.01382 -0.1617 0.007207 -0.0042994 | -1.42 0.01433 0.2789 -0.004299 0.01434
25/1
2D-Histogramme
void twodhistos (){gROOT ->Reset();gROOT ->SetStyle("Plain");gStyle ->SetPalette (1);TCanvas *c1 = new TCanvas("c1","Canvas fuer viele Histogramme" ,800,800);c1->Divide (2,2);TH2F *h2 = new TH2F("h2","Energie vs Impuls" ,40,-5.,5.,40,-5.,5.);TF2 *f2 = new TF2("gaus2", "exp(- .5*x**2 -.1*y**2)", -5., 5., -5., 5.);h2->FillRandom("gaus2" ,6000);h2->GetXaxis ()->SetTitle("Energie E (GeV)");h2->GetYaxis ()->SetTitle("Impuls p (GeV)");h2->GetZaxis ()->SetTitle("Ereignisse");TF2* f2=new TF2("func2","sin(x)*sin(y)/(x*y)" ,-10.,10.,-10.,10.);c1->cd(1);h2->GetXaxis ()->SetTitleOffset (1.5);h2->GetYaxis ()->SetTitleOffset (1.5);h2->GetZaxis ()->SetTitleOffset (1.2);h2->Draw("LEGO2");c1->cd(2);h2->Draw("COL");c1->cd(3);f2->Draw("SURF1");c1->cd(4);f2->Draw("COLZ");c1->SaveAs("../ plots/twodhistos.pdf");
}
twodhistos.C 26/1
2D-Histogramme
Energie E (GeV)
-5 -4 -3 -2 -1 0 1 2 3 4 5
Impuls p (GeV)-5-4
-3-2-10123
45
Ere
ign
isse
0
510
15
20
2530
35
Energie vs Impuls h2Entries 6000
Mean x 0.003083
Mean y 0.01904
RMS x 1.016
RMS y 2.077
Energie vs Impuls Energie vs Impuls
Energie E (GeV)
-5 -4 -3 -2 -1 0 1 2 3 4 5Im
pu
ls p
(G
eV)
-5
-4
-3
-2
-1
0
1
2
3
4
5
h2Entries 6000
Mean x 0.003083
Mean y 0.01904
RMS x 1.016
RMS y 2.077
h2Entries 6000
Mean x 0.003083
Mean y 0.01904
RMS x 1.016
RMS y 2.077
Energie vs Impuls
-10 -8 -6 -4 -2 0 2 4 6 8 10
-10-8-6-4-20
246810
-0.2
0
0.2
0.4
0.6
0.8
1
sin(x)*sin(y)/(x*y)sin(x)*sin(y)/(x*y)
-0.2
0
0.2
0.4
0.6
0.8
sin(x)*sin(y)/(x*y)
-10 -8 -6 -4 -2 0 2 4 6 8 10-10
-8
-6
-4
-2
0
2
4
6
8
10
sin(x)*sin(y)/(x*y)
27/1
Graphen
void graph(){gROOT ->Reset();gROOT ->SetStyle("Plain");
const int n = 300; // const wird zur Array Initialisierung benoetigt//300 ist die Anzahl der Zeilen in der Dateidouble x[n];double y[n];
ifstream in; //Input Streamin.open("peak.dat"); // Oeffnen der DateiInt_t nlines = 0;
while( !in.eof() && nlines < n ){ //Bis zum Ende der Dateiif(in >> x[nlines] >> y[nlines ]){ // Einlesen einer Zeile
nlines ++;cout << nlines << ": " << x[nlines] << " " << y[nlines] << endl;
}}
cout << "found "<< nlines << " data points."<<endl;in.close ();
TGraph *gr = new TGraph(n,x,y);gr ->Draw("AL");// Option A zeichnet Achsen , sollte immer benutzt werden , L ⤦Ç zeichnet "eckige" Linien , C zeichnet "runde Linien", * zeichnet Punkte
c1 ->SaveAs("../ plots/graph.pdf");}
graph.C28/1
Graphen
0 50 100 150 200 250 3000
20
40
60
80
100
GraphGraph
29/1
Graphen mit Fehlern
void grapherrors (){gROOT ->Reset();gROOT ->SetStyle("Plain");
const int n = 10;//const is need in array initializationdouble x[n] = {-0.22, 0.05, 0.25, 0.35, 0.5, 0.61 ,0.7 ,0.85 ,0.89 ,0.95};double y[n] = {1 ,2.9 ,5.6 ,7.4 ,9 ,9.6 ,8.7 ,6.3 ,4.5 ,1};double ex[n] = {.05 ,.1 ,.07 ,.07 ,.04 ,.05 ,.06 ,.07 ,.08 ,.05};double ey[n] = {.8 ,.7 ,.6 ,.5 ,.4 ,.4 ,.5 ,.6 ,.7 ,.8};TGraphErrors *gr = new TGraphErrors(n,x,y,ex,ey);gr->Draw("ALP");c1->SaveAs("../ plots/grapherrors.pdf");
}
grapherrors.C
30/1
Graphen
-0.2 0 0.2 0.4 0.6 0.8 10
2
4
6
8
10
GraphGraph
31/1
Zusammenfassung
▸ Root zu benutzen ist eigentlich garnicht so schwer
▸ Die Online-Hilfe ist empfehlenswertunverzichtbar
▸ Google ist euer Freund▸ Ansonsten eure Betreuer fragen
root.cern.ch
ROOT is user friendly (but it picks its friends carefully)
32/1