-- FrancescoCirotto - 2021-04-14

ROOT Tutorial per Lab5

Francesco Cirotto - cirotto@naNOSPAMPLEASE.infn.it

Indice

Introduzione

L'idea di questo tutorial è di fornire gli strumenti per eseguire semplici operazioni sugli oggetti fisici di interesse conservati in una nTupla di root. Dovete creare dei tree su cui fare le analisi a partire da file di testo contenenti variabili cinematiche.

In particolare, i file di testo contengono informazioni su un decadimento in due fotoni. Una parte dei decadimenti derivano dal bosone di Higgs, i rimanenti da processi detti di "fondo". Dovrete individuare la corretta distribuzione del fondo ed effettuare un fit alla distribuzione di massa invariante dei vostri eventi.

Settings

Installazione di wsl2

Se non lavorate in un ambiente UNIX (Mac o Linux) avrete bisogno di installare un terminale per fare il tutorial. Microsoft mette a disposizione degli utenti di windows 10 l'utility wsl2 ( sottosistema Windows per Linux) che permette di eseguire un ambiente GNU/Linux, inclusi quasi tutti gli strumenti da riga di comando, le utilità e le applicazioni, direttamente in Windows, senza modifiche e senza il sovraccarico di una macchina virtuale tradizionale o di una partizione.

Una guida esaustiva su tutti i passaggi da seguire la trovate qui. In sintesi si deve

  • installare wsl2, cioè windows subsystem for linux, che permette di avere un terminale esattamente come in linux
  • installare la GUI, cioè l'interfaccia grafica per aprire in maniera grafica i programmi
  • installare un X-server, VcXsrv (seguite le indicazioni)

Potete fermarvi qui, senza fare la parte Full Linux Desktop, che permette di installare tutto linux (non solo il terminale) in windows.

Opzionale: Potreste pensare di proseguire con l'installazione di ROOT per lavorare sul vostro pc (o potrebbe tornarvi utile in futuro). Seguite questa guida o questa.

Login sulle macchine di Napoli

Potete lavorare su una delle tre macchine disponibili, atlasui01, atlasui02, atlasui03. Tutto il materiale che scrivete su una di queste è presente anche nelle altre. Può capitare qualche volta che una UI non funziona perchè è in manutenzione, scegliete una tra le rimanenti.

Per accedere alla UI bisogna usare il seguente comando

$ ssh -XY -p5022 Gr1_21Lab5@atlasui03.na.infn.it
E analoghi comandi cambiando Gr1 con Gr2 etc...

Trovate altre istruzioni su ATLAS ui e alcuni comandi tipici di unix in queste slide

Per fare il setup di ROOT i comandi sono:

$ setupATLAS
$ lsetup "root 6.14.04-x86_64-slc6-gcc62-opt"

Potete copiare queste due righe in un file con estensione .sh, ad esempio setup.sh, che potete lanciare ad ogni login con il comando:

$ source setup.sh

Informazioni preliminari per il tutorial

I file di testo si trovano a questo path

/data3/cirotto/Lab5Tutorial/GruppoX/

per copiare in locale questo file:

