Grundlagen der fortgeschrittenen Teilchenphysik-Analyse

Technisches setup

Für dieses Tutorial braucht ihr ssh oder X2GO Zugriff auf die Maschinen in Garching. Falls ihr im VPN seid sollte der Zugriff über <rechner-name>.garching.physik.uni-muenchen.de funktionieren. Ohne VPN kann man über den login server mit -J (ProxyJump) verbinden, z.B. (etpXY durch zutreffendes ersetzen)

ssh -XY -J <Benutzername>@gar-sv-login01.garching.physik.uni-muenchen.de <Benutzername>@gar-ws-etpXY.garching.physik.uni-muenchen.de

Oder entsprechend in ~/.ssh/config konfigurieren

Host gar-ws-etp*
    User <Benutzername>
    ProxyJump <Benutzername>@gar-sv-login01.garching.physik.uni-muenchen.de
    ForwardX11 yes
    ForwardX11Trusted yes

Und dann mit ssh gar-ws-etpXY verbinden (2x Passwort eingeben). In X2GO gibt es die Option "Use Proxy Server for SSH connection":

ETP-Wiki

https://wiki.physik.uni-muenchen.de/etp/index.php/Main_Page

Die typische Teilchenphysik-Analyse

Software Framework I

Software Framework II

Wo läuft Analyse-Software

Generelle Vorgehensweise von Datenanalyse I

Prinzipielle Idee der meisten Frameworks

Generelle Vorgehensweise von Datenanalyse II

bool Analysis::initialize(){
  ...
  std::cout << "Number of total events: " << n_events << std::endl;
  ...
  return true;
}
bool Analysis::execute(){
  ...
  my_histogram->Fill(muon_pt);
  ...
  return true;
}
bool Analysis::finalize(){
  ...
  my_histogram->Write();
  ...
  return true;
}

Datenformate: Zwei Ansätze

Um eine aufgenommene Teilchenkollision zu beschreiben werden bei ATLAS grob zwei Methoden verwendet

- NTupels

- Objekt-orientierte Datenformate

NTuples

Beispiel: Um N Myonen eines Events zu beschreiben sind muon_px, muon_py, muon_pz, muon_E Listen von je N doubles.

muon_py[3] // ist die Impulskomponente in y-Richtung des 4. Myons.

Tipps und Tricks zu scripts mit TTree::Draw

Dokumentation

TTree::Draw unterstützt eine ganze Reihe von Ausdrücken. Die Dokumentation im ROOT Reference Guide ist relativ ausführlich

https://root.cern/doc/master/classTTree.html#a73450649dc6e54b5b94516c468523e45

TDirectory

Um ein Histogramm mit TTree::Draw zu füllen muss es dem gleichen TDirectory zugeordnet sein wie der TTree. Das geschieht automatisch wenn das Histogramm erstellt wird nachdem ein TFile geöffnet wurde

rootfile = ROOT.TFile.Open(filename)
tree = rootfile.Get(treename)
hist = ROOT.TH1F(histname, title, nbins, xmin, xmax)

Nach dem Befüllen kann dann das assoziierte Directory auf 0 gesetzt werden, sofern das Histogramm nicht in einer ROOT Datei gespeichert werden soll. Andernfalls wird das Histogramm gelöscht wenn TFile::Close aufgerufen wird!

hist.SetDirectory(0)

Nicht-interaktiv

Um TTree::Draw nicht-interaktiv zu verwenden (kein erstellen von TCanvas beim Aufruf) kann TTree::Project oder die option "goff" verwendet werden

tree.Draw("{}>>{}".format(expr, histname), cut, "goff")

Gewichtete Ereignisse

TTree::Draw akzeptiert ein Argument cut mit dem zugleich eine Selektion und auch eine Gewichtung mitgegeben werden kann (Ereignisse mit Gewicht 0 füllen das Histogramm nicht).

tree.Draw("lep_pt[0]>>myhist", "(lep_n<2)*(mcWeight)", "goff")

