Lezione 2: Grafici e istogrammi con ROOT - INFN...

37
Antonio Uras Corso di Laboratorio I Laurea Specialistica Dott. Corrado Cicalò a.a. 2009/2010 Università di Cagliari & INFN Introduzione all'analisi dei dati sperimentali con il framework ROOT Università di Cagliari – Corso di Laurea Specialistica in Fisica Lezione 2: Grafici e istogrammi con ROOT

Transcript of Lezione 2: Grafici e istogrammi con ROOT - INFN...

Antonio Uras

Corso diLaboratorio I Laurea Specialistica

Dott. Corrado Cicalò a.a. 2009/2010

Università di Cagliari & INFN

Introduzione all'analisi dei dati sperimentali con il framework ROOT

Università di Cagliari – Corso di Laurea Specialistica in Fisica

Lezione 2: Grafici e istogrammi con ROOT

Sommario

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT2

Brevissimi richiami sul C++

Cos'è ROOT?

Scrivere una “macro” in ROOT

Creare un istogramma in ROOT

Creare un grafico in ROOT

/35

Due parole prima di iniziare

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT3/35

NON sono un esperto di C++ (nè di alcun altro linguaggio di programmazione...)

NON sono un esperto di ROOT

NON occorre che diventiate esperti di C++

NON occorre che diventiate esperti di ROOT

In queste lezioni non andremo oltre le competenze minime di C++ e di ROOT che occorrono per gestire l'analisi dei dati raccolti nelle semplici esperienze di laboratorio

Brevissimi richiami sul C++

Alcune regole generali

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT5/35

