{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# An introductional notebook to HEP analysis in C++" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this notebook, you'll explore computing techniques commonly used in High Energy Physics (HEP) analysis. We'll guide you through creating, filling, and plotting a histogram to visualize physics data, such as the number of leptons, all in under 20 lines of code!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This tutorial also serves as an introduction to [ROOT](https://root.cern.ch/), a scientific data analysis framework. ROOT offers a comprehensive set of tools for big data processing, statistical analysis, visualization, and storage—making it useful for modern HEP research." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following analysis is looking at events where [Z bosons](https://en.wikipedia.org/wiki/W_and_Z_bosons) decay to two leptons of same flavour and opposite charge, (e.g., Z → e$^+$e$^-$ or Z → μ$^+$μ$^-$), as shown in the [Feynman diagram](https://en.wikipedia.org/wiki/Feynman_diagram).\n", "\n", "
\n", "\n", "## What is the Z Boson?\n", "\n", "The Z boson is one of the mediators of the weak force, which is responsible for processes such as [beta decay](https://en.wikipedia.org/wiki/Beta_decay) in atomic nuclei. It interacts with all known fermions (quarks and leptons), but unlike the W boson, it does not change the type (flavor) of particle it interacts with. The Z boson couples to both [left-handed and right-handed](https://en.wikipedia.org/wiki/Chirality_(physics)) particles, making its behavior distinct from the charged W boson.\n", "\n", "Since the Z boson is electrically neutral, its decay products must have balanced charges. The decays of the Z boson into leptons (electrons, muons, and taus) are particularly useful for experimental studies because these particles can be precisely measured in detectors, giving a clear signature of the Z boson's presence.\n", "\n", "## The Decay of the Z Boson\n", "The Z boson decays rapidly due to its high mass, with a mean lifetime of around 3 × 10$^{-25}$ seconds. Its decay channels include hadrons (quarks) and leptons, but in this analysis, we are particularly interested in the lepton channels because they produce clean final states that are easier to measure." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Running a Jupyter notebook\n", "A Jupyter notebook consists of cell blocks, each containing lines of Python code. Each cell can be run independently of each other, yielding respective outputs below the cells. Conventionally,cells are run in order from top to bottom.\n", "\n", "- To run the whole notebook, in the top menu click Cell $\\to$ Run All.\n", "- To propagate a change you've made to a piece of code, click Cell $\\to$ Run All Below.\n", "- You can also run a single code cell, by clicking Cell $\\to$ Run Cells, or using the keyboard shortcut Shift+Enter.\n", "\n", "For more information, refer to [How To Use Jupyter Notebooks](https://www.codecademy.com/article/how-to-use-jupyter-notebooks).\n", "\n", "By the end of this notebook you will be able to:\n", "1. Learn to process large data sets using cuts\n", "2. Understand some general principles of a particle physics analysis\n", "3. Discover the Z boson!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Initializing the notebook\n", "To begin, we need to **include several libraries** that will support our analysis:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "#include \n", "#include \n", "#include " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- ``: Provides input/output stream functionalities, such as printing output to the console.\n", "- ``: Enables easy manipulation of strings.\n", "- ``: A standard input/output library that provides functions for reading and writing data, such as `printf`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To enable you **interactive visualization** of the histogram we'll create later, we can use the **JSROOT** magic command. This command activates JSROOT, a JavaScript-based ROOT viewer, allowing you to interact with the plots directly within the notebook. This makes it easier to explore the data by zooming in, rotating, or hovering over specific parts of the plot." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "%jsroot on" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Making a histogram\n", "We begin by opening the data file we wish to analyze. The data is stored in a ***.root*** file, which consists of a tree structure containing branches and leaves. In this example, we are reading the data directly from a remote source:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "// In case xrootd is not available, you can use the first line instead that uses https for file reading:\n", "// TFile *dataFile = TFile::Open(\"https://opendata.cern.ch/eos/opendata/atlas/rucio/opendata/ODEO_FEB2025_v0_1LMET30_mc_700320.Sh_2211_Zee_maxHTpTV2_BFilter.1LMET30.root\");\n", "TFile *dataFile = TFile::Open(\"root://eospublic.cern.ch:1094//eos/opendata/atlas/rucio/opendata//ODEO_FEB2025_v0_1LMET30_mc_700320.Sh_2211_Zee_maxHTpTV2_BFilter.1LMET30.root\");" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, we define a tree (we'll name it ***tree***) to extract the data from the ***.root*** file, from the tree called `analysis`, that holds the data." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "TTree *tree = (TTree*) dataFile->Get(\"analysis\");" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To analyze the dataset, we need to extract specific variables. In this case, we will plot the number of leptons. Here, we bind the lep_n branch to the variable `lepton_n`:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "Int_t lepton_n = -1;\n", "tree->SetBranchAddress(\"lep_n\", &lepton_n);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", " ‼️ NOTE:\n", " To know more about the contents of the ATLAS Open Data datasets, please visit our documentation.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, we create a canvas on which we will draw our histogram. Without a canvas, we won't be able to visualize the histogram. The following command creates a canvas named ***Canvas*** with a title and sets its width and height:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "TCanvas *canvas = new TCanvas(\"Canvas\", \"A first way to plot a variable\", 800, 600);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We also need to define the histogram that will be placed on this canvas. The histogram is named **variable** and its title is **\"Number of leptons\"**. It has 5 bins that span the range from -0.5 to 4.5 (for a total range of 0 to 4 leptons):" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "TH1F *hist = new TH1F(\"variable\",\"Number of leptons; Number of leptons ; Events \",5, -0.5, 4.5);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The next step is to fill the histogram. We use a loop to iterate over all entries in the tree and fill the histogram for each event without applying any cuts, i.e. just copying the data as it is in the source. Once done, the word **\"Done!\"** will be printed:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Done!\n" ] } ], "source": [ "int nentries, nbytes, i;\n", "nentries = (Int_t)tree->GetEntries();\n", "\n", "for (i = 0; i < nentries; i++) {\n", " nbytes = tree->GetEntry(i);\n", " hist->Fill(lepton_n);\n", "}\n", "\n", "std::cout << \"Done!\" << std::endl;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, after filling the histogram, we want to visualize the results. First, we set the fill color of the histogram to red, then we draw it on the canvas, and lastly, display the canvas:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "hist->SetFillColor(kRed);\n", "hist->Draw();\n", "canvas->Draw();\n", "\n", "// If you want a copy of your plot locally, uncomment the following line\n", "// canvas->SaveAs(\"Zll_plot.pdf\"); // pdf image" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Interpreting the histogram\n", "In the plot above, we visualize the distribution of the number of leptons per event. This histogram provides insight into the frequency of events containing different numbers of leptons.\n", "\n", "- **X-axis**: Represents the number of leptons detected in each event. The values range from 0 to 4, where each bin corresponds to an integer number of leptons.\n", "- **Y-axis**: Shows the number of events (scaled to thousands) that contain the corresponding number of leptons.\n", "\n", "From the data:\n", "\n", "- The majority of events contain either 1 or 2 leptons, with the peak occurring at 2 leptons, suggesting that this number of leptons is the most common in the analyzed dataset.\n", "- Events with 0, 3, or 4 leptons are significantly less frequent, as indicated by the lower heights of their corresponding bins.\n", "\n", "In the statistics box on the top right:\n", "\n", "- We see that the total number of events analyzed is 1,550,382.\n", "- The mean number of leptons per event is around 1.68, indicating that most events contain slightly fewer than 2 leptons on average.\n", "- The standard deviation of around 0.5839 shows a relatively low spread, meaning that most events are clustered around the mean number of leptons, with little variation.\n", "\n", "This histogram gives us a snapshot of the lepton content in the events, which can be further analyzed to study processes like lepton production in proton-proton collisions at high energies. The distribution is an important aspect of understanding the data and may inform further cuts or selection criteria for a complex physics analysis.\n", "\n", "In this example, as always, it is a good idea to see if the result matches your intuition. Here we began with a sample of Z bosons decaying to electrons, so it makes good sense that most events contain exactly two electrons. Can you think of some reasons why there might be only one or three in some events? The file we selected has **1LMET30** in the name, meaning that the events in it were pre-selected to have at least one lepton. That also helps explain why there are no zero-electron events. If you would like, you can try picking a file from a [different sample](https://opendata.atlas.cern/docs/data/for_education/13TeV25_metadata) to see how the result changes." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "@webio": { "lastCommId": null, "lastKernelId": null }, "kernelspec": { "display_name": "ROOT C++", "language": "c++", "name": "root" }, "language_info": { "codemirror_mode": "text/x-c++src", "file_extension": ".C", "mimetype": " text/x-c++src", "name": "c++" } }, "nbformat": 4, "nbformat_minor": 4 }