Der Standardabweichung einer gewichteten Summe einer poissonverteilten Anzahl Ereignisse lässt sich über \(\sqrt{\sum w_i^2}\) abschätzen. Damit ROOT diese Summe der quadrierten Gewichte pro Bin speichert wird vor dem Füllen des Histogramms folgender Aufruf benötigt

hist.Sumw2()

Kleine Übung: TTree::Draw in einem python script

Ein kleines Beispiel:

cp /project/etp3/bachelorkurs2019/fill_hist.py .
./fill_hist.py
evince plot.pdf

Für kompliziertere Plots könnt ihr in der Regel auf fertigen Code zurückgreifen der für die jeweiligen Analysen entwickelt wurde (bekommt ihr von euren Betreuern). Ein etwas allgemeineres Framework für einige "Standardplots" mit Ntuples ist MPF:

Code
Dokumentation

Objekt-Orientierte Datenformate, speziell xAOD

muons // Liste von Myonen
muons->at(3) // 4. Myon
muons->at(3)->p4() // 4er Vektor des 4. Myons
muons->at(3)->p4().Py() // Impulskomponente in y-Richtung des 4. Myons

Beispiele von xAOD Datentypen

xAOD::MuonContainer *muons // Liste aller Myonen im Event
xAOD::Muon *mu = muon->at(0); // einzelnes Myon, gepickt aus der Liste
xAOD::ElectronContainer, xAOD::Electron, xAOD::JetContainer, xAOD::Jet, ...
xAOD::EventInfo // Metainformationen über das Event, ob Simulation oder Daten, Eventnummer, ...

Eine volle Liste aller Objekte in einem xAOD gibt checkxAOD.py (in der später aufgesetzten Umgebung)

checkxAOD.py /project/etp3/bachelorkurs2019/xAODs/mc16_13TeV_Wmunu/DAOD_SUSY5.16135178._000014.pool.root.1

ATLAS Software Umgebung

Nach Eingabe von

source /project/etpsw/Common/bin/setup_image.sh

kann man mit folgendem Befehl in eine CentOS 7 Umgebung wechseln

centos7

In dieser kann man dann die ATLAS Software Umgebung von CVMFS aufsetzen

export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase
alias setupATLAS='source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh'

setupATLAS

Um sich das Leben einfacher zu machen kann man sich diese 3 Zeilen auch in "~/.bashrc" schreiben

source /project/etpsw/Common/bin/setup_image.sh
export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase
alias setupATLAS='source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh'

dann hat man centos7 und setupATLAS in jeder neuen Konsole zur Verfügung.

CVMFS

Netzwerk-Dateisystem, das unsere spezielle ATLAS-Software bereitstellt (ROOT, Athena, ...)

Ausführen des Befehls auf der vorherigen Folie:

centos7 # (falls noch nicht in einer CentOS Umgebung)
setupATLAS

Zeigt eine Übersicht zum Aufsetzen einzelner Pakete an.

Zum Beispiel um ROOT aufzusetzen

lsetup root

ACM (asetup und CMake)

Aufsetzen einer bestimmten Version von AnalysisBase

acmSetup AnalysisBase,21.2.116

Umgebung wieder-aufsetzen (im "build" Verzeichnis, siehe nächste Seite)

acmSetup

Alles Kompilierte löschen, sauberer Neuanfang

acm clean

Lokale Pakete finden

acm find_packages

Kompilieren

acm compile

Kleine xAOD Analyse: Umgebung aufsetzen

# In ein temporäres verzeichnis wechseln (nur für dieses Tutorial)
TEMPDIR=$(mktemp -d /tmp/$(id -un)_XXXX)
cd $TEMPDIR

# Sofern nicht in "~/.bashrc"
source /project/etpsw/Common/bin/setup_image.sh

# Falls noch nicht in centos7 Umgebung
centos7

# Sofern nicht in "~/.bashrc"
export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase
alias setupATLAS='source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh'

# ATLAS Software von CVMFS aufsetzen
setupATLAS

# Analyse Skelett herkopieren und in build Verzeichnis wechseln
cp -r /project/etp3/bachelorkurs2020/ROOTAnalysisTutorial .
cd ROOTAnalysisTutorial/build

# AnalysisBase aufsetzen und CMake ausführen
acmSetup AnalysisBase,21.2.116

Wenn alles gut gegangen ist, sollte erscheinen:

ACM Setup complete. Use acm help to get started.

Erste Kompilierung

In der selben Konsole

acm compile

Erfolg wenn letzte Zeile lautet

[100%] Built target Package_MyAnalysis

Code ausführen mittels (in einem dediziertem "run" Verzeichnis)

cd ../run
runAnalysis.py /project/etp3/bachelorkurs2020/xAODs/mc16_13TeV_Wmunu/DAOD_SUSY5.16135178._000014.pool.root.1

Ergebnisse werden in submitDir gespeichert

ls submitDir

Dieses Verzeichnis wird bei jedem Ausführen von runAnalysis.py überschrieben. Sofern Ergebnisse behalten werden sollen müssen wir sie woanders hin tun:

mv submitDir results-data

Intermezzo: Text editieren

Falls ihr mit x2go eingeloggt seid (oder lokal angemeldet) könnt ihr in in einer NEUEN Konsole (die CentOS Umgebung hat relativ wenig extra Programme) einen Texteditor (z.B. kate) öffnen

# temporäres Verzeichnis suchen
ls -d /tmp/$(id -un)*

# Verzeichnis betreten
cd <pfad-zu-temporärem-verzeichnis>/ROOTAnalysisTutorial/source

# Dateien mit kate öffnen
kate MyAnalysis/Root/MyxAODAnalysis.cxx \
  MyAnalysis/MyAnalysis/MyxAODAnalysis.h \
  MyAnalysis/CMakeLists.txt \
  MyAnalysis/share/runAnalysis.py

Alternative 1: sshfs

Falls ihr auf Linux oder macOS arbeitet und dort bereits einen Texteditor installiert habt könnt ihr mit Hilfe von sshfs (sollte in den meisten Distributionen mit dem Paketmanager installierbar sein) das Arbeitsverzeichnis auf eurem lokalen Rechner mounten und die Dateien mit dem lokalen Texteditor editieren. Z.B.

# (das lokale verzeichnis sollte leer sein)
sshfs -o ssh_command="ssh -J <Benutzername>@gar-sv-login01.garching.physik.uni-muenchen.de" \
    <Benutzername>@<remote-workstation>:<pfad-zu-remote-verzeichnis> <pfad-zu-lokalem-verzeichnis>

Das lokale Verzeichnis sollte leer sein. Nach dem Aufruf von sshfs solltet ihr darin den Inhalt des Remote Verzeichnisses sehen können. remote-workstation ist der Name eures Arbeitsrechners z.B. gar-ws-etp01. Falls ihr direkt auf dem login server arbeitet (nicht dauerhaft zu empfehlen, aber fürs Tutorial ok) oder ein Verzeichnis mounten wollt dass auf dem login server verfügbar ist könnt ihr direkt über den login server mounten:

sshfs <Benutzername>@gar-sv-login01.garching.physik.uni-muenchen.de:<pfad-zu-remote-verzeichnis> <pfad-zu-lokalem-verzeichnis>

Alternative 2: vim oder andere textbasierte Editoren

Falls ihr mit vim vertraut seid könnt ihr diesen Editor auch direkt in der ssh Konsole ausführen (ist sowohl auf dem Rechner als auch in der centos7 Umgebung installiert). Alternative gibt es (in der Ubuntu Umbgebung) emacs und nano.

Überblick über die Dateien

Daten lesen

Wir werden uns hier auf Myonen beschränken, da diese ohne viel Aufwand eine saubere Signatur liefern

Für Myonen wird das Paket xAODMuon benötigt, d.h. wir müssen es in MyAnalysis/CMakeLists.txt nach LINK_LIBRARIES AnaAlgorithmLib hinzufügen:

LINK_LIBRARIES AnaAlgorithmLib xAODMuon

und in MyAnalysis/MyxAODAnalysis.cxx das folgende Include Statement am Anfang der Datei:

#include "xAODMuon/MuonContainer.h"

