Skip to content

Instantly share code, notes, and snippets.

@xaratustrah
Last active July 15, 2022 12:52
Show Gist options
  • Save xaratustrah/474404d56b7664ab6ad2f8130eb1331e to your computer and use it in GitHub Desktop.
Save xaratustrah/474404d56b7664ab6ad2f8130eb1331e to your computer and use it in GitHub Desktop.

CERN ROOT: Converting C/C++ examples to Python

What is ROOT?

ROOT is a popular data analysis framework developed at CERN based on C/C++ programming language. Historically it played a crucial role for the data analysis at CERN and also around the world and it is still being used in many many experiments.

At the first glance, from the programming point of view and considering modern methods and analysis frameworks, there might not be enough justification to continue using ROOT except for very large scale experiments. Almost all of ROOTs features are already available as standard Python functions or in its libraries such as numpy and scipy. So among the many features inside of the ROOT library, some of them come out as really handy and can be used in Python with more comfort. These include the histogram objects TH1 and TH2, but also TGraph, TFile and many available fitting algorithms. TBrowser which also has a web version, allows for viewing different graphs and histograms and specifically using the Fit Panel.

In general ROOT is sometimes a bit more comfortable and hence enjoys a huge popularity in the high energy and particle physics and generally science communities. The code developement is very active with a very good documentation there is a nice support forum where people can get help.

So why not use ROOT inside Python?

What is PyROOT

Many thanks to the PyROOT interface, the whole ROOT functionality can be imported to Python just by using an import call, as if you are importing just another Python library.

Installing ROOT

The easiest way to install ROOT is using Anaconda, as described in this article. In summary, after setting up Anaconda, just create a ROOT env by using this command:

conda create -n my_root_env root -c conda-forge

then you can activate your environment by:

conda activate my_root_env

Converting examples

There are many examples on the internet which show how to use ROOT, but these are mainly written in C/C++. In fact the PyROOT interface makes it easy to use the same commands inside PyROOT. In order to achieve this, one might need to "clean-up" the C++ code and make a Python code out of it. In fact this can be done with little effort, as the following example shows:

This example is taken from here:

#include <TCanvas.h>
#include <TCutG.h>
#include <TH2F.h>
#include <TProfile.h>
#include <TRandom.h>
 
void fit2d()
{
   // generate a 2-d histogram using a TCutG
   const int n = 6;
   float x[n] = {0.092,0.83,0.94,0.81,0.12,0.1};
   float y[n] = {0.71,9.4,9,8,0.3,0.71};
   TCutG *cut = new TCutG("cut",n,x,y);
   TH2F *h2 = new TH2F("h2","h2",40,0,1,40,0,10);
   float u,v;
   for (int i=0;i<100000;i++) {
      u = gRandom->Rndm();
      v = 10*gRandom->Rndm();
      if (cut->IsInside(u,v)) h2->Fill(u,v);
   }
   TCanvas *c1 = new TCanvas("c1","show profile",600,900);
   c1->Divide(1,2);
   c1->cd(1);
   h2->Draw();
   c1->cd(2);
 
   //use a TProfile to convert the 2-d to 1-d problem
   TProfile *prof = h2->ProfileX();
   prof->Fit("pol1");
}

Now in order to make a Python code out of this, just remove the typical C/C++ code style, like semicolons, brackets, etc... the rest stays the same as the C/C++ code. Here is how the resulting code looks like:

from ROOT import TCanvas, TCutG, TH2F, TProfile, gRandom
import numpy as np

def fit2d():
   # generate a 2-d histogram using a TCutG
   n = 6
   x = np.array([0.092,0.83,0.94,0.81,0.12,0.1])
   y = np.array([0.71,9.4,9,8,0.3,0.71])
   cut = TCutG("cut",n,x,y)
   h2 = TH2F("h2","h2",40,0,1,40,0,10)

   for i in range(100000):
      u = gRandom.Rndm()
      v = 10*gRandom.Rndm()
      if cut.IsInside(u,v):
         h2.Fill(u,v)

   c1 = TCanvas("c1","show profile",600,900)
   c1.Divide(1,2)
   c1.cd(1)
   h2.Draw()
   c1.cd(2)

   # use a TProfile to convert the 2-d to 1-d problem
   prof = h2.ProfileX()
   prof.Fit("pol1")

Note that here we additionally imported numpy to add the functionality of ndarrays. Also, instead of importing TRandom, we are importing gRandom directly. This is a typical change from C/C++ ROOT to PyROOT. Finally you may notice, that in the original C/C++ code the actual call for making the plot c1->Drtaw(); is missing. This should be done by hand in ROOT's CINT interface, or in the Python code in form of c1.Draw(). The results can be seen in the picture in this gist.

Even more pythonic?

In the example above you can see that the function fit2d itself is actually not needed. So you can remove it and make a flatter code. Also, you may notice that the module gRandom is used. Actually this is also not really needed, as you can use python's own random generators, such as the random module inside of the numpy module.

BTW, it is a matter of taste in the Python world, to use single quotes rather than double quotes. But your code will probably be judged as more pythonic if you use single quotes for strings.

Here is the more pythonic code:

from ROOT import TCanvas, TCutG, TH2F, TProfile
import numpy as np

# generate a 2-d histogram using a TCutG

x = np.array([0.092,0.83,0.94,0.81,0.12,0.1])
y = np.array([0.71,9.4,9,8,0.3,0.71])
cut = TCutG('cut',len(x),x,y)
h2 = TH2F('h2','h2',40,0,1,40,0,10)

for i in range(100000):
   u = np.random.random()
   v = 10 * np.random.random()
   if cut.IsInside(u,v):
      h2.Fill(u,v)

c1 = TCanvas('c1','show profile',600,900)
c1.Divide(1,2)

c1.cd(1)
h2.Draw('')

c1.cd(2)
# use a TProfile to convert the 2-d to 1-d problem
prof = h2.ProfileX()
prof.Fit('pol1')

c1.Draw()

Similarly, many other features, like the above TCutG can be eliminated and replaced by pure python functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment