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