Alcuni approcci all’analisi dati
(tra CMSSW e ROOT)
Massimo Nespolo
Riunione mensile di software e analisi, 15/12/2008
1
Alcuni approcci all’analisi dati
(tra CMSSW e ROOT)
Sommario:
• Dalle root-uple all’EDM di CMS:
– Motivazione;
– Confronto critico;
• Nella pratica:
– Grafici immediati;
– Approccio uniforme;
• Soluzione “definitiva”:
– TFWLiteSelector.
2
Il problema
L’analisi viene effettuata parte in
CMSSW e parte in ROOT
L’analisi in ROOT deve essere il
piu’ possibile “agile”
Bisogna far comunicare i due
framework
ROOT opera su alberi, ma non
impone l’organizzazione dei dati
Necessità di avere un formato dati che faccia da ponte,
ma che sia insieme facile da manipolare e da interpretare
3
Prima idea: Ntupla
Utilizziamo i costrutti di base del C++ (arrays,
puntatori, tipi base) e di ROOT (TTree, TBranches)
TTree* anaTree = new TTree("events", "analysis tree" );
const int Nmus = 100;
float* ptmu = new float[Nmus];
int Nmuons = 0;
anaTree->Branch("ptmu", ptmu, "ptmu[Nmuons]/F" );
Otteniamo l’obbiettivo: un file per l’analisi in ROOT
ma
Ci siamo appiattiti sul minimo comune a CMSSW e ROOT !
4
Semplicità solo apparente
Estremamente incline all’errore (riservato ai piu’ esperti)
1. Spesso nessun delete[].
2. Rischio di sforare il limite
dell’array.
3. Impossibile il type-cheking
a tempo di compilazione.
1. Memory leaks.
2. Errore a run-time con morte
del programma.
3. Si perdono i vantaggi del
controllo forte sui tipi.
Ci siamo dimenticati (come spesso succede) che il C++ e’ un linguaggio
“a due livelli” (Carlo Pescio, C++ Informer 12, ottobre 2000):
Iniziamo cosi' a capire la natura "a due livelli" del C++, (…): il C++ offre
un supporto nativo low-level per costruire astrazioni di piu' alto livello.
Il programmatore dovrebbe lavorare con queste astrazioni, costruendole
quando servono, e non lavorare costantemente al livello nativo.
5
Destrutturazione dell’evento
La Ntupla costituisce una rappresentazione
“piatta” (flat) dell’evento, senza sotto-strutture
Vantaggio per pochi dati,
immediatamente visibili
Vi sono raggruppamenti “logici”
di alcune variabili (prefissi)
Mostra velocemente i suoi limiti al
crescere del numero delle varibili
Dovrebbero essere ottenuti tramite
le strutture (branches) di ROOT
6
Seconda idea: classi custom (adapter)
Ambedue i problemi che abbiamo visto possono essere
risolti ricorrendo ad opportune astrazioni
Scrivere delle classi, che incapsulino i dettagli
Idea subito abbandonata (fortunatamente), poiché:
1. Numerose (una per ogni classe di CMSSW).
2. Per loro stessa natura instabili, modificate spesso.
3. Non standard, cosa che si cerca di evitare.
7
EDM dentro ROOT
Tutti i files di CMS sono in realtà files di ROOT,
con una struttura gerarchica “naturale”
1. A ciascuna collezione corrisponde un ramo.
2. A ciascuna variabile corrisponde una foglia.
3. Esistono alias compatti e standardizzati.
E’ sempre possibile fare
un’analisi “tipo rootupla”,
a partire da ogni file di CMSSW
Dal prompt o tramite le classi
generate da MakeClass e
(meglio) da MakeSelector
Abbiamo solo bisogno di un sistema che ci isoli dalle variabili
private, per loro stessa natura soggette a cambiamento...
8
FWLite
Libreria (sottinsieme del FrameWork CMSSW) che
consente di interpretare il contenuto dei files di CMS
In pratica…
gSystem->Load("libFWCoreFWLite");
AutoLibraryLoader::enable();
gSystem->Load("libDataFormatsFWLite");
TFile file(“rootFile.root" );
A questo punto, abbiamo acceso diretto alla struttura
gerarchica definita dall’EDM di CMS, ma soprattutto
alle funzioni che costituiscono l’interfaccia delle classi.
9
Un esempio grafico…
10
… e due esempi dal prompt
Events->Draw("IC5CaloJet.theta():IC5CaloJet.phi()", "", "LEGO2 CYL")
Events->Draw("Muons.pt():Muons.isolationR03().sumPt/Muons.pt()",
"Muons.pt()<100")
11
Vantaggi
E’ possibile visualizzare il
contenuto di ogni file, così come
produrre istogrammi e matrici
Non dipendiamo dalla
traduzione operata da una
classe di tipo EDAnalyzer
Tutte le proprietà degli oggetti
che stiamo analizzando sono
sempre disponibili
Non devo ripassare per
CMSSW se mi serve una
nuova variabile
Il codice è sostanzialmente
identico a quello che utilizziamo
in CMSSW: nomi delle classi,
delle funzioni, degli alias…
Una volta capito l’EDM,
possiamo concentrarci
sull’obbiettivo dell’analisi
12
Aggiungere dati all’evento
Se il prodotto è relativamente
“stabile”
Scriviamo un EDProducer
(non un EDAnalyzer)
Se e’ una cosa che cambia spesso
(tipo la massa invariante calcolata
per diversi tagli)
Lavoriamo in ROOT, e
salviamo il prodotto in un
albero friend
I due approcci non sono mutualmente esclusivi:
il concetto di albero friend si applica al momento in cui i files
vengono aperti per l’analisi in ROOT
13
fwlite::Event
Event loop esplicito, ma astrazione dai dettagli dei Branches
TFile file(“rootFile.root");
fwlite::Event ev(&file);
for( ev.toBegin(); ! ev.atEnd(); ++ev) { //sort of iterator
fwlite::Handle<std::vector<reco::Muon> > muons;
muons.getByLabel(ev,“Muons");
//now we can access data
}
1. fwlite::Handle muons;
2. muons.getByLabel(ev, “Muons”)
1. edm::Handle muons;
2. ev.getByLabel( “Muons”, muons)
14
Un esempio: la Z
Rosso: pt > 20 GeV e 2 muoni
Rosso: pt > 20 GeV
15
TFWLiteSelector
TFWLiteSelector eredita da TSelector
1. Impone di separare Begin/Process/Terminate.
2. Nessun loop esplicito (gestito internamente).
3. Supporta il parallelismo tramite PROOF.
Differenza fondamentale rispetto a fwlite::Event
Alla funzione Process viene
passato edm::Event, non
fwlite::Event
Il codice di analisi è
identico (non solo simile) a
quello dell’EDAnalyzer
16
TFWLiteSelector: in pratica
Isoliamo l’algoritmo di
analisi in una classe (o una
struct) a parte
class MyAnalysisAlgorithm
{
public:
void process( const edm::Event & );
void postProcess( TList & );
void terminate( TList & );
};
Creiamo un’istanza di TFWLiteSelector
passando l’algoritmo come template
TFile file(“rootFile.root");
TSelector* mysel = new TFWLiteSelector<MyAnalysisAlgorithm>
Events->Process( mysel );
17
TFWLiteSelector ed EDAnalyzer
Lo stesso algoritmo può essere eseguito in CMSSW
Basta scrivere un EDAnalyzer
molto semplice e standard
(pattern Adapter, GoF)
L’algoritmo visto prima
diventa un membro privato
della classe EDAnalyzer
void MyAnalyzer::analyze(const edm::Event& ev, const edm::EventSetup& )
{
algo_.process( ev );
}
Soluzione ottima, ma non aggiornata al formato di CMSSW 2_1_X
18
In sintesi…
• Il C++ è un linguaggio “a due livelli”:
– Le classi devono rappresentare elementi del problema.
– Vantaggi programmazione Object-based (non ancora
Object-oriented, di cui non abbiamo parlato).
• FWLite:
– Accesso completo dell’EDM di CMS.
• TFWLiteSelector:
– Analisi “ordinata” e parallelizzabile.
– Possibilità di muovere il codice da ROOT a CMSSW.
• Analisi agili a partire da ogni file di CMS:
– Interpretare i risultati è già abbastanza complicato…
19