In MyAnalysis/MyxAODAnalysis.cxx, Funktion StatusCode MyxAODAnalysis :: execute ():

    const xAOD::MuonContainer* muons = 0;
    evtStore()->retrieve( muons, "Muons" );
    Info("execute", "Anzahl Myonen: %ld", muons->size());

    for (const xAOD::Muon* muon: *muons) {
        // Grössen wie Energie und Impuls werden konventionell in MeV gespeichert -> Umrechnung in GeV
        Info("execute()", "  Originaler Myon pt = %.3f GeV", (muon->pt() * 0.001));
    }

Warnung: Info() Funktion erzeugt hierbei SEHR viel Output, nur für Testzwecke sinnvoll!

Nach jeder Änderung am Code ist es notwendig erneut zu kompilieren:

acm compile

runAnalysis.py /project/etp3/bachelorkurs2020/xAODs/mc16_13TeV_Wmunu/DAOD_SUSY5.16135178._000014.pool.root.1

# Abbrechen mit Strg+c

Histogramme

Eventloop übernimmt einen Grossteil des Output Managements, das einzige was zu tun ist ist am Anfang von MyxAODAnalysis.cxx den ROOT Histogram Header zu inkludieren:

#include <TH1F.h>

Wir können nun Gebrauch von der book und hist Funktion in Eventloop machen um Histogramme zu initialisieren und zu befüllen. Um z.B. ein Histogramm für den Myon Impuls zu erzeugen müssen wir book in initialize () aufrufen.

In MyAnalysis/MyxAODAnalysis.cxx, Funktion StatusCode MyxAODAnalysis :: initialize ():

    book(TH1F("h_muon_pt", "Transverser Myon Impuls", 100, 0, 100));

In der Schleife über die Myonen können wir nun das Histogramm befüllen, welches wir mit hist aufrufen mit dem Namen "h_muon_pt" den wir bei book vorher benutzt haben.

In MyAnalysis/MyxAODAnalysis.cxx, Funktion StatusCode MyxAODAnalysis :: execute ():

    for (const xAOD::Muon* muon: *muons) {
        // Grössen wie Energie und Impuls werden konventionell in MeV gespeichert -> Umrechnung in GeV
        Info("execute()", "  Originaler Myon pt = %.3f GeV", (muon->pt() * 0.001));

        // Histogram befüllen
        hist("h_muon_pt")->Fill(muon->pt() * 0.001 );
    }

Kompilieren und Code ausführen:

acm compile
runAnalysis.py /project/etp3/bachelorkurs2019/xAODs/mc16_13TeV_Wmunu/DAOD_SUSY5.16135178._000014.pool.root.1

Jetzt sollte das Histogramm in dem Output submitDir/hist-xAOD.root sein. Mit ROOT öffnen, und mit TBrowser ansehen:

rootbrowse submitDir/hist-xAOD.root

Physik!

Interessante Messgrössen für Ereignisse mit Zwei Myonen sind unter Anderem die invariante Masse des Zwei-Myon-Systems und der Öffnungswinkel zwischen den Myonen.

In MyAnalysis/MyxAODAnalysis.cxx, Funktion StatusCode MyxAODAnalysis :: execute ():

    if (muons->size() == 2) { // falls wir genau 2 Myonen haben
        const xAOD::Muon *mu1 = muons->at(0); // Numerierung fängt bei 0 an!
        const xAOD::Muon *mu2 = muons->at(1);

        TLorentzVector dimuon = mu1->p4() + mu2->p4();
        double Mll = dimuon.M() *0.001;  // umrechnen von MeV in GeV
        Info("execute()", "Die Dimuon-Masse ist %.2f GeV", Mll);

        double dphi = fabs(mu1->p4().DeltaPhi(mu2->p4()));
        Info("execute()", "Der Öffnungswinkel ist %.2f Rad", dphi);
    }

Aufgaben

Event-Typ: Daten oder Simulation

In MyAnalysis/CMakeLists.txt:

LINK_LIBRARIES AnaAlgorithmLib xAODMuon xAODEventInfo

In MyAnalysis/MyxAODAnalysis.cxx:

#include "xAODEventInfo/EventInfo.h"