$ mkdir myDirectory
$ cd myDirectory
$ cp /data3/cirotto/Lab5Tutorial/GruppoX/*.txt .

Dove X si riferisce al numero del vostro gruppo e "*.txt" permette di selezionare tutti i file con estensione .txt.

I file di testo sono composti da 9 colonne, così identificate

mass   Pseudorapidity  Et1     Eta1    Phi1    Et2     Eta2    Phi2    isHiggs

Tranne l'ultima colonna, che è di numeri interi, il resto sono tutti numeri decimali. Nello specifico dunque avrete a disposizione la massa invariante e la pseudorapidità (eta) del sistema dei due fotoni, l'energia trasversa, eta e phi di ciascun fotone della coppia. L'ultima colonna (isHiggs) vi permette di selezionare eventi provenienti dal decadimento dell'Higgs (quando è uguale a 1) da eventi di fondo (quando è 0).

ROOT tips and tricks

Tutorial

Come creare un Tree a partire da un file di testo

Un esempio di come scrivere un file .root contenente un Tree a partire da un file di testo si trova qui. Di seguito una versione molto simile

void writeTree()
{

   //stringhe che rimandano ai nome dei file di output e di input
  TString filenameROOT = "esempio.root";
  TString filenameInput = "ilmioinput.txt"

  TFile* myFile = TFile::Open(filenameROOT,"RECREATE");
  TTree *tree = new TTree("Nome_tree","Qui potete metterci un titolo a scelta");


  tree->ReadFile(filenameInput, "x/D:y/D:z/I");
  tree->Write();
  myFile->Close();

}

Vediamo nel dettaglio alcune righe

TFile* myFile = TFile::Open(filenameROOT,"RECREATE");
  TTree *tree = new TTree("Nome_tree","Qui potete metterci un titolo a scelta");

Queste due righe si occupano di creare un file root, il cui nome è contenuto nella stringa filenameROOT (l'opzione "RECREATE" serve per sovrascrivere ogni volta il file), e di creare un tree con nome e titolo di vostra scelta. La parte di scrittura è gestita da una singola riga

tree->ReadFile(filenameInput, "x/D:y/D:z/I");

dove filenameInput è il file di testo da leggere e il secondo argomento del metodo ReadFile indica il nome (ed il tipo) che attribuite a ciascuna colonna. Nell'esempio dunque, state salvando 3 colonne nel tree con i nomi x,y e z. x e y sono double (D) e z è un int (I). Modificate secondo la formattazione del vostro file questa riga, in base anche alla descrizione fatta precedentemente. Il metodo utilizzerà di default lo spazio come delimitatore tra due colonne. Nota: il metodo ignora nel file di testo tutte le righe che iniziano con il carattere '#'

Warning, important ATTENZIONE! nel caso in cui avete a che fare con un testo che utilzza un altro delimitatore, ad esempio una virgola, potete specificare questa cosa nel seguente modo

tree->ReadFile(filenameInput, "x/D:y/D:z/I", ',');

Le ultime due righe scrivono l'oggetto tree nel file, e chiudono il file.

Aprire e visualizzare il tree

Supponiamo che abbiate salvato il file root con il nome ilmiofile.root. Per aprirlo da terminale basta fare
root -l ilmiofile.root

per vedere cosa c'è all'interno del file root:

.ls

Supponendo che il tree si chiami ilmiotree

per vedere quali variabili sono presenti nel tree:

ilmiotree->Print()

Potete utilizzare il metodo Draw() per visualizzare la distribuzione delle variabili. Il metodo vi permette di applicare anche una selezione. Supponiamo che le variabili salvate abbiano i seguenti nomi mass, Pseudorapidity ,Et1 ,Eta1,Phi1,Et2, Eta2 ,Phi2 ,isHiggs posso graficare la distribuzione della massa facendo

ilmiotree->Draw("mass")

o, con una particolare selezione:

ilmiotree->Draw("mass", "isHiggs==1")
ilmiotree->Draw("mass", "Et1>60 && Et2<45")

Scrivere una macro per creare istogrammi

Per poter riempire degli istogrammi a partire dalle variabili del tree esistono diversi metodi.

Tra i più immediati c'è quello di utilizzare il metodo della classe TTree , Draw salvando il risultato in un istogramma. Vediamo nel dettaglio un esempio (spiegazione riga per riga nei commenti)

void makeHisto(){

  
  TFile *file = new TFile("ilmiofile.root"); //Crea e apre il file root esistente
  TTree *tree = (TTree*)file->Get("ilmiotree"); //Recupera nel file un oggetto di tipo TTree che si chiama ilmiotree

  TH1F *myHisto = new TH1F("h","titolo h", 50, 100,300); //nome e titolo dell'histo, numero di bin, minimo e massimo dell'intervallo
   myHisto->SetLineColor(2); //Colore della linea rosso
   myHisto->SetMinimum(0); //Setta il minimo
   myHisto->GetXaxis()->SetTitle("titolo asse X");
   myHisto->GetYaxis()->SetTitle("titolo asse Y");
 
  tree->Draw("mass>>h","isHiggs==1","goff"); //la distribuzione della variabile mass viene riempita nell'histo con nome h, con la selezione applicata. L'opzione "goff" non visualizza l'istogramma,


  TCanvas *c =  new TCanvas ("c","c", 800,800); //Creo una finestra. Se non lo faccio quando utilizzo il metodo Draw dell'histo viene comunque creata di default
  myHisto->Draw();

  c->Print("ilmioplot.pdf"); //salvataggio in pdf dell'istogramma
  myFile->Close();

}

Warning, important ATTENZIONE! questo metodo funziona molto bene, ed è veloce nel caso in cui le selezioni da applicare sono semplici, e riconducibili alle variabili salvate nel tree.

Un secondo metodo per analizzare i dati è quello di accedere alle variabili evento per evento e scrivere la propria selezione.

void tree1r(){
   // Supponiamo di star leggendo un file col nome "tree1.root", contenente un tree col nome "t1"

   TFile *f = new TFile("tree1.root");
   TTree *t1 = (TTree*)f->Get("t1");

   Float_t px, py, pz; //Devo creare le variabili che punteranno a quelle salvate nel tree

   //Punto le variabili create precedentemente ai branch del mio tree
   t1->SetBranchAddress("px",&px); //quindi la variabile px punta al branch con nome "px"
   t1->SetBranchAddress("py",&py);
   t1->SetBranchAddress("pz",&pz);

   // creo un histo
   TH1F *hpx   = new TH1F("hpx","px distribution",100,-3,3);

   //Accedo evento per evento alle variabili ed eseguo la mia analisi

   Int_t nentries = (Int_t)t1->GetEntries(); //Questo metodo mi restistuisce il numero di eventi salvati nel tree

  //Eseguo un loop
   for (Int_t i=0; i<nentries; i++) {
      t1->GetEntry(i); //questo metodo "carica" l'evento i-esimo con tutti valori dei branch

     //posso ora scrivere la mia selezione
      if(px>0 && py<1){
      hpx->Fill(px); //Utilizzo il metodo Fill per riempire l'istogramma 
      }
   } //Fine loop

   hpx->Draw();  
}

Un'alternativa all'esempio di sopra è quello di utilizzare il metodo MakeClass. Questo genera una class personalizzata che permette di accedere ad un loop pre-scritto da ROOT, dove implementare l'analisi. Può essere utile se si ha a che fare con tree con molte variabili, dove il SetBranchAddress va fatto molte volte. Per maggiori informazioni potete guardare nella guida di ROOT .

Eseguire un fit

Vogliamo ora eseguire un fit ad un istogramma. Anche qui si può proseguire in modi diversi a seconda dei casi. Supponiamo che myHisto sia l'istogramma sul quale vogliamo eseguire un fit.

Vediamo alcuni esempi:

TF1 *gaussian = new TF1("gaussian", "gaus", 80, 100);  //Definizione di una funzione gaussiana nell'intervallo 80,100. 
myHisto->Fit("gaussian","R");

TF1 *pol2 = new TF1("parabola", "pol2", 80, 100);  //Definizione di una parabola nell'intervallo 80,100. 
myHisto->Fit("parabola","R");

TF1 *pol2_V2 = new TF1("parabolaV2", "[0] + [1]*x + [2]*x*x", 80, 100);  //Definizione di una parabola nell'intervallo 80,100. 
myHisto->Fit("parabolaV2","R");

ROOT fornisce, per le funzioni più comuni, delle funzioni predefinite. Negli esempi precedenti ; gaus e po2 (in generale polN, dove N va specificato). Si veda qui per una lista completa. Nel terzo esempio, la funzione è stata scritta utilizzando una formula, con i parametri [0],[1],[2] da stimare nel fit (si noti che è sempre una parabola). L'intervallo di definizione nell'esempio è 80,100. L'opzione "R" nel metodo "Fit" sta ad indicare di eseguire il fit nel range di definizione della funzione. Altre opzioni per il fit qui.

Può essere utile "aiutare" il fit settando opportunamente i parametri. Con riferimento all'esempio della gaussiana, abbiamo 3 parametri da stimare, nell'ordine costante di normalizzazione, media e sigma. Possiamo pensare di settare i parametri nel seguente modo

gaussian->SetParameters(100,5,1); //Stiamo settando nell'ordine costante, media e sigma

oppure pensare di agire sul singolo parametro:

gaussian->SetParameter(1, 125); //Setta il parametro 1 della gaussiana (la media) a 125
gaussian->SetParLimits(2, 2,10); // Limita il parametro 2 nell'intervallo 2,10

Possiamo pensare di fissare un parametro del fit, e quindi eliminarlo dalla stima

gaussian->FixParameter(1, 125); //Fissa a 125 il parametro 1

Si può accedere ad un parametro nel seguente modo

Double_t media = gaussian->GetParameter(1); 
Double_t errore_media = gaussian->GetParError(1); 
Ovviamente il valore cambierà prima e dopo il fit. Dopo il fit abbiamo quindi stimato il numero dei parametri e possiamo ad esempio integrare la funzione per stimare il numero di eventi:
Double_t integral = gaussian->Integral(20,40)/myHisto->GetBinWidth(1); //Integrale nell'intervallo 20,40. Per renderlo indipendente dall'istogramma va diviso per la larghezza del bin

Possiamo pensare di sommare due funzioni nel seguente modo

TF1 *f_somma= new TF1("f_somma", "[0] + [1]*x + [2]*x*x + gaus(3)", 80, 100);  //Notare che la gaussiana parte dal parametro 3, quindi avrà i parametri 3,4,5
TF1 *f_sommaV2= new TF1("f_sommaV2", " gaus(0) + pol1(3) + gaus(5)", 80, 100);  //Tra parentesi è indicata la prima posizione del parametro della funzione
Le funzioni f_somma e f_sommaV2 hanno rispettivamente 6 (3 per la parabola e 3 per la gaussiana) ed 8 parametri (3 per la prima gaussiana, 2 per pol1 e 3 per la seconda gaussiana), bisogna quindi specificare quali parametri si riferiscono a ciascuna funzione che compare nella somma, indicando il numero relativo al primo dei parametri assegnati a quella funzione.

TODO Esercizi

  • Scrivere un tree a partire dal file di testo
  • Contare il numero di eventi di segnale, e di fondo dal tree
Utilizzare la variabile isHiggs

  • Riprodurre la distribuzione della massa invariante per il segnale, per il fondo e per il totale dei due
Utilizzare la variabile isHiggs per ottenere le diverse distribuzioni

  • Effettuare un fit alla distribuzione della massa invariante per il fondo, segnale e totale. Che funzione avete utilizzato?. Stimare il numero di eventi
Una volta definite le funzione per il fondo e per il segnale la funzione sul totale sarà la funzione somma delle due. Utilizzate i metodi per settare i parametri per "aiutare" il fit. Potete evidenziare il contributo della funzione del fondo andando a definire una funzione nuova con i parametri stimati dal fit sulla distribuzione totale e graficandola.

//Sia myHisto l'histo totale
//supponiamo che la funzione totale sia la somma di una gaussiana e di un polinomio di primo grado

TF1 * f_totale = new TF1("f_totale","gaus(0) + pol1(3)", 50,200);
//Setting di parametri

myHisto->Fit("f_totale","R");

//Recupero i valori dei parametri per la pol1
Double_t p0 = f_totale->GetParameter(3);
Double_t p1 = f_totale->GetParameter(4);

//Creo una nuova funzione pol1 con i pametri fittati, cambio il colore e la disegno nella stessa canvas
TF1 *fondo = new TF1("fondo", "pol1",50,200);
fondo->SetParameters(p0, p1); //Settati i prametri
fondo->SetLineColor(4); //cambio colore

fondo->Draw("same"); //l'opzione same disegna nella stessa canvas

Alcune info sulla classe vector di C++

La classe vector risulta estremamente più efficiente rispetto agli array. Il tipo del vettore va specificato tra <>. Di seguito alcuni esempi

#include <vector>
int main()
{
 // Un vettore dinamico
 std::vector <double> v_dyna;

 // Un vettore con 10 elementi (inizializzati tutti a 0)
 std::vector <int> vint_10_elements(10);

 // Un vettore con 10 elementi, inizializzati a 90
 std::vector <int> vint_10(10, 90);

 // Un vettore inizializzato con il contenuto di un altro
 std::vector<int> vcopy(vint_10_elements);

 // Un vettore con 5 valori presi da un altro
 std::vector<int> vcopy_5(vint_10.begin(),vint_10.begin()+5);

}

Se voglio inizializzarlo con dei valori iniziali, posso scrivere così:

std::vector<int> v = {1, 2, 3, 4, 5};
//(attenzione: questo tipo di inizializzazione è disponibile solo nel nuovo standard C++11).

Per accedere all’i-esimo elemento, si può fare in diversi modi:

std::cout << v[2] << std::endl; //come negli array
std::cout << v.at(2) << std::endl;

Anche con il vettore, se cercate di accedere un elemento al di fuori della dimensione dell’array, otterrete un errore.

Per aggiungere un elemento ad un vettore basta fare

v.push_back(10);

// per avere la dimensione
std::cout << v.size() << std::endl;

Un loop con i vettori si può fare in diversi modi:

std::vector<int> v = {0, 1, 2, 3, 4, 5};

// ciclo for con iteratori
for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
std::cout << *it << "\n"; //notate che il contenuto del vettore è *it
}


 // iterazione basata su indici
for (int i = 0; i<v.size();i++)
{
std::cout << v.at(i) << "\n"; //si accede all'i-esimo evento
}

Altre info sull'utilizzo dei vector in c++ qui

Edit | Attach | Watch | Print version | History: r8 < r7 < r6 < r5 < r4 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r8 - 2021-04-19 - FrancescoCirotto
 
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    Sandbox All webs login

This site is powered by the TWiki collaboration platform Powered by PerlCopyright &© 2008-2021 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
or Ideas, requests, problems regarding TWiki? use Discourse or Send feedback