[Ci concentriamo sulle regole utili ad usare il C++ nell'ambito di ROOT]

Il C++ è case-sensitive (“Pippo” è diverso da “pippo”)

Ogni variabile va dichiarata, e possibilmente inizializzata

Per ogni variabile, avete accesso anche al suo indirizzo di memoria (puntatore), e spesso è comodo lavorare con i puntatori delle variabili piuttosto che con le variabili stesse

Ogni blocco di istruzioni va compreso fra parentesi graffe: { . . . }

Al termine di ogni istruzione va posto il carattere punto e virgola ;

http://www.cplusplus.com/doc/tutorial/

Operatori utili

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT6/35

Operatori matematici: + − * /

Operatori composti: += (a += b ↔ a = a+b)−= (a −= b ↔ a = a−b)*= (a *= b ↔ a = a*b)/= (a /= b ↔ a = a/b) ++ (a++ ↔ a = a+1) −− (a−− ↔ a = a−1)

Operatori relazionali: == (uguale a) != (diverso da) > (maggiore di)< (minore di) >= (maggiore o uguale a) <= (minore o uguale a)

Operatori logici: && (AND)|| (OR)

Tipi di variabile predefiniti

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT7/35

Usiamo il tipo double (o Double_t in ROOT) per variabili numeriche non intere

Usiamo il tipo int (o Int_t in ROOT) per variabili numeriche intere

Usiamo il tipo bool (o Bool_t in ROOT) per variabili di tipo Booleano (vero/falso)

Poche regole, senza alcuna pretesa di completezza:

Double_t a = 1.618 ;

Int_t b = 4 ;

Bool_t c = 0 ;

Potete inizializzare le variabili al momento stesso della dichiarazione. Per esempio:

Array

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT8/35

Per definire una variabile come array di valori, si deve specificare la dimensione fra parentesi quadre:

Double_t a[26] ;

Int_t b[2] ;

Bool_t c[82] ;

Il contenuto dell'array può essere inizializzato tutto insieme al momento della definizione, oppure elemento per elemento:

Double_t a[3] = {2.998e8, 6.626e−34, 6.67e−11} ;

Int_t b[2] ;b[0] = 19 ;b[1] = 23 ;

Consiglio: inizializzate sempre tutti gli array. Per inizializzare a zero basta usare: a[...] = {0}

Stringhe di caratteri

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT9/35

Le stringhe di caratteri possono essere trattate come array di caratteri. Per definirle e inizializzarle si possono usare varie alternative:

Char_t a[4] = “ciao” ;

Char_t a[] = “ciao” ;

Char_t *a = “ciao” ;

Char_t a[4] = {'c', 'i', 'a', 'o'} ;

Char_t a[4] ;sprintf(a, “ciao”) ;

Cicli

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT10/35

Ciclo for: esegue un blocco di istruzioni un numero definito di volte (in questo caso 100)

for (Int_t i = 0; i < 100; i++) {. . . ;. . . ;

}

Ciclo while: esegue un blocco di istruzioni fino a quando una condizione è vera

while (i < 100) {. . . ;. . . ;

}

Strutture di controllo

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT11/35

La più importante è la condizione di controllo “if...else” : esegue un certo blocco di istruzioni se è verificata la condizione tra parentesi

if (a > b) {. . . ;. . . ;

}else if (a < b) {

. . . ;

. . . ;}else {

. . . ;

. . . ;}

Eseguito quando a == b

Output su schermo

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT12/35

Per l'output su schermo si può usare la funzione printf(...)

printf (“ciao”) ; Scrive “ciao”

printf (“ciao\n”) ; Scrive “ciao” e va a capo

printf (“%d\n”, a) ; Scrive il valore di a (se a è un intero)

printf (“%g\n”, a) ; Scrive il valore di a (se a è un double)

printf (“%s\n”, a) ; Scrive il valore di a (se a è una stringa di caratteri)

Classi

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT13/35

Nel C++ è possibile definire nuovi tipi di variabili. Un nuovo tipo di variabile è chiamato CLASSE, e va definito secondo regole precise

Se si vuole usare un oggetto (variabile) appartenente ad una classe non predefinita, la definizione va inclusa all'inizio del programma

NON ci interessa sapere come creare nuove classi, perché sfrutteremo sempre classi aggiuntive già pronte da usare

Le uniche cose che dobbiamo sapere sugli oggetti di una classe sono:

come vanno creati

quali operazioni possiamo fare con/su di essi

Classi

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT14/35

Per esempio, se si è creata la classe “Istogramma”, un oggetto di questa classe va dichiarato come:

Istogramma hist ;

Oppure come puntatore:

Istogramma *hist ; D'ora in poi useremo questa opzione

Le operazioni che è possibile fare con/sugli oggetti della classe sono specificate nella sua definizione. Ciascuna operazione è associata a un “metodo” della classe, che:

ha un nome ben preciso

accetta una lista di argomenti (anche vuota)

esegue una serie di istruzioni

restituisce un output (opzionale)

Classi

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT15/35

Istogramma *hist ;

. . . . . .

hist -> Riempi(0.9) ;

Qui andranno inserite le istruzioni per definire il range dell'istogramma e la suddivisione in bin (tramite altri metodi)

La classe “Istogramma” potrebbe ad esempio possedere un metodo chiamato “Riempi(Double_t A)”, che:

accetta come argomenti un numero decimale A

identifica il bin dell'istogramma nel quale è compreso il valore A

aumenta di un'unità il contenuto del bin

non restituisce alcun output

Classi

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT16/35

Istogramma *hist ;

. . . . . .

hist -> Riempi(0.9) ;

La combinazione tratto-maggiore (freccia) esegue il metodo specificato alla sua destra sull'oggetto presente alla sua sinistra

La classe “Istogramma” potrebbe ad esempio possedere un metodo chiamato “Riempi(Double_t A)”, che:

accetta come argomenti un numero decimale A

identifica il bin dell'istogramma nel quale è compreso il valore A

aumenta di un'unità il contenuto del bin

non restituisce alcun output

ROOT

ROOT

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT18/35

ROOT è un framework per l'analisi dati basato sul linguaggio C++

Per quanto ci riguarda, esso si compone di:

un interprete (anche interattivo) di comandi C++

una collezione di classi utili per l'analisi dati (e non solo!)

Trovate tutte le informazioni e la risposta a tutti i possibili dubbi su:

http://root.cern.ch

ROOT è fra i pacchetti predefiniti in alcune recenti distribuzioni di Linux!!!

ROOT

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT19/35

Per avviare ROOT digitate “root” nel terminale:

ROOT

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT20/35

L'interprete dei comandi C++ è già pronto. Possiamo provare a digitare qualche comando C++

ROOT – Le macro

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT21/35

L'interprete dei comandi C++ può essere più utilmente usato per processare interi blocchi di istruzioni, anziché una singola istruzione alla volta

I blocchi di istruzioni vengono scritti in un programma chiamato MACRO, memorizzato su un file esterno

Il nostro obbiettivo è imparare a scrivere delle MACRO che possano essere eseguite da ROOT per eseguire l'analisi dei nostri dati

Le macro che useremo hanno una struttura fissata:

le istruzioni sono raggruppate in “metodi”

ogni metodo possiede un nome, una lista di argomenti, una serie di istruzioni e restituisce (opzionalmente) un output

ROOT – Una macro semplice semplice

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT22/35

void PrimaProva(Int_t a) {

for (Int_t i=0; i<10; i++) {

Int_t b = a*i;

printf("%d\n", b);

}

}

Qualche commento:

la macro è costituita da un solo metodo, che accetta un intero come variabile input

il metodo è di tipo “void”, cioè non restituirà alcun argomento

Per caricare la macro in root: .L <nome-del-file>

Una volta caricata, digitare il nome del metodo specificando il valore dell'argomento fra parentesi, e premere INVIO

ROOT – Una macro un po' meno semplice

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT23/35

void PrimaProva(Double_t a) { for (Int_t i=0; i<10; i++) { Double_t b = Funzione(a*i); printf("%g\n", b); }}

Double_t Funzione(Double_t argument) { return 3.0*argument + 4.2;}

Qualche commento:

la macro è costituita da due metodi

una volta caricata la macro, possiamo eseguire entrambi i metodi, independentemente

il primo metodo fa uso del secondo: il calcolo di b risulta in questo modo “decentrato”

ROOT – Struttura generale di una macro

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT24/35

Non ci sono particolari prescrizioni sulla scrittura di una macro di ROOT – a parte il rispetto della sintassi del C++

Tipicamente, tuttavia, nelle macro si distingue fra:

metodo “principale”: un metodo “void”, cioè che esegue operazioni senza restituire alcun risultato (spesso il suo nome è quello stesso del file della macro). È il metodo che viene eseguito dopo aver caricato la macro

metodi “ausiliari”: metodi dedicati all'esecuzione di particolari operazioni richieste all'interno del motodo principale

La presenza dei metodi ausiliari permette di avere dei “moduli” di codice dedicati ad operazioni specifiche – riutilizzabili da macro a macro!!!

ROOT – Le classi

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT25/35

ROOT mette a disposizione una grande quantità di classi, per la definizione degli oggetti da usare nella nostra analisi

Tutto quello che dovete sapere per creare un oggetto appartenente ad una classe è:

come si chiama la classe

come si usa il metodo di creazione dell'oggetto

come si usano i metodi per operare sull'oggetto

Nelle prossime slide impareremo a usare due classi di ROOT: la classe per gli istogrammi e la classe per i grafici

Gestire istogrammi in ROOT

Creare un istogramma

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT27/35

Per la gestione degli istogrammi useremo la classe TH1D. Per creare un istogramma occorre specificare:

nome dell'oggetto

titolo dell'istogramma

numero di bin

valore minimo della variabile

valore massimo della variabile

Come modello, potete assumere l'istruzione:

TH1D *hist = new TH1D("Histogram", "My Title", 10, -3.0 , 7.0) ;

che crea un [puntatore ad un] oggetto di classe TH1D avente “Histogram” come nome, “My Title” come titolo (in un immane sforzo di fantasia!) e diviso in 10 bin fra -3.0 e 7.0

Riempire e disegnare un istogramma

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT28/35

Una volta creato l'istogramma, lo vogliamo riempire con i valori dalle misurazioni. Per esempio, se abbiamo ottenuto il valore -1.5, questo ricade nell'intervallo del quinto bin: dunque vogliamo che il contenuto del quinto bin venga aumentato di una unità

La classe TH1D fa tutto in automatico. Il metodo corrispondente si chiama Fill, e chiede come argomento il valore da inserire, in formato Double_t:

hist -> Fill(1.5) ;

Possiamo ovviamente riempire l'istogramma quante volte vogliamo, inserendo tutti i valori ottenuti nelle misurazioni. Quando avete terminato la fase di riempimento, potete disegnare l'istogramma con il metodo Draw:

hist -> Draw() ;

Istogrammi – Riassunto

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT29/35

void MacroIstogramma() {

TH1D *hist = new TH1D("Histogram", "My Title", 10, -3.0 , 7.0) ;

hist -> Fill(1.5) ;

hist -> Fill(1.1) ;

hist -> Fill(-2) ;

hist -> Fill(4.8) ;

hist -> Fill(6.2) ;

hist -> Fill(0.3) ;

hist -> Fill(1.2) ;

hist -> Fill(-2.3) ;

hist -> Draw() ;}

Gestire grafici in ROOT

Creare un grafico (metodo 1)

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT31/35

Per la gestione dei grafici useremo la classe TGraphErrors. Per creare un grafico occorre specificare:

numero di punti del grafico

array contenente le coordinate x di ciascun punto

array contenente le coordinate y di ciascun punto

array contenente gli errori sulla x di ciascun punto

array contenente gli errori sulla y di ciascun punto

NOTA BENE

per gli istogrammi, prima si crea l'oggetto (vuoto) e poi lo si riempie con i dati

per i grafici, con il “metodo 1” i dati devono essere a disposizione in array numerici PRIMA della creazione del grafico

!

Creare un grafico (metodo 1)

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT32/35

Ecco un esempio completo per la creazione di un grafico con cinque punti:

void MacroGrafico() {

const Int_t nPoints = 5 ;

Double_t x[nPoints] = {0.1, 0.6, 1.8, 2.4, 3.1} ;

Double_t y[nPoints] = {0.09, 0.47, 0.93, 1.12, 1.21} ;

Double_t errX[nPoints] = {0.05, 0.07, 0.10, 0.12, 0.13} ;

Double_t errY[nPoints] = {0.05, 0.05, 0.08, 0.09, 0.10} ;

TGraphErrors *graph = new TGraphErrors(nPoints, x, y, errX, errY) ;

graph -> SetName("Graph") ;

graph -> SetTitle("My Title") ;

graph -> Draw("ap") ;

}

Creare un grafico (metodo 1)

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT33/35

Ecco un esempio completo per la creazione di un grafico con cinque punti:

void MacroGrafico() {

const Int_t nPoints = 5 ;

Double_t x[nPoints] = {0.1, 0.6, 1.8, 2.4, 3.1} ;

Double_t y[nPoints] = {0.09, 0.47, 0.93, 1.12, 1.21} ;

Double_t errX[nPoints] = {0.05, 0.07, 0.10, 0.12, 0.13} ;

Double_t errY[nPoints] = {0.05, 0.05, 0.08, 0.09, 0.10} ;

TGraphErrors *graph = new TGraphErrors(nPoints, x, y, errX, errY) ;

graph -> SetName("Graph") ;

graph -> SetTitle("My Title") ;

graph -> Draw("ap") ;

}

Creare un grafico (metodo 2)

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT34/35

Un metodo alternativo per creare un grafico consiste nel:

creare un grafico “vuoto”

aggiungere i punti uno ad uno

[Potete ovviamente anche aggiungere un punto ad un grafico creato con il “metodo 1”] Ecco come si imposta il primo punto del grafico visto nella slide predente:

TGraphErrors *graph = new TGraphErrors() ;

graph -> SetPoint(0, 0.1, 0.09) ;

graph -> SetPointError(0, 0.05, 0.05) ;

Il primo argomento dei due metodi identifica il punto che state creando. Iniziate sempre dal punto numero 0. Lo stesso metodo permette di modificare le coordinate o gli errori di un punto già impostato

Creare un grafico – Istruzioni complementari

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT35/35

Qualche commento sul codice per la creazione del grafico (per entrambi i “metodi”)

Le istruzioni:

graph -> SetName("Graph") ;

graph -> SetTitle("My Title") ;

permettono di specificare rispettivamente il nome e il titolo del grafico (nel caso dell'istogramma sono specificati alla creazione dell'oggetto)

L'istruzione:

graph -> Draw("ap") ;

specifica che nel disegno dovranno comparire gli assi del grafico (lettera “a”) e i punti (lettera “p”). Non so perché, ma l'opzione predefinita (Draw senza argomenti) NON prevede il disegno degli assi e dei punti!!!

Backup Slides

Variabili e puntatori

Antonio Uras Lezione 2: Grafici e istogrammi con ROOT37/35

Nel C++ si può accedere all'indirizzo di memoria di una variabile tramite il suo puntatore. Il puntatore è identificato da una stringa di caratteri, per esempio 0x80cb700

Se A è una variabile, il suo puntatore si ottiene chiedendo &A

Se A è il puntatore di una variabile, la variabile si ottiene chiedendo *A

A = 1.618 &A = 0x80cb700SE ALLORA

SE ALLORAB = &A *B = 1.618

Se definiamo: Double_t *A = 1.618 allora A è un puntatore, perché la variabile è *A