In MyAnalysis/MyxAODAnalysis.cxx, Funktion StatusCode MyxAODAnalysis :: execute () (am besten vor der Myonenschleife):

    bool isMC = false;  // wir nehmen an es ist keine Simulation
    const xAOD::EventInfo* eventInfo = 0;
    evtStore()->retrieve( eventInfo, "EventInfo");  // wir laden das EventInfo Objekt
    if(eventInfo->eventType( xAOD::EventInfo::IS_SIMULATION ) ){
        isMC = true;  // falls es doch Simulation ist, setzen wir isMC auf wahr
    }

Myon Kalibrierung

In simulierten Daten müssen Myonen kalibriert werden, wofür wir das offizielle ATLAS Tool MuonCalibrationAndSmearingTool benutzen. Dazu benutzen wir die Pakete AsgAnalysisInterfaces und MuonAnalysisInterfacesLib.

In MyAnalysis/CMakeLists.txt:

LINK_LIBRARIES AnaAlgorithmLib xAODMuon xAODEventInfo AsgAnalysisInterfaces MuonAnalysisInterfacesLib

In MyAnalysis/MyxAODAnalysis.h:

#include <AsgTools/AnaToolHandle.h>
#include <MuonAnalysisInterfaces/IMuonCalibrationAndSmearingTool.h>

ToolHandle deklarieren in MyAnalysis/MyxAODAnalysis.h, unter public::

    // MuonCalibrationAndSmearing
    asg::AnaToolHandle<CP::IMuonCalibrationAndSmearingTool> m_muonCalibrationAndSmearingTool; //!

Hinweis: //! ist aus technischen Gründen notwendig!

Das Tool selber soll erst erzeugt werden wenn der Algorithmus erstellt wird. Also schreiben wir eine entsprechende Zeile in die Initializer Liste des Konstruktors in MyAnalysis/MyxAODAnalysis.cxx (am Anfang der Datei, unter den Include Statements). Dieser sollte hinterher so aussehen:

MyxAODAnalysis :: MyxAODAnalysis (const std::string& name, ISvcLocator *pSvcLocator) :
    EL::AnaAlgorithm (name, pSvcLocator),
    m_muonCalibrationAndSmearingTool ("CP::MuonCalibrationAndSmearingTool/MuonCorrectionTool",this)
{
    // Here you put any code for the base initialization of variables,
    // e.g. initialize all pointers to 0. Note that things like resetting
    // statistics variables should rather go into the initialize() function.
}

In MyAnalysis/MyxAODAnalysis.cxx, Funktion StatusCode MyxAODAnalysis :: initialize () (direkt unterhalb der Histogram Initialisierung):

    m_muonCalibrationAndSmearingTool.initialize();

Wir brauchen eine veränderbare Kopie unserer Myonen ("Shallow Copy"). Danach laufen wir über die Myonen und wenden die Kalibrierung an, sofern es sich um MC Ereignisse handelt.

In MyAnalysis/MyxAODAnalysis.cxx:

#include <xAODCore/ShallowAuxContainer.h>
#include <xAODCore/ShallowCopy.h>

In MyAnalysis/MyxAODAnalysis.cxx, Funktion StatusCode MyxAODAnalysis :: execute ():

    // Eine "shallow copy" vom Myon Container erstellen
    auto muons_shallowCopy = xAOD::shallowCopyContainer( *muons );
    std::unique_ptr<xAOD::MuonContainer> muonsSC (muons_shallowCopy.first);
    std::unique_ptr<xAOD::ShallowAuxContainer> muonsAuxSC (muons_shallowCopy.second);

    // Über die Kopien iterieren
    for (xAOD::Muon* muonSC : *muonsSC) {
        if (isMC) {
            // Kalibrierung anwenden
            m_muonCalibrationAndSmearingTool->applyCorrection(*muonSC);
            Info("execute()", "  Korrigierter Myon pt = %.5f GeV", (muonSC->pt() * 0.001));
        }
    }

Kompilieren und ausführen:

acm compile

runAnalysis.py /project/etp3/bachelorkurs2019/xAODs/mc16_13TeV_Zmumu/DAOD_HIGG3D1.15802786._001411.pool